From 84055a25de25c7b5a9cce2151b0e5e4f250ce7d9 Mon Sep 17 00:00:00 2001 From: Hanzo_dev <2002samudiojohan@gmail.com> Date: Wed, 25 Feb 2026 21:49:26 -0500 Subject: [PATCH] refactor: migrate fully to Supabase, remove Firebase/Render/Python backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DELETED: entire backend/ (Python/FastAPI — replaced by Supabase) - DELETED: old/ directory (obsolete code) - DELETED: render.yaml, inject_api.py, check_tags.py, PENDING_FOR_TOMORROW.md - DELETED: frontend/src/firebaseConfig.ts (Firebase Auth replaced by Supabase Auth) - DELETED: frontend/src/services/apiClient.ts (HTTP client for dead backend) - MIGRATED services to Supabase native: schedulesService, favoritesService, usersService, telemetryService (stub), reportsService, analyticsService (stub) - MIGRATED stores/favorites.ts to Supabase direct queries - MIGRATED views: SplashScreen, AdminTaxis, AdminDrivers, StrategicAnalytics - MIGRATED utils/imageUrl.ts to Supabase Storage URLs - FIXED router/index.ts: guard now uses supabase.auth.getSession() instead of old localStorage auth_token (fixes logout + map loading) - FIXED AuthView.vue: removed aggressive watch({ immediate: true }) that caused wrong redirects on map route - FIXED SplashScreen.vue: navigate() now reads Supabase session + role - FIXED RLS: added INSERT policy on public.users for trigger - CONFIRMED: admin@sibu.com assigned ADMIN role in Supabase --- PENDING_FOR_TOMORROW.md | 24 - backend/.env.development | 6 - backend/Dockerfile | 43 - backend/alembic.ini | 92 - backend/alembic/env.py | 95 - backend/alembic/script.py.mako | 27 - .../2088667c3a5f_add_search_indexes.py | 32 - .../versions/2f4936eb86f0_initial_schema.py | 88 - .../3fe72cd3f722_sync_shuttle_fields.py | 46 - .../versions/414da6754b1e_add_user_roles.py | 57 - .../4c9211307d7a_add_user_profile_photo.py | 31 - ...4d_add_speaks_english_to_driver_profile.py | 40 - .../versions/8a5661aac24b_add_user_coupons.py | 44 - ...0a3e67_add_is_published_to_bus_schedule.py | 33 - ...54da1a687_add_coupons_and_promoter_role.py | 54 - ...4b4cb57c6c1_add_social_media_to_coupons.py | 32 - .../9f2fbe81a055_add_area_to_business.py | 32 - ...a1b2c3d4e5f6_merge_heads_and_fix_routes.py | 38 - ...d432f0_add_average_speed_and_stop_delay.py | 33 - ...bb5c406b9af5_add_stop_order_to_bus_stop.py | 31 - ...8628a640b6_add_taxi_and_favorite_models.py | 64 - .../c9bb64354775_add_business_coords.py | 33 - .../ceda6a5abf0e_add_telemetry_table.py | 46 - ...78_enrich_coupons_with_business_details.py | 40 - ...reate_businesses_table_and_link_coupons.py | 47 - ...d1234abcd_add_color_direction_to_routes.py | 25 - backend/app/__init__.py | 2 - backend/app/api/__init__.py | 2 - backend/app/api/analytics.py | 122 - backend/app/api/auth/__init__.py | 314 - backend/app/api/bus_stops/__init__.py | 92 - backend/app/api/businesses.py | 145 - backend/app/api/coupons.py | 147 - backend/app/api/deps.py | 76 - backend/app/api/favorites/__init__.py | 109 - backend/app/api/reports.py | 96 - backend/app/api/routes/__init__.py | 294 - backend/app/api/schedules/__init__.py | 86 - backend/app/api/shuttles/__init__.py | 180 - backend/app/api/taxis/__init__.py | 144 - backend/app/api/telemetry.py | 84 - backend/app/api/users.py | 116 - backend/app/core/__init__.py | 2 - backend/app/core/config.py | 53 - backend/app/core/database.py | 33 - backend/app/core/export_database_to_seeder.py | 251 - backend/app/core/export_supabase_data.py | 92 - backend/app/core/generate_route_stops.py | 99 - .../app/core/import_supabase_coordinates.py | 223 - backend/app/core/security.py | 46 - backend/app/core/seed.py | 5900 ---------------- backend/app/main.py | 175 - backend/app/models/__init__.py | 18 - backend/app/models/analytics.py | 19 - backend/app/models/bus_schedule.py | 31 - backend/app/models/bus_stop.py | 35 - backend/app/models/business.py | 58 - backend/app/models/coupon.py | 79 - backend/app/models/favorite.py | 31 - backend/app/models/report.py | 27 - backend/app/models/route.py | 35 - backend/app/models/route_stop.py | 23 - backend/app/models/shuttle.py | 32 - backend/app/models/taxi.py | 26 - backend/app/models/telemetry.py | 35 - backend/app/models/user.py | 59 - backend/app/models/user_coupon.py | 49 - backend/app/schemas/__init__.py | 2 - backend/app/schemas/bus_stop.py | 53 - backend/app/schemas/report.py | 22 - backend/app/schemas/route.py | 53 - backend/app/schemas/route_stop.py | 21 - backend/app/schemas/shuttle.py | 45 - backend/app/schemas/user.py | 65 - backend/app/services/__init__.py | 0 backend/app/services/image_handler.py | 79 - backend/check_db.py | 19 - backend/check_db_async.py | 25 - backend/create_admin.py | 28 - backend/create_promo_user.py | 47 - backend/database_export.json | 6289 ----------------- backend/docker-entrypoint.sh | 21 - backend/get_remote_users.py | 40 - backend/get_remote_users_db.py | 21 - backend/get_remote_users_urllib.py | 43 - backend/get_remote_users_v2.py | 55 - backend/init_db.py | 7 - backend/inject_routes.py | 140 - backend/inspect_db.py | 15 - backend/list_paths.py | 12 - backend/main.py | 6 - backend/migrate_taxis.py | 25 - backend/parse_openapi.py | 8 - backend/parse_openapi_v2.py | 16 - backend/pyproject.toml | 21 - backend/reset_favorites.py | 13 - backend/seed_promos.py | 106 - backend/seed_shuttles.py | 84 - backend/seed_taxis.py | 82 - backend/seed_test_data.py | 58 - backend/seed_tourist_spots.py | 70 - backend/seed_users.py | 95 - backend/setup_db.py | 24 - backend/test_db_fix.py | 20 - backend/uv.lock | 1980 ------ backend/vertexdc_openapi.json | Bin 38210 -> 0 bytes frontend/src/firebaseConfig.ts | 74 - frontend/src/router/index.ts | 133 +- frontend/src/services/analyticsService.ts | 23 +- frontend/src/services/apiClient.ts | 56 - frontend/src/services/favoritesService.ts | 62 +- frontend/src/services/reportsService.ts | 35 +- frontend/src/services/schedulesService.ts | 42 +- frontend/src/services/telemetryService.ts | 36 +- frontend/src/services/usersService.ts | 34 +- frontend/src/stores/favorites.ts | 59 +- frontend/src/utils/imageUrl.ts | 25 +- frontend/src/views/AdminDrivers.vue | 75 +- frontend/src/views/AdminShuttles.vue | 5 +- frontend/src/views/AdminTaxis.vue | 60 +- frontend/src/views/AuthView.vue | 16 +- frontend/src/views/BusinessDetailsView.vue | 5 +- frontend/src/views/CouponsView.vue | 5 +- frontend/src/views/FavoritesView.vue | 5 +- frontend/src/views/PromoterDashboard.vue | 5 +- frontend/src/views/SplashScreen.vue | 120 +- frontend/src/views/StrategicAnalytics.vue | 46 +- inject_api.py | 52 - old/.gitignore | 47 - old/.metadata | 30 - old/QUICK-START-POSTGRESQL.md | 116 - old/README-POSTGRESQL-SETUP.md | 210 - old/README-SUPABASE-LOCAL.md | 196 - old/README-SUPABASE-PRODUCTION.md | 103 - old/README.md | 142 - old/analysis_options.yaml | 28 - old/android/.gitignore | 13 - old/android/app/build.gradle | 56 - old/android/app/proguard-rules.pro | 7 - old/android/app/src/debug/AndroidManifest.xml | 6 - old/android/app/src/main/AndroidManifest.xml | 58 - .../main/kotlin/com/sibu/app/MainActivity.kt | 7 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 - .../app/src/main/res/values/strings.xml | 5 - .../app/src/main/res/values/styles.xml | 17 - .../app/src/profile/AndroidManifest.xml | 6 - old/android/build.gradle | 18 - old/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 6 - old/android/settings.gradle | 25 - old/assets/images/img_app_logo.svg | 31 - old/assets/images/no-image.jpg | Bin 20735 -> 0 bytes old/assets/images/sad_face.svg | 6 - old/env.json | 10 - old/ios/.gitignore | 34 - old/ios/Flutter/AppFrameworkInfo.plist | 26 - old/ios/Flutter/Debug.xcconfig | 2 - old/ios/Flutter/Release.xcconfig | 2 - old/ios/Podfile | 43 - old/ios/Runner.xcodeproj/project.pbxproj | 617 -- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 98 - .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - old/ios/Runner/AppDelegate.swift | 17 - .../AppIcon.appiconset/Contents.json | 122 - .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 295 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 406 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 450 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 282 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 462 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 704 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 406 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 586 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 862 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 862 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 1674 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 762 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 1226 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 1418 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 - old/ios/Runner/Base.lproj/Main.storyboard | 26 - old/ios/Runner/Info.plist | 55 - old/ios/Runner/Runner-Bridging-Header.h | 1 - old/ios/RunnerTests/RunnerTests.swift | 12 - old/lib/core/app_export.dart | 6 - old/lib/main.dart | 75 - old/lib/models/bus_stop_model.dart | 203 - old/lib/models/coupon_model.dart | 113 - old/lib/models/route_model.dart | 154 - old/lib/models/route_stop_model.dart | 72 - old/lib/models/taxi_model.dart | 140 - .../bus_stop_details/bus_stop_details.dart | 440 -- .../widgets/bus_route_card_widget.dart | 207 - .../widgets/nearby_landmarks_widget.dart | 172 - .../widgets/report_issue_widget.dart | 396 -- .../widgets/stop_amenities_widget.dart | 144 - .../widgets/user_comments_widget.dart | 236 - .../coupons_screen/coupons_screen.dart | 256 - .../widgets/category_filter_chips.dart | 73 - .../widgets/coupon_card_widget.dart | 157 - .../widgets/coupon_detail_modal.dart | 251 - .../widgets/empty_state_widget.dart | 90 - .../widgets/filter_bottom_sheet.dart | 273 - .../coupons_screen/widgets/sort_dropdown.dart | 74 - .../presentation/map_screen/map_screen.dart | 760 -- .../widgets/bus_arrival_bottom_sheet.dart | 461 -- .../widgets/bus_stop_marker_widget.dart | 53 - .../widgets/loading_overlay_widget.dart | 120 - .../widgets/map_controls_widget.dart | 113 - .../schedules_screen/schedules_screen.dart | 632 -- .../widgets/empty_state_widget.dart | 71 - .../widgets/notification_badge_widget.dart | 58 - .../widgets/route_selection_card.dart | 100 - .../widgets/schedule_card.dart | 236 - .../widgets/search_bar_widget.dart | 109 - .../splash_screen/splash_screen.dart | 357 - .../presentation/taxi_screen/taxi_screen.dart | 265 - .../taxi_screen/widgets/taxi_card_widget.dart | 159 - .../widgets/taxi_empty_state_widget.dart | 116 - .../widgets/taxi_filters_widget.dart | 189 - old/lib/routes/app_routes.dart | 29 - old/lib/services/api_client.dart | 170 - old/lib/services/app_state_service.dart | 207 - old/lib/services/coupon_service.dart | 130 - old/lib/services/supabase_service.dart | 255 - old/lib/services/taxi_service.dart | 243 - old/lib/services/transportation_service.dart | 446 -- old/lib/theme/app_theme.dart | 652 -- old/lib/widgets/custom_app_bar.dart | 210 - old/lib/widgets/custom_bottom_bar.dart | 202 - old/lib/widgets/custom_error_widget.dart | 84 - old/lib/widgets/custom_icon_widget.dart | 2189 ------ old/lib/widgets/custom_image_widget.dart | 182 - old/lib/widgets/debug_banner_widget.dart | 188 - .../widgets/route_selection_bottom_sheet.dart | 284 - old/pubspec.yaml | 52 - old/scripts/get-local-credentials.sh | 25 - old/scripts/run-flutter-backend.sh | 25 - old/scripts/run-flutter-local.sh | 65 - old/scripts/run-flutter-supabase.sh | 64 - old/scripts/setup-local-supabase.sh | 45 - old/supabase/.gitignore | 8 - old/supabase/config.toml | 357 - ...41019215951_sibu_transportation_system.sql | 445 -- .../20241019220000_fix_existing_schema.sql | 362 - .../migrations/20250126225029_taxi_module.sql | 77 - .../20251031165808_enhance_taxi_directory.sql | 97 - ...181019_enhance_coupons_with_categories.sql | 119 - old/test/widget_test.dart | 30 - render.yaml | 28 - 267 files changed, 377 insertions(+), 37834 deletions(-) delete mode 100644 PENDING_FOR_TOMORROW.md delete mode 100644 backend/.env.development delete mode 100644 backend/Dockerfile delete mode 100644 backend/alembic.ini delete mode 100644 backend/alembic/env.py delete mode 100644 backend/alembic/script.py.mako delete mode 100644 backend/alembic/versions/2088667c3a5f_add_search_indexes.py delete mode 100644 backend/alembic/versions/2f4936eb86f0_initial_schema.py delete mode 100644 backend/alembic/versions/3fe72cd3f722_sync_shuttle_fields.py delete mode 100644 backend/alembic/versions/414da6754b1e_add_user_roles.py delete mode 100644 backend/alembic/versions/4c9211307d7a_add_user_profile_photo.py delete mode 100644 backend/alembic/versions/5caf8ba3ed4d_add_speaks_english_to_driver_profile.py delete mode 100644 backend/alembic/versions/8a5661aac24b_add_user_coupons.py delete mode 100644 backend/alembic/versions/8b3e5b0a3e67_add_is_published_to_bus_schedule.py delete mode 100644 backend/alembic/versions/93054da1a687_add_coupons_and_promoter_role.py delete mode 100644 backend/alembic/versions/94b4cb57c6c1_add_social_media_to_coupons.py delete mode 100644 backend/alembic/versions/9f2fbe81a055_add_area_to_business.py delete mode 100644 backend/alembic/versions/a1b2c3d4e5f6_merge_heads_and_fix_routes.py delete mode 100644 backend/alembic/versions/aac025d432f0_add_average_speed_and_stop_delay.py delete mode 100644 backend/alembic/versions/bb5c406b9af5_add_stop_order_to_bus_stop.py delete mode 100644 backend/alembic/versions/c88628a640b6_add_taxi_and_favorite_models.py delete mode 100644 backend/alembic/versions/c9bb64354775_add_business_coords.py delete mode 100644 backend/alembic/versions/ceda6a5abf0e_add_telemetry_table.py delete mode 100644 backend/alembic/versions/dfbcee895f78_enrich_coupons_with_business_details.py delete mode 100644 backend/alembic/versions/e5fb60c22245_create_businesses_table_and_link_coupons.py delete mode 100644 backend/alembic/versions/ffcd1234abcd_add_color_direction_to_routes.py delete mode 100644 backend/app/__init__.py delete mode 100644 backend/app/api/__init__.py delete mode 100644 backend/app/api/analytics.py delete mode 100644 backend/app/api/auth/__init__.py delete mode 100644 backend/app/api/bus_stops/__init__.py delete mode 100644 backend/app/api/businesses.py delete mode 100644 backend/app/api/coupons.py delete mode 100644 backend/app/api/deps.py delete mode 100644 backend/app/api/favorites/__init__.py delete mode 100644 backend/app/api/reports.py delete mode 100644 backend/app/api/routes/__init__.py delete mode 100644 backend/app/api/schedules/__init__.py delete mode 100644 backend/app/api/shuttles/__init__.py delete mode 100644 backend/app/api/taxis/__init__.py delete mode 100644 backend/app/api/telemetry.py delete mode 100644 backend/app/api/users.py delete mode 100644 backend/app/core/__init__.py delete mode 100644 backend/app/core/config.py delete mode 100644 backend/app/core/database.py delete mode 100644 backend/app/core/export_database_to_seeder.py delete mode 100644 backend/app/core/export_supabase_data.py delete mode 100644 backend/app/core/generate_route_stops.py delete mode 100644 backend/app/core/import_supabase_coordinates.py delete mode 100644 backend/app/core/security.py delete mode 100644 backend/app/core/seed.py delete mode 100644 backend/app/main.py delete mode 100644 backend/app/models/__init__.py delete mode 100644 backend/app/models/analytics.py delete mode 100644 backend/app/models/bus_schedule.py delete mode 100644 backend/app/models/bus_stop.py delete mode 100644 backend/app/models/business.py delete mode 100644 backend/app/models/coupon.py delete mode 100644 backend/app/models/favorite.py delete mode 100644 backend/app/models/report.py delete mode 100644 backend/app/models/route.py delete mode 100644 backend/app/models/route_stop.py delete mode 100644 backend/app/models/shuttle.py delete mode 100644 backend/app/models/taxi.py delete mode 100644 backend/app/models/telemetry.py delete mode 100644 backend/app/models/user.py delete mode 100644 backend/app/models/user_coupon.py delete mode 100644 backend/app/schemas/__init__.py delete mode 100644 backend/app/schemas/bus_stop.py delete mode 100644 backend/app/schemas/report.py delete mode 100644 backend/app/schemas/route.py delete mode 100644 backend/app/schemas/route_stop.py delete mode 100644 backend/app/schemas/shuttle.py delete mode 100644 backend/app/schemas/user.py delete mode 100644 backend/app/services/__init__.py delete mode 100644 backend/app/services/image_handler.py delete mode 100644 backend/check_db.py delete mode 100644 backend/check_db_async.py delete mode 100644 backend/create_admin.py delete mode 100644 backend/create_promo_user.py delete mode 100644 backend/database_export.json delete mode 100644 backend/docker-entrypoint.sh delete mode 100644 backend/get_remote_users.py delete mode 100644 backend/get_remote_users_db.py delete mode 100644 backend/get_remote_users_urllib.py delete mode 100644 backend/get_remote_users_v2.py delete mode 100644 backend/init_db.py delete mode 100644 backend/inject_routes.py delete mode 100644 backend/inspect_db.py delete mode 100644 backend/list_paths.py delete mode 100644 backend/main.py delete mode 100644 backend/migrate_taxis.py delete mode 100644 backend/parse_openapi.py delete mode 100644 backend/parse_openapi_v2.py delete mode 100644 backend/pyproject.toml delete mode 100644 backend/reset_favorites.py delete mode 100644 backend/seed_promos.py delete mode 100644 backend/seed_shuttles.py delete mode 100644 backend/seed_taxis.py delete mode 100644 backend/seed_test_data.py delete mode 100644 backend/seed_tourist_spots.py delete mode 100644 backend/seed_users.py delete mode 100644 backend/setup_db.py delete mode 100644 backend/test_db_fix.py delete mode 100644 backend/uv.lock delete mode 100644 backend/vertexdc_openapi.json delete mode 100644 frontend/src/firebaseConfig.ts delete mode 100644 frontend/src/services/apiClient.ts delete mode 100644 inject_api.py delete mode 100644 old/.gitignore delete mode 100644 old/.metadata delete mode 100644 old/QUICK-START-POSTGRESQL.md delete mode 100644 old/README-POSTGRESQL-SETUP.md delete mode 100644 old/README-SUPABASE-LOCAL.md delete mode 100644 old/README-SUPABASE-PRODUCTION.md delete mode 100644 old/README.md delete mode 100644 old/analysis_options.yaml delete mode 100644 old/android/.gitignore delete mode 100644 old/android/app/build.gradle delete mode 100644 old/android/app/proguard-rules.pro delete mode 100644 old/android/app/src/debug/AndroidManifest.xml delete mode 100644 old/android/app/src/main/AndroidManifest.xml delete mode 100644 old/android/app/src/main/kotlin/com/sibu/app/MainActivity.kt delete mode 100644 old/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 old/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 old/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 old/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 old/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 old/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 old/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 old/android/app/src/main/res/values-night/styles.xml delete mode 100644 old/android/app/src/main/res/values/strings.xml delete mode 100644 old/android/app/src/main/res/values/styles.xml delete mode 100644 old/android/app/src/profile/AndroidManifest.xml delete mode 100644 old/android/build.gradle delete mode 100644 old/android/gradle.properties delete mode 100644 old/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 old/android/settings.gradle delete mode 100644 old/assets/images/img_app_logo.svg delete mode 100644 old/assets/images/no-image.jpg delete mode 100644 old/assets/images/sad_face.svg delete mode 100644 old/env.json delete mode 100644 old/ios/.gitignore delete mode 100644 old/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 old/ios/Flutter/Debug.xcconfig delete mode 100644 old/ios/Flutter/Release.xcconfig delete mode 100644 old/ios/Podfile delete mode 100644 old/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 old/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 old/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 old/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 old/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 old/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 old/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 old/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 old/ios/Runner/AppDelegate.swift delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 old/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 old/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 old/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 old/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 old/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 old/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 old/ios/Runner/Info.plist delete mode 100644 old/ios/Runner/Runner-Bridging-Header.h delete mode 100644 old/ios/RunnerTests/RunnerTests.swift delete mode 100644 old/lib/core/app_export.dart delete mode 100644 old/lib/main.dart delete mode 100644 old/lib/models/bus_stop_model.dart delete mode 100644 old/lib/models/coupon_model.dart delete mode 100644 old/lib/models/route_model.dart delete mode 100644 old/lib/models/route_stop_model.dart delete mode 100644 old/lib/models/taxi_model.dart delete mode 100644 old/lib/presentation/bus_stop_details/bus_stop_details.dart delete mode 100644 old/lib/presentation/bus_stop_details/widgets/bus_route_card_widget.dart delete mode 100644 old/lib/presentation/bus_stop_details/widgets/nearby_landmarks_widget.dart delete mode 100644 old/lib/presentation/bus_stop_details/widgets/report_issue_widget.dart delete mode 100644 old/lib/presentation/bus_stop_details/widgets/stop_amenities_widget.dart delete mode 100644 old/lib/presentation/bus_stop_details/widgets/user_comments_widget.dart delete mode 100644 old/lib/presentation/coupons_screen/coupons_screen.dart delete mode 100644 old/lib/presentation/coupons_screen/widgets/category_filter_chips.dart delete mode 100644 old/lib/presentation/coupons_screen/widgets/coupon_card_widget.dart delete mode 100644 old/lib/presentation/coupons_screen/widgets/coupon_detail_modal.dart delete mode 100644 old/lib/presentation/coupons_screen/widgets/empty_state_widget.dart delete mode 100644 old/lib/presentation/coupons_screen/widgets/filter_bottom_sheet.dart delete mode 100644 old/lib/presentation/coupons_screen/widgets/sort_dropdown.dart delete mode 100644 old/lib/presentation/map_screen/map_screen.dart delete mode 100644 old/lib/presentation/map_screen/widgets/bus_arrival_bottom_sheet.dart delete mode 100644 old/lib/presentation/map_screen/widgets/bus_stop_marker_widget.dart delete mode 100644 old/lib/presentation/map_screen/widgets/loading_overlay_widget.dart delete mode 100644 old/lib/presentation/map_screen/widgets/map_controls_widget.dart delete mode 100644 old/lib/presentation/schedules_screen/schedules_screen.dart delete mode 100644 old/lib/presentation/schedules_screen/widgets/empty_state_widget.dart delete mode 100644 old/lib/presentation/schedules_screen/widgets/notification_badge_widget.dart delete mode 100644 old/lib/presentation/schedules_screen/widgets/route_selection_card.dart delete mode 100644 old/lib/presentation/schedules_screen/widgets/schedule_card.dart delete mode 100644 old/lib/presentation/schedules_screen/widgets/search_bar_widget.dart delete mode 100644 old/lib/presentation/splash_screen/splash_screen.dart delete mode 100644 old/lib/presentation/taxi_screen/taxi_screen.dart delete mode 100644 old/lib/presentation/taxi_screen/widgets/taxi_card_widget.dart delete mode 100644 old/lib/presentation/taxi_screen/widgets/taxi_empty_state_widget.dart delete mode 100644 old/lib/presentation/taxi_screen/widgets/taxi_filters_widget.dart delete mode 100644 old/lib/routes/app_routes.dart delete mode 100644 old/lib/services/api_client.dart delete mode 100644 old/lib/services/app_state_service.dart delete mode 100644 old/lib/services/coupon_service.dart delete mode 100644 old/lib/services/supabase_service.dart delete mode 100644 old/lib/services/taxi_service.dart delete mode 100644 old/lib/services/transportation_service.dart delete mode 100644 old/lib/theme/app_theme.dart delete mode 100644 old/lib/widgets/custom_app_bar.dart delete mode 100644 old/lib/widgets/custom_bottom_bar.dart delete mode 100644 old/lib/widgets/custom_error_widget.dart delete mode 100644 old/lib/widgets/custom_icon_widget.dart delete mode 100644 old/lib/widgets/custom_image_widget.dart delete mode 100644 old/lib/widgets/debug_banner_widget.dart delete mode 100644 old/lib/widgets/route_selection_bottom_sheet.dart delete mode 100644 old/pubspec.yaml delete mode 100644 old/scripts/get-local-credentials.sh delete mode 100644 old/scripts/run-flutter-backend.sh delete mode 100644 old/scripts/run-flutter-local.sh delete mode 100644 old/scripts/run-flutter-supabase.sh delete mode 100644 old/scripts/setup-local-supabase.sh delete mode 100644 old/supabase/.gitignore delete mode 100644 old/supabase/config.toml delete mode 100644 old/supabase/migrations/20241019215951_sibu_transportation_system.sql delete mode 100644 old/supabase/migrations/20241019220000_fix_existing_schema.sql delete mode 100644 old/supabase/migrations/20250126225029_taxi_module.sql delete mode 100644 old/supabase/migrations/20251031165808_enhance_taxi_directory.sql delete mode 100644 old/supabase/migrations/20251031181019_enhance_coupons_with_categories.sql delete mode 100644 old/test/widget_test.dart delete mode 100644 render.yaml diff --git a/PENDING_FOR_TOMORROW.md b/PENDING_FOR_TOMORROW.md deleted file mode 100644 index 58d816b..0000000 --- a/PENDING_FOR_TOMORROW.md +++ /dev/null @@ -1,24 +0,0 @@ -# Plan de Trabajo - SIBU (Continuación) - -## 🎯 Avances de Hoy (2026-01-28) -* **Estabilidad del Inicio:** Se solucionó el bloqueo de la "Loading Screen" con un timeout de seguridad y correcciones de enrutamiento/roles. -* **Refactorización Completa del Panel de Promotor:** - * Nuevo diseño de cabecera centrado y moderno. - * Contadores de estadísticas dinámicos en la barra de acciones. - * **Subida de Imágenes Real:** Implementado soporte para subir fotos de negocios desde el dispositivo (sustituyendo URLs). - * Alineación de tablas corregida (headers y celdas centradas). - * Categorías actualizadas: "Área Turística" y "Viajes de Turismo". -* **Gestión de Versiones:** Commit y Tag `promos-admin` creados y pusheados a GitHub. - -## 🔜 Pendiente para Mañana -1. **Visualización en Mapa:** Hacer que los negocios con promociones activas aparezcan como pines especiales o destacados en el mapa principal. -2. **Dashboard del Conductor:** - * Verificar la transmisión de ubicación en tiempo real (Telemetry). - * Asegurar que el estado "In Service" sea persistente y visible para los usuarios. -3. **Sistema de Notificaciones:** Implementar avisos cuando un transporte favorito esté cerca (Punto 4 original). -4. **Admin Verification:** Mejorar la visualización de documentos en el panel de administración para agilizar validaciones. - -## 🛠️ Notas Técnicas -* Las imágenes de negocios se guardan en `backend/uploads/businesses/`. -* El frontend usa la constante `API_URL` de `apiClient.ts` para resolver las rutas de imágenes. -* Se configuró el `.gitignore` para no subir archivos de la carpeta `uploads`. diff --git a/backend/.env.development b/backend/.env.development deleted file mode 100644 index 11e37ea..0000000 --- a/backend/.env.development +++ /dev/null @@ -1,6 +0,0 @@ -DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/sibu -ENVIRONMENT=production -DEBUG=false -RUN_SEEDERS=false -SECRET_KEY=sibu-secret-key-for-dev-12345 -ADMIN_PASSWORD=admin diff --git a/backend/Dockerfile b/backend/Dockerfile deleted file mode 100644 index a1222cb..0000000 --- a/backend/Dockerfile +++ /dev/null @@ -1,43 +0,0 @@ -# Use Python 3.13 slim image as base -FROM python:3.13-slim as base - -# Set working directory -WORKDIR /app - -# Install system dependencies -RUN apt-get update && apt-get install -y \ - curl \ - build-essential \ - && rm -rf /var/lib/apt/lists/* - -# Install uv -COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv - -# Create a non-root user -RUN useradd -m -u 1000 appuser && \ - chown -R appuser:appuser /app - -# Copy dependency files -COPY pyproject.toml uv.lock ./ - -# Install dependencies -RUN uv sync --frozen --no-dev - -# Copy application code -COPY --chown=appuser:appuser . . - -# Ensure entrypoint script is executable -RUN chmod +x /app/docker-entrypoint.sh - -# Switch to non-root user -USER appuser - -# Expose port -EXPOSE 8000 - -# Set entrypoint -ENTRYPOINT ["/app/docker-entrypoint.sh"] - -# Default command -CMD ["uv", "run", "fastapi", "run", "app/main.py", "--host", "0.0.0.0", "--port", "8000"] - diff --git a/backend/alembic.ini b/backend/alembic.ini deleted file mode 100644 index e8f35d5..0000000 --- a/backend/alembic.ini +++ /dev/null @@ -1,92 +0,0 @@ -# A generic, single database configuration. - -[alembic] -# path to migration scripts -script_location = alembic - -# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s -# Uncomment the line below if you want the files to be prepended with date and time -# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s - -# sys.path path, will be prepended to sys.path if present. -# defaults to the current working directory. -prepend_sys_path = . - -# timezone to use when rendering the date within the migration file -# as well as the filename. -# If specified, requires the python-dateutil library that can be -# installed by adding `alembic[tz]` to the pip requirements -# string value is passed to dateutil.tz.gettz() -# leave blank for localtime -# timezone = - -# max length of characters to apply to the -# "slug" field -# truncate_slug_length = 40 - -# set to 'true' to run the environment during -# the 'revision' command, regardless of autogenerate -# revision_environment = false - -# set to 'true' to allow .pyc files to -# be detected as revisions in the versions/ directory -# pyc_files = false - -# set to 'true' to search source files recursively -# in each "version_locations" directory -# new in Alembic version 1.10 -# recursive_version_locations = false - -# the output encoding used when revision files -# are written from script.py.mako -# output_encoding = utf-8 - -sqlalchemy.url = driver://user:pass@localhost/dbname - - -[post_write_hooks] -# post_write_hooks defines scripts or Python functions that are run -# on newly generated revision scripts. See the documentation for further -# detail and examples - -# format using "black" - use the console_scripts runner, against the "black" entrypoint -# hooks = black -# black.type = console_scripts -# black.entrypoint = black -# black.options = -l 79 REVISION_SCRIPT_FILENAME - -# Logging configuration -[loggers] -keys = root,sqlalchemy,alembic - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine - -[logger_alembic] -level = INFO -handlers = -qualname = alembic - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S - diff --git a/backend/alembic/env.py b/backend/alembic/env.py deleted file mode 100644 index 04837c5..0000000 --- a/backend/alembic/env.py +++ /dev/null @@ -1,95 +0,0 @@ -"""Alembic environment configuration.""" -from logging.config import fileConfig -from sqlmodel import SQLModel -from sqlalchemy import engine_from_config -from sqlalchemy import pool -from sqlalchemy import text as sa_text -from alembic import context - -# Import your models and database configuration -from app.core.config import settings -from app.models import * # noqa: F401, F403 - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -if config.config_file_name is not None: - fileConfig(config.config_file_name) - -# Set the sqlalchemy.url from our settings -# Convert asyncpg URL to psycopg2 for Alembic (Alembic doesn't support async) -database_url = settings.database_url.replace("+asyncpg", "+psycopg2") -config.set_main_option("sqlalchemy.url", database_url) - -# add your model's MetaData object here -# for 'autogenerate' support - - -# Import all models to ensure they're registered - -target_metadata = SQLModel.metadata - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - - -def run_migrations_offline() -> None: - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure( - url=url, - target_metadata=target_metadata, - literal_binds=True, - dialect_opts={"paramstyle": "named"}, - ) - - with context.begin_transaction(): - context.run_migrations() - - -def run_migrations_online() -> None: - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - connectable = engine_from_config( - config.get_section(config.config_ini_section, {}), - prefix="sqlalchemy.", - poolclass=pool.NullPool, - ) - - with connectable.connect() as connection: - # Set search_path to public schema - connection.execute(sa_text("SET search_path TO public")) - connection.commit() - - context.configure( - connection=connection, target_metadata=target_metadata - ) - - with context.begin_transaction(): - context.run_migrations() - - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() - diff --git a/backend/alembic/script.py.mako b/backend/alembic/script.py.mako deleted file mode 100644 index 3c2e787..0000000 --- a/backend/alembic/script.py.mako +++ /dev/null @@ -1,27 +0,0 @@ -"""${message} - -Revision ID: ${up_revision} -Revises: ${down_revision | comma,n} -Create Date: ${create_date} - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -${imports if imports else ""} - -# revision identifiers, used by Alembic. -revision: str = ${repr(up_revision)} -down_revision: Union[str, None] = ${repr(down_revision)} -branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} -depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} - - -def upgrade() -> None: - ${upgrades if upgrades else "pass"} - - -def downgrade() -> None: - ${downgrades if downgrades else "pass"} - diff --git a/backend/alembic/versions/2088667c3a5f_add_search_indexes.py b/backend/alembic/versions/2088667c3a5f_add_search_indexes.py deleted file mode 100644 index 4f306b3..0000000 --- a/backend/alembic/versions/2088667c3a5f_add_search_indexes.py +++ /dev/null @@ -1,32 +0,0 @@ -"""add_search_indexes - -Revision ID: 2088667c3a5f -Revises: 4c9211307d7a -Create Date: 2026-01-28 18:35:15.269274 - -""" -from typing import Sequence, Union - -from alembic import op - - -# revision identifiers, used by Alembic. -revision: str = '2088667c3a5f' -down_revision: Union[str, None] = '4c9211307d7a' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_index(op.f('ix_coupons_title'), 'coupons', ['title'], unique=False) - op.create_index(op.f('ix_users_full_name'), 'users', ['full_name'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_users_full_name'), table_name='users') - op.drop_index(op.f('ix_coupons_title'), table_name='coupons') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/2f4936eb86f0_initial_schema.py b/backend/alembic/versions/2f4936eb86f0_initial_schema.py deleted file mode 100644 index 6413f50..0000000 --- a/backend/alembic/versions/2f4936eb86f0_initial_schema.py +++ /dev/null @@ -1,88 +0,0 @@ -"""initial_schema - -Revision ID: 2f4936eb86f0 -Revises: -Create Date: 2025-12-02 21:34:08.468033 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '2f4936eb86f0' -down_revision: Union[str, None] = None -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('bus_stops', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('name', sa.String(), nullable=False), - sa.Column('latitude', sa.Float(), nullable=False), - sa.Column('longitude', sa.Float(), nullable=False), - sa.Column('city', sa.String(), nullable=False), - sa.Column('address', sa.String(), nullable=True), - sa.Column('stop_type', sa.Enum('TERMINAL', 'REGULAR', 'EXPRESS_ONLY', name='stoptype'), nullable=False), - sa.Column('has_shelter', sa.Boolean(), nullable=False), - sa.Column('has_seating', sa.Boolean(), nullable=False), - sa.Column('is_accessible', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('routes', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('name', sa.String(), nullable=False), - sa.Column('description', sa.String(), nullable=True), - sa.Column('origin_city', sa.String(), nullable=False), - sa.Column('destination_city', sa.String(), nullable=False), - sa.Column('distance_km', sa.Float(), nullable=True), - sa.Column('estimated_duration_minutes', sa.Integer(), nullable=True), - sa.Column('status', sa.Enum('ACTIVE', 'INACTIVE', 'MAINTENANCE', name='routestatus'), nullable=False), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_routes_name'), 'routes', ['name'], unique=True) - op.create_table('bus_schedules', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('route_id', sa.Uuid(), nullable=False), - sa.Column('departure_time', sa.Time(), nullable=False), - sa.Column('frequency_minutes', sa.Integer(), nullable=True), - sa.Column('schedule_type', sa.Enum('WEEKDAY', 'WEEKEND', 'HOLIDAY', name='busscheduletype'), nullable=False), - sa.Column('is_active', sa.Boolean(), nullable=False), - sa.Column('notes', sa.String(), nullable=True), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['route_id'], ['routes.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('route_stops', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('route_id', sa.Uuid(), nullable=False), - sa.Column('stop_id', sa.Uuid(), nullable=False), - sa.Column('stop_order', sa.Integer(), nullable=False), - sa.Column('travel_time_minutes', sa.Integer(), nullable=True), - sa.Column('is_pickup_point', sa.Boolean(), nullable=False), - sa.Column('is_dropoff_point', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['route_id'], ['routes.id'], ), - sa.ForeignKeyConstraint(['stop_id'], ['bus_stops.id'], ), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('route_stops') - op.drop_table('bus_schedules') - op.drop_index(op.f('ix_routes_name'), table_name='routes') - op.drop_table('routes') - op.drop_table('bus_stops') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/3fe72cd3f722_sync_shuttle_fields.py b/backend/alembic/versions/3fe72cd3f722_sync_shuttle_fields.py deleted file mode 100644 index 16a72be..0000000 --- a/backend/alembic/versions/3fe72cd3f722_sync_shuttle_fields.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Sync shuttle fields - -Revision ID: 3fe72cd3f722 -Revises: 5caf8ba3ed4d -Create Date: 2026-02-15 16:20:02.326548 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '3fe72cd3f722' -down_revision: Union[str, None] = '5caf8ba3ed4d' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # 1. Reparar valores nulos existentes en driver_profiles antes de restringir - op.execute("UPDATE driver_profiles SET speaks_english = FALSE WHERE speaks_english IS NULL") - - op.alter_column('driver_profiles', 'speaks_english', - existing_type=sa.BOOLEAN(), - nullable=False) - - # 2. Asegurar campos de Shuttles (solo si no existen, usando try/except o verificando primero) - # Nota: Alembic no los detectó, pero los forzamos por si acaso - with op.get_context().autocommit_block(): - op.execute("ALTER TABLE shuttles ADD COLUMN IF NOT EXISTS company_name VARCHAR") - op.execute("ALTER TABLE shuttles ADD COLUMN IF NOT EXISTS trip_type VARCHAR DEFAULT 'one_way'") - op.execute("ALTER TABLE shuttles ADD COLUMN IF NOT EXISTS price_private_trip FLOAT") - op.execute("ALTER TABLE shuttles ADD COLUMN IF NOT EXISTS departure_times VARCHAR") - op.execute("ALTER TABLE shuttles ADD COLUMN IF NOT EXISTS contact_whatsapp VARCHAR") - op.execute("ALTER TABLE shuttles ADD COLUMN IF NOT EXISTS estimated_duration VARCHAR") - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.alter_column('driver_profiles', 'speaks_english', - existing_type=sa.BOOLEAN(), - nullable=True) - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/414da6754b1e_add_user_roles.py b/backend/alembic/versions/414da6754b1e_add_user_roles.py deleted file mode 100644 index 657c759..0000000 --- a/backend/alembic/versions/414da6754b1e_add_user_roles.py +++ /dev/null @@ -1,57 +0,0 @@ -"""add_user_roles - -Revision ID: 414da6754b1e -Revises: aac025d432f0 -Create Date: 2026-01-27 15:26:58.408563 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = '414da6754b1e' -down_revision: Union[str, None] = 'aac025d432f0' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('users', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('hashed_password', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('full_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('role', sa.Enum('ADMIN', 'PASSENGER', 'DRIVER', name='userrole'), nullable=False), - sa.Column('is_active', sa.Boolean(), nullable=False), - sa.Column('is_verified', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True) - op.create_table('driver_profiles', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('user_id', sa.Uuid(), nullable=False), - sa.Column('cedula', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('vehicle_type', sa.Enum('TAXI', 'BUS', name='vehicletype'), nullable=False), - sa.Column('license_plate', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('photo_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('vehicle_photo_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('cooperative_name', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('driver_profiles') - op.drop_index(op.f('ix_users_email'), table_name='users') - op.drop_table('users') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/4c9211307d7a_add_user_profile_photo.py b/backend/alembic/versions/4c9211307d7a_add_user_profile_photo.py deleted file mode 100644 index b1e4077..0000000 --- a/backend/alembic/versions/4c9211307d7a_add_user_profile_photo.py +++ /dev/null @@ -1,31 +0,0 @@ -"""add_user_profile_photo - -Revision ID: 4c9211307d7a -Revises: 8a5661aac24b -Create Date: 2026-01-28 18:13:37.548321 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '4c9211307d7a' -down_revision: Union[str, None] = '8a5661aac24b' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('users', sa.Column('profile_photo_url', sa.String(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('users', 'profile_photo_url') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/5caf8ba3ed4d_add_speaks_english_to_driver_profile.py b/backend/alembic/versions/5caf8ba3ed4d_add_speaks_english_to_driver_profile.py deleted file mode 100644 index 08ff168..0000000 --- a/backend/alembic/versions/5caf8ba3ed4d_add_speaks_english_to_driver_profile.py +++ /dev/null @@ -1,40 +0,0 @@ -"""add_speaks_english_to_driver_profile - -Revision ID: 5caf8ba3ed4d -Revises: 9f2fbe81a055 -Create Date: 2026-01-31 16:02:13.521306 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = '5caf8ba3ed4d' -down_revision: Union[str, None] = '9f2fbe81a055' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('driver_profiles', sa.Column('shift', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - op.add_column('driver_profiles', sa.Column('payment_methods', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - op.add_column('driver_profiles', sa.Column('speaks_english', sa.Boolean(), nullable=True)) - op.add_column('taxis', sa.Column('rating', sa.Float(), nullable=False, server_default=sa.text('5.0'))) - op.add_column('taxis', sa.Column('english_speaking', sa.Boolean(), nullable=False, server_default=sa.text('false'))) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('taxis', 'english_speaking') - op.drop_column('taxis', 'rating') - op.drop_column('driver_profiles', 'speaks_english') - op.drop_column('driver_profiles', 'payment_methods') - op.drop_column('driver_profiles', 'shift') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/8a5661aac24b_add_user_coupons.py b/backend/alembic/versions/8a5661aac24b_add_user_coupons.py deleted file mode 100644 index 8444472..0000000 --- a/backend/alembic/versions/8a5661aac24b_add_user_coupons.py +++ /dev/null @@ -1,44 +0,0 @@ -"""add_user_coupons - -Revision ID: 8a5661aac24b -Revises: e5fb60c22245 -Create Date: 2026-01-28 18:01:08.102678 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '8a5661aac24b' -down_revision: Union[str, None] = 'e5fb60c22245' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('user_coupons', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('user_id', sa.Uuid(), nullable=False), - sa.Column('coupon_id', sa.Uuid(), nullable=False), - sa.Column('status', sa.Enum('CLAIMED', 'REDEEMED', 'EXPIRED', name='usercouponstatus'), nullable=False), - sa.Column('redemption_code', sa.String(), nullable=True), - sa.Column('claimed_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.Column('redeemed_at', sa.DateTime(timezone=True), nullable=True), - sa.ForeignKeyConstraint(['coupon_id'], ['coupons.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_user_coupons_redemption_code'), 'user_coupons', ['redemption_code'], unique=True) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_user_coupons_redemption_code'), table_name='user_coupons') - op.drop_table('user_coupons') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/8b3e5b0a3e67_add_is_published_to_bus_schedule.py b/backend/alembic/versions/8b3e5b0a3e67_add_is_published_to_bus_schedule.py deleted file mode 100644 index 9377fa7..0000000 --- a/backend/alembic/versions/8b3e5b0a3e67_add_is_published_to_bus_schedule.py +++ /dev/null @@ -1,33 +0,0 @@ -"""add_is_published_to_bus_schedule - -Revision ID: 8b3e5b0a3e67 -Revises: 414da6754b1e -Create Date: 2026-01-27 17:05:19.915106 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '8b3e5b0a3e67' -down_revision: Union[str, None] = '414da6754b1e' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('bus_schedules', sa.Column('is_published', sa.Boolean(), nullable=True)) - op.execute("UPDATE bus_schedules SET is_published = false") - op.alter_column('bus_schedules', 'is_published', nullable=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('bus_schedules', 'is_published') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/93054da1a687_add_coupons_and_promoter_role.py b/backend/alembic/versions/93054da1a687_add_coupons_and_promoter_role.py deleted file mode 100644 index 1274174..0000000 --- a/backend/alembic/versions/93054da1a687_add_coupons_and_promoter_role.py +++ /dev/null @@ -1,54 +0,0 @@ -"""add_coupons_and_promoter_role - -Revision ID: 93054da1a687 -Revises: ceda6a5abf0e -Create Date: 2026-01-28 10:41:47.113948 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = '93054da1a687' -down_revision: Union[str, None] = 'ceda6a5abf0e' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # Add 'promoter' to UserRole enum - # Postgres specific command to add value to existing Enum - with op.get_context().autocommit_block(): - op.execute("ALTER TYPE userrole ADD VALUE IF NOT EXISTS 'promoter'") - - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('coupons', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('title', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('discount_percentage', sa.Integer(), nullable=True), - sa.Column('discount_amount', sa.Float(), nullable=True), - sa.Column('category', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('valid_from', sa.DateTime(timezone=True), nullable=True), - sa.Column('valid_until', sa.DateTime(timezone=True), nullable=True), - sa.Column('is_active', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('coupons') - # ### end Alembic commands ### - # Note: Removing a value from a Postgres Enum is complex and usually not done in migrations - # unless you recreate the whole type. - diff --git a/backend/alembic/versions/94b4cb57c6c1_add_social_media_to_coupons.py b/backend/alembic/versions/94b4cb57c6c1_add_social_media_to_coupons.py deleted file mode 100644 index f892074..0000000 --- a/backend/alembic/versions/94b4cb57c6c1_add_social_media_to_coupons.py +++ /dev/null @@ -1,32 +0,0 @@ -"""add_social_media_to_coupons - -Revision ID: 94b4cb57c6c1 -Revises: dfbcee895f78 -Create Date: 2026-01-28 11:31:47.625569 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = '94b4cb57c6c1' -down_revision: Union[str, None] = 'dfbcee895f78' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('coupons', sa.Column('social_media', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('coupons', 'social_media') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/9f2fbe81a055_add_area_to_business.py b/backend/alembic/versions/9f2fbe81a055_add_area_to_business.py deleted file mode 100644 index 712070f..0000000 --- a/backend/alembic/versions/9f2fbe81a055_add_area_to_business.py +++ /dev/null @@ -1,32 +0,0 @@ -"""add area to business - -Revision ID: 9f2fbe81a055 -Revises: c9bb64354775 -Create Date: 2026-01-29 13:36:34.379966 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = '9f2fbe81a055' -down_revision: Union[str, None] = 'c9bb64354775' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('businesses', sa.Column('area', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('businesses', 'area') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/a1b2c3d4e5f6_merge_heads_and_fix_routes.py b/backend/alembic/versions/a1b2c3d4e5f6_merge_heads_and_fix_routes.py deleted file mode 100644 index d1ff4a7..0000000 --- a/backend/alembic/versions/a1b2c3d4e5f6_merge_heads_and_fix_routes.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Fix routes table: ensure color, direction, average_speed_kmh columns exist - -This migration uses IF NOT EXISTS to safely add missing columns regardless -of the current database state in production. - -Revision ID: a1b2c3d4e5f6 -Revises: ffcd1234abcd -Create Date: 2026-02-26 00:30:00.000000 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'a1b2c3d4e5f6' -down_revision: Union[str, None] = 'ffcd1234abcd' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # Use raw SQL with IF NOT EXISTS to be safe regardless of prior migration state. - # This ensures the columns exist in production even if the previous migration - # had issues being applied. - with op.get_context().autocommit_block(): - op.execute("ALTER TABLE routes ADD COLUMN IF NOT EXISTS color VARCHAR DEFAULT '#FEE715'") - op.execute("ALTER TABLE routes ADD COLUMN IF NOT EXISTS direction VARCHAR DEFAULT 'outbound'") - op.execute("ALTER TABLE routes ADD COLUMN IF NOT EXISTS average_speed_kmh FLOAT") - # Update any existing NULLs - op.execute("UPDATE routes SET color = '#FEE715' WHERE color IS NULL") - op.execute("UPDATE routes SET direction = 'outbound' WHERE direction IS NULL") - - -def downgrade() -> None: - pass diff --git a/backend/alembic/versions/aac025d432f0_add_average_speed_and_stop_delay.py b/backend/alembic/versions/aac025d432f0_add_average_speed_and_stop_delay.py deleted file mode 100644 index dcb90a1..0000000 --- a/backend/alembic/versions/aac025d432f0_add_average_speed_and_stop_delay.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Add average_speed and stop_delay - -Revision ID: aac025d432f0 -Revises: bb5c406b9af5 -Create Date: 2026-01-02 22:36:27.855381 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'aac025d432f0' -down_revision: Union[str, None] = 'bb5c406b9af5' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('route_stops', sa.Column('stop_delay_minutes', sa.Integer(), server_default='0', nullable=False)) - op.add_column('routes', sa.Column('average_speed_kmh', sa.Float(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('routes', 'average_speed_kmh') - op.drop_column('route_stops', 'stop_delay_minutes') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/bb5c406b9af5_add_stop_order_to_bus_stop.py b/backend/alembic/versions/bb5c406b9af5_add_stop_order_to_bus_stop.py deleted file mode 100644 index 834d394..0000000 --- a/backend/alembic/versions/bb5c406b9af5_add_stop_order_to_bus_stop.py +++ /dev/null @@ -1,31 +0,0 @@ -"""add_stop_order_to_bus_stop - -Revision ID: bb5c406b9af5 -Revises: 2f4936eb86f0 -Create Date: 2026-01-02 16:16:02.081811 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'bb5c406b9af5' -down_revision: Union[str, None] = '2f4936eb86f0' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('bus_stops', sa.Column('stop_order', sa.Integer(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('bus_stops', 'stop_order') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/c88628a640b6_add_taxi_and_favorite_models.py b/backend/alembic/versions/c88628a640b6_add_taxi_and_favorite_models.py deleted file mode 100644 index 1b46fb2..0000000 --- a/backend/alembic/versions/c88628a640b6_add_taxi_and_favorite_models.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Add taxi and favorite models - -Revision ID: c88628a640b6 -Revises: 8b3e5b0a3e67 -Create Date: 2026-01-27 19:54:26.038491 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = 'c88628a640b6' -down_revision: Union[str, None] = '8b3e5b0a3e67' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('taxis', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('owner_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('phone_number', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('license_plate', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('cooperative', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('corregimiento', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('shift', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('is_active', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_taxis_corregimiento'), 'taxis', ['corregimiento'], unique=False) - op.create_index(op.f('ix_taxis_license_plate'), 'taxis', ['license_plate'], unique=True) - op.create_table('favorites', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('user_id', sa.Uuid(), nullable=False), - sa.Column('item_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('item_id', sa.Uuid(), nullable=False), - sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_favorites_item_id'), 'favorites', ['item_id'], unique=False) - op.create_index(op.f('ix_favorites_item_type'), 'favorites', ['item_type'], unique=False) - op.create_index(op.f('ix_favorites_user_id'), 'favorites', ['user_id'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_favorites_user_id'), table_name='favorites') - op.drop_index(op.f('ix_favorites_item_type'), table_name='favorites') - op.drop_index(op.f('ix_favorites_item_id'), table_name='favorites') - op.drop_table('favorites') - op.drop_index(op.f('ix_taxis_license_plate'), table_name='taxis') - op.drop_index(op.f('ix_taxis_corregimiento'), table_name='taxis') - op.drop_table('taxis') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/c9bb64354775_add_business_coords.py b/backend/alembic/versions/c9bb64354775_add_business_coords.py deleted file mode 100644 index 096088c..0000000 --- a/backend/alembic/versions/c9bb64354775_add_business_coords.py +++ /dev/null @@ -1,33 +0,0 @@ -"""add_business_coords - -Revision ID: c9bb64354775 -Revises: 2088667c3a5f -Create Date: 2026-01-29 09:34:11.595352 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'c9bb64354775' -down_revision: Union[str, None] = '2088667c3a5f' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('businesses', sa.Column('latitude', sa.Float(), nullable=True)) - op.add_column('businesses', sa.Column('longitude', sa.Float(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('businesses', 'longitude') - op.drop_column('businesses', 'latitude') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/ceda6a5abf0e_add_telemetry_table.py b/backend/alembic/versions/ceda6a5abf0e_add_telemetry_table.py deleted file mode 100644 index 6b91428..0000000 --- a/backend/alembic/versions/ceda6a5abf0e_add_telemetry_table.py +++ /dev/null @@ -1,46 +0,0 @@ -"""add telemetry table - -Revision ID: ceda6a5abf0e -Revises: c88628a640b6 -Create Date: 2026-01-27 20:51:06.463716 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'ceda6a5abf0e' -down_revision: Union[str, None] = 'c88628a640b6' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('telemetry', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('user_id', sa.Uuid(), nullable=False), - sa.Column('latitude', sa.Float(), nullable=False), - sa.Column('longitude', sa.Float(), nullable=False), - sa.Column('speed', sa.Float(), nullable=True), - sa.Column('heading', sa.Float(), nullable=True), - sa.Column('status', sa.Enum('ACTIVE', 'OFFLINE', 'BREAK', name='vehiclestatus'), nullable=False), - sa.Column('timestamp', sa.DateTime(), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_telemetry_timestamp'), 'telemetry', ['timestamp'], unique=False) - op.create_index(op.f('ix_telemetry_user_id'), 'telemetry', ['user_id'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_telemetry_user_id'), table_name='telemetry') - op.drop_index(op.f('ix_telemetry_timestamp'), table_name='telemetry') - op.drop_table('telemetry') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/dfbcee895f78_enrich_coupons_with_business_details.py b/backend/alembic/versions/dfbcee895f78_enrich_coupons_with_business_details.py deleted file mode 100644 index 1d50181..0000000 --- a/backend/alembic/versions/dfbcee895f78_enrich_coupons_with_business_details.py +++ /dev/null @@ -1,40 +0,0 @@ -"""enrich_coupons_with_business_details - -Revision ID: dfbcee895f78 -Revises: 93054da1a687 -Create Date: 2026-01-28 11:08:39.830857 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = 'dfbcee895f78' -down_revision: Union[str, None] = '93054da1a687' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('coupons', sa.Column('business_name', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - op.add_column('coupons', sa.Column('business_address', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - op.add_column('coupons', sa.Column('business_phone', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - op.add_column('coupons', sa.Column('image_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - op.add_column('coupons', sa.Column('terms', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('coupons', 'terms') - op.drop_column('coupons', 'image_url') - op.drop_column('coupons', 'business_phone') - op.drop_column('coupons', 'business_address') - op.drop_column('coupons', 'business_name') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/e5fb60c22245_create_businesses_table_and_link_coupons.py b/backend/alembic/versions/e5fb60c22245_create_businesses_table_and_link_coupons.py deleted file mode 100644 index 8927625..0000000 --- a/backend/alembic/versions/e5fb60c22245_create_businesses_table_and_link_coupons.py +++ /dev/null @@ -1,47 +0,0 @@ -"""create_businesses_table_and_link_coupons - -Revision ID: e5fb60c22245 -Revises: 94b4cb57c6c1 -Create Date: 2026-01-28 12:47:52.191359 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import sqlmodel - - -# revision identifiers, used by Alembic. -revision: str = 'e5fb60c22245' -down_revision: Union[str, None] = '94b4cb57c6c1' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('businesses', - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), - sa.Column('address', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('phone', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('image_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('social_media', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('category', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.add_column('coupons', sa.Column('business_id', sa.Uuid(), nullable=True)) - op.create_foreign_key(None, 'coupons', 'businesses', ['business_id'], ['id']) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, 'coupons', type_='foreignkey') - op.drop_column('coupons', 'business_id') - op.drop_table('businesses') - # ### end Alembic commands ### - diff --git a/backend/alembic/versions/ffcd1234abcd_add_color_direction_to_routes.py b/backend/alembic/versions/ffcd1234abcd_add_color_direction_to_routes.py deleted file mode 100644 index 0929638..0000000 --- a/backend/alembic/versions/ffcd1234abcd_add_color_direction_to_routes.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Add color and direction to routes - -Revision ID: ffcd1234abcd -Revises: 3fe72cd3f722 -Create Date: 2026-02-24 16:50:00.000000 - -""" -from typing import Sequence, Union -from alembic import op -import sqlalchemy as sa -import sqlmodel - -# revision identifiers, used by Alembic. -revision: str = 'ffcd1234abcd' -down_revision: Union[str, None] = '3fe72cd3f722' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - -def upgrade() -> None: - op.add_column('routes', sa.Column('color', sqlmodel.sql.sqltypes.AutoString(), nullable=True, server_default='#FEE715')) - op.add_column('routes', sa.Column('direction', sqlmodel.sql.sqltypes.AutoString(), nullable=True, server_default='outbound')) - -def downgrade() -> None: - op.drop_column('routes', 'direction') - op.drop_column('routes', 'color') diff --git a/backend/app/__init__.py b/backend/app/__init__.py deleted file mode 100644 index 38a80f7..0000000 --- a/backend/app/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""SIBU Backend Application.""" - diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py deleted file mode 100644 index 842a1a7..0000000 --- a/backend/app/api/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""API routes.""" - diff --git a/backend/app/api/analytics.py b/backend/app/api/analytics.py deleted file mode 100644 index 7d52fb9..0000000 --- a/backend/app/api/analytics.py +++ /dev/null @@ -1,122 +0,0 @@ -from fastapi import APIRouter, Depends -from sqlmodel import Session, select, func -from app.core.database import get_session -from app.models.analytics import AnalyticsEvent -from app.models.user import User -from typing import Optional, Dict -from datetime import datetime, timedelta -from app.api.deps import get_current_user_optional - -router = APIRouter() - -@router.post("/event") -async def log_event( - event: Dict, - session: Session = Depends(get_session), - current_user: Optional[User] = Depends(get_current_user_optional) -): - user_id = current_user.id if current_user else None - - new_event = AnalyticsEvent( - event_name=event.get("event_name"), - user_id=user_id, - screen_name=event.get("screen_name"), - item_id=event.get("item_id"), - properties=event.get("properties", {}) - ) - session.add(new_event) - session.commit() - return {"status": "ok"} - -@router.get("/strategic") -async def get_strategic_analysis( - session: Session = Depends(get_session) -): - """Deep analysis of how businesses and shuttles are performing.""" - - # 1. SHUTTLE PERFORMANCE - shuttle_previews = session.exec( - select(AnalyticsEvent.item_id, func.count(AnalyticsEvent.id)) - .where(AnalyticsEvent.event_name == "shuttle_view") - .group_by(AnalyticsEvent.item_id) - ).all() - - shuttle_contacts = session.exec( - select(AnalyticsEvent.item_id, func.count(AnalyticsEvent.id)) - .where(AnalyticsEvent.event_name == "shuttle_contact") - .group_by(AnalyticsEvent.item_id) - ).all() - - shuttle_map = {r[0]: {"views": r[1], "contacts": 0} for r in shuttle_previews if r[0]} - for r in shuttle_contacts: - if r[0] in shuttle_map: - shuttle_map[r[0]]["contacts"] = r[1] - else: - shuttle_map[r[0]] = {"views": 0, "contacts": r[1]} - - # 2. BUSINESS PERFORMANCE - biz_views = session.exec( - select(AnalyticsEvent.item_id, func.count(AnalyticsEvent.id)) - .where(AnalyticsEvent.event_name == "business_view") - .group_by(AnalyticsEvent.item_id) - ).all() - - promo_clicks = session.exec( - select(AnalyticsEvent.item_id, func.count(AnalyticsEvent.id)) - .where(AnalyticsEvent.event_name == "promo_click") - .group_by(AnalyticsEvent.item_id) - ).all() - - biz_map = {r[0]: {"views": r[1], "promos": 0} for r in biz_views if r[0]} - for r in promo_clicks: - if r[0] in biz_map: - biz_map[r[0]]["promos"] = r[1] - else: - biz_map[r[0]] = {"views": 0, "promos": r[1]} - - # 3. TOP STOPS (CASETAS CON MÁS GENTE) - top_stops = session.exec( - select(AnalyticsEvent.item_id, func.count(AnalyticsEvent.id)) - .where(AnalyticsEvent.event_name == "stop_selected") - .group_by(AnalyticsEvent.item_id) - .order_by(func.count(AnalyticsEvent.id).desc()) - .limit(10) - ).all() - - # 4. ACTIVE USERS - total_active_users = session.exec(select(func.count(func.distinct(AnalyticsEvent.user_id))).where(AnalyticsEvent.user_id != None)).one() - - # 5. PEAK HOURS BY USER TYPE - hour_expr = func.extract('hour', AnalyticsEvent.timestamp) - reg_usage = session.exec(select(hour_expr, func.count(AnalyticsEvent.id)).where(AnalyticsEvent.user_id != None).group_by(hour_expr)).all() - guest_usage = session.exec(select(hour_expr, func.count(AnalyticsEvent.id)).where(AnalyticsEvent.user_id == None).group_by(hour_expr)).all() - - usage_patterns = { - "registered": {int(h): c for h, c in reg_usage}, - "guests": {int(h): c for h, c in guest_usage} - } - - return { - "shuttles": shuttle_map, - "businesses": biz_map, - "top_stops": [{"id": r[0], "count": r[1]} for r in top_stops], - "users": { - "registered_active": total_active_users, - "patterns": usage_patterns - }, - "summary": { - "total_shuttle_contacts": sum(sh[1] for sh in shuttle_contacts), - "total_promo_clicks": sum(p[1] for p in promo_clicks), - "total_biz_views": sum(b[1] for b in biz_views) - } - } - -@router.get("/dashboard/stats") -async def get_dashboard_stats( - session: Session = Depends(get_session) -): - # Base dashboard stats for general overview - total_events = session.exec(select(func.count(AnalyticsEvent.id))).one() - return { - "total_events": total_events - } diff --git a/backend/app/api/auth/__init__.py b/backend/app/api/auth/__init__.py deleted file mode 100644 index 1e5b0ba..0000000 --- a/backend/app/api/auth/__init__.py +++ /dev/null @@ -1,314 +0,0 @@ -import os -import json -import shutil -from uuid import uuid4 -from typing import Annotated, Optional -from fastapi import APIRouter, HTTPException, status, Depends, UploadFile, File, Form -from sqlmodel import Session, select -from app.core.database import get_session -from app.core.security import verify_password, get_password_hash, create_access_token, get_token_payload -from app.models.user import User, DriverProfile, UserRole, VehicleType -from app.api.deps import oauth2_scheme -from app.schemas.user import PassengerCreate, Token, UserResponse, LoginRequest, GoogleLoginRequest -import firebase_admin -from firebase_admin import auth as firebase_auth, credentials - -# Initialize Firebase Admin SDK -# Supports two methods: -# 1. FIREBASE_SERVICE_ACCOUNT_JSON env var with the full JSON as a string (recommended for Render/production) -# 2. GOOGLE_APPLICATION_CREDENTIALS env var pointing to a JSON file path (local dev) -try: - if not firebase_admin._apps: - sa_json = os.environ.get("FIREBASE_SERVICE_ACCOUNT_JSON") - if sa_json: - # Parse the JSON string directly from environment variable - sa_dict = json.loads(sa_json) - cred = credentials.Certificate(sa_dict) - firebase_admin.initialize_app(cred) - print("DEBUG: Firebase Admin initialized from FIREBASE_SERVICE_ACCOUNT_JSON env var") - elif os.environ.get("GOOGLE_APPLICATION_CREDENTIALS"): - # Use file path from GOOGLE_APPLICATION_CREDENTIALS - firebase_admin.initialize_app() - print("DEBUG: Firebase Admin initialized from GOOGLE_APPLICATION_CREDENTIALS file") - else: - print("WARNING: No Firebase credentials found. Set FIREBASE_SERVICE_ACCOUNT_JSON or GOOGLE_APPLICATION_CREDENTIALS.") - firebase_admin.initialize_app() -except Exception as e: - print(f"WARNING: Firebase Admin could not be initialized: {e}") - -router = APIRouter(prefix="/api/auth", tags=["auth"]) - -UPLOAD_DIR = "uploads" - - -@router.post("/login", response_model=Token) -async def login( - data: LoginRequest, - session: Session = Depends(get_session) -): - print(f"DEBUG: Login attempt for email: {data.email}") - user = session.exec(select(User).where(User.email == data.email)).first() - if not user: - print(f"DEBUG: User not found: {data.email}") - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect email or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - - if not verify_password(data.password, user.hashed_password): - print(f"DEBUG: Invalid password for: {data.email}") - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect email or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - - print(f"DEBUG: Successful login for: {data.email} as {user.role}") - - # Token expiration can be extended if keep_session is true - import datetime - expires = datetime.timedelta(days=30) if data.keep_session else datetime.timedelta(days=1) - - access_token = create_access_token( - subject=user.id, - role=user.role, - full_name=user.full_name, - expires_delta=expires - ) - return { - "access_token": access_token, - "token_type": "bearer", - "role": user.role, - "full_name": user.full_name, - "profile_photo_url": user.profile_photo_url - } - - -@router.post("/google", response_model=Token) -async def google_login( - data: GoogleLoginRequest, - session: Session = Depends(get_session) -): - try: - # Verify the ID token sent by the frontend - decoded_token = firebase_auth.verify_id_token(data.id_token) - email = decoded_token.get("email") - full_name = decoded_token.get("name", "") - profile_photo = decoded_token.get("picture", "") - - # Check if user exists - user = session.exec(select(User).where(User.email == email)).first() - - if not user: - # Create new user if it doesn't exist (Passenger as default) - user = User( - email=email, - full_name=full_name, - hashed_password=get_password_hash(str(uuid4())), # Random pass, won't be used - role=UserRole.PASSENGER, - profile_photo_url=profile_photo, - is_verified=True - ) - session.add(user) - session.commit() - session.refresh(user) - print(f"DEBUG: Created new user via Google: {email}") - - # Create access token - import datetime - expires = datetime.timedelta(days=30) - access_token = create_access_token( - subject=user.id, - role=user.role, - full_name=user.full_name, - expires_delta=expires - ) - - return { - "access_token": access_token, - "token_type": "bearer", - "role": user.role, - "full_name": user.full_name, - "profile_photo_url": user.profile_photo_url - } - except Exception as e: - print(f"DEBUG: Google Login failed: {e}") - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=f"Invalid Google Token: {str(e)}", - headers={"WWW-Authenticate": "Bearer"}, - ) - - -@router.post("/register/passenger", response_model=UserResponse) -async def register_passenger( - data: PassengerCreate, - session: Session = Depends(get_session) -): - # Check if user exists - existing_user = session.exec(select(User).where(User.email == data.email)).first() - if existing_user: - raise HTTPException(status_code=400, detail="Email already registered") - - new_user = User( - email=data.email, - full_name=data.full_name, - hashed_password=get_password_hash(data.password), - role=UserRole.PASSENGER - ) - session.add(new_user) - session.commit() - session.refresh(new_user) - return new_user - - -@router.post("/register/driver", response_model=UserResponse) -async def register_driver( - full_name: str = Form(...), - email: str = Form(...), - phone_number: str = Form(...), - password: str = Form(...), - cedula: str = Form(...), - vehicle_type: VehicleType = Form(...), - license_plate: str = Form(...), - cooperative_name: Optional[str] = Form(None), - profile_photo: Optional[UploadFile] = File(None), - vehicle_photo: UploadFile = File(...), - shift: Optional[str] = Form(None), - payment_methods: Optional[str] = Form(None), - speaks_english: bool = Form(False), - session: Session = Depends(get_session) -): - # Check if user exists - existing_user = session.exec(select(User).where(User.email == email)).first() - if existing_user: - raise HTTPException(status_code=400, detail="Email already registered") - - # Save photos - profile_photo_url = None - if profile_photo: - ext = os.path.splitext(profile_photo.filename)[1] - filename = f"{uuid4()}{ext}" - path = os.path.join(UPLOAD_DIR, "profiles", filename) - with open(path, "wb") as buffer: - shutil.copyfileobj(profile_photo.file, buffer) - profile_photo_url = f"/uploads/profiles/{filename}" - - ext_v = os.path.splitext(vehicle_photo.filename)[1] - v_filename = f"{uuid4()}{ext_v}" - v_path = os.path.join(UPLOAD_DIR, "vehicles", v_filename) - with open(v_path, "wb") as buffer: - shutil.copyfileobj(vehicle_photo.file, buffer) - vehicle_photo_url = f"/uploads/vehicles/{v_filename}" - - # Create User - new_user = User( - email=email, - full_name=full_name, - hashed_password=get_password_hash(password), - role=UserRole.DRIVER, - is_verified=True, # Auto verify since it's admin registered now - profile_photo_url=profile_photo_url - ) - session.add(new_user) - session.commit() - session.refresh(new_user) - - # Create Driver Profile - profile = DriverProfile( - user_id=new_user.id, - cedula=cedula, - vehicle_type=vehicle_type, - license_plate=license_plate, - photo_url=profile_photo_url, - vehicle_photo_url=vehicle_photo_url, - cooperative_name=cooperative_name, - shift=shift, - payment_methods=payment_methods, - speaks_english=speaks_english - ) - session.add(profile) - session.commit() - - return new_user - -@router.get("/me") -async def get_current_user( - token: Annotated[str, Depends(oauth2_scheme)], - session: Session = Depends(get_session) -): - """Get current logged in user details.""" - payload = get_token_payload(token) - user_id = payload.get("sub") - - user = session.get(User, user_id) - if not user: - raise HTTPException(status_code=404, detail="User not found") - - result = { - "id": user.id, - "email": user.email, - "full_name": user.full_name, - "role": user.role, - "is_verified": user.is_verified, - "profile_photo_url": user.profile_photo_url, - "driver_profile": None - } - - if user.driver_profile: - dp = user.driver_profile - result["driver_profile"] = { - "cedula": dp.cedula, - "vehicle_type": dp.vehicle_type, - "license_plate": dp.license_plate, - "cooperative_name": dp.cooperative_name, - "photo_url": dp.photo_url, - "shift": dp.shift, - "payment_methods": dp.payment_methods, - "speaks_english": dp.speaks_english - } - - return result - -@router.patch("/me", response_model=UserResponse) -async def update_me( - full_name: Optional[str] = Form(None), - password: Optional[str] = Form(None), - profile_photo: Optional[UploadFile] = File(None), - token: Annotated[str, Depends(oauth2_scheme)] = None, - session: Session = Depends(get_session) -): - """Update current user profile info.""" - payload = get_token_payload(token) - user_id = payload.get("sub") - user = session.get(User, user_id) - if not user: - raise HTTPException(status_code=404, detail="User not found") - - if full_name: - user.full_name = full_name - if password: - user.hashed_password = get_password_hash(password) - - if profile_photo: - # Create directory if not exists - profile_dir = os.path.join(UPLOAD_DIR, "profiles") - os.makedirs(profile_dir, exist_ok=True) - - ext = os.path.splitext(profile_photo.filename)[1] - filename = f"{uuid4()}{ext}" - path = os.path.join(profile_dir, filename) - with open(path, "wb") as buffer: - shutil.copyfileobj(profile_photo.file, buffer) - user.profile_photo_url = f"/uploads/profiles/{filename}" - - # If user is driver, also update driver profile photo_url for backwards compatibility/sync - if user.driver_profile: - user.driver_profile.photo_url = user.profile_photo_url - session.add(user.driver_profile) - - session.add(user) - session.commit() - session.refresh(user) - return user diff --git a/backend/app/api/bus_stops/__init__.py b/backend/app/api/bus_stops/__init__.py deleted file mode 100644 index 29cfe1a..0000000 --- a/backend/app/api/bus_stops/__init__.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Bus stops API endpoints.""" -from fastapi import APIRouter, Depends, HTTPException -from sqlmodel import Session, select -from typing import List -from uuid import UUID - -from app.core.database import get_session -from app.models.bus_stop import BusStop -from app.schemas.bus_stop import BusStopResponse, BusStopCreate, BusStopUpdate -from app.api.deps import get_current_admin - -router = APIRouter(prefix="/api/bus-stops", tags=["bus-stops"]) - - -@router.get("", response_model=List[BusStopResponse]) -async def get_bus_stops(session: Session = Depends(get_session)): - """Get all bus stops.""" - statement = select(BusStop) - stops = session.exec(statement).all() - return stops - - -@router.get("/{stop_id}", response_model=BusStopResponse) -async def get_bus_stop(stop_id: UUID, session: Session = Depends(get_session)): - """Get a single bus stop by ID.""" - stop = session.get(BusStop, stop_id) - if not stop: - raise HTTPException(status_code=404, detail="Bus stop not found") - return stop - - -@router.get("/{stop_id}/routes") -async def get_bus_stop_routes(stop_id: UUID, session: Session = Depends(get_session)): - """Get all routes passing through a bus stop.""" - from app.models.route_stop import RouteStop - from app.models.route import Route - - statement = select(Route).join( - RouteStop, RouteStop.route_id == Route.id - ).where(RouteStop.stop_id == stop_id) - - routes = session.exec(statement).all() - return routes - -@router.post("", response_model=BusStopResponse) -async def create_bus_stop( - bus_stop: BusStopCreate, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Create a new bus stop (Admin only).""" - db_stop = BusStop.model_validate(bus_stop) - session.add(db_stop) - session.commit() - session.refresh(db_stop) - return db_stop - -@router.put("/{stop_id}", response_model=BusStopResponse) -async def update_bus_stop( - stop_id: UUID, - stop_update: BusStopUpdate, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update a bus stop (Admin only).""" - db_stop = session.get(BusStop, stop_id) - if not db_stop: - raise HTTPException(status_code=404, detail="Bus stop not found") - - stop_data = stop_update.model_dump(exclude_unset=True) - for key, value in stop_data.items(): - setattr(db_stop, key, value) - - session.add(db_stop) - session.commit() - session.refresh(db_stop) - return db_stop - -@router.delete("/{stop_id}") -async def delete_bus_stop( - stop_id: UUID, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Delete a bus stop (Admin only).""" - db_stop = session.get(BusStop, stop_id) - if not db_stop: - raise HTTPException(status_code=404, detail="Bus stop not found") - - session.delete(db_stop) - session.commit() - return {"ok": True} diff --git a/backend/app/api/businesses.py b/backend/app/api/businesses.py deleted file mode 100644 index 92b42fb..0000000 --- a/backend/app/api/businesses.py +++ /dev/null @@ -1,145 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status, Form, File, UploadFile -from sqlmodel import Session, select -from typing import List, Optional -from app.core.database import get_session -from app.models.business import Business -from app.models.user import User, UserRole -from app.api.deps import get_current_user - -from app.services.image_handler import save_image, delete_image - -router = APIRouter(prefix="/api/businesses", tags=["businesses"]) - -@router.get("", response_model=List[Business]) -async def list_businesses( - *, - session: Session = Depends(get_session) -): - """List all businesses.""" - statement = select(Business) - businesses = session.exec(statement).all() - return businesses - -@router.post("", response_model=Business) -async def create_business( - *, - session: Session = Depends(get_session), - name: str = Form(...), - category: str = Form(...), - address: str = Form(...), - phone: Optional[str] = Form(None), - social_media: Optional[str] = Form(None), - latitude: Optional[float] = Form(None), - longitude: Optional[float] = Form(None), - image: Optional[UploadFile] = File(None), - current_user: User = Depends(get_current_user) -): - """Create a new business (Promoters and Admins only).""" - if current_user.role not in [UserRole.ADMIN, UserRole.PROMOTER]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only promoters and admins can manage businesses" - ) - - image_url = None - if image: - image_url = save_image(image, "businesses") - - db_business = Business( - name=name, - category=category, - address=address, - phone=phone, - social_media=social_media, - latitude=latitude, - longitude=longitude, - image_url=image_url - ) - session.add(db_business) - session.commit() - session.refresh(db_business) - return db_business - -@router.patch("/{business_id}", response_model=Business) -async def update_business( - *, - session: Session = Depends(get_session), - business_id: str, - name: Optional[str] = Form(None), - category: Optional[str] = Form(None), - address: Optional[str] = Form(None), - phone: Optional[str] = Form(None), - social_media: Optional[str] = Form(None), - latitude: Optional[float] = Form(None), - longitude: Optional[float] = Form(None), - image: Optional[UploadFile] = File(None), - current_user: User = Depends(get_current_user) -): - """Update a business (Promoters and Admins only).""" - if current_user.role not in [UserRole.ADMIN, UserRole.PROMOTER]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only promoters and admins can manage businesses" - ) - - db_business = session.get(Business, business_id) - if not db_business: - raise HTTPException(status_code=404, detail="Business not found") - - if name is not None: - db_business.name = name - if category is not None: - db_business.category = category - if address is not None: - db_business.address = address - if phone is not None: - db_business.phone = phone - if social_media is not None: - db_business.social_media = social_media - if latitude is not None: - db_business.latitude = latitude - if longitude is not None: - db_business.longitude = longitude - - if image: - if db_business.image_url: - delete_image(db_business.image_url) - db_business.image_url = save_image(image, "businesses") - - session.add(db_business) - session.commit() - session.refresh(db_business) - return db_business - -@router.get("/{business_id}", response_model=Business) -async def get_business(business_id: str, session: Session = Depends(get_session)): - """Get a single business by ID.""" - business = session.get(Business, business_id) - if not business: - raise HTTPException(status_code=404, detail="Business not found") - return business - -@router.delete("/{business_id}") -async def delete_business( - *, - session: Session = Depends(get_session), - business_id: str, - current_user: User = Depends(get_current_user) -): - """Delete a business (Promoters and Admins only).""" - if current_user.role not in [UserRole.ADMIN, UserRole.PROMOTER]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only promoters and admins can manage businesses" - ) - - db_business = session.get(Business, business_id) - if not db_business: - raise HTTPException(status_code=404, detail="Business not found") - - if db_business.image_url: - delete_image(db_business.image_url) - - session.delete(db_business) - session.commit() - return {"status": "success", "message": "Business deleted"} diff --git a/backend/app/api/coupons.py b/backend/app/api/coupons.py deleted file mode 100644 index 9d27844..0000000 --- a/backend/app/api/coupons.py +++ /dev/null @@ -1,147 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status, Form, File, UploadFile -from sqlmodel import Session, select -from sqlalchemy.orm import joinedload -from typing import List, Optional -from uuid import UUID -from datetime import datetime -from app.core.database import get_session -from app.models.coupon import Coupon -from app.models.user import User, UserRole -from app.api.deps import get_current_user -from app.services.image_handler import save_image, delete_image - -router = APIRouter(prefix="/api/coupons", tags=["coupons"]) - -@router.get("", response_model=List[Coupon]) -async def list_coupons( - *, - session: Session = Depends(get_session), - active_only: bool = True -): - """List all coupons.""" - statement = select(Coupon).options(joinedload(Coupon.business)) - if active_only: - statement = statement.where(Coupon.is_active) - - coupons = session.exec(statement).all() - return coupons - -@router.post("", response_model=Coupon) -async def create_coupon( - *, - session: Session = Depends(get_session), - title: str = Form(...), - business_id: Optional[UUID] = Form(None), - description: Optional[str] = Form(None), - business_name: Optional[str] = Form(None), - business_address: Optional[str] = Form(None), - business_phone: Optional[str] = Form(None), - discount_percentage: Optional[int] = Form(None), - discount_amount: Optional[float] = Form(None), - category: Optional[str] = Form(None), - valid_from: Optional[datetime] = Form(None), - valid_until: Optional[datetime] = Form(None), - is_active: bool = Form(True), - image: Optional[UploadFile] = File(None), - current_user: User = Depends(get_current_user) -): - """Create a new coupon (Promoters and Admins only).""" - if current_user.role not in [UserRole.ADMIN, UserRole.PROMOTER]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only promoters and admins can create coupons" - ) - - image_url = None - if image: - image_url = save_image(image, "coupons") - - db_coupon = Coupon( - title=title, - business_id=business_id, - description=description, - business_name=business_name, - business_address=business_address, - business_phone=business_phone, - discount_percentage=discount_percentage, - discount_amount=discount_amount, - category=category, - valid_from=valid_from, - valid_until=valid_until, - is_active=is_active, - image_url=image_url - ) - session.add(db_coupon) - session.commit() - session.refresh(db_coupon) - return db_coupon - -@router.patch("/{coupon_id}", response_model=Coupon) -async def update_coupon( - *, - session: Session = Depends(get_session), - coupon_id: UUID, - title: Optional[str] = Form(None), - description: Optional[str] = Form(None), - discount_percentage: Optional[int] = Form(None), - valid_until: Optional[datetime] = Form(None), - is_active: Optional[bool] = Form(None), - image: Optional[UploadFile] = File(None), - current_user: User = Depends(get_current_user) -): - """Update a coupon (Promoters and Admins only).""" - if current_user.role not in [UserRole.ADMIN, UserRole.PROMOTER]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only promoters and admins can update coupons" - ) - - db_coupon = session.get(Coupon, coupon_id) - if not db_coupon: - raise HTTPException(status_code=404, detail="Coupon not found") - - if title is not None: - db_coupon.title = title - if description is not None: - db_coupon.description = description - if discount_percentage is not None: - db_coupon.discount_percentage = discount_percentage - if valid_until is not None: - db_coupon.valid_until = valid_until - if is_active is not None: - db_coupon.is_active = is_active - - if image: - if db_coupon.image_url: - delete_image(db_coupon.image_url) - db_coupon.image_url = save_image(image, "coupons") - - session.add(db_coupon) - session.commit() - session.refresh(db_coupon) - return db_coupon - -@router.delete("/{coupon_id}") -async def delete_coupon( - *, - session: Session = Depends(get_session), - coupon_id: UUID, - current_user: User = Depends(get_current_user) -): - """Delete a coupon (Promoters and Admins only).""" - if current_user.role not in [UserRole.ADMIN, UserRole.PROMOTER]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only promoters and admins can delete coupons" - ) - - db_coupon = session.get(Coupon, coupon_id) - if not db_coupon: - raise HTTPException(status_code=404, detail="Coupon not found") - - if db_coupon.image_url: - delete_image(db_coupon.image_url) - - session.delete(db_coupon) - session.commit() - return {"status": "success", "message": "Coupon deleted"} diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py deleted file mode 100644 index 1865e64..0000000 --- a/backend/app/api/deps.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import Annotated, Dict, Optional -from fastapi import Depends, HTTPException, status -from fastapi.security import OAuth2PasswordBearer -from jose import jwt, JWTError -from app.core.config import settings -from app.core.security import ALGORITHM -from sqlmodel import Session -from app.core.database import get_session -from app.models.user import User - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/auth/login", auto_error=False) - -def get_token_payload(token: Annotated[str, Depends(oauth2_scheme)]) -> Dict: - if not token: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, settings.secret_key, algorithms=[ALGORITHM]) - return payload - except JWTError: - raise credentials_exception - -async def get_current_user_token(token: Annotated[str, Depends(oauth2_scheme)]) -> Dict: - return get_token_payload(token) - -async def get_current_admin(token: Annotated[str, Depends(oauth2_scheme)]) -> bool: - from app.models.user import UserRole - payload = get_token_payload(token) - role: str = payload.get("role") - - # Check for both "admin" and "ADMIN" for robust authorization - if role not in ["admin", "ADMIN", UserRole.ADMIN]: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="The user doesn't have enough privileges", - ) - return True - -async def get_current_user( - token: Annotated[str, Depends(oauth2_scheme)], - session: Session = Depends(get_session) -) -> User: - payload = get_token_payload(token) - user_id = payload.get("sub") - if not user_id: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - ) - user = session.get(User, user_id) - if not user: - raise HTTPException(status_code=404, detail="User not found") - return user - -async def get_current_user_optional( - token: Optional[str] = Depends(oauth2_scheme), - session: Session = Depends(get_session) -) -> Optional[User]: - if not token: - return None - try: - payload = jwt.decode(token, settings.secret_key, algorithms=[ALGORITHM]) - user_id = payload.get("sub") - if not user_id: - return None - return session.get(User, user_id) - except JWTError: - return None diff --git a/backend/app/api/favorites/__init__.py b/backend/app/api/favorites/__init__.py deleted file mode 100644 index 0f27f84..0000000 --- a/backend/app/api/favorites/__init__.py +++ /dev/null @@ -1,109 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException -from sqlmodel import Session, select -from typing import List -from app.core.database import get_session -from app.models.favorite import Favorite -from app.api.deps import get_current_user -from app.models.user import User -from pydantic import BaseModel - -router = APIRouter(prefix="/api/favorites", tags=["favorites"]) - - -class FavoriteCreate(BaseModel): - item_type: str # 'coupon', 'business', 'taxi', 'route' - item_id: str - item_name: str | None = None - item_image: str | None = None - - -@router.get("") -async def get_favorites( - item_type: str | None = None, - session: Session = Depends(get_session), - current_user: User = Depends(get_current_user) -) -> List[Favorite]: - """Get all favorites for the current user, optionally filtered by type.""" - statement = select(Favorite).where(Favorite.user_id == current_user.id) - - if item_type: - statement = statement.where(Favorite.item_type == item_type) - - statement = statement.order_by(Favorite.created_at.desc()) - favorites = session.exec(statement).all() - return list(favorites) - - -@router.post("") -async def add_favorite( - favorite_data: FavoriteCreate, - session: Session = Depends(get_session), - current_user: User = Depends(get_current_user) -) -> Favorite: - """Add an item to favorites.""" - # Check if already favorited - existing = session.exec( - select(Favorite).where( - Favorite.user_id == current_user.id, - Favorite.item_type == favorite_data.item_type, - Favorite.item_id == favorite_data.item_id - ) - ).first() - - if existing: - raise HTTPException(status_code=400, detail="Item already in favorites") - - favorite = Favorite( - user_id=current_user.id, - item_type=favorite_data.item_type, - item_id=favorite_data.item_id, - item_name=favorite_data.item_name, - item_image=favorite_data.item_image - ) - session.add(favorite) - session.commit() - session.refresh(favorite) - return favorite - - -@router.delete("/{item_type}/{item_id}") -async def remove_favorite( - item_type: str, - item_id: str, - session: Session = Depends(get_session), - current_user: User = Depends(get_current_user) -): - """Remove an item from favorites.""" - favorite = session.exec( - select(Favorite).where( - Favorite.user_id == current_user.id, - Favorite.item_type == item_type, - Favorite.item_id == item_id - ) - ).first() - - if not favorite: - raise HTTPException(status_code=404, detail="Favorite not found") - - session.delete(favorite) - session.commit() - return {"ok": True} - - -@router.get("/check/{item_type}/{item_id}") -async def check_favorite( - item_type: str, - item_id: str, - session: Session = Depends(get_session), - current_user: User = Depends(get_current_user) -) -> dict: - """Check if an item is favorited.""" - favorite = session.exec( - select(Favorite).where( - Favorite.user_id == current_user.id, - Favorite.item_type == item_type, - Favorite.item_id == item_id - ) - ).first() - - return {"is_favorite": favorite is not None} diff --git a/backend/app/api/reports.py b/backend/app/api/reports.py deleted file mode 100644 index 8d7970c..0000000 --- a/backend/app/api/reports.py +++ /dev/null @@ -1,96 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from sqlmodel import Session, select -from typing import List, Optional -from uuid import UUID - -from app.core.database import get_session -from app.api.deps import get_current_admin, get_current_user_optional -from app.models.report import Report -from app.models.user import User -from app.schemas.report import ReportCreate, ReportUpdate, ReportResponse - -router = APIRouter(prefix="/api/reports", tags=["reports"]) - -@router.post("", response_model=ReportResponse, status_code=status.HTTP_201_CREATED) -async def create_report( - report_in: ReportCreate, - session: Session = Depends(get_session), - current_user: Optional[User] = Depends(get_current_user_optional) -): - """Create a new user report.""" - report = Report( - message=report_in.message, - user_id=current_user.id if current_user else None - ) - session.add(report) - session.commit() - session.refresh(report) - - return ReportResponse( - id=report.id, - user_id=report.user_id, - user_name=current_user.full_name if current_user else "Anónimo", - message=report.message, - status=report.status, - created_at=report.created_at - ) - -@router.get("", response_model=List[ReportResponse]) -async def get_reports( - session: Session = Depends(get_session), - admin_auth: bool = Depends(get_current_admin) -): - """Get all reports (Admin only).""" - statement = select(Report) - results = session.exec(statement).all() - - reports = [] - for report in results: - user_name = "Anónimo" - if report.user_id: - user = session.get(User, report.user_id) - if user: - user_name = user.full_name - - reports.append(ReportResponse( - id=report.id, - user_id=report.user_id, - user_name=user_name, - message=report.message, - status=report.status, - created_at=report.created_at - )) - - return reports - -@router.patch("/{report_id}", response_model=ReportResponse) -async def update_report_status( - report_id: UUID, - report_update: ReportUpdate, - session: Session = Depends(get_session), - admin_auth: bool = Depends(get_current_admin) -): - """Update report status (Admin only).""" - report = session.get(Report, report_id) - if not report: - raise HTTPException(status_code=404, detail="Report not found") - - report.status = report_update.status - session.add(report) - session.commit() - session.refresh(report) - - user_name = "Anónimo" - if report.user_id: - user = session.get(User, report.user_id) - if user: - user_name = user.full_name - - return ReportResponse( - id=report.id, - user_id=report.user_id, - user_name=user_name, - message=report.message, - status=report.status, - created_at=report.created_at - ) diff --git a/backend/app/api/routes/__init__.py b/backend/app/api/routes/__init__.py deleted file mode 100644 index 84e857b..0000000 --- a/backend/app/api/routes/__init__.py +++ /dev/null @@ -1,294 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, Query -from sqlmodel import Session, select -from typing import List, Optional -from sqlalchemy import func - -from app.core.database import get_session -from app.models.route import Route -from app.models.route_stop import RouteStop -from app.schemas.route import RouteResponse, RouteCreate, RouteUpdate -from app.schemas.route_stop import RouteStopCreate, RouteStopUpdate -from app.api.deps import get_current_admin - -router = APIRouter(prefix="/api/routes", tags=["routes"]) - - -@router.get("", response_model=List[RouteResponse]) -async def get_routes( - origin_city: Optional[str] = Query(None), - destination_city: Optional[str] = Query(None), - session: Session = Depends(get_session) -): - """Get all routes with optional filtering by origin and destination city.""" - statement = select(Route) - - if origin_city: - statement = statement.where(Route.origin_city.contains(origin_city)) - - if destination_city: - statement = statement.where(Route.destination_city.contains(destination_city)) - - routes = session.exec(statement).all() - return routes - - -@router.get("/{route_id}", response_model=RouteResponse) -async def get_route(route_id: str, session: Session = Depends(get_session)): - """Get a single route by ID.""" - route = session.get(Route, route_id) - if not route: - raise HTTPException(status_code=404, detail="Route not found") - return route - - -@router.get("/{route_id}/stops") -async def get_route_stops(route_id: str, session: Session = Depends(get_session)): - """Get all stops for a route.""" - from app.models.route_stop import RouteStop - from app.models.bus_stop import BusStop - from uuid import UUID - - try: - route_id_uuid = UUID(route_id) - except ValueError: - raise HTTPException(status_code=400, detail="Invalid route ID format") - - statement = select(RouteStop, BusStop).join( - BusStop, RouteStop.stop_id == BusStop.id - ).where(RouteStop.route_id == route_id_uuid).order_by(RouteStop.stop_order) - - results = session.exec(statement).all() - # Merge RouteStop data into BusStop response - stops = [] - for route_stop, bus_stop in results: - stop_data = bus_stop.model_dump() - # Convert UUIDs to strings for JSON compatibility - stop_data['id'] = str(stop_data['id']) - stop_data['stop_order'] = route_stop.stop_order - stop_data['travel_time_minutes'] = route_stop.travel_time_minutes - stop_data['stop_delay_minutes'] = route_stop.stop_delay_minutes - stop_data['is_pickup_point'] = route_stop.is_pickup_point - stop_data['is_dropoff_point'] = route_stop.is_dropoff_point - stops.append(stop_data) - - return stops - -@router.post("", response_model=RouteResponse) -async def create_route( - route: RouteCreate, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Create a new route (Admin only).""" - try: - db_route = Route.model_validate(route) - session.add(db_route) - session.commit() - session.refresh(db_route) - return db_route - except Exception as e: - session.rollback() - import traceback - error_detail = f"{str(e)}\n\n{traceback.format_exc()}" - raise HTTPException(status_code=400, detail=error_detail) - -@router.put("/{route_id}", response_model=RouteResponse) -async def update_route( - route_id: str, - route_update: RouteUpdate, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update a route (Admin only).""" - db_route = session.get(Route, route_id) - if not db_route: - raise HTTPException(status_code=404, detail="Route not found") - - route_data = route_update.model_dump(exclude_unset=True) - for key, value in route_data.items(): - setattr(db_route, key, value) - - session.add(db_route) - session.commit() - session.refresh(db_route) - return db_route - -@router.delete("/{route_id}") -async def delete_route( - route_id: str, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Delete a route (Admin only).""" - db_route = session.get(Route, route_id) - if not db_route: - raise HTTPException(status_code=404, detail="Route not found") - - session.delete(db_route) - session.commit() - return {"ok": True} - -# Route Stop Management with Cascade - -@router.post("/{route_id}/stops") -async def add_stop_to_route( - route_id: str, - stop_data: RouteStopCreate, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Add a stop to a route with cascading order adjustment.""" - from uuid import UUID - try: - route_id_uuid = UUID(route_id) - stop_id_uuid = UUID(stop_data.stop_id) - except ValueError: - raise HTTPException(status_code=400, detail="Invalid UUID format") - - # 1. Check if route exists - route = session.get(Route, route_id_uuid) - if not route: - raise HTTPException(status_code=404, detail="Route not found") - - # 2. Determine stop order - if stop_data.stop_order is None: - # Append to end - max_order = session.exec(select(func.max(RouteStop.stop_order)).where(RouteStop.route_id == route_id_uuid)).one() - # handle case where max_order is None (no stops) - stop_data.stop_order = (max_order or 0) + 1 - else: - # Shift existing stops equal to or greater than new order - existing_stops = session.exec( - select(RouteStop).where(RouteStop.route_id == route_id_uuid, RouteStop.stop_order >= stop_data.stop_order) - ).all() - for stop in existing_stops: - stop.stop_order += 1 - session.add(stop) - - # 3. Create new RouteStop - new_stop = RouteStop( - route_id=route_id_uuid, - stop_id=stop_id_uuid, - stop_order=stop_data.stop_order, - travel_time_minutes=stop_data.travel_time_minutes, - stop_delay_minutes=stop_data.stop_delay_minutes or 0, - is_pickup_point=stop_data.is_pickup_point, - is_dropoff_point=stop_data.is_dropoff_point - ) - session.add(new_stop) - session.commit() - session.refresh(new_stop) - return new_stop - -@router.put("/{route_id}/stops/{stop_id}") -async def update_route_stop_order( - route_id: str, - stop_id: str, - update_data: RouteStopUpdate, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update a route stop, potentially reordering others.""" - from uuid import UUID - try: - route_id_uuid = UUID(route_id) - stop_id_uuid = UUID(stop_id) - except ValueError: - raise HTTPException(status_code=400, detail="Invalid UUID format") - route_stop = session.exec( - select(RouteStop).where(RouteStop.route_id == route_id_uuid, RouteStop.stop_id == stop_id_uuid) - ).first() - - if not route_stop: - raise HTTPException(status_code=404, detail="Stop not found on this route") - - old_order = route_stop.stop_order - - # Update fields - if update_data.is_pickup_point is not None: - route_stop.is_pickup_point = update_data.is_pickup_point - if update_data.is_dropoff_point is not None: - route_stop.is_dropoff_point = update_data.is_dropoff_point - if update_data.travel_time_minutes is not None: - route_stop.travel_time_minutes = update_data.travel_time_minutes - if update_data.stop_delay_minutes is not None: - route_stop.stop_delay_minutes = update_data.stop_delay_minutes - - # Reordering logic - if update_data.stop_order is not None and update_data.stop_order != old_order: - new_order = update_data.stop_order - - if new_order > old_order: - # Moving down: shift stops between old+1 and new DOWN (-1) - stops_to_shift = session.exec( - select(RouteStop).where( - RouteStop.route_id == route_id_uuid, - RouteStop.stop_order > old_order, - RouteStop.stop_order <= new_order - ) - ).all() - for s in stops_to_shift: - s.stop_order -= 1 - session.add(s) - else: - # Moving up: shift stops between new and old-1 UP (+1) - stops_to_shift = session.exec( - select(RouteStop).where( - RouteStop.route_id == route_id_uuid, - RouteStop.stop_order >= new_order, - RouteStop.stop_order < old_order - ) - ).all() - for s in stops_to_shift: - s.stop_order += 1 - session.add(s) - - route_stop.stop_order = new_order - - session.add(route_stop) - session.commit() - session.refresh(route_stop) - return route_stop - - -@router.delete("/{route_id}/stops/{stop_id}") -async def remove_stop_from_route( - route_id: str, - stop_id: str, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Remove a stop from a route.""" - from uuid import UUID - try: - route_id_uuid = UUID(route_id) - stop_id_uuid = UUID(stop_id) - except ValueError: - raise HTTPException(status_code=400, detail="Invalid UUID format") - - route_stop = session.exec( - select(RouteStop).where( - RouteStop.route_id == route_id_uuid, - RouteStop.stop_id == stop_id_uuid - ) - ).first() - - if not route_stop: - raise HTTPException(status_code=404, detail="Stop not found on this route") - - # Re-order remaining stops - removed_order = route_stop.stop_order - remaining_stops = session.exec( - select(RouteStop).where( - RouteStop.route_id == route_id_uuid, - RouteStop.stop_order > removed_order - ) - ).all() - for s in remaining_stops: - s.stop_order -= 1 - session.add(s) - - session.delete(route_stop) - session.commit() - return {"ok": True} - diff --git a/backend/app/api/schedules/__init__.py b/backend/app/api/schedules/__init__.py deleted file mode 100644 index 9f9c950..0000000 --- a/backend/app/api/schedules/__init__.py +++ /dev/null @@ -1,86 +0,0 @@ -from fastapi import APIRouter, Depends, Query, HTTPException -from sqlmodel import Session, select -from typing import Optional -from uuid import UUID - -from app.core.database import get_session -from app.models.bus_schedule import BusSchedule -from app.api.deps import get_current_admin - -router = APIRouter(prefix="/api/schedules", tags=["schedules"]) - - -@router.get("") -async def get_schedules( - route_id: Optional[UUID] = Query(None), - stop_id: Optional[UUID] = Query(None), - only_published: bool = Query(True), - session: Session = Depends(get_session) -): - """Get schedules for a route or stop.""" - statement = select(BusSchedule) - - if only_published: - statement = statement.where(BusSchedule.is_published) - - if route_id: - statement = statement.where(BusSchedule.route_id == route_id) - - if stop_id: - from app.models.route_stop import RouteStop - statement = statement.join( - RouteStop, BusSchedule.route_id == RouteStop.route_id - ).where(RouteStop.stop_id == stop_id) - - schedules = session.exec(statement).all() - return schedules - -@router.post("") -async def create_schedule( - schedule: BusSchedule, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Create a new bus schedule (Admin only).""" - db_schedule = BusSchedule.model_validate(schedule) - session.add(db_schedule) - session.commit() - session.refresh(db_schedule) - return db_schedule - -@router.put("/{schedule_id}") -async def update_schedule( - schedule_id: UUID, - schedule_update: dict, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update a bus schedule (Admin only).""" - db_schedule = session.get(BusSchedule, schedule_id) - if not db_schedule: - raise HTTPException(status_code=404, detail="Schedule not found") - - for key, value in schedule_update.items(): - if hasattr(db_schedule, key): - setattr(db_schedule, key, value) - - session.add(db_schedule) - session.commit() - session.refresh(db_schedule) - return db_schedule - -@router.delete("/{schedule_id}") -async def delete_schedule( - schedule_id: UUID, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Delete a bus schedule (Admin only).""" - db_schedule = session.get(BusSchedule, schedule_id) - if not db_schedule: - raise HTTPException(status_code=404, detail="Schedule not found") - - session.delete(db_schedule) - session.commit() - return {"ok": True} - diff --git a/backend/app/api/shuttles/__init__.py b/backend/app/api/shuttles/__init__.py deleted file mode 100644 index cae9da0..0000000 --- a/backend/app/api/shuttles/__init__.py +++ /dev/null @@ -1,180 +0,0 @@ -from fastapi import APIRouter, Depends, Query, HTTPException, UploadFile, File, Form -from sqlmodel import Session, select -from typing import Optional, List -import os -import shutil -from uuid import uuid4, UUID -from app.core.database import get_session -from app.models.shuttle import Shuttle -from app.api.deps import get_current_admin - -from app.services.image_handler import save_image, delete_image - -router = APIRouter(prefix="/api/shuttles", tags=["shuttles"]) - -@router.get("", response_model=List[Shuttle]) -async def get_shuttles( - origin: Optional[str] = Query(None), - destination: Optional[str] = Query(None), - company_name: Optional[str] = Query(None), - trip_type: Optional[str] = Query(None), - is_active: Optional[bool] = Query(None), - session: Session = Depends(get_session) -): - """Get all shuttles with optional filters.""" - statement = select(Shuttle) - - if is_active is not None: - statement = statement.where(Shuttle.is_active == is_active) - - if origin: - statement = statement.where(Shuttle.origin.contains(origin)) - if destination: - statement = statement.where(Shuttle.destination.contains(destination)) - if company_name: - statement = statement.where(Shuttle.company_name.contains(company_name)) - if trip_type: - statement = statement.where(Shuttle.trip_type == trip_type) - - shuttles = session.exec(statement).all() - return shuttles - -@router.post("", response_model=Shuttle) -async def create_shuttle( - route_name: str = Form(...), - origin: str = Form(...), - destination: str = Form(...), - vehicle_type: str = Form(...), - company_name: Optional[str] = Form(None), - trip_type: str = Form("one_way"), - price_per_person: Optional[float] = Form(None), - price_private_trip: Optional[float] = Form(None), - estimated_duration: str = Form(...), - contact_whatsapp: str = Form(...), - phone_number: Optional[str] = Form(None), - english_speaking: bool = Form(False), - description: Optional[str] = Form(None), - departure_times: Optional[str] = Form(None), - is_active: bool = Form(True), - image: Optional[UploadFile] = File(None), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Create a new shuttle trip (Admin only).""" - image_url = None - if image: - image_url = save_image(image, "vehicles") - - shuttle = Shuttle( - route_name=route_name, - origin=origin, - destination=destination, - vehicle_type=vehicle_type, - company_name=company_name, - trip_type=trip_type, - price_per_person=price_per_person, - price_private_trip=price_private_trip, - estimated_duration=estimated_duration, - contact_whatsapp=contact_whatsapp, - phone_number=phone_number, - english_speaking=english_speaking, - description=description, - departure_times=departure_times, - image_url=image_url, - is_active=is_active - ) - session.add(shuttle) - session.commit() - session.refresh(shuttle) - return shuttle - -@router.put("/{shuttle_id}", response_model=Shuttle) -async def update_shuttle( - shuttle_id: UUID, - route_name: str = Form(...), - origin: str = Form(...), - destination: str = Form(...), - vehicle_type: str = Form(...), - company_name: Optional[str] = Form(None), - trip_type: str = Form("one_way"), - price_per_person: Optional[float] = Form(None), - price_private_trip: Optional[float] = Form(None), - estimated_duration: str = Form(...), - contact_whatsapp: str = Form(...), - phone_number: Optional[str] = Form(None), - english_speaking: bool = Form(False), - description: Optional[str] = Form(None), - departure_times: Optional[str] = Form(None), - is_active: bool = Form(True), - image: Optional[UploadFile] = File(None), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update a shuttle trip (Admin only).""" - db_shuttle = session.get(Shuttle, shuttle_id) - if not db_shuttle: - raise HTTPException(status_code=404, detail="Shuttle not found") - - db_shuttle.route_name = route_name - db_shuttle.origin = origin - db_shuttle.destination = destination - db_shuttle.vehicle_type = vehicle_type - db_shuttle.company_name = company_name - db_shuttle.trip_type = trip_type - db_shuttle.price_per_person = price_per_person - db_shuttle.price_private_trip = price_private_trip - db_shuttle.estimated_duration = estimated_duration - db_shuttle.contact_whatsapp = contact_whatsapp - db_shuttle.phone_number = phone_number - db_shuttle.english_speaking = english_speaking - db_shuttle.description = description - db_shuttle.departure_times = departure_times - db_shuttle.is_active = is_active - - if image: - # Delete old image if exists - if db_shuttle.image_url: - delete_image(db_shuttle.image_url) - db_shuttle.image_url = save_image(image, "vehicles") - - session.add(db_shuttle) - session.commit() - session.refresh(db_shuttle) - return db_shuttle - -@router.delete("/{shuttle_id}") -async def delete_shuttle( - shuttle_id: UUID, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Delete a shuttle trip (Admin only).""" - db_shuttle = session.get(Shuttle, shuttle_id) - if not db_shuttle: - raise HTTPException(status_code=404, detail="Shuttle not found") - - # Delete image from storage - if db_shuttle.image_url: - delete_image(db_shuttle.image_url) - - session.delete(db_shuttle) - session.commit() - return {"ok": True} - -@router.patch("/{shuttle_id}/status") -async def update_shuttle_status( - shuttle_id: UUID, - is_active: bool = Query(...), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update shuttle active status (Admin only).""" - db_shuttle = session.get(Shuttle, shuttle_id) - if not db_shuttle: - raise HTTPException(status_code=404, detail="Shuttle not found") - - db_shuttle.is_active = is_active - session.add(db_shuttle) - session.commit() - session.refresh(db_shuttle) - return db_shuttle diff --git a/backend/app/api/taxis/__init__.py b/backend/app/api/taxis/__init__.py deleted file mode 100644 index 81c4e1b..0000000 --- a/backend/app/api/taxis/__init__.py +++ /dev/null @@ -1,144 +0,0 @@ -from fastapi import APIRouter, Depends, Query, HTTPException, UploadFile, File, Form -from sqlmodel import Session, select -import os -import shutil -from uuid import uuid4, UUID -from typing import List, Optional -from app.core.database import get_session -from app.models.taxi import Taxi -from app.api.deps import get_current_admin - -from app.services.image_handler import save_image, delete_image - -router = APIRouter(prefix="/api/taxis", tags=["taxis"]) - -@router.get("", response_model=List[Taxi]) -async def get_taxis( - corregimiento: Optional[str] = Query(None), - shift: Optional[str] = Query(None), - english_speaking: Optional[bool] = Query(None), - is_active: Optional[bool] = Query(None), - session: Session = Depends(get_session) -): - """Get all taxis with optional filters.""" - try: - statement = select(Taxi) - - if is_active is not None: - statement = statement.where(Taxi.is_active == is_active) - - if corregimiento: - statement = statement.where(Taxi.corregimiento.contains(corregimiento)) - - if shift: - statement = statement.where(Taxi.shift == shift) - - if english_speaking is not None: - statement = statement.where(Taxi.english_speaking == english_speaking) - - taxis = session.exec(statement).all() - return taxis - except Exception as e: - print(f"Error fetching taxis: {e}") - raise HTTPException(status_code=500, detail=str(e)) - - -@router.post("") -async def create_taxi( - owner_name: str = Form(...), - phone_number: str = Form(...), - license_plate: str = Form(...), - corregimiento: str = Form(...), - shift: str = Form(...), - cooperative: Optional[str] = Form(None), - rating: float = Form(5.0), - english_speaking: bool = Form(False), - is_active: bool = Form(True), - image: Optional[UploadFile] = File(None), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Create a new taxi entry (Admin only).""" - image_url = None - if image: - image_url = save_image(image, "profiles") - - taxi = Taxi( - owner_name=owner_name, - phone_number=phone_number, - license_plate=license_plate, - cooperative=cooperative, - corregimiento=corregimiento, - shift=shift, - rating=rating, - english_speaking=english_speaking, - image_url=image_url, - is_active=is_active - ) - session.add(taxi) - session.commit() - session.refresh(taxi) - return taxi - - -@router.put("/{taxi_id}", response_model=Taxi) -async def update_taxi( - taxi_id: UUID, - owner_name: str = Form(...), - phone_number: str = Form(...), - license_plate: str = Form(...), - corregimiento: str = Form(...), - shift: str = Form(...), - cooperative: Optional[str] = Form(None), - rating: float = Form(5.0), - english_speaking: bool = Form(False), - is_active: bool = Form(True), - image: Optional[UploadFile] = File(None), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Update a taxi entry (Admin only).""" - db_taxi = session.get(Taxi, taxi_id) - if not db_taxi: - raise HTTPException(status_code=404, detail="Taxi not found") - - # Update fields - db_taxi.owner_name = owner_name - db_taxi.phone_number = phone_number - db_taxi.license_plate = license_plate - db_taxi.corregimiento = corregimiento - db_taxi.shift = shift - db_taxi.cooperative = cooperative - db_taxi.rating = rating - db_taxi.english_speaking = english_speaking - db_taxi.is_active = is_active - - # Handle image upload - if image: - if db_taxi.image_url: - delete_image(db_taxi.image_url) - db_taxi.image_url = save_image(image, "profiles") - - session.add(db_taxi) - session.commit() - session.refresh(db_taxi) - return db_taxi - - -@router.delete("/{taxi_id}") -async def delete_taxi( - taxi_id: UUID, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Delete a taxi entry (Admin only).""" - db_taxi = session.get(Taxi, taxi_id) - if not db_taxi: - raise HTTPException(status_code=404, detail="Taxi not found") - - if db_taxi.image_url: - delete_image(db_taxi.image_url) - - session.delete(db_taxi) - session.commit() - return {"ok": True} diff --git a/backend/app/api/telemetry.py b/backend/app/api/telemetry.py deleted file mode 100644 index 7fafebe..0000000 --- a/backend/app/api/telemetry.py +++ /dev/null @@ -1,84 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from sqlmodel import Session, select -from typing import List -from datetime import datetime, timedelta -from app.core.database import get_session -from app.models.telemetry import Telemetry, TelemetryCreate, VehicleStatus -from app.models.user import User -from app.api.deps import get_current_user - -router = APIRouter(prefix="/api/telemetry", tags=["telemetry"]) - -@router.post("", response_model=Telemetry) -async def create_telemetry_record( - *, - session: Session = Depends(get_session), - telemetry_in: TelemetryCreate, - current_user: User = Depends(get_current_user) -): - """ - Create a new telemetry record for the current driver. - """ - if current_user.role != "driver": - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Only drivers can send telemetry data" - ) - - db_telemetry = Telemetry( - user_id=current_user.id, - latitude=telemetry_in.latitude, - longitude=telemetry_in.longitude, - speed=telemetry_in.speed, - heading=telemetry_in.heading, - status=telemetry_in.status - ) - - session.add(db_telemetry) - session.commit() - session.refresh(db_telemetry) - return db_telemetry - -@router.get("/active", response_model=List[dict]) -async def get_active_units( - *, - session: Session = Depends(get_session) -): - """ - Get the latest location of all active units (last 5 minutes). - """ - # Subquery to get the latest timestamp per user - five_minutes_ago = datetime.utcnow() - timedelta(minutes=5) - - # This is a bit complex in SQLModel/SQLAlchemy for "latest record per group" - # We'll use a simpler approach: get all records from last 5 mins and filter in python - # or use a more efficient distinct on if supported. - - statement = ( - select(Telemetry) - .where(Telemetry.timestamp >= five_minutes_ago) - .where(Telemetry.status == VehicleStatus.ACTIVE) - .order_by(Telemetry.user_id, Telemetry.timestamp.desc()) - ) - - results = session.exec(statement).all() - - # Filter to get only the latest unique user_id - latest_units = {} - for t in results: - if t.user_id not in latest_units: - # We also want the driver name and vehicle info - user = session.get(User, t.user_id) - latest_units[t.user_id] = { - "user_id": t.user_id, - "full_name": user.full_name if user else "Unknown", - "latitude": t.latitude, - "longitude": t.longitude, - "speed": t.speed, - "heading": t.heading, - "timestamp": t.timestamp, - "vehicle_type": user.driver_profile.vehicle_type if user and user.driver_profile else "unknown", - "license_plate": user.driver_profile.license_plate if user and user.driver_profile else "unknown" - } - - return list(latest_units.values()) diff --git a/backend/app/api/users.py b/backend/app/api/users.py deleted file mode 100644 index 563f243..0000000 --- a/backend/app/api/users.py +++ /dev/null @@ -1,116 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, Query -from sqlmodel import Session, select -from uuid import UUID - -from app.core.database import get_session -from app.models.user import User -from app.api.deps import get_current_admin - -router = APIRouter(prefix="/api/users", tags=["users"]) - -@router.get("/search") -async def search_users( - email: str = Query(..., description="Email to search for"), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Search for users by email (Admin only).""" - statement = select(User).where(User.email.contains(email)) - users = session.exec(statement).all() - - # Clean response (don't send hashed passwords) - return [ - { - "id": user.id, - "email": user.email, - "full_name": user.full_name, - "role": user.role, - "is_verified": user.is_verified, - "created_at": user.created_at - } for user in users - ] - -@router.get("/{user_id}") -async def get_user_details( - user_id: UUID, - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Get detailed user info including driver profile (Admin only).""" - user = session.get(User, user_id) - if not user: - raise HTTPException(status_code=404, detail="User not found") - - result = { - "id": user.id, - "email": user.email, - "full_name": user.full_name, - "role": user.role, - "is_active": user.is_active, - "is_verified": user.is_verified, - "created_at": user.created_at, - "driver_profile": None - } - - if user.driver_profile: - dp = user.driver_profile - result["driver_profile"] = { - "cedula": dp.cedula, - "vehicle_type": dp.vehicle_type, - "license_plate": dp.license_plate, - "cooperative_name": dp.cooperative_name, - "photo_url": dp.photo_url, - "vehicle_photo_url": dp.vehicle_photo_url, - "shift": dp.shift, - "payment_methods": dp.payment_methods, - "speaks_english": dp.speaks_english - } - - return result - -@router.get("/pending-drivers") -async def get_pending_drivers( - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """List drivers waiting for verification (Admin only).""" - # Find users with DRIVER role who are NOT verified - from app.models.user import UserRole - statement = select(User).where(User.role == UserRole.DRIVER, User.is_verified.is_(False)) - - return [ - { - "id": driver.id, - "email": driver.email, - "full_name": driver.full_name, - "created_at": driver.created_at, - "driver_profile": { - "cedula": driver.driver_profile.cedula, - "vehicle_type": driver.driver_profile.vehicle_type, - "license_plate": driver.driver_profile.license_plate, - "cooperative_name": driver.driver_profile.cooperative_name, - "shift": driver.driver_profile.shift, - "payment_methods": driver.driver_profile.payment_methods, - "speaks_english": driver.driver_profile.speaks_english - } if driver.driver_profile else None - } for driver in session.exec(statement).all() - ] - -@router.post("/{user_id}/verify") -async def verify_user( - user_id: UUID, - is_verified: bool = Query(..., description="True to approve, False to stay unverified/reject"), - session: Session = Depends(get_session), - _: bool = Depends(get_current_admin) -): - """Approve or Reject a user verification (Admin only).""" - user = session.get(User, user_id) - if not user: - raise HTTPException(status_code=404, detail="User not found") - - user.is_verified = is_verified - session.add(user) - session.commit() - session.refresh(user) - - return {"id": user.id, "email": user.email, "is_verified": user.is_verified} diff --git a/backend/app/core/__init__.py b/backend/app/core/__init__.py deleted file mode 100644 index 5e62adb..0000000 --- a/backend/app/core/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Core configuration and utilities.""" - diff --git a/backend/app/core/config.py b/backend/app/core/config.py deleted file mode 100644 index 0c03832..0000000 --- a/backend/app/core/config.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Configuration settings using pydantic-settings.""" -import os -from pydantic_settings import BaseSettings, SettingsConfigDict -from typing import Literal - - -def get_env_file() -> str: - """Get the appropriate env file based on ENVIRONMENT variable.""" - env = os.getenv("ENVIRONMENT", "development") - env_file = f".env.{env}" - - # Check if env file exists, fallback to .env.development - if not os.path.exists(env_file): - env_file = ".env.development" - - return env_file - - -class Settings(BaseSettings): - """Application settings loaded from environment variables.""" - - # Database - database_url: str = "postgresql+asyncpg://sibu:sibu@localhost:5432/sibu" - - # Google Maps (for server-side APIs) - google_maps_api_key: str = "" - google_maps_url_signing_secret: str = "" - - # Environment - environment: Literal["development", "production", "testing"] = "development" - debug: bool = False - - # Security - admin_password: str = "admin" # Default for development, override in .env - secret_key: str = "insecure-secret-key-dev" # Default for development, override in .env - - model_config = SettingsConfigDict( - env_file=get_env_file(), - env_file_encoding="utf-8", - case_sensitive=False, - extra="ignore", - ) - - - # Global settings instance - @property - def get_database_url(self) -> str: - url = self.database_url - if url.startswith("postgres://"): - url = url.replace("postgres://", "postgresql://", 1) - return url - -settings = Settings() diff --git a/backend/app/core/database.py b/backend/app/core/database.py deleted file mode 100644 index 01f0fc2..0000000 --- a/backend/app/core/database.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Database connection and session management.""" -from sqlmodel import SQLModel, create_engine, Session -from app import models # Ensure all models are loaded for metadata -from typing import Generator - -from app.core.config import settings - - -# Create database engine -# Convert asyncpg URL to psycopg2 for synchronous operations -database_url = settings.get_database_url -if "+asyncpg" in database_url: - database_url = database_url.replace("+asyncpg", "+psycopg2") -elif "postgresql://" in database_url and "+psycopg2" not in database_url: - database_url = database_url.replace("postgresql://", "postgresql+psycopg2://") - -engine = create_engine( - database_url, - echo=settings.debug, - future=True, -) - - -def init_db() -> None: - """Initialize database by creating all tables.""" - SQLModel.metadata.create_all(engine) - - -def get_session() -> Generator[Session, None, None]: - """Dependency for getting database session.""" - with Session(engine) as session: - yield session - diff --git a/backend/app/core/export_database_to_seeder.py b/backend/app/core/export_database_to_seeder.py deleted file mode 100644 index 45a8afd..0000000 --- a/backend/app/core/export_database_to_seeder.py +++ /dev/null @@ -1,251 +0,0 @@ -"""Export current database data and generate a seeder script.""" -from sqlmodel import Session, select -from typing import Dict, Any -import json - -from app.core.database import engine -from app.models.route import Route -from app.models.bus_stop import BusStop -from app.models.route_stop import RouteStop -from app.models.bus_schedule import BusSchedule - - -def export_all_data() -> Dict[str, Any]: - """Export all data from the database.""" - with Session(engine) as session: - # Export routes - routes = session.exec(select(Route)).all() - routes_data = [] - for route in routes: - routes_data.append({ - "id": str(route.id), - "name": route.name, - "description": route.description, - "origin_city": route.origin_city, - "destination_city": route.destination_city, - "distance_km": route.distance_km, - "estimated_duration_minutes": route.estimated_duration_minutes, - "status": route.status.value if route.status else "active", - }) - - # Export bus stops - bus_stops = session.exec(select(BusStop)).all() - bus_stops_data = [] - for stop in bus_stops: - bus_stops_data.append({ - "id": str(stop.id), - "name": stop.name, - "latitude": stop.latitude, - "longitude": stop.longitude, - "city": stop.city, - "address": stop.address, - "stop_type": stop.stop_type.value if stop.stop_type else "regular", - "has_shelter": stop.has_shelter, - "has_seating": stop.has_seating, - "is_accessible": stop.is_accessible, - }) - - # Export route stops - route_stops = session.exec(select(RouteStop)).all() - route_stops_data = [] - for route_stop in route_stops: - route_stops_data.append({ - "id": str(route_stop.id), - "route_id": str(route_stop.route_id), - "stop_id": str(route_stop.stop_id), - "stop_order": route_stop.stop_order, - "travel_time_minutes": route_stop.travel_time_minutes, - "is_pickup_point": route_stop.is_pickup_point, - "is_dropoff_point": route_stop.is_dropoff_point, - }) - - # Export bus schedules - bus_schedules = session.exec(select(BusSchedule)).all() - bus_schedules_data = [] - for schedule in bus_schedules: - bus_schedules_data.append({ - "id": str(schedule.id), - "route_id": str(schedule.route_id), - "departure_time": schedule.departure_time.strftime("%H:%M:%S") if schedule.departure_time else None, - "frequency_minutes": schedule.frequency_minutes, - "schedule_type": schedule.schedule_type.value if schedule.schedule_type else "weekday", - "is_active": schedule.is_active, - "notes": schedule.notes, - }) - - return { - "routes": routes_data, - "bus_stops": bus_stops_data, - "route_stops": route_stops_data, - "bus_schedules": bus_schedules_data, - } - - -def generate_seeder_code(data: Dict[str, Any]) -> str: - """Generate Python seeder code from exported data.""" - - code = '''"""Database seeding script generated from current database.""" -from sqlmodel import Session, select, create_engine -from uuid import UUID -from datetime import time - -from app.core.config import settings -from app.models.route import Route, RouteStatus -from app.models.bus_stop import BusStop, StopType -from app.models.route_stop import RouteStop -from app.models.bus_schedule import BusSchedule, BusScheduleType - - -def seed_database(): - """Seed the database with exported data.""" - # Use synchronous engine for seeding (replace asyncpg with psycopg2) - sync_database_url = settings.database_url.replace("+asyncpg", "+psycopg2") - sync_engine = create_engine(sync_database_url, echo=False) - - with Session(sync_engine) as session: - # Check if data already exists - try: - existing_routes = session.exec(select(Route)).first() - if existing_routes: - print("Database already has data. Skipping seed.") - print("To reseed, drop the tables first or use: make db-reset") - return - except Exception as e: - # If tables don't exist yet, that's fine - we'll create the data - print(f"Note: {e}") - print("Proceeding with seed...") - -''' - - # Generate routes - code += " # Insert Routes\n" - code += " routes = [\n" - for route in data["routes"]: - status_enum = route["status"].upper().replace("-", "_") - code += f''' Route( - id=UUID("{route["id"]}"), - name={repr(route["name"])}, - description={repr(route["description"])}, - origin_city={repr(route["origin_city"])}, - destination_city={repr(route["destination_city"])}, - distance_km={route["distance_km"] if route["distance_km"] is not None else "None"}, - estimated_duration_minutes={route["estimated_duration_minutes"] if route["estimated_duration_minutes"] is not None else "None"}, - status=RouteStatus.{status_enum}, - ), -''' - code += " ]\n" - code += " for route in routes:\n" - code += " session.add(route)\n" - code += " session.flush() # Flush routes so we can reference them in foreign keys\n\n" - - # Generate bus stops - code += " # Insert Bus Stops\n" - code += " bus_stops = [\n" - for stop in data["bus_stops"]: - stop_type_enum = stop["stop_type"].upper().replace("-", "_") - code += f''' BusStop( - id=UUID("{stop["id"]}"), - name={repr(stop["name"])}, - latitude={stop["latitude"]}, - longitude={stop["longitude"]}, - city={repr(stop["city"])}, - address={repr(stop["address"]) if stop["address"] else "None"}, - stop_type=StopType.{stop_type_enum}, - has_shelter={stop["has_shelter"]}, - has_seating={stop["has_seating"]}, - is_accessible={stop["is_accessible"]}, - ), -''' - code += " ]\n" - code += " for stop in bus_stops:\n" - code += " session.add(stop)\n" - code += " session.flush() # Flush stops so we can reference them in route_stops\n\n" - - # Generate route stops - code += " # Insert Route Stops\n" - code += " route_stops = [\n" - for route_stop in data["route_stops"]: - code += f''' RouteStop( - route_id=UUID("{route_stop["route_id"]}"), - stop_id=UUID("{route_stop["stop_id"]}"), - stop_order={route_stop["stop_order"]}, - travel_time_minutes={route_stop["travel_time_minutes"] if route_stop["travel_time_minutes"] is not None else "None"}, - is_pickup_point={route_stop["is_pickup_point"]}, - is_dropoff_point={route_stop["is_dropoff_point"]}, - ), -''' - code += " ]\n" - code += " for route_stop in route_stops:\n" - code += " session.add(route_stop)\n" - code += " session.flush() # Flush route_stops before adding schedules\n\n" - - # Generate bus schedules - code += " # Insert Bus Schedules\n" - code += " bus_schedules = [\n" - for schedule in data["bus_schedules"]: - if schedule["departure_time"]: - hour, minute, second = schedule["departure_time"].split(":") - # Convert to int to remove leading zeros - hour_int = int(hour) - minute_int = int(minute) - time_str = f"time({hour_int}, {minute_int})" - else: - time_str = "None" - - schedule_type_enum = schedule["schedule_type"].upper().replace("-", "_") - code += f''' BusSchedule( - route_id=UUID("{schedule["route_id"]}"), - departure_time={time_str}, - frequency_minutes={schedule["frequency_minutes"] if schedule["frequency_minutes"] is not None else "None"}, - schedule_type=BusScheduleType.{schedule_type_enum}, - is_active={schedule["is_active"]}, - notes={repr(schedule["notes"]) if schedule["notes"] else "None"}, - ), -''' - code += " ]\n" - code += " for schedule in bus_schedules:\n" - code += " session.add(schedule)\n\n" - - code += " session.commit()\n" - code += ' print("Database seeded successfully!")\n\n' - - code += ''' -if __name__ == "__main__": - seed_database() -''' - - return code - - -def main(): - """Main function to export database and generate seeder.""" - print("Exporting database data...") - - try: - data = export_all_data() - - # Save JSON export - json_file = "database_export.json" - with open(json_file, "w", encoding="utf-8") as f: - json.dump(data, f, indent=2, default=str, ensure_ascii=False) - print(f"✅ Exported data to {json_file}") - print(f" - {len(data['routes'])} routes") - print(f" - {len(data['bus_stops'])} bus stops") - print(f" - {len(data['route_stops'])} route stops") - print(f" - {len(data['bus_schedules'])} bus schedules") - - # Generate seeder code - seeder_code = generate_seeder_code(data) - seeder_file = "app/core/seed.py" - with open(seeder_file, "w", encoding="utf-8") as f: - f.write(seeder_code) - print(f"✅ Generated seeder script: {seeder_file}") - - except Exception as e: - print(f"❌ Error exporting database: {e}") - raise - - -if __name__ == "__main__": - main() - diff --git a/backend/app/core/export_supabase_data.py b/backend/app/core/export_supabase_data.py deleted file mode 100644 index e1b5b5f..0000000 --- a/backend/app/core/export_supabase_data.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Script to export route data from Supabase to update seed script.""" -import os -from supabase import create_client, Client -from typing import Dict, Any -import json - -def get_supabase_client() -> Client: - """Create Supabase client from environment variables.""" - supabase_url = os.getenv("SUPABASE_URL") - supabase_key = os.getenv("SUPABASE_ANON_KEY") - - if not supabase_url or not supabase_key: - raise ValueError("SUPABASE_URL and SUPABASE_ANON_KEY must be set in environment") - - return create_client(supabase_url, supabase_key) - -def export_route_data(route_name: str = "Boquete>David") -> Dict[str, Any]: - """Export route data including all stops from Supabase.""" - supabase = get_supabase_client() - - # Get route - route_response = supabase.table("routes").select("*").eq("name", route_name).execute() - if not route_response.data: - raise ValueError(f"Route '{route_name}' not found in Supabase") - - route = route_response.data[0] - route_id = route["id"] - - # Get all route stops with stop details - route_stops_response = supabase.table("route_stops").select( - "*, bus_stops(*)" - ).eq("route_id", route_id).order("stop_order").execute() - - route_stops = route_stops_response.data - - return { - "route": route, - "route_stops": route_stops, - "total_stops": len(route_stops) - } - -def export_all_routes() -> Dict[str, Any]: - """Export all routes and their stops from Supabase.""" - supabase = get_supabase_client() - - # Get all routes - routes_response = supabase.table("routes").select("*").execute() - routes = routes_response.data - - all_data = {} - - for route in routes: - route_id = route["id"] - route_name = route["name"] - - # Get all route stops - route_stops_response = supabase.table("route_stops").select( - "*, bus_stops(*)" - ).eq("route_id", route_id).order("stop_order").execute() - - all_data[route_name] = { - "route": route, - "route_stops": route_stops_response.data, - "total_stops": len(route_stops_response.data) - } - - return all_data - -if __name__ == "__main__": - import sys - - if len(sys.argv) > 1 and sys.argv[1] == "--all": - # Export all routes - data = export_all_routes() - output_file = "supabase_export_all.json" - else: - # Export specific route - route_name = sys.argv[1] if len(sys.argv) > 1 else "Boquete>David" - data = export_route_data(route_name) - output_file = f"supabase_export_{route_name.replace('>', '_')}.json" - - # Save to JSON file - with open(output_file, "w") as f: - json.dump(data, f, indent=2, default=str) - - print(f"✅ Exported data to {output_file}") - if isinstance(data, dict) and "total_stops" in data: - print(f" Total stops: {data['total_stops']}") - elif isinstance(data, dict): - for route_name, route_data in data.items(): - print(f" {route_name}: {route_data['total_stops']} stops") - diff --git a/backend/app/core/generate_route_stops.py b/backend/app/core/generate_route_stops.py deleted file mode 100644 index 1e09708..0000000 --- a/backend/app/core/generate_route_stops.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Helper script to generate intermediate stops along a route.""" -from typing import List, Tuple - -def interpolate_point( - start: Tuple[float, float], - end: Tuple[float, float], - fraction: float -) -> Tuple[float, float]: - """Interpolate a point between start and end coordinates.""" - lat = start[0] + (end[0] - start[0]) * fraction - lng = start[1] + (end[1] - start[1]) * fraction - return (lat, lng) - -def generate_intermediate_stops( - start_coords: Tuple[float, float], - end_coords: Tuple[float, float], - num_stops: int, - start_name: str = "Start", - end_name: str = "End", - city: str = "Route" -) -> List[dict]: - """Generate intermediate stops along a route. - - Args: - start_coords: (latitude, longitude) of start point - end_coords: (latitude, longitude) of end point - num_stops: Total number of stops to generate (including start and end) - start_name: Name of the start stop - end_name: Name of the end stop - city: City name for intermediate stops - - Returns: - List of stop dictionaries with name, lat, lng, city - """ - if num_stops < 2: - return [ - {"name": start_name, "lat": start_coords[0], "lng": start_coords[1], "city": city}, - {"name": end_name, "lat": end_coords[0], "lng": end_coords[1], "city": city} - ] - - stops = [] - - # Add start stop - stops.append({ - "name": start_name, - "lat": start_coords[0], - "lng": start_coords[1], - "city": city - }) - - # Generate intermediate stops - for i in range(1, num_stops - 1): - fraction = i / (num_stops - 1) - lat, lng = interpolate_point(start_coords, end_coords, fraction) - - # Generate realistic stop names - stop_name = f"Parada {i}" - if i % 10 == 0: - stop_name = f"Parada Principal {i // 10}" - elif i % 5 == 0: - stop_name = f"Intersección {i // 5}" - - stops.append({ - "name": stop_name, - "lat": lat, - "lng": lng, - "city": city - }) - - # Add end stop - stops.append({ - "name": end_name, - "lat": end_coords[0], - "lng": end_coords[1], - "city": city - }) - - return stops - -# Example: Generate 61 stops for Boquete>David route -if __name__ == "__main__": - # Boquete coordinates (Terminal) - boquete_start = (8.7697, -82.4328) - # David coordinates (Terminal) - david_end = (8.4177, -82.4270) - - stops = generate_intermediate_stops( - boquete_start, - david_end, - num_stops=61, - start_name="Terminal de Boquete", - end_name="Terminal de David", - city="Ruta Boquete-David" - ) - - print(f"Generated {len(stops)} stops:") - for i, stop in enumerate(stops, 1): - print(f"{i:2d}. {stop['name']:30s} ({stop['lat']:.6f}, {stop['lng']:.6f})") - diff --git a/backend/app/core/import_supabase_coordinates.py b/backend/app/core/import_supabase_coordinates.py deleted file mode 100644 index a017c1e..0000000 --- a/backend/app/core/import_supabase_coordinates.py +++ /dev/null @@ -1,223 +0,0 @@ -"""Script to import bus stop coordinates from Supabase that follow actual roads.""" -import os -from pathlib import Path -from supabase import create_client, Client -from sqlmodel import Session, select, create_engine -import sys - -from app.core.config import settings, get_env_file -from app.models.bus_stop import BusStop -from app.models.route import Route -from app.models.route_stop import RouteStop - - -def load_env_file(): - """Load environment variables from .env.development file.""" - env_file = get_env_file() - env_path = Path(env_file) - - # If relative path, make it relative to backend directory - if not env_path.is_absolute(): - backend_dir = Path(__file__).parent.parent.parent - env_path = backend_dir / env_file - - if env_path.exists(): - from dotenv import load_dotenv - load_dotenv(env_path) - print(f"✓ Loaded environment from {env_path}") - else: - print(f"⚠️ Warning: {env_path} not found, using system environment variables") - - -def get_supabase_client() -> Client: - """Create Supabase client from environment variables.""" - # Load .env.development file first - load_env_file() - - supabase_url = os.getenv("SUPABASE_URL") - supabase_key = os.getenv("SUPABASE_ANON_KEY") - - if not supabase_url or not supabase_key: - raise ValueError( - "SUPABASE_URL and SUPABASE_ANON_KEY must be set in environment or .env.development file.\n" - f"Checked file: {get_env_file()}" - ) - - return create_client(supabase_url, supabase_key) - - -def import_coordinates_from_supabase(route_name: str = "Boquete>David", supabase_route_name: str = None): - """Import bus stop coordinates from Supabase for a specific route. - - Args: - route_name: Route name in local database format (e.g., "Boquete>David") - supabase_route_name: Route name in Supabase format (e.g., "Boquete – David"). - If None, will try to find it automatically. - """ - supabase = get_supabase_client() - - # If supabase_route_name is provided, use it directly - if supabase_route_name: - route_response = supabase.table("routes").select("*").eq("name", supabase_route_name).execute() - else: - # Get route from Supabase - try exact match first, then try variations - route_response = supabase.table("routes").select("*").eq("name", route_name).execute() - - # If not found, try with different separators (Supabase uses " – " em dash) - if not route_response.data: - # Try with different separators - variations = [ - route_name.replace(">", " – "), # Em dash (Supabase format) - route_name.replace(">", "-"), # Regular dash - route_name.replace(">", " to "), # " to " - route_name.replace(">", " -> "), # " -> " - ] - for variant in variations: - route_response = supabase.table("routes").select("*").eq("name", variant).execute() - if route_response.data: - print(f"Found route with name variation: '{variant}'") - break - - # If still not found, list available routes - if not route_response.data: - all_routes = supabase.table("routes").select("name").execute() - available = [r["name"] for r in all_routes.data] if all_routes.data else [] - raise ValueError( - f"Route '{route_name}' not found in Supabase.\n" - f"Available routes: {', '.join(available) if available else 'None found'}" - ) - - supabase_route = route_response.data[0] - supabase_route_id = supabase_route["id"] - - # Get all route stops with stop details from Supabase - # Old app uses 'stops' table with 'lat' and 'lng' columns, and 'seq' for order - # Try different query formats to match Supabase schema - try: - # Try the format used by old Flutter app: stops:stop_id with seq - route_stops_response = supabase.table("route_stops").select( - "seq, stops:stop_id(id, name, lat, lng)" - ).eq("route_id", supabase_route_id).order("seq").execute() - - except Exception as e1: - try: - # Try with stop_order instead of seq - route_stops_response = supabase.table("route_stops").select( - "stop_order, stops:stop_id(id, name, lat, lng)" - ).eq("route_id", supabase_route_id).order("stop_order").execute() - - except Exception as e2: - try: - # Try bus_stops table (new schema) - route_stops_response = supabase.table("route_stops").select( - "stop_order, bus_stops(*)" - ).eq("route_id", supabase_route_id).order("stop_order").execute() - - except Exception as e3: - raise Exception(f"Could not query Supabase: {e1}, {e2}, {e3}") - - if not route_stops_response.data: - print(f"No stops found for route '{route_name}' in Supabase") - return - - # Connect to local database - sync_database_url = settings.database_url.replace("+asyncpg", "+psycopg2") - sync_engine = create_engine(sync_database_url, echo=False) - - with Session(sync_engine) as session: - # Find the route in local database - local_route = session.exec(select(Route).where(Route.name == route_name)).first() - if not local_route: - print(f"Route '{route_name}' not found in local database. Please create it first.") - return - - print(f"Found route '{route_name}' in local database (ID: {local_route.id})") - - # Get local route stops ordered by stop_order - local_route_stops = session.exec( - select(RouteStop, BusStop) - .join(BusStop, RouteStop.stop_id == BusStop.id) - .where(RouteStop.route_id == local_route.id) - .order_by(RouteStop.stop_order) - ).all() - - if len(local_route_stops) != len(route_stops_response.data): - print(f"⚠️ Warning: Local database has {len(local_route_stops)} stops, Supabase has {len(route_stops_response.data)} stops") - print(" Updating coordinates for matching stops...") - - # Update coordinates for each stop - updated_count = 0 - for i, supabase_stop_data in enumerate(route_stops_response.data): - if i >= len(local_route_stops): - break - - # Try different possible field names for the stop data - supabase_stop = ( - supabase_stop_data.get("bus_stops") or - supabase_stop_data.get("stops") or - supabase_stop_data # If the stop data is directly in the response - ) - if not supabase_stop or not isinstance(supabase_stop, dict): - continue - - # Get the local stop - local_route_stop, local_bus_stop = local_route_stops[i] - - # Update coordinates from Supabase - # Supabase may use 'lat'/'lng' (old schema) or 'latitude'/'longitude' (new schema) - new_latitude = supabase_stop.get("latitude") or supabase_stop.get("lat") - new_longitude = supabase_stop.get("longitude") or supabase_stop.get("lng") - - if new_latitude is None or new_longitude is None: - print(f"⚠️ Skipping stop {i+1}: missing coordinates in Supabase") - continue - - # Check if coordinates are different - if abs(local_bus_stop.latitude - new_latitude) > 0.0001 or \ - abs(local_bus_stop.longitude - new_longitude) > 0.0001: - local_bus_stop.latitude = new_latitude - local_bus_stop.longitude = new_longitude - session.add(local_bus_stop) - updated_count += 1 - print(f"✓ Updated stop {i+1} ({local_bus_stop.name}): " - f"({new_latitude:.6f}, {new_longitude:.6f})") - - session.commit() - print(f"\n✅ Successfully updated {updated_count} stops with coordinates from Supabase") - - -def import_all_routes(): - """Import coordinates for all routes from Supabase.""" - supabase = get_supabase_client() - - # Get all routes from Supabase - routes_response = supabase.table("routes").select("*").execute() - routes = routes_response.data - - print(f"Found {len(routes)} routes in Supabase") - - for route in routes: - supabase_route_name = route["name"] # Format: "Boquete – David" - # Convert Supabase format to local format for matching - local_route_name = supabase_route_name.replace(" – ", ">").replace(" - ", ">").replace(" to ", ">").replace(" -> ", ">") - - print(f"\n{'='*60}") - print(f"Importing coordinates for route: {supabase_route_name}") - print(f"Looking for local route: {local_route_name}") - print(f"{'='*60}") - try: - import_coordinates_from_supabase(local_route_name, supabase_route_name=supabase_route_name) - except Exception as e: - print(f"❌ Error importing route '{supabase_route_name}': {e}") - continue - - -if __name__ == "__main__": - if len(sys.argv) > 1 and sys.argv[1] == "--all": - # Import all routes - import_all_routes() - else: - # Import specific route - route_name = sys.argv[1] if len(sys.argv) > 1 else "Boquete>David" - import_coordinates_from_supabase(route_name) - diff --git a/backend/app/core/security.py b/backend/app/core/security.py deleted file mode 100644 index 282ccef..0000000 --- a/backend/app/core/security.py +++ /dev/null @@ -1,46 +0,0 @@ -import bcrypt -from datetime import datetime, timedelta, timezone -from typing import Any, Union, Optional -from jose import jwt -from app.core.config import settings - -ALGORITHM = "HS256" - -def create_access_token( - subject: Union[str, Any], - role: str, - full_name: str, - expires_delta: Optional[timedelta] = None -) -> str: - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=1440) - - to_encode = { - "exp": expire, - "sub": str(subject), - "role": role, - "full_name": full_name - } - encoded_jwt = jwt.encode(to_encode, settings.secret_key, algorithm=ALGORITHM) - return encoded_jwt - -def verify_password(plain_password: str, hashed_password: str) -> bool: - return bcrypt.checkpw( - plain_password.encode('utf-8'), - hashed_password.encode('utf-8') - ) - -def get_password_hash(password: str) -> str: - return bcrypt.hashpw( - password.encode('utf-8'), - bcrypt.gensalt() - ).decode('utf-8') - -def get_token_payload(token: str) -> dict: - try: - payload = jwt.decode(token, settings.secret_key, algorithms=[ALGORITHM]) - return payload - except Exception: - return {} diff --git a/backend/app/core/seed.py b/backend/app/core/seed.py deleted file mode 100644 index fe57301..0000000 --- a/backend/app/core/seed.py +++ /dev/null @@ -1,5900 +0,0 @@ -"""Database seeding script generated from current database.""" -from sqlmodel import Session, select, create_engine -from uuid import UUID -from datetime import time - -from app.core.config import settings -from app.models.route import Route, RouteStatus -from app.models.bus_stop import BusStop, StopType -from app.models.route_stop import RouteStop -from app.models.bus_schedule import BusSchedule, BusScheduleType - - -def seed_database(): - """Seed the database with exported data.""" - # Use synchronous engine for seeding (replace asyncpg with psycopg2) - sync_database_url = settings.database_url.replace("+asyncpg", "+psycopg2") - sync_engine = create_engine(sync_database_url, echo=False) - - with Session(sync_engine) as session: - # Check if data already exists - try: - existing_routes = session.exec(select(Route)).first() - if existing_routes: - print("Database already has data. Skipping seed.") - print("To reseed, drop the tables first or use: make db-reset") - return - except Exception as e: - # If tables don't exist yet, that's fine - we'll create the data - print(f"Note: {e}") - print("Proceeding with seed...") - - # Insert Routes - routes = [ - Route( - id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - name='Boquete>David', - description='Ruta desde Boquete hacia David con paradas principales', - origin_city='Boquete', - destination_city='David', - distance_km=38.5, - estimated_duration_minutes=45, - status=RouteStatus.ACTIVE, - ), - Route( - id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - name='David>Boquete', - description='Ruta desde David hacia Boquete con paradas principales', - origin_city='David', - destination_city='Boquete', - distance_km=38.5, - estimated_duration_minutes=45, - status=RouteStatus.ACTIVE, - ), - Route( - id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - name='Palmira>David', - description='Ruta desde Palmira hacia David', - origin_city='Palmira', - destination_city='David', - distance_km=25.2, - estimated_duration_minutes=35, - status=RouteStatus.ACTIVE, - ), - Route( - id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - name='David>Palmira', - description='Ruta desde David hacia Palmira', - origin_city='David', - destination_city='Palmira', - distance_km=25.2, - estimated_duration_minutes=35, - status=RouteStatus.ACTIVE, - ), - Route( - id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - name='Caldera>David', - description='Ruta desde Caldera hacia David', - origin_city='Caldera', - destination_city='David', - distance_km=42.8, - estimated_duration_minutes=50, - status=RouteStatus.ACTIVE, - ), - Route( - id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - name='David>Caldera', - description='Ruta desde David hacia Caldera', - origin_city='David', - destination_city='Caldera', - distance_km=42.8, - estimated_duration_minutes=50, - status=RouteStatus.ACTIVE, - ), - ] - for route in routes: - session.add(route) - session.flush() # Flush routes so we can reference them in foreign keys - - # Insert Bus Stops - bus_stops = [ - BusStop( - id=UUID("12fc09fc-5e48-4c54-b414-4133f0f12a37"), - name='Parada Principal 1', - latitude=8.6589562, - longitude=-82.442055, - city='Ruta Caldera-David', - address='Parada Principal 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("39274b2b-7d5a-4c6e-b3e9-4f05a66f1c7e"), - name='Parada 18', - latitude=8.5746042, - longitude=-82.4212994, - city='Ruta Palmira-David', - address='Parada 18', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("46588013-d616-4eae-8e50-c98bf38e050f"), - name='Parada 22', - latitude=8.5472523, - longitude=-82.419091, - city='Ruta Palmira-David', - address='Parada 22', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("506e4aff-1cb6-47e9-a85f-3dafd2d49308"), - name='Parada Principal 4', - latitude=8.4445818, - longitude=-82.4221416, - city='Ruta Palmira-David', - address='Parada Principal 4', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("51043828-726d-4245-a975-59723eb2f08f"), - name='Parada 34', - latitude=8.4759182, - longitude=-82.4202329, - city='Ruta Palmira-David', - address='Parada 34', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("05baf1ef-af1d-4f76-8027-2482b37b8c37"), - name='Parada 31', - latitude=8.4978514, - longitude=-82.4254706, - city='Ruta Palmira-David', - address='Parada 31', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("10a60237-1189-49d6-8da3-54893f849212"), - name='Intersección 5', - latitude=8.5259111, - longitude=-82.4219091, - city='Ruta Palmira-David', - address='Intersección 5', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("1d74e1ef-e488-4fc9-9df8-9c88f007e204"), - name='Parada 13', - latitude=8.6006107, - longitude=-82.4211566, - city='Ruta Palmira-David', - address='Parada 13', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("2050bc76-6534-4b6b-891f-33fe3bac8407"), - name='Parada 21', - latitude=8.5516692, - longitude=-82.4189188, - city='Ruta Palmira-David', - address='Parada 21', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("29c3fa50-965a-47fc-9aa9-5216593fd863"), - name='Parada 36', - latitude=8.4552106, - longitude=-82.4207317, - city='Ruta Palmira-David', - address='Parada 36', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("2c2ba744-3c20-4485-aca4-22b00b4f622f"), - name='Parada 8', - latitude=8.6234797, - longitude=-82.4254989, - city='Ruta Palmira-David', - address='Parada 8', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("2c669c57-a164-4437-8114-85a7ec8b4e3c"), - name='Intersección 7', - latitude=8.475465, - longitude=-82.4204772, - city='Ruta Palmira-David', - address='Intersección 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("2e00b45d-9c28-4aac-b895-546f213e3309"), - name='Parada 27', - latitude=8.5116647, - longitude=-82.4237289, - city='Ruta Palmira-David', - address='Parada 27', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("2f17114c-6bfc-45bf-a436-ed64860df62e"), - name='Parada 29', - latitude=8.5080045, - longitude=-82.4242084, - city='Ruta Palmira-David', - address='Parada 29', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("3386ad96-9012-472f-a756-9093c602a416"), - name='Parada 32', - latitude=8.4948946, - longitude=-82.4254776, - city='Ruta Palmira-David', - address='Parada 32', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("2a03ba34-5483-4783-bb78-e8c92c200fbe"), - name='Parada 58', - latitude=8.5097514, - longitude=-82.4239683, - city='Ruta Caldera-David', - address='Parada 58', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("4d182cbe-c108-46ed-a9b3-4b6cdef33aa9"), - name='Parada 64', - latitude=8.4759182, - longitude=-82.4202329, - city='Ruta Caldera-David', - address='Parada 64', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("51e94d40-56fb-4842-8cfe-8b76c46aa13b"), - name='Parada 59', - latitude=8.5080045, - longitude=-82.4242084, - city='Ruta Caldera-David', - address='Parada 59', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("53d8b9b6-ef59-439e-97a5-39dacac56a24"), - name='Parada 52', - latitude=8.5472523, - longitude=-82.419091, - city='Ruta Caldera-David', - address='Parada 52', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("5433c8d0-002a-45f0-a17a-c4fcf84e5169"), - name='Parada 62', - latitude=8.4948946, - longitude=-82.4254776, - city='Ruta Caldera-David', - address='Parada 62', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("6d4aa16d-5683-48b1-8507-b0aba05d4aaa"), - name='Parada 53', - latitude=8.5344038, - longitude=-82.420778, - city='Ruta Caldera-David', - address='Parada 53', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("6eabfea4-f0e8-4f8d-b97f-bc8febb39344"), - name='Parada 68', - latitude=8.450325, - longitude=-82.4213788, - city='Ruta Caldera-David', - address='Parada 68', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("6eb8d5e3-4319-40d3-bd16-e3383cb113af"), - name='Parada 67', - latitude=8.4521084, - longitude=-82.4211461, - city='Ruta Caldera-David', - address='Parada 67', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("707c8544-533f-4e42-8767-0490170cb083"), - name='Parada 56', - latitude=8.520598, - longitude=-82.4225716, - city='Ruta Caldera-David', - address='Parada 56', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8085a65b-18fd-439d-8fa6-760b3b26ea55"), - name='Parada 63', - latitude=8.4919557, - longitude=-82.4251941, - city='Ruta Caldera-David', - address='Parada 63', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("81644bb0-0afb-4cd0-8496-f066a4bd1701"), - name='Parada Principal 5', - latitude=8.5584545, - longitude=-82.4151901, - city='Ruta Caldera-David', - address='Parada Principal 5', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("89d0f353-8316-4c22-ab4e-1006121ee23a"), - name='Parada 66', - latitude=8.4552106, - longitude=-82.4207317, - city='Ruta Caldera-David', - address='Parada 66', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8db9b2c9-769b-4ec6-aae7-8a43ef99b9bc"), - name='Parada 57', - latitude=8.5116647, - longitude=-82.4237289, - city='Ruta Caldera-David', - address='Parada 57', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("9c9a32d7-1bef-4824-95db-3761b4688111"), - name='Intersección 13', - latitude=8.475465, - longitude=-82.4204772, - city='Ruta Caldera-David', - address='Intersección 13', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("a364477b-c104-4ec5-bc4e-67bc04d4fd84"), - name='Parada 61', - latitude=8.4978514, - longitude=-82.4254706, - city='Ruta Caldera-David', - address='Parada 61', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("b5c4dbb3-3225-462e-b865-79216d8564f4"), - name='Parada 51', - latitude=8.5516692, - longitude=-82.4189188, - city='Ruta Caldera-David', - address='Parada 51', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("b64f9a9a-0568-476f-b229-403e6a4cf448"), - name='Parada Principal 7', - latitude=8.4445818, - longitude=-82.4221416, - city='Ruta Caldera-David', - address='Parada Principal 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("bd0f3e38-f7f4-4d8f-a9d3-33191468a58d"), - name='Parada 69', - latitude=8.4462536, - longitude=-82.4213439, - city='Ruta Caldera-David', - address='Parada 69', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("d3773f11-9393-40ab-9295-9305412d16ce"), - name='Intersección 11', - latitude=8.5259111, - longitude=-82.4219091, - city='Ruta Caldera-David', - address='Intersección 11', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("d5af00b9-9f40-4afd-a67f-abf98a06ed6a"), - name='Parada 71', - latitude=8.4426552, - longitude=-82.42181, - city='Ruta Caldera-David', - address='Parada 71', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("dee5dc1b-5101-43f1-a322-b59cfdd18ed1"), - name='Parada 73', - latitude=8.4357775, - longitude=-82.4210319, - city='Ruta Caldera-David', - address='Parada 73', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("e51839b2-1bb8-47c6-ab80-224cd5f17cb7"), - name='Parada 72', - latitude=8.4388768, - longitude=-82.4220722, - city='Ruta Caldera-David', - address='Parada 72', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("eef5ca98-8a8d-42a6-9616-e3cabc7fcf0b"), - name='Parada 54', - latitude=8.5322854, - longitude=-82.421057, - city='Ruta Caldera-David', - address='Parada 54', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f475143d-f78b-4b27-87d9-5a8867673695"), - name='Parada Principal 6', - latitude=8.5040506, - longitude=-82.4246805, - city='Ruta Caldera-David', - address='Parada Principal 6', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("c9c1378e-19de-4730-9590-844df9bab1e5"), - name='Centro de David', - latitude=8.4194, - longitude=-82.4255, - city='David', - address='Parque Cervantes', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("20b52f70-0b6f-4932-a71e-4cb179a88f38"), - name='Hospital Chiriquí', - latitude=8.4156, - longitude=-82.4289, - city='David', - address='Complejo Hospitalario', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("0d277d0c-1069-45df-805c-ce59ef2dfd23"), - name='Chiriquí Mall', - latitude=8.4089, - longitude=-82.4178, - city='David', - address='Centro Comercial', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("c0c28ce0-88fa-4d01-a4e9-530101b35990"), - name='Escuela de Palmira', - latitude=8.3567, - longitude=-82.3598, - city='Palmira', - address='Zona Escolar', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("752e1079-4ae3-4345-8a03-05d58c63388a"), - name='Centro de Caldera', - latitude=8.2478, - longitude=-81.7198, - city='Caldera', - address='Centro del Pueblo', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("0666a01b-0055-4b3a-9756-5053690cfae5"), - name='Terminal de David', - latitude=8.4334255, - longitude=-82.4231136, - city='Ruta Boquete-David', - address='Terminal de David', - stop_type=StopType.TERMINAL, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("3d73312c-eba3-43d1-ba3d-2381cfe6abd8"), - name='Parada 56', - latitude=8.4445115, - longitude=-82.4221416, - city='Ruta Boquete-David', - address='Parada 56', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("926d4e83-1f08-4504-95e3-71f4d2c9666c"), - name='Parada 49', - latitude=8.4919557, - longitude=-82.4251941, - city='Ruta Boquete-David', - address='Parada 49', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("4d7a3281-563a-491d-bbde-3a5fc4b87198"), - name='Terminal de David', - latitude=8.4334255, - longitude=-82.4231136, - city='Ruta Caldera-David', - address='Terminal de David', - stop_type=StopType.TERMINAL, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("089afec3-6911-4c41-9d12-223b8607c4a9"), - name='Parada 34', - latitude=8.5746042, - longitude=-82.4212994, - city='Ruta Boquete-David', - address='Parada 34', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("0948094e-1132-4a94-8873-4fbbb9bd25e5"), - name='Parada 6', - latitude=8.7275817, - longitude=-82.4348154, - city='Ruta Boquete-David', - address='Parada 6', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("0b5970c0-343f-4c9d-972e-1ec6926f9807"), - name='Parada 22', - latitude=8.643388, - longitude=-82.4345935, - city='Ruta Boquete-David', - address='Parada 22', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("0b660dd6-e935-4be8-b470-eea9bf995c75"), - name='Parada 51', - latitude=8.475465, - longitude=-82.4204772, - city='Ruta Boquete-David', - address='Parada 51', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("18dabf19-4f52-4d92-be42-6bd3623b4f06"), - name='Parada 17', - latitude=8.6874249, - longitude=-82.4510803, - city='Ruta Boquete-David', - address='Parada 17', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("24428491-2b6a-4ac0-9ca5-17df33138a18"), - name='Parada 11', - latitude=8.7179038, - longitude=-82.440164, - city='Ruta Boquete-David', - address='Parada 11', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("2802d866-56d1-4200-9c41-402cc967f35b"), - name='Intersección 5', - latitude=8.6202619, - longitude=-82.4239767, - city='Ruta Boquete-David', - address='Intersección 5', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("00a14099-a862-455f-abfa-c2ec1489ab70"), - name='Parada 17', - latitude=8.6171078, - longitude=-82.4232463, - city='Ruta Caldera-David', - address='Parada 17', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("21f322a7-ac14-4144-abad-7e7f2502eef6"), - name='Parada 22', - latitude=8.5912165, - longitude=-82.4217292, - city='Ruta Caldera-David', - address='Parada 22', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("2b2e6858-be6d-4f18-a3a2-92373cfd9a9d"), - name='Parada 2', - latitude=8.6585931, - longitude=-82.3713713, - city='Ruta Caldera-David', - address='Parada 2', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("3d769def-cf21-4560-be21-13b828aafe54"), - name='Parada 3', - latitude=8.6565684, - longitude=-82.3751424, - city='Ruta Caldera-David', - address='Parada 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("682705d5-5413-4bd3-a31c-144832e7ec96"), - name='Parada 9', - latitude=8.6677249, - longitude=-82.4464655, - city='Ruta Caldera-David', - address='Parada 9', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("69c374a2-a062-4b28-8308-6aff793cd631"), - name='Intersección 3', - latitude=8.6233007, - longitude=-82.425637, - city='Ruta Caldera-David', - address='Intersección 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("77f80a0a-450c-42c3-bb8a-b9a3b6e5758d"), - name='Parada 6', - latitude=8.6660748, - longitude=-82.4257239, - city='Ruta Caldera-David', - address='Parada 6', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("788abd79-3d4b-4810-a5c0-7d8fec3d1a27"), - name='Parada 11', - latitude=8.657646, - longitude=-82.441363, - city='Ruta Caldera-David', - address='Parada 11', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("7db160e3-05b2-4778-baee-789cea0f0bfd"), - name='Parada 4', - latitude=8.6559353, - longitude=-82.3772655, - city='Ruta Caldera-David', - address='Parada 4', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8ba33c36-303a-4182-8e08-065c2961e05d"), - name='Parada 16', - latitude=8.6201558, - longitude=-82.4242288, - city='Ruta Caldera-David', - address='Parada 16', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("9bdf297b-6312-43fa-b945-bfaa01fd49bc"), - name='Parada 19', - latitude=8.6102291, - longitude=-82.4228095, - city='Ruta Caldera-David', - address='Parada 19', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("9d9ffbcc-b4d8-427b-b5a3-add1c25f66a7"), - name='Parada Principal 2', - latitude=8.6005179, - longitude=-82.4214315, - city='Ruta Caldera-David', - address='Parada Principal 2', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a20332a5-08f3-46f4-9dfd-f27e5539469e"), - name='Parada 1', - latitude=8.659617, - longitude=-82.3693378, - city='Ruta Caldera-David', - address='Parada 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("b321b88d-5032-4383-85e1-ec99c3e3cb3f"), - name='Parada 12', - latitude=8.6471196, - longitude=-82.4365581, - city='Ruta Caldera-David', - address='Parada 12', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("b95c7990-65ac-40db-bb49-b99ed3b9d8dd"), - name='Parada 18', - latitude=8.6144144, - longitude=-82.4230377, - city='Ruta Caldera-David', - address='Parada 18', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("bd2f01ab-0406-4b6d-b4c5-052f8915fc30"), - name='Parada 14', - latitude=8.6277337, - longitude=-82.4276677, - city='Ruta Caldera-David', - address='Parada 14', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("d86649cc-7286-46c3-933c-168716d1b304"), - name='Parada 13', - latitude=8.6431851, - longitude=-82.4347209, - city='Ruta Caldera-David', - address='Parada 13', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("dc3e0510-7cdd-4521-8dc2-6181120b4f26"), - name='Intersección 1', - latitude=8.6528035, - longitude=-82.3823114, - city='Ruta Caldera-David', - address='Intersección 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("decf0e21-7488-4dc1-b5b6-9997e2437403"), - name='Parada 21', - latitude=8.5986961, - longitude=-82.4203193, - city='Ruta Caldera-David', - address='Parada 21', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("df528e47-8fc2-49b7-81db-3c8f4f7a176a"), - name='Puerto de Caldera', - latitude=8.6623636, - longitude=-82.3643095, - city='Ruta Caldera-David', - address='Puerto de Caldera', - stop_type=StopType.TERMINAL, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("edfb904e-66be-4a8d-80f7-3a30403d3fca"), - name='Parada 7', - latitude=8.6668357, - longitude=-82.4271414, - city='Ruta Caldera-David', - address='Parada 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("f7317833-9adc-40c0-9132-5c66c1822210"), - name='Parada 8', - latitude=8.667541, - longitude=-82.4288313, - city='Ruta Caldera-David', - address='Parada 8', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("0512d2ed-abc0-4f95-b39f-515eac489d27"), - name='Parada 31', - latitude=8.667541, - longitude=-82.4288313, - city='Ruta Caldera-David', - address='Parada 31', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("156ce6b5-1683-4654-aab5-17e6d55547e8"), - name='Parada 27', - latitude=8.6559353, - longitude=-82.3772655, - city='Ruta Caldera-David', - address='Parada 27', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("1fb1faef-ae69-4875-8598-7839e6268741"), - name='Parada 46', - latitude=8.5842058, - longitude=-82.4229429, - city='Ruta Caldera-David', - address='Parada 46', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("267afc65-88a6-4ac1-9be5-46d22bfec4d5"), - name='Parada 34', - latitude=8.6577004, - longitude=-82.4411605, - city='Ruta Caldera-David', - address='Parada 34', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f30ed3ab-b629-4320-b254-32d4d8341ee6"), - name='Intersección 3', - latitude=8.6969771, - longitude=-82.4484517, - city='Ruta Boquete-David', - address='Intersección 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("f38abc02-65e0-4a35-b19e-474359d7477e"), - name='Parada 26', - latitude=8.6169195, - longitude=-82.4229218, - city='Ruta Boquete-David', - address='Parada 26', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f63e9060-33e9-4263-9023-f37d0e848260"), - name='Parada 12', - latitude=8.7165669, - longitude=-82.4408624, - city='Ruta Boquete-David', - address='Parada 12', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("fa9a49ee-146f-4ed2-8473-cc17da8dcab2"), - name='Parada 13', - latitude=8.7139392, - longitude=-82.4423294, - city='Ruta Boquete-David', - address='Parada 13', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("fb9882db-bb01-46ad-bbb1-5cb8cf4f78f2"), - name='Parada 8', - latitude=8.7248711, - longitude=-82.4363221, - city='Ruta Boquete-David', - address='Parada 8', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("29819fa8-f25e-4cb5-b142-c65a6f11baa9"), - name='Parada 29', - latitude=8.6660748, - longitude=-82.4257239, - city='Ruta Caldera-David', - address='Parada 29', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("3211b00c-4c3a-41e9-a560-794d77c1cfab"), - name='Parada 42', - latitude=8.610253, - longitude=-82.4225976, - city='Ruta Caldera-David', - address='Parada 42', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8265275c-8f02-487b-a8d2-4a33a04515d2"), - name='Parada 16', - latitude=8.5842058, - longitude=-82.4229429, - city='Ruta Palmira-David', - address='Parada 16', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("83f03e06-bb17-41ef-9760-565f7c6b7905"), - name='Parada 12', - latitude=8.610253, - longitude=-82.4225976, - city='Ruta Palmira-David', - address='Parada 12', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("848e3f5c-0500-4ffa-a92f-5f56a339fda2"), - name='Parada 41', - latitude=8.4426552, - longitude=-82.42181, - city='Ruta Palmira-David', - address='Parada 41', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("85b7e107-6d21-44cf-84c9-ddef2be9bbdb"), - name='Parada 28', - latitude=8.5097514, - longitude=-82.4239683, - city='Ruta Palmira-David', - address='Parada 28', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8b26bd01-f59e-40d4-9f5b-91eb86ae9d0f"), - name='Parada Principal 3', - latitude=8.5040506, - longitude=-82.4246805, - city='Ruta Palmira-David', - address='Parada Principal 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8b5246b1-c4cb-4435-85a3-0330ac8db62e"), - name='Parada 38', - latitude=8.450325, - longitude=-82.4213788, - city='Ruta Palmira-David', - address='Parada 38', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("9740fe20-cde6-467f-8de4-174426fcbc7f"), - name='Parada 7', - latitude=8.627808, - longitude=-82.4274531, - city='Ruta Palmira-David', - address='Parada 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("9cc2dd3d-59fd-4a5f-a24e-c52082625190"), - name='Parada 2', - latitude=8.6678999, - longitude=-82.4462348, - city='Ruta Palmira-David', - address='Parada 2', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a324ca30-9831-48ce-a5cc-cfcf21d91ee0"), - name='Intersección 1', - latitude=8.6472681, - longitude=-82.4363596, - city='Ruta Palmira-David', - address='Intersección 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("a5704227-9658-4118-8566-19d7b5827fc6"), - name='Parada 19', - latitude=8.565803, - longitude=-82.4162278, - city='Ruta Palmira-David', - address='Parada 19', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("acea0a34-f564-4f30-b97d-445c5c2f3864"), - name='Centro de Palmira', - latitude=8.6960095, - longitude=-82.4488575, - city='Ruta Palmira-David', - address='Centro de Palmira', - stop_type=StopType.TERMINAL, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("bf949ab0-c554-41ab-a852-917b6aed4251"), - name='Parada 1', - latitude=8.6874249, - longitude=-82.4510803, - city='Ruta Palmira-David', - address='Parada 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("c01ee146-0148-4e5d-bff3-3db389de1dd8"), - name='Parada Principal 2', - latitude=8.5584545, - longitude=-82.4151901, - city='Ruta Palmira-David', - address='Parada Principal 2', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("d20f93f6-f187-47d3-b46a-9f067ca71258"), - name='Parada 39', - latitude=8.4462536, - longitude=-82.4213439, - city='Ruta Palmira-David', - address='Parada 39', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("d649e756-a1a7-4b07-80a1-7040cffc5567"), - name='Parada 3', - latitude=8.6588979, - longitude=-82.4417667, - city='Ruta Palmira-David', - address='Parada 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("d8e82b75-e2a3-47f7-ab91-299282456076"), - name='Parada 14', - latitude=8.5983885, - longitude=-82.4200162, - city='Ruta Palmira-David', - address='Parada 14', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("d99779b3-07e4-4a53-bd87-1d3dec150346"), - name='Parada 24', - latitude=8.5322854, - longitude=-82.421057, - city='Ruta Palmira-David', - address='Parada 24', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("378993ec-7689-475c-8f4a-21177bbf6b73"), - name='Parada 33', - latitude=8.6588979, - longitude=-82.4417667, - city='Ruta Caldera-David', - address='Parada 33', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("37f0aeff-4345-4429-9c39-1a95be47d19f"), - name='Parada 36', - latitude=8.643388, - longitude=-82.4345935, - city='Ruta Caldera-David', - address='Parada 36', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("432d38b5-4ef5-4ca0-ad06-cbb98abfcdc1"), - name='Parada 37', - latitude=8.627808, - longitude=-82.4274531, - city='Ruta Caldera-David', - address='Parada 37', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("595f2ffe-2ab7-4cdb-9e49-087b3dddd12e"), - name='Parada 24', - latitude=8.6596151, - longitude=-82.3693519, - city='Ruta Caldera-David', - address='Parada 24', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("5ac77ca0-882f-41be-b434-f95731b4f947"), - name='Parada 49', - latitude=8.565803, - longitude=-82.4162278, - city='Ruta Caldera-David', - address='Parada 49', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5b8ed1ee-43fe-4bf2-8baf-ba7fb046bb16"), - name='Parada 39', - latitude=8.6202619, - longitude=-82.4239767, - city='Ruta Caldera-David', - address='Parada 39', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5c1bdc42-ab43-42a1-a257-66e547df75ff"), - name='Intersección 5', - latitude=8.6585719, - longitude=-82.3713712, - city='Ruta Caldera-David', - address='Intersección 5', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("54a34108-7928-4ec9-944c-5bcf33d59147"), - name='Intersección 3', - latitude=8.5914154, - longitude=-82.4213832, - city='Ruta Palmira-David', - address='Intersección 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("54d3e908-e2c6-4a8c-90e3-694daefea995"), - name='Parada 11', - latitude=8.6144011, - longitude=-82.4228017, - city='Ruta Palmira-David', - address='Parada 11', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("6ca67be5-7084-46ad-940d-277caeaebb9e"), - name='Parada 4', - latitude=8.6577004, - longitude=-82.4411605, - city='Ruta Palmira-David', - address='Parada 4', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("78017d28-3996-4820-a033-034e7a20c9bf"), - name='Parada 23', - latitude=8.5344038, - longitude=-82.420778, - city='Ruta Palmira-David', - address='Parada 23', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("54a8ce58-a383-48f2-8c58-d3c32c4878ef"), - name='Parada 39', - latitude=8.5344038, - longitude=-82.420778, - city='Ruta Boquete-David', - address='Parada 39', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5669e724-da62-42cc-8250-6d645d460e7b"), - name='Intersección 11', - latitude=8.4462536, - longitude=-82.4213439, - city='Ruta Boquete-David', - address='Intersección 11', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("56d12752-cb1e-448e-a54c-ac4ceb5b85c9"), - name='Parada 4', - latitude=8.7321499, - longitude=-82.4336354, - city='Ruta Boquete-David', - address='Parada 4', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("5966ddf4-4ad1-47c0-962d-20d4a19438fc"), - name='Parada 27', - latitude=8.6144011, - longitude=-82.4228017, - city='Ruta Boquete-David', - address='Parada 27', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5eff88c8-be0a-40a6-81b7-050b0e660b2a"), - name='Parada 41', - latitude=8.5259111, - longitude=-82.4219091, - city='Ruta Boquete-David', - address='Parada 41', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("652426c4-ba01-4191-8969-88701ad482a6"), - name='Terminal de Boquete', - latitude=8.7520024, - longitude=-82.4318432, - city='Ruta Boquete-David', - address='Terminal de Boquete', - stop_type=StopType.TERMINAL, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("680fb194-6f56-4f12-8042-4e97b477019c"), - name='Parada 54', - latitude=8.450325, - longitude=-82.4213788, - city='Ruta Boquete-David', - address='Parada 54', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("70cb67c0-3ff5-45ce-812a-f996e0a7f44d"), - name='Parada 21', - latitude=8.6472681, - longitude=-82.4363596, - city='Ruta Boquete-David', - address='Parada 21', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("71ce16ce-5aa5-4e39-a7fe-fa3272e75e41"), - name='Parada 9', - latitude=8.7218976, - longitude=-82.4379503, - city='Ruta Boquete-David', - address='Parada 9', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("2bf338e4-3cf0-4815-aaa5-7e4aa4774863"), - name='Parada 57', - latitude=8.4426552, - longitude=-82.42181, - city='Ruta Boquete-David', - address='Parada 57', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("30349a8c-65f4-481e-acd2-510efe0bbe78"), - name='Parada 32', - latitude=8.5842058, - longitude=-82.4229429, - city='Ruta Boquete-David', - address='Parada 32', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("33f07c2b-1618-482d-92c7-8d56c0e44960"), - name='Parada 43', - latitude=8.5116647, - longitude=-82.4237289, - city='Ruta Boquete-David', - address='Parada 43', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("358461df-1b48-4527-a457-f94277b47c60"), - name='Parada 24', - latitude=8.6234797, - longitude=-82.4254989, - city='Ruta Boquete-David', - address='Parada 24', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("35f25575-b799-4167-b94c-912c66e525ce"), - name='Parada 52', - latitude=8.4552106, - longitude=-82.4207317, - city='Ruta Boquete-David', - address='Parada 52', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("39e8a80a-cb67-464f-99e0-4c55602abc14"), - name='Parada 48', - latitude=8.4948946, - longitude=-82.4254776, - city='Ruta Boquete-David', - address='Parada 48', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("39fc64f7-4630-4197-a0ca-436c18a6cc8a"), - name='Intersección 9', - latitude=8.5080045, - longitude=-82.4242084, - city='Ruta Boquete-David', - address='Intersección 9', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("3f34c52b-28f6-4afb-8284-7e287322e5bf"), - name='Parada 23', - latitude=8.627808, - longitude=-82.4274531, - city='Ruta Boquete-David', - address='Parada 23', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("41bbb27f-5ee0-41a1-9cc4-98f491977023"), - name='Parada 33', - latitude=8.5785467, - longitude=-82.4231551, - city='Ruta Boquete-David', - address='Parada 33', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("447d004f-2952-4a7d-becf-3502f3bb43f8"), - name='Parada Principal 3', - latitude=8.5983885, - longitude=-82.4200162, - city='Ruta Boquete-David', - address='Parada Principal 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("46b43a9d-a71d-4276-9252-86a143def245"), - name='Parada 1', - latitude=8.7500574, - longitude=-82.4320427, - city='Ruta Boquete-David', - address='Parada 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5250f47d-3885-4566-ad93-25d8a223e25b"), - name='Parada 53', - latitude=8.4521084, - longitude=-82.4211461, - city='Ruta Boquete-David', - address='Parada 53', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("ffbe020d-97cb-4552-800a-1979bebcf3f9"), - name='Parada 17', - latitude=8.5785467, - longitude=-82.4231551, - city='Ruta Palmira-David', - address='Parada 17', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5dda8c4c-1134-4bef-a4d5-08de4234ccea"), - name='Intersección 9', - latitude=8.5914154, - longitude=-82.4213832, - city='Ruta Caldera-David', - address='Intersección 9', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("5e276d2f-6d8c-4e29-b14f-2088acb32ea0"), - name='Parada Principal 4', - latitude=8.6169195, - longitude=-82.4229218, - city='Ruta Caldera-David', - address='Parada Principal 4', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("62ba8246-ead0-49ad-ae56-e76afd35765e"), - name='Parada 23', - latitude=8.6623761, - longitude=-82.3642991, - city='Ruta Caldera-David', - address='Parada 23', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("6837aea7-cf79-4fc5-9530-9a7d02db7662"), - name='Parada 47', - latitude=8.5785467, - longitude=-82.4231551, - city='Ruta Caldera-David', - address='Parada 47', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("6ed29cc6-f1ad-407a-b27c-2a45ef50d506"), - name='Parada 41', - latitude=8.6144011, - longitude=-82.4228017, - city='Ruta Caldera-David', - address='Parada 41', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("817b72ba-d4e6-4cc5-814c-7055dbcbeba5"), - name='Parada 43', - latitude=8.6006107, - longitude=-82.4211566, - city='Ruta Caldera-David', - address='Parada 43', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("a1d2c520-d8dd-45e8-ad6e-16c1f8ecfe08"), - name='Parada 26', - latitude=8.6565959, - longitude=-82.3751945, - city='Ruta Caldera-David', - address='Parada 26', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a1df2b63-5a62-41fd-9f32-4c947d153d07"), - name='Parada 32', - latitude=8.6678999, - longitude=-82.4462348, - city='Ruta Caldera-David', - address='Parada 32', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a7996b81-206d-49af-bb42-e167f4f96a0a"), - name='Parada Principal 3', - latitude=8.6668438, - longitude=-82.4271677, - city='Ruta Caldera-David', - address='Parada Principal 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("bc19ef7d-7379-413e-bb2f-f32f224b0c64"), - name='Parada 44', - latitude=8.5983885, - longitude=-82.4200162, - city='Ruta Caldera-David', - address='Parada 44', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("bf4a14b1-2c0a-4405-8653-9a7ad24cd9ba"), - name='Intersección 7', - latitude=8.6472681, - longitude=-82.4363596, - city='Ruta Caldera-David', - address='Intersección 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("e2246bb6-1f69-4550-9239-fca81114892c"), - name='Terminal de David', - latitude=8.4334255, - longitude=-82.4231136, - city='Ruta Palmira-David', - address='Terminal de David', - stop_type=StopType.TERMINAL, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("ea305b8a-bffe-42b1-948e-72c9dbc6752d"), - name='Parada 26', - latitude=8.520598, - longitude=-82.4225716, - city='Ruta Palmira-David', - address='Parada 26', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("ecc0d404-bf6e-4266-bccd-4050e54a442a"), - name='Parada 9', - latitude=8.6202619, - longitude=-82.4239767, - city='Ruta Palmira-David', - address='Parada 9', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("efb5c05b-d52c-4030-aa82-960e41894ec3"), - name='Parada Principal 1', - latitude=8.6169195, - longitude=-82.4229218, - city='Ruta Palmira-David', - address='Parada Principal 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f184de4f-a708-4464-91a5-53e836c342fb"), - name='Parada 42', - latitude=8.4388768, - longitude=-82.4220722, - city='Ruta Palmira-David', - address='Parada 42', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f374aad0-549f-4754-859d-10465229c5fa"), - name='Parada 6', - latitude=8.643388, - longitude=-82.4345935, - city='Ruta Palmira-David', - address='Parada 6', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f42e378e-d63a-4747-aea9-1dfd179d9864"), - name='Parada 33', - latitude=8.4919557, - longitude=-82.4251941, - city='Ruta Palmira-David', - address='Parada 33', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("f6d8d3d7-7209-40ad-bf35-7cf9cb4de1d3"), - name='Parada 43', - latitude=8.4357775, - longitude=-82.4210319, - city='Ruta Palmira-David', - address='Parada 43', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("f6fc1c86-5b7e-4e83-86b1-4b999a33a2ba"), - name='Parada 37', - latitude=8.4521084, - longitude=-82.4211461, - city='Ruta Palmira-David', - address='Parada 37', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("84761977-665d-4b96-8c6b-766e7c8c779d"), - name='Parada Principal 1', - latitude=8.7197081, - longitude=-82.4391483, - city='Ruta Boquete-David', - address='Parada Principal 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("88e91734-fe05-4187-890f-b37c7c3d70ef"), - name='Parada 59', - latitude=8.4357775, - longitude=-82.4210319, - city='Ruta Boquete-David', - address='Parada 59', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("8a40a5a0-acee-49e3-b07d-3923128e4908"), - name='Parada 18', - latitude=8.6678999, - longitude=-82.4462348, - city='Ruta Boquete-David', - address='Parada 18', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("8e538436-3fba-478c-be7e-36d79e4c8e34"), - name='Parada 29', - latitude=8.6006107, - longitude=-82.4211566, - city='Ruta Boquete-David', - address='Parada 29', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("91d641eb-5564-4f8f-957e-aa2851078d98"), - name='Intersección 1', - latitude=8.729323, - longitude=-82.4340776, - city='Ruta Boquete-David', - address='Intersección 1', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("9412a5db-85b7-4eb4-b51e-1052c84de4f6"), - name='Parada 46', - latitude=8.5040506, - longitude=-82.4246805, - city='Ruta Boquete-David', - address='Parada 46', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("945f6bd5-5795-49d5-a874-b063e9611b5a"), - name='Parada 31', - latitude=8.5914154, - longitude=-82.4213832, - city='Ruta Boquete-David', - address='Parada 31', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("96d1c7d3-a6a7-4b56-9cb4-6f23260bf0a7"), - name='Parada 38', - latitude=8.5472523, - longitude=-82.419091, - city='Ruta Boquete-David', - address='Parada 38', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("9a773cda-fc7b-4020-8605-5a85b04a1049"), - name='Parada 16', - latitude=8.6960095, - longitude=-82.4488575, - city='Ruta Boquete-David', - address='Parada 16', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a23339b9-25b1-4219-b27e-ab153e2efcd7"), - name='Parada Principal 2', - latitude=8.6577004, - longitude=-82.4411605, - city='Ruta Boquete-David', - address='Parada Principal 2', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a37b73a8-9436-4c57-bf84-83b51659ae0f"), - name='Parada 58', - latitude=8.4388768, - longitude=-82.4220722, - city='Ruta Boquete-David', - address='Parada 58', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a48906a3-459e-40cf-b3c7-06aa1261b75e"), - name='Parada 42', - latitude=8.520598, - longitude=-82.4225716, - city='Ruta Boquete-David', - address='Parada 42', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("a8c62a6a-edf4-48ee-8fa7-6af9cf0165ed"), - name='Parada 14', - latitude=8.7122196, - longitude=-82.4433471, - city='Ruta Boquete-David', - address='Parada 14', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("ad214625-1468-4bf5-bf8c-ef4c27d64c38"), - name='Parada 19', - latitude=8.6588979, - longitude=-82.4417667, - city='Ruta Boquete-David', - address='Parada 19', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("ad39742d-5cc3-4288-a5ce-ec4fa132ae47"), - name='Parada 7', - latitude=8.7255787, - longitude=-82.4359451, - city='Ruta Boquete-David', - address='Parada 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("b8eec28f-3d45-4a65-9bfc-6df0a6f525bd"), - name='Parada 28', - latitude=8.610253, - longitude=-82.4225976, - city='Ruta Boquete-David', - address='Parada 28', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("c78c5f09-92da-4b82-a1db-c9e686c178b1"), - name='Parada 3', - latitude=8.7382538, - longitude=-82.4330994, - city='Ruta Boquete-David', - address='Parada 3', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("d20c75b9-605f-4aa9-b6f6-da9244f00bbd"), - name='Parada 36', - latitude=8.5584545, - longitude=-82.4151901, - city='Ruta Boquete-David', - address='Parada 36', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("d68fa99a-5e46-4db2-bc90-527addb6570b"), - name='Intersección 7', - latitude=8.565803, - longitude=-82.4162278, - city='Ruta Boquete-David', - address='Intersección 7', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("d982f3fc-8dca-4450-b932-7a975b6a6a86"), - name='Parada 44', - latitude=8.5097514, - longitude=-82.4239683, - city='Ruta Boquete-David', - address='Parada 44', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("d9e3cda5-b5d1-4c16-a51b-532cdcb9904f"), - name='Parada Principal 5', - latitude=8.4759182, - longitude=-82.4202329, - city='Ruta Boquete-David', - address='Parada Principal 5', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("e1fb75a6-2e2a-44f0-adcf-cae892b5976b"), - name='Parada 37', - latitude=8.5516692, - longitude=-82.4189188, - city='Ruta Boquete-David', - address='Parada 37', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("e6aa65fd-a2cb-4c83-b237-bc4ed6c31f57"), - name='Parada 47', - latitude=8.4978514, - longitude=-82.4254706, - city='Ruta Boquete-David', - address='Parada 47', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=False, - is_accessible=False, - ), - BusStop( - id=UUID("e7c404fe-6db7-4fa8-be3c-d20bfaea30b4"), - name='Parada 2', - latitude=8.7451912, - longitude=-82.4324671, - city='Ruta Boquete-David', - address='Parada 2', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("f10f4c8a-d04c-4ebe-a46d-ae3532867a4a"), - name='Parada Principal 4', - latitude=8.5322854, - longitude=-82.421057, - city='Ruta Boquete-David', - address='Parada Principal 4', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("d57a03ef-26ae-49b8-b0ab-a24701fecf8c"), - name='Parada 38', - latitude=8.6234797, - longitude=-82.4254989, - city='Ruta Caldera-David', - address='Parada 38', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("dd5b1ddb-80ca-4709-801a-dd8376df0b4e"), - name='Parada 48', - latitude=8.5746042, - longitude=-82.4212994, - city='Ruta Caldera-David', - address='Parada 48', - stop_type=StopType.REGULAR, - has_shelter=True, - has_seating=True, - is_accessible=False, - ), - BusStop( - id=UUID("eb875940-9aa6-42bc-bc9a-15fce44c4287"), - name='Parada 28', - latitude=8.6528035, - longitude=-82.3823114, - city='Ruta Caldera-David', - address='Parada 28', - stop_type=StopType.REGULAR, - has_shelter=False, - has_seating=True, - is_accessible=False, - ), - ] - for stop in bus_stops: - session.add(stop) - session.flush() # Flush stops so we can reference them in route_stops - - # Insert Route Stops - route_stops = [ - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("652426c4-ba01-4191-8969-88701ad482a6"), - stop_order=1, - travel_time_minutes=0, - is_pickup_point=True, - is_dropoff_point=False, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("46b43a9d-a71d-4276-9252-86a143def245"), - stop_order=2, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("e7c404fe-6db7-4fa8-be3c-d20bfaea30b4"), - stop_order=3, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("c78c5f09-92da-4b82-a1db-c9e686c178b1"), - stop_order=4, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("56d12752-cb1e-448e-a54c-ac4ceb5b85c9"), - stop_order=5, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("91d641eb-5564-4f8f-957e-aa2851078d98"), - stop_order=6, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("0948094e-1132-4a94-8873-4fbbb9bd25e5"), - stop_order=7, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("ad39742d-5cc3-4288-a5ce-ec4fa132ae47"), - stop_order=8, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("fb9882db-bb01-46ad-bbb1-5cb8cf4f78f2"), - stop_order=9, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("71ce16ce-5aa5-4e39-a7fe-fa3272e75e41"), - stop_order=10, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("84761977-665d-4b96-8c6b-766e7c8c779d"), - stop_order=11, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("24428491-2b6a-4ac0-9ca5-17df33138a18"), - stop_order=12, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("f63e9060-33e9-4263-9023-f37d0e848260"), - stop_order=13, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("fa9a49ee-146f-4ed2-8473-cc17da8dcab2"), - stop_order=14, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("a8c62a6a-edf4-48ee-8fa7-6af9cf0165ed"), - stop_order=15, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("f30ed3ab-b629-4320-b254-32d4d8341ee6"), - stop_order=16, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("9a773cda-fc7b-4020-8605-5a85b04a1049"), - stop_order=17, - travel_time_minutes=12, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("18dabf19-4f52-4d92-be42-6bd3623b4f06"), - stop_order=18, - travel_time_minutes=13, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("8a40a5a0-acee-49e3-b07d-3923128e4908"), - stop_order=19, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("ad214625-1468-4bf5-bf8c-ef4c27d64c38"), - stop_order=20, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("a23339b9-25b1-4219-b27e-ab153e2efcd7"), - stop_order=21, - travel_time_minutes=15, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("70cb67c0-3ff5-45ce-812a-f996e0a7f44d"), - stop_order=22, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("0b5970c0-343f-4c9d-972e-1ec6926f9807"), - stop_order=23, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("3f34c52b-28f6-4afb-8284-7e287322e5bf"), - stop_order=24, - travel_time_minutes=17, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("358461df-1b48-4527-a457-f94277b47c60"), - stop_order=25, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("2802d866-56d1-4200-9c41-402cc967f35b"), - stop_order=26, - travel_time_minutes=19, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("f38abc02-65e0-4a35-b19e-474359d7477e"), - stop_order=27, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("5966ddf4-4ad1-47c0-962d-20d4a19438fc"), - stop_order=28, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("b8eec28f-3d45-4a65-9bfc-6df0a6f525bd"), - stop_order=29, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("8e538436-3fba-478c-be7e-36d79e4c8e34"), - stop_order=30, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("447d004f-2952-4a7d-becf-3502f3bb43f8"), - stop_order=31, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("945f6bd5-5795-49d5-a874-b063e9611b5a"), - stop_order=32, - travel_time_minutes=23, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("30349a8c-65f4-481e-acd2-510efe0bbe78"), - stop_order=33, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("41bbb27f-5ee0-41a1-9cc4-98f491977023"), - stop_order=34, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("089afec3-6911-4c41-9d12-223b8607c4a9"), - stop_order=35, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("d68fa99a-5e46-4db2-bc90-527addb6570b"), - stop_order=36, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("d20c75b9-605f-4aa9-b6f6-da9244f00bbd"), - stop_order=37, - travel_time_minutes=27, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("e1fb75a6-2e2a-44f0-adcf-cae892b5976b"), - stop_order=38, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("96d1c7d3-a6a7-4b56-9cb4-6f23260bf0a7"), - stop_order=39, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("54a8ce58-a383-48f2-8c58-d3c32c4878ef"), - stop_order=40, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("f10f4c8a-d04c-4ebe-a46d-ae3532867a4a"), - stop_order=41, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("5eff88c8-be0a-40a6-81b7-050b0e660b2a"), - stop_order=42, - travel_time_minutes=31, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("a48906a3-459e-40cf-b3c7-06aa1261b75e"), - stop_order=43, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("33f07c2b-1618-482d-92c7-8d56c0e44960"), - stop_order=44, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("d982f3fc-8dca-4450-b932-7a975b6a6a86"), - stop_order=45, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("39fc64f7-4630-4197-a0ca-436c18a6cc8a"), - stop_order=46, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("9412a5db-85b7-4eb4-b51e-1052c84de4f6"), - stop_order=47, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("e6aa65fd-a2cb-4c83-b237-bc4ed6c31f57"), - stop_order=48, - travel_time_minutes=35, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("39e8a80a-cb67-464f-99e0-4c55602abc14"), - stop_order=49, - travel_time_minutes=36, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("926d4e83-1f08-4504-95e3-71f4d2c9666c"), - stop_order=50, - travel_time_minutes=37, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("d9e3cda5-b5d1-4c16-a51b-532cdcb9904f"), - stop_order=51, - travel_time_minutes=38, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("0b660dd6-e935-4be8-b470-eea9bf995c75"), - stop_order=52, - travel_time_minutes=38, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("35f25575-b799-4167-b94c-912c66e525ce"), - stop_order=53, - travel_time_minutes=39, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("5250f47d-3885-4566-ad93-25d8a223e25b"), - stop_order=54, - travel_time_minutes=40, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("680fb194-6f56-4f12-8042-4e97b477019c"), - stop_order=55, - travel_time_minutes=40, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("5669e724-da62-42cc-8250-6d645d460e7b"), - stop_order=56, - travel_time_minutes=41, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("3d73312c-eba3-43d1-ba3d-2381cfe6abd8"), - stop_order=57, - travel_time_minutes=42, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("2bf338e4-3cf0-4815-aaa5-7e4aa4774863"), - stop_order=58, - travel_time_minutes=43, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("a37b73a8-9436-4c57-bf84-83b51659ae0f"), - stop_order=59, - travel_time_minutes=44, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("88e91734-fe05-4187-890f-b37c7c3d70ef"), - stop_order=60, - travel_time_minutes=44, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - stop_id=UUID("0666a01b-0055-4b3a-9756-5053690cfae5"), - stop_order=61, - travel_time_minutes=45, - is_pickup_point=False, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("0666a01b-0055-4b3a-9756-5053690cfae5"), - stop_order=1, - travel_time_minutes=0, - is_pickup_point=True, - is_dropoff_point=False, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("88e91734-fe05-4187-890f-b37c7c3d70ef"), - stop_order=2, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("a37b73a8-9436-4c57-bf84-83b51659ae0f"), - stop_order=3, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("2bf338e4-3cf0-4815-aaa5-7e4aa4774863"), - stop_order=4, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("3d73312c-eba3-43d1-ba3d-2381cfe6abd8"), - stop_order=5, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("5669e724-da62-42cc-8250-6d645d460e7b"), - stop_order=6, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("680fb194-6f56-4f12-8042-4e97b477019c"), - stop_order=7, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("5250f47d-3885-4566-ad93-25d8a223e25b"), - stop_order=8, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("35f25575-b799-4167-b94c-912c66e525ce"), - stop_order=9, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("0b660dd6-e935-4be8-b470-eea9bf995c75"), - stop_order=10, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("d9e3cda5-b5d1-4c16-a51b-532cdcb9904f"), - stop_order=11, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("926d4e83-1f08-4504-95e3-71f4d2c9666c"), - stop_order=12, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("39e8a80a-cb67-464f-99e0-4c55602abc14"), - stop_order=13, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("e6aa65fd-a2cb-4c83-b237-bc4ed6c31f57"), - stop_order=14, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("9412a5db-85b7-4eb4-b51e-1052c84de4f6"), - stop_order=15, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("39fc64f7-4630-4197-a0ca-436c18a6cc8a"), - stop_order=16, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("d982f3fc-8dca-4450-b932-7a975b6a6a86"), - stop_order=17, - travel_time_minutes=12, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("33f07c2b-1618-482d-92c7-8d56c0e44960"), - stop_order=18, - travel_time_minutes=13, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("a48906a3-459e-40cf-b3c7-06aa1261b75e"), - stop_order=19, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("5eff88c8-be0a-40a6-81b7-050b0e660b2a"), - stop_order=20, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("f10f4c8a-d04c-4ebe-a46d-ae3532867a4a"), - stop_order=21, - travel_time_minutes=15, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("54a8ce58-a383-48f2-8c58-d3c32c4878ef"), - stop_order=22, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("96d1c7d3-a6a7-4b56-9cb4-6f23260bf0a7"), - stop_order=23, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("e1fb75a6-2e2a-44f0-adcf-cae892b5976b"), - stop_order=24, - travel_time_minutes=17, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("d20c75b9-605f-4aa9-b6f6-da9244f00bbd"), - stop_order=25, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("d68fa99a-5e46-4db2-bc90-527addb6570b"), - stop_order=26, - travel_time_minutes=19, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("089afec3-6911-4c41-9d12-223b8607c4a9"), - stop_order=27, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("41bbb27f-5ee0-41a1-9cc4-98f491977023"), - stop_order=28, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("30349a8c-65f4-481e-acd2-510efe0bbe78"), - stop_order=29, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("945f6bd5-5795-49d5-a874-b063e9611b5a"), - stop_order=30, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("447d004f-2952-4a7d-becf-3502f3bb43f8"), - stop_order=31, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("8e538436-3fba-478c-be7e-36d79e4c8e34"), - stop_order=32, - travel_time_minutes=23, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("b8eec28f-3d45-4a65-9bfc-6df0a6f525bd"), - stop_order=33, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("5966ddf4-4ad1-47c0-962d-20d4a19438fc"), - stop_order=34, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("f38abc02-65e0-4a35-b19e-474359d7477e"), - stop_order=35, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("2802d866-56d1-4200-9c41-402cc967f35b"), - stop_order=36, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("358461df-1b48-4527-a457-f94277b47c60"), - stop_order=37, - travel_time_minutes=27, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("3f34c52b-28f6-4afb-8284-7e287322e5bf"), - stop_order=38, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("0b5970c0-343f-4c9d-972e-1ec6926f9807"), - stop_order=39, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("70cb67c0-3ff5-45ce-812a-f996e0a7f44d"), - stop_order=40, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("a23339b9-25b1-4219-b27e-ab153e2efcd7"), - stop_order=41, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("ad214625-1468-4bf5-bf8c-ef4c27d64c38"), - stop_order=42, - travel_time_minutes=31, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("8a40a5a0-acee-49e3-b07d-3923128e4908"), - stop_order=43, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("18dabf19-4f52-4d92-be42-6bd3623b4f06"), - stop_order=44, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("9a773cda-fc7b-4020-8605-5a85b04a1049"), - stop_order=45, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("f30ed3ab-b629-4320-b254-32d4d8341ee6"), - stop_order=46, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("a8c62a6a-edf4-48ee-8fa7-6af9cf0165ed"), - stop_order=47, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("fa9a49ee-146f-4ed2-8473-cc17da8dcab2"), - stop_order=48, - travel_time_minutes=35, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("f63e9060-33e9-4263-9023-f37d0e848260"), - stop_order=49, - travel_time_minutes=36, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("24428491-2b6a-4ac0-9ca5-17df33138a18"), - stop_order=50, - travel_time_minutes=37, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("84761977-665d-4b96-8c6b-766e7c8c779d"), - stop_order=51, - travel_time_minutes=38, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("71ce16ce-5aa5-4e39-a7fe-fa3272e75e41"), - stop_order=52, - travel_time_minutes=38, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("fb9882db-bb01-46ad-bbb1-5cb8cf4f78f2"), - stop_order=53, - travel_time_minutes=39, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("ad39742d-5cc3-4288-a5ce-ec4fa132ae47"), - stop_order=54, - travel_time_minutes=40, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("0948094e-1132-4a94-8873-4fbbb9bd25e5"), - stop_order=55, - travel_time_minutes=40, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("91d641eb-5564-4f8f-957e-aa2851078d98"), - stop_order=56, - travel_time_minutes=41, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("56d12752-cb1e-448e-a54c-ac4ceb5b85c9"), - stop_order=57, - travel_time_minutes=42, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("c78c5f09-92da-4b82-a1db-c9e686c178b1"), - stop_order=58, - travel_time_minutes=43, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("e7c404fe-6db7-4fa8-be3c-d20bfaea30b4"), - stop_order=59, - travel_time_minutes=44, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("46b43a9d-a71d-4276-9252-86a143def245"), - stop_order=60, - travel_time_minutes=44, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - stop_id=UUID("652426c4-ba01-4191-8969-88701ad482a6"), - stop_order=61, - travel_time_minutes=45, - is_pickup_point=False, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("acea0a34-f564-4f30-b97d-445c5c2f3864"), - stop_order=1, - travel_time_minutes=0, - is_pickup_point=True, - is_dropoff_point=False, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("bf949ab0-c554-41ab-a852-917b6aed4251"), - stop_order=2, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("9cc2dd3d-59fd-4a5f-a24e-c52082625190"), - stop_order=3, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("d649e756-a1a7-4b07-80a1-7040cffc5567"), - stop_order=4, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("6ca67be5-7084-46ad-940d-277caeaebb9e"), - stop_order=5, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("a324ca30-9831-48ce-a5cc-cfcf21d91ee0"), - stop_order=6, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("f374aad0-549f-4754-859d-10465229c5fa"), - stop_order=7, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("9740fe20-cde6-467f-8de4-174426fcbc7f"), - stop_order=8, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("2c2ba744-3c20-4485-aca4-22b00b4f622f"), - stop_order=9, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("ecc0d404-bf6e-4266-bccd-4050e54a442a"), - stop_order=10, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("efb5c05b-d52c-4030-aa82-960e41894ec3"), - stop_order=11, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("54d3e908-e2c6-4a8c-90e3-694daefea995"), - stop_order=12, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("83f03e06-bb17-41ef-9760-565f7c6b7905"), - stop_order=13, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("1d74e1ef-e488-4fc9-9df8-9c88f007e204"), - stop_order=14, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("d8e82b75-e2a3-47f7-ab91-299282456076"), - stop_order=15, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("54a34108-7928-4ec9-944c-5bcf33d59147"), - stop_order=16, - travel_time_minutes=12, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("8265275c-8f02-487b-a8d2-4a33a04515d2"), - stop_order=17, - travel_time_minutes=13, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("ffbe020d-97cb-4552-800a-1979bebcf3f9"), - stop_order=18, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("39274b2b-7d5a-4c6e-b3e9-4f05a66f1c7e"), - stop_order=19, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("a5704227-9658-4118-8566-19d7b5827fc6"), - stop_order=20, - travel_time_minutes=15, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("c01ee146-0148-4e5d-bff3-3db389de1dd8"), - stop_order=21, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("2050bc76-6534-4b6b-891f-33fe3bac8407"), - stop_order=22, - travel_time_minutes=17, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("46588013-d616-4eae-8e50-c98bf38e050f"), - stop_order=23, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("78017d28-3996-4820-a033-034e7a20c9bf"), - stop_order=24, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("d99779b3-07e4-4a53-bd87-1d3dec150346"), - stop_order=25, - travel_time_minutes=19, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("10a60237-1189-49d6-8da3-54893f849212"), - stop_order=26, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("ea305b8a-bffe-42b1-948e-72c9dbc6752d"), - stop_order=27, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("2e00b45d-9c28-4aac-b895-546f213e3309"), - stop_order=28, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("85b7e107-6d21-44cf-84c9-ddef2be9bbdb"), - stop_order=29, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("2f17114c-6bfc-45bf-a436-ed64860df62e"), - stop_order=30, - travel_time_minutes=23, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("8b26bd01-f59e-40d4-9f5b-91eb86ae9d0f"), - stop_order=31, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("05baf1ef-af1d-4f76-8027-2482b37b8c37"), - stop_order=32, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("3386ad96-9012-472f-a756-9093c602a416"), - stop_order=33, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("f42e378e-d63a-4747-aea9-1dfd179d9864"), - stop_order=34, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("51043828-726d-4245-a975-59723eb2f08f"), - stop_order=35, - travel_time_minutes=27, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("2c669c57-a164-4437-8114-85a7ec8b4e3c"), - stop_order=36, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("29c3fa50-965a-47fc-9aa9-5216593fd863"), - stop_order=37, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("f6fc1c86-5b7e-4e83-86b1-4b999a33a2ba"), - stop_order=38, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("8b5246b1-c4cb-4435-85a3-0330ac8db62e"), - stop_order=39, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("d20f93f6-f187-47d3-b46a-9f067ca71258"), - stop_order=40, - travel_time_minutes=31, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("506e4aff-1cb6-47e9-a85f-3dafd2d49308"), - stop_order=41, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("848e3f5c-0500-4ffa-a92f-5f56a339fda2"), - stop_order=42, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("f184de4f-a708-4464-91a5-53e836c342fb"), - stop_order=43, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("f6d8d3d7-7209-40ad-bf35-7cf9cb4de1d3"), - stop_order=44, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - stop_id=UUID("e2246bb6-1f69-4550-9239-fca81114892c"), - stop_order=45, - travel_time_minutes=35, - is_pickup_point=False, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("e2246bb6-1f69-4550-9239-fca81114892c"), - stop_order=1, - travel_time_minutes=0, - is_pickup_point=True, - is_dropoff_point=False, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("f6d8d3d7-7209-40ad-bf35-7cf9cb4de1d3"), - stop_order=2, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("f184de4f-a708-4464-91a5-53e836c342fb"), - stop_order=3, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("848e3f5c-0500-4ffa-a92f-5f56a339fda2"), - stop_order=4, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("506e4aff-1cb6-47e9-a85f-3dafd2d49308"), - stop_order=5, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("d20f93f6-f187-47d3-b46a-9f067ca71258"), - stop_order=6, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("8b5246b1-c4cb-4435-85a3-0330ac8db62e"), - stop_order=7, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("f6fc1c86-5b7e-4e83-86b1-4b999a33a2ba"), - stop_order=8, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("29c3fa50-965a-47fc-9aa9-5216593fd863"), - stop_order=9, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("2c669c57-a164-4437-8114-85a7ec8b4e3c"), - stop_order=10, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("51043828-726d-4245-a975-59723eb2f08f"), - stop_order=11, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("f42e378e-d63a-4747-aea9-1dfd179d9864"), - stop_order=12, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("3386ad96-9012-472f-a756-9093c602a416"), - stop_order=13, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("05baf1ef-af1d-4f76-8027-2482b37b8c37"), - stop_order=14, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("8b26bd01-f59e-40d4-9f5b-91eb86ae9d0f"), - stop_order=15, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("2f17114c-6bfc-45bf-a436-ed64860df62e"), - stop_order=16, - travel_time_minutes=12, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("85b7e107-6d21-44cf-84c9-ddef2be9bbdb"), - stop_order=17, - travel_time_minutes=13, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("2e00b45d-9c28-4aac-b895-546f213e3309"), - stop_order=18, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("ea305b8a-bffe-42b1-948e-72c9dbc6752d"), - stop_order=19, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("10a60237-1189-49d6-8da3-54893f849212"), - stop_order=20, - travel_time_minutes=15, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("d99779b3-07e4-4a53-bd87-1d3dec150346"), - stop_order=21, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("78017d28-3996-4820-a033-034e7a20c9bf"), - stop_order=22, - travel_time_minutes=17, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("46588013-d616-4eae-8e50-c98bf38e050f"), - stop_order=23, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("2050bc76-6534-4b6b-891f-33fe3bac8407"), - stop_order=24, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("c01ee146-0148-4e5d-bff3-3db389de1dd8"), - stop_order=25, - travel_time_minutes=19, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("a5704227-9658-4118-8566-19d7b5827fc6"), - stop_order=26, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("39274b2b-7d5a-4c6e-b3e9-4f05a66f1c7e"), - stop_order=27, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("ffbe020d-97cb-4552-800a-1979bebcf3f9"), - stop_order=28, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("8265275c-8f02-487b-a8d2-4a33a04515d2"), - stop_order=29, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("54a34108-7928-4ec9-944c-5bcf33d59147"), - stop_order=30, - travel_time_minutes=23, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("d8e82b75-e2a3-47f7-ab91-299282456076"), - stop_order=31, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("1d74e1ef-e488-4fc9-9df8-9c88f007e204"), - stop_order=32, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("83f03e06-bb17-41ef-9760-565f7c6b7905"), - stop_order=33, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("54d3e908-e2c6-4a8c-90e3-694daefea995"), - stop_order=34, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("efb5c05b-d52c-4030-aa82-960e41894ec3"), - stop_order=35, - travel_time_minutes=27, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("ecc0d404-bf6e-4266-bccd-4050e54a442a"), - stop_order=36, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("2c2ba744-3c20-4485-aca4-22b00b4f622f"), - stop_order=37, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("9740fe20-cde6-467f-8de4-174426fcbc7f"), - stop_order=38, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("f374aad0-549f-4754-859d-10465229c5fa"), - stop_order=39, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("a324ca30-9831-48ce-a5cc-cfcf21d91ee0"), - stop_order=40, - travel_time_minutes=31, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("6ca67be5-7084-46ad-940d-277caeaebb9e"), - stop_order=41, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("d649e756-a1a7-4b07-80a1-7040cffc5567"), - stop_order=42, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("9cc2dd3d-59fd-4a5f-a24e-c52082625190"), - stop_order=43, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("bf949ab0-c554-41ab-a852-917b6aed4251"), - stop_order=44, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - stop_id=UUID("acea0a34-f564-4f30-b97d-445c5c2f3864"), - stop_order=45, - travel_time_minutes=35, - is_pickup_point=False, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("df528e47-8fc2-49b7-81db-3c8f4f7a176a"), - stop_order=1, - travel_time_minutes=0, - is_pickup_point=True, - is_dropoff_point=False, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("a20332a5-08f3-46f4-9dfd-f27e5539469e"), - stop_order=2, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("2b2e6858-be6d-4f18-a3a2-92373cfd9a9d"), - stop_order=3, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("3d769def-cf21-4560-be21-13b828aafe54"), - stop_order=4, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("7db160e3-05b2-4778-baee-789cea0f0bfd"), - stop_order=5, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("dc3e0510-7cdd-4521-8dc2-6181120b4f26"), - stop_order=6, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("77f80a0a-450c-42c3-bb8a-b9a3b6e5758d"), - stop_order=7, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("edfb904e-66be-4a8d-80f7-3a30403d3fca"), - stop_order=8, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("f7317833-9adc-40c0-9132-5c66c1822210"), - stop_order=9, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("682705d5-5413-4bd3-a31c-144832e7ec96"), - stop_order=10, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("12fc09fc-5e48-4c54-b414-4133f0f12a37"), - stop_order=11, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("788abd79-3d4b-4810-a5c0-7d8fec3d1a27"), - stop_order=12, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("b321b88d-5032-4383-85e1-ec99c3e3cb3f"), - stop_order=13, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("d86649cc-7286-46c3-933c-168716d1b304"), - stop_order=14, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("bd2f01ab-0406-4b6d-b4c5-052f8915fc30"), - stop_order=15, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("69c374a2-a062-4b28-8308-6aff793cd631"), - stop_order=16, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("8ba33c36-303a-4182-8e08-065c2961e05d"), - stop_order=17, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("00a14099-a862-455f-abfa-c2ec1489ab70"), - stop_order=18, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("b95c7990-65ac-40db-bb49-b99ed3b9d8dd"), - stop_order=19, - travel_time_minutes=12, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("9bdf297b-6312-43fa-b945-bfaa01fd49bc"), - stop_order=20, - travel_time_minutes=13, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("9d9ffbcc-b4d8-427b-b5a3-add1c25f66a7"), - stop_order=21, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("decf0e21-7488-4dc1-b5b6-9997e2437403"), - stop_order=22, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("21f322a7-ac14-4144-abad-7e7f2502eef6"), - stop_order=23, - travel_time_minutes=15, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("62ba8246-ead0-49ad-ae56-e76afd35765e"), - stop_order=24, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("595f2ffe-2ab7-4cdb-9e49-087b3dddd12e"), - stop_order=25, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("5c1bdc42-ab43-42a1-a257-66e547df75ff"), - stop_order=26, - travel_time_minutes=17, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("a1d2c520-d8dd-45e8-ad6e-16c1f8ecfe08"), - stop_order=27, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("156ce6b5-1683-4654-aab5-17e6d55547e8"), - stop_order=28, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("eb875940-9aa6-42bc-bc9a-15fce44c4287"), - stop_order=29, - travel_time_minutes=19, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("29819fa8-f25e-4cb5-b142-c65a6f11baa9"), - stop_order=30, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("a7996b81-206d-49af-bb42-e167f4f96a0a"), - stop_order=31, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("0512d2ed-abc0-4f95-b39f-515eac489d27"), - stop_order=32, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("a1df2b63-5a62-41fd-9f32-4c947d153d07"), - stop_order=33, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("378993ec-7689-475c-8f4a-21177bbf6b73"), - stop_order=34, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("267afc65-88a6-4ac1-9be5-46d22bfec4d5"), - stop_order=35, - travel_time_minutes=23, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("bf4a14b1-2c0a-4405-8653-9a7ad24cd9ba"), - stop_order=36, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("37f0aeff-4345-4429-9c39-1a95be47d19f"), - stop_order=37, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("432d38b5-4ef5-4ca0-ad06-cbb98abfcdc1"), - stop_order=38, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("d57a03ef-26ae-49b8-b0ab-a24701fecf8c"), - stop_order=39, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("5b8ed1ee-43fe-4bf2-8baf-ba7fb046bb16"), - stop_order=40, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("5e276d2f-6d8c-4e29-b14f-2088acb32ea0"), - stop_order=41, - travel_time_minutes=27, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("6ed29cc6-f1ad-407a-b27c-2a45ef50d506"), - stop_order=42, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("3211b00c-4c3a-41e9-a560-794d77c1cfab"), - stop_order=43, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("817b72ba-d4e6-4cc5-814c-7055dbcbeba5"), - stop_order=44, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("bc19ef7d-7379-413e-bb2f-f32f224b0c64"), - stop_order=45, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("5dda8c4c-1134-4bef-a4d5-08de4234ccea"), - stop_order=46, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("1fb1faef-ae69-4875-8598-7839e6268741"), - stop_order=47, - travel_time_minutes=31, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("6837aea7-cf79-4fc5-9530-9a7d02db7662"), - stop_order=48, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("dd5b1ddb-80ca-4709-801a-dd8376df0b4e"), - stop_order=49, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("5ac77ca0-882f-41be-b434-f95731b4f947"), - stop_order=50, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("81644bb0-0afb-4cd0-8496-f066a4bd1701"), - stop_order=51, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("b5c4dbb3-3225-462e-b865-79216d8564f4"), - stop_order=52, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("53d8b9b6-ef59-439e-97a5-39dacac56a24"), - stop_order=53, - travel_time_minutes=35, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("6d4aa16d-5683-48b1-8507-b0aba05d4aaa"), - stop_order=54, - travel_time_minutes=36, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("eef5ca98-8a8d-42a6-9616-e3cabc7fcf0b"), - stop_order=55, - travel_time_minutes=36, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("d3773f11-9393-40ab-9295-9305412d16ce"), - stop_order=56, - travel_time_minutes=37, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("707c8544-533f-4e42-8767-0490170cb083"), - stop_order=57, - travel_time_minutes=38, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("8db9b2c9-769b-4ec6-aae7-8a43ef99b9bc"), - stop_order=58, - travel_time_minutes=39, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("2a03ba34-5483-4783-bb78-e8c92c200fbe"), - stop_order=59, - travel_time_minutes=39, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("51e94d40-56fb-4842-8cfe-8b76c46aa13b"), - stop_order=60, - travel_time_minutes=40, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("f475143d-f78b-4b27-87d9-5a8867673695"), - stop_order=61, - travel_time_minutes=41, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("a364477b-c104-4ec5-bc4e-67bc04d4fd84"), - stop_order=62, - travel_time_minutes=41, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("5433c8d0-002a-45f0-a17a-c4fcf84e5169"), - stop_order=63, - travel_time_minutes=42, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("8085a65b-18fd-439d-8fa6-760b3b26ea55"), - stop_order=64, - travel_time_minutes=43, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("4d182cbe-c108-46ed-a9b3-4b6cdef33aa9"), - stop_order=65, - travel_time_minutes=43, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("9c9a32d7-1bef-4824-95db-3761b4688111"), - stop_order=66, - travel_time_minutes=44, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("89d0f353-8316-4c22-ab4e-1006121ee23a"), - stop_order=67, - travel_time_minutes=45, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("6eb8d5e3-4319-40d3-bd16-e3383cb113af"), - stop_order=68, - travel_time_minutes=45, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("6eabfea4-f0e8-4f8d-b97f-bc8febb39344"), - stop_order=69, - travel_time_minutes=46, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("bd0f3e38-f7f4-4d8f-a9d3-33191468a58d"), - stop_order=70, - travel_time_minutes=47, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("b64f9a9a-0568-476f-b229-403e6a4cf448"), - stop_order=71, - travel_time_minutes=47, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("d5af00b9-9f40-4afd-a67f-abf98a06ed6a"), - stop_order=72, - travel_time_minutes=48, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("e51839b2-1bb8-47c6-ab80-224cd5f17cb7"), - stop_order=73, - travel_time_minutes=49, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("dee5dc1b-5101-43f1-a322-b59cfdd18ed1"), - stop_order=74, - travel_time_minutes=49, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - stop_id=UUID("4d7a3281-563a-491d-bbde-3a5fc4b87198"), - stop_order=75, - travel_time_minutes=50, - is_pickup_point=False, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("4d7a3281-563a-491d-bbde-3a5fc4b87198"), - stop_order=1, - travel_time_minutes=0, - is_pickup_point=True, - is_dropoff_point=False, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("dee5dc1b-5101-43f1-a322-b59cfdd18ed1"), - stop_order=2, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("e51839b2-1bb8-47c6-ab80-224cd5f17cb7"), - stop_order=3, - travel_time_minutes=1, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("d5af00b9-9f40-4afd-a67f-abf98a06ed6a"), - stop_order=4, - travel_time_minutes=2, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("b64f9a9a-0568-476f-b229-403e6a4cf448"), - stop_order=5, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("bd0f3e38-f7f4-4d8f-a9d3-33191468a58d"), - stop_order=6, - travel_time_minutes=3, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("6eabfea4-f0e8-4f8d-b97f-bc8febb39344"), - stop_order=7, - travel_time_minutes=4, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("6eb8d5e3-4319-40d3-bd16-e3383cb113af"), - stop_order=8, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("89d0f353-8316-4c22-ab4e-1006121ee23a"), - stop_order=9, - travel_time_minutes=5, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("9c9a32d7-1bef-4824-95db-3761b4688111"), - stop_order=10, - travel_time_minutes=6, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("4d182cbe-c108-46ed-a9b3-4b6cdef33aa9"), - stop_order=11, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("8085a65b-18fd-439d-8fa6-760b3b26ea55"), - stop_order=12, - travel_time_minutes=7, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("5433c8d0-002a-45f0-a17a-c4fcf84e5169"), - stop_order=13, - travel_time_minutes=8, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("a364477b-c104-4ec5-bc4e-67bc04d4fd84"), - stop_order=14, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("f475143d-f78b-4b27-87d9-5a8867673695"), - stop_order=15, - travel_time_minutes=9, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("51e94d40-56fb-4842-8cfe-8b76c46aa13b"), - stop_order=16, - travel_time_minutes=10, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("2a03ba34-5483-4783-bb78-e8c92c200fbe"), - stop_order=17, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("8db9b2c9-769b-4ec6-aae7-8a43ef99b9bc"), - stop_order=18, - travel_time_minutes=11, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("707c8544-533f-4e42-8767-0490170cb083"), - stop_order=19, - travel_time_minutes=12, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("d3773f11-9393-40ab-9295-9305412d16ce"), - stop_order=20, - travel_time_minutes=13, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("eef5ca98-8a8d-42a6-9616-e3cabc7fcf0b"), - stop_order=21, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("6d4aa16d-5683-48b1-8507-b0aba05d4aaa"), - stop_order=22, - travel_time_minutes=14, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("53d8b9b6-ef59-439e-97a5-39dacac56a24"), - stop_order=23, - travel_time_minutes=15, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("b5c4dbb3-3225-462e-b865-79216d8564f4"), - stop_order=24, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("81644bb0-0afb-4cd0-8496-f066a4bd1701"), - stop_order=25, - travel_time_minutes=16, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("5ac77ca0-882f-41be-b434-f95731b4f947"), - stop_order=26, - travel_time_minutes=17, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("dd5b1ddb-80ca-4709-801a-dd8376df0b4e"), - stop_order=27, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("6837aea7-cf79-4fc5-9530-9a7d02db7662"), - stop_order=28, - travel_time_minutes=18, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("1fb1faef-ae69-4875-8598-7839e6268741"), - stop_order=29, - travel_time_minutes=19, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("5dda8c4c-1134-4bef-a4d5-08de4234ccea"), - stop_order=30, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("bc19ef7d-7379-413e-bb2f-f32f224b0c64"), - stop_order=31, - travel_time_minutes=20, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("817b72ba-d4e6-4cc5-814c-7055dbcbeba5"), - stop_order=32, - travel_time_minutes=21, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("3211b00c-4c3a-41e9-a560-794d77c1cfab"), - stop_order=33, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("6ed29cc6-f1ad-407a-b27c-2a45ef50d506"), - stop_order=34, - travel_time_minutes=22, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("5e276d2f-6d8c-4e29-b14f-2088acb32ea0"), - stop_order=35, - travel_time_minutes=23, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("5b8ed1ee-43fe-4bf2-8baf-ba7fb046bb16"), - stop_order=36, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("d57a03ef-26ae-49b8-b0ab-a24701fecf8c"), - stop_order=37, - travel_time_minutes=24, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("432d38b5-4ef5-4ca0-ad06-cbb98abfcdc1"), - stop_order=38, - travel_time_minutes=25, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("37f0aeff-4345-4429-9c39-1a95be47d19f"), - stop_order=39, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("bf4a14b1-2c0a-4405-8653-9a7ad24cd9ba"), - stop_order=40, - travel_time_minutes=26, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("267afc65-88a6-4ac1-9be5-46d22bfec4d5"), - stop_order=41, - travel_time_minutes=27, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("378993ec-7689-475c-8f4a-21177bbf6b73"), - stop_order=42, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("a1df2b63-5a62-41fd-9f32-4c947d153d07"), - stop_order=43, - travel_time_minutes=28, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("0512d2ed-abc0-4f95-b39f-515eac489d27"), - stop_order=44, - travel_time_minutes=29, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("a7996b81-206d-49af-bb42-e167f4f96a0a"), - stop_order=45, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("29819fa8-f25e-4cb5-b142-c65a6f11baa9"), - stop_order=46, - travel_time_minutes=30, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("eb875940-9aa6-42bc-bc9a-15fce44c4287"), - stop_order=47, - travel_time_minutes=31, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("156ce6b5-1683-4654-aab5-17e6d55547e8"), - stop_order=48, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("a1d2c520-d8dd-45e8-ad6e-16c1f8ecfe08"), - stop_order=49, - travel_time_minutes=32, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("5c1bdc42-ab43-42a1-a257-66e547df75ff"), - stop_order=50, - travel_time_minutes=33, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("595f2ffe-2ab7-4cdb-9e49-087b3dddd12e"), - stop_order=51, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("62ba8246-ead0-49ad-ae56-e76afd35765e"), - stop_order=52, - travel_time_minutes=34, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("21f322a7-ac14-4144-abad-7e7f2502eef6"), - stop_order=53, - travel_time_minutes=35, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("decf0e21-7488-4dc1-b5b6-9997e2437403"), - stop_order=54, - travel_time_minutes=36, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("9d9ffbcc-b4d8-427b-b5a3-add1c25f66a7"), - stop_order=55, - travel_time_minutes=36, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("9bdf297b-6312-43fa-b945-bfaa01fd49bc"), - stop_order=56, - travel_time_minutes=37, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("b95c7990-65ac-40db-bb49-b99ed3b9d8dd"), - stop_order=57, - travel_time_minutes=38, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("00a14099-a862-455f-abfa-c2ec1489ab70"), - stop_order=58, - travel_time_minutes=39, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("8ba33c36-303a-4182-8e08-065c2961e05d"), - stop_order=59, - travel_time_minutes=39, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("69c374a2-a062-4b28-8308-6aff793cd631"), - stop_order=60, - travel_time_minutes=40, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("bd2f01ab-0406-4b6d-b4c5-052f8915fc30"), - stop_order=61, - travel_time_minutes=41, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("d86649cc-7286-46c3-933c-168716d1b304"), - stop_order=62, - travel_time_minutes=41, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("b321b88d-5032-4383-85e1-ec99c3e3cb3f"), - stop_order=63, - travel_time_minutes=42, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("788abd79-3d4b-4810-a5c0-7d8fec3d1a27"), - stop_order=64, - travel_time_minutes=43, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("12fc09fc-5e48-4c54-b414-4133f0f12a37"), - stop_order=65, - travel_time_minutes=43, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("682705d5-5413-4bd3-a31c-144832e7ec96"), - stop_order=66, - travel_time_minutes=44, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("f7317833-9adc-40c0-9132-5c66c1822210"), - stop_order=67, - travel_time_minutes=45, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("edfb904e-66be-4a8d-80f7-3a30403d3fca"), - stop_order=68, - travel_time_minutes=45, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("77f80a0a-450c-42c3-bb8a-b9a3b6e5758d"), - stop_order=69, - travel_time_minutes=46, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("dc3e0510-7cdd-4521-8dc2-6181120b4f26"), - stop_order=70, - travel_time_minutes=47, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("7db160e3-05b2-4778-baee-789cea0f0bfd"), - stop_order=71, - travel_time_minutes=47, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("3d769def-cf21-4560-be21-13b828aafe54"), - stop_order=72, - travel_time_minutes=48, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("2b2e6858-be6d-4f18-a3a2-92373cfd9a9d"), - stop_order=73, - travel_time_minutes=49, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("a20332a5-08f3-46f4-9dfd-f27e5539469e"), - stop_order=74, - travel_time_minutes=49, - is_pickup_point=True, - is_dropoff_point=True, - ), - RouteStop( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - stop_id=UUID("df528e47-8fc2-49b7-81db-3c8f4f7a176a"), - stop_order=75, - travel_time_minutes=50, - is_pickup_point=False, - is_dropoff_point=True, - ), - ] - for route_stop in route_stops: - session.add(route_stop) - session.flush() # Flush route_stops before adding schedules - - # Insert Bus Schedules - bus_schedules = [ - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(5, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(5, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(6, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(6, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(7, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(7, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(8, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(8, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(9, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(9, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(10, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(10, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(11, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(11, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(12, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(12, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(13, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(13, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(14, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(14, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(15, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(15, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(16, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(16, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(17, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(17, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(18, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(18, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(19, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(19, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(20, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("944457a8-7edd-42f4-9ff6-8018f4ec7e9c"), - departure_time=time(20, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(5, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(6, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(6, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(7, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(7, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(8, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(8, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(9, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(9, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(10, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(10, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(11, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(11, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(12, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(12, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(13, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(13, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(14, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(14, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(15, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(15, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(16, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(16, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(17, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(17, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(18, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(18, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(19, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(19, 0), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(20, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("5da1dfb6-760a-4f59-aa5b-667149eb9ae6"), - departure_time=time(20, 30), - frequency_minutes=30, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - departure_time=time(6, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - departure_time=time(7, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - departure_time=time(8, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - departure_time=time(12, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - departure_time=time(17, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("27ef54e9-196f-478f-ba56-9d46c0949098"), - departure_time=time(18, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - departure_time=time(8, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - departure_time=time(14, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("22dc631f-1f8c-4a34-9f3e-1dc450d9be9a"), - departure_time=time(18, 0), - frequency_minutes=60, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - departure_time=time(5, 30), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - departure_time=time(6, 15), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - departure_time=time(7, 0), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - departure_time=time(7, 45), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - departure_time=time(16, 0), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("6239c83b-7466-476f-be54-df33977fc32e"), - departure_time=time(17, 0), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - departure_time=time(9, 0), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - departure_time=time(15, 0), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - BusSchedule( - route_id=UUID("9d315fa5-f87e-4737-8013-9fe2617ffb23"), - departure_time=time(18, 30), - frequency_minutes=45, - schedule_type=BusScheduleType.WEEKDAY, - is_active=True, - notes=None, - ), - ] - for schedule in bus_schedules: - session.add(schedule) - - session.commit() - print("Database seeded successfully!") - - -if __name__ == "__main__": - seed_database() diff --git a/backend/app/main.py b/backend/app/main.py deleted file mode 100644 index c2c31d4..0000000 --- a/backend/app/main.py +++ /dev/null @@ -1,175 +0,0 @@ -"""FastAPI application entry point.""" -from fastapi import FastAPI -from fastapi.middleware.cors import CORSMiddleware -from fastapi.staticfiles import StaticFiles -import os - -# Absolute path for uploads directory (relative to this file: app/main.py -> backend/uploads) -_BACKEND_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -UPLOAD_BASE = os.path.join(_BACKEND_DIR, "uploads") - -from app.core.config import settings -from app.core.database import init_db, engine -from sqlmodel import Session, select -from app.models.taxi import Taxi -from app.models.shuttle import Shuttle -from app.models.business import Business -from app.models.coupon import Coupon -from app.api.routes import router as routes_router -from app.api.bus_stops import router as bus_stops_router -from app.api.schedules import router as schedules_router -from app.api.coupons import router as coupons_router -from app.api.taxis import router as taxis_router -from app.api.auth import router as auth_router -from app.api.users import router as users_router -from app.api.favorites import router as favorites_router -from app.api.telemetry import router as telemetry_router -from app.api.businesses import router as businesses_router -from app.api.analytics import router as analytics_router -from app.api.reports import router as reports_router -from app.api.shuttles import router as shuttles_router - -from contextlib import asynccontextmanager -from alembic.config import Config -from alembic import command -import random -from datetime import datetime, timedelta - -from app.services.image_handler import cleanup_expired_coupons - -@asynccontextmanager -async def lifespan(app: FastAPI): - # Run migrations - try: - alembic_cfg = Config("alembic.ini") - command.upgrade(alembic_cfg, "head") - print("DEBUG: Database migrations completed successfully") - except Exception as e: - print(f"WARNING: Database migrations failed: {e}") - # Fallback to init_db if alembic fails or isn't configured - try: - init_db() - except: - pass - - # Run cleanup of expired coupons - try: - with Session(engine) as session: - cleanup_expired_coupons(session) - except Exception as e: - print(f"WARNING: Initial cleanup failed: {e}") - - # Seed sample data if empty - with Session(engine) as session: - # 1. Taxis - taxi_count = session.exec(select(Taxi)).first() - if not taxi_count: - sample_taxis = [ - Taxi( - owner_name="Don José (Sibu Demo)", - phone_number="+507 6000-0001", - license_plate="T-001-SIBU", - corregimiento="Boquete", - shift="dia", - rating=4.9, - english_speaking=True - ), - Taxi( - owner_name="María C. (Sibu Demo)", - phone_number="+507 6000-0002", - license_plate="T-002-SIBU", - corregimiento="Boquete", - shift="tarde", - rating=5.0, - english_speaking=False - ) - ] - session.add_all(sample_taxis) - session.commit() - - # 2. Shuttles - shuttle_count = session.exec(select(Shuttle)).first() - if not shuttle_count: - shuttles_data = [ - {'route_name': 'Boquete > Santa Catalina', 'origin': 'Boquete', 'destination': 'Santa Catalina', 'vehicle_type': 'Mini Van', 'company_name': 'Chiriqui Transfers', 'trip_type': 'one_way', 'price_per_person': 35.0, 'estimated_duration': '4.5 horas', 'departure_times': '8:00 AM', 'contact_whatsapp': '+50760000000', 'is_active': True}, - {'route_name': 'Boquete > Bocas del Toro', 'origin': 'Boquete', 'destination': 'Bocas del Toro', 'vehicle_type': 'Van + Bote', 'company_name': 'Hello Panama', 'trip_type': 'one_way', 'price_per_person': 30.0, 'estimated_duration': '3.5 horas', 'departure_times': '8:00 AM', 'contact_whatsapp': '+50760000000', 'is_active': True} - ] - for data in shuttles_data: - session.add(Shuttle(**data)) - session.commit() - - # 3. Businesses & Coupons (Tourist spots) - biz_count = session.exec(select(Business)).first() - if not biz_count: - tourist_spots = [ - {"name": "Finca El Explorador", "area": "Boquete", "lat": 8.7845, "lng": -82.4350}, - {"name": "Cascada San Ramón", "area": "Boquete", "lat": 8.8120, "lng": -82.4650} - ] - for spot in tourist_spots: - biz = Business(name=spot["name"], address=f"Sector {spot['area']}", phone="6000-0000", category="Area Turistica", area=spot["area"], latitude=spot["lat"], longitude=spot["lng"]) - session.add(biz) - session.flush() - coupon = Coupon(title=f"Oferta en {biz.name}", description=f"Descuento especial en {biz.name}", business_id=biz.id, business_name=biz.name, business_address=biz.address, business_phone=biz.phone, category=biz.category, discount_percentage=15, valid_from=datetime.now(), valid_until=(datetime.now() + timedelta(days=30)), is_active=True) - session.add(coupon) - session.commit() - yield - -app = FastAPI( - title="SIBU Transportation API", - description="API for SIBU public transportation system", - version="1.0.0", - debug=settings.debug, - lifespan=lifespan -) - -# CORS middleware -origins = [ - "http://localhost:5173", - "http://127.0.0.1:5173", - "https://sibu-frontend.vercel.app", - "https://sibu-transport.web.app", - "https://sibu2-0-transport-2026.firebaseapp.com", - "https://sibu2-0-transport-2026.web.app", -] - -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# Ensure upload directories exist -for sub in ["profiles", "vehicles", "businesses", "coupons"]: - os.makedirs(os.path.join(UPLOAD_BASE, sub), exist_ok=True) - -# Mount static files -app.mount("/uploads", StaticFiles(directory=UPLOAD_BASE), name="uploads") - -# Include routers -app.include_router(routes_router) -app.include_router(bus_stops_router) -app.include_router(schedules_router) -app.include_router(coupons_router) -app.include_router(taxis_router) -app.include_router(auth_router) -app.include_router(users_router) -app.include_router(favorites_router) -app.include_router(telemetry_router) -app.include_router(businesses_router) -app.include_router(analytics_router, prefix="/api/analytics", tags=["analytics"]) -app.include_router(reports_router) -app.include_router(shuttles_router) - - -@app.get("/") -async def root(): - """Root endpoint.""" - return {"message": "SIBU Transportation API", "version": "1.0.0"} - - -@app.get("/health") -async def health(): - """Health check endpoint.""" - return {"status": "healthy", "environment": settings.environment} diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py deleted file mode 100644 index 601e486..0000000 --- a/backend/app/models/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Database models.""" -from app.models.route import Route -from app.models.bus_stop import BusStop -from app.models.route_stop import RouteStop -from app.models.bus_schedule import BusSchedule -from app.models.user import User, DriverProfile -from app.models.taxi import Taxi -from app.models.favorite import Favorite -from app.models.telemetry import Telemetry -from app.models.coupon import Coupon -from app.models.business import Business -from app.models.user_coupon import UserCoupon -from app.models.analytics import AnalyticsEvent -from app.models.report import Report -from app.models.shuttle import Shuttle - -__all__ = ["Route", "BusStop", "RouteStop", "BusSchedule", "User", "DriverProfile", "Taxi", "Favorite", "Telemetry", "Coupon", "Business", "UserCoupon", "AnalyticsEvent", "Report", "Shuttle"] - diff --git a/backend/app/models/analytics.py b/backend/app/models/analytics.py deleted file mode 100644 index 02e48c8..0000000 --- a/backend/app/models/analytics.py +++ /dev/null @@ -1,19 +0,0 @@ -from sqlmodel import SQLModel, Field -from typing import Optional, Dict -from uuid import UUID, uuid4 -from datetime import datetime -from sqlalchemy import Column, DateTime, func, JSON - -class AnalyticsEvent(SQLModel, table=True): - __tablename__ = "analytics_events" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - event_name: str = Field(index=True) - user_id: Optional[UUID] = Field(default=None, index=True, foreign_key="users.id") - screen_name: Optional[str] = None - item_id: Optional[str] = None # route_id, stop_id, promo_id, etc. - properties: Optional[Dict] = Field(default_factory=dict, sa_column=Column(JSON)) - timestamp: datetime = Field( - default_factory=datetime.utcnow, - sa_column=Column(DateTime(timezone=True), server_default=func.now(), index=True) - ) diff --git a/backend/app/models/bus_schedule.py b/backend/app/models/bus_schedule.py deleted file mode 100644 index 6bd35d5..0000000 --- a/backend/app/models/bus_schedule.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Bus schedule model.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime, time -from typing import Optional -from enum import Enum -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - - -class BusScheduleType(str, Enum): - """Schedule type enumeration.""" - WEEKDAY = "weekday" - WEEKEND = "weekend" - HOLIDAY = "holiday" - - -class BusSchedule(SQLModel, table=True): - """Bus schedule model.""" - - __tablename__ = "bus_schedules" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - route_id: UUID = Field(foreign_key="routes.id") - departure_time: time - frequency_minutes: Optional[int] = 30 - schedule_type: BusScheduleType = BusScheduleType.WEEKDAY - is_active: bool = Field(default=True) - is_published: bool = Field(default=False) - notes: Optional[str] = None - created_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now())) - diff --git a/backend/app/models/bus_stop.py b/backend/app/models/bus_stop.py deleted file mode 100644 index ee5a36d..0000000 --- a/backend/app/models/bus_stop.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Bus stop model.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime -from typing import Optional -from enum import Enum -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - - -class StopType(str, Enum): - """Stop type enumeration.""" - TERMINAL = "terminal" - REGULAR = "regular" - EXPRESS_ONLY = "express_only" - - -class BusStop(SQLModel, table=True): - """Bus stop model.""" - - __tablename__ = "bus_stops" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - name: str - latitude: float - longitude: float - city: str - address: Optional[str] = None - stop_type: StopType = StopType.REGULAR - has_shelter: bool = False - has_seating: bool = False - is_accessible: bool = False - stop_order: Optional[int] = None - created_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now())) - updated_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now(), onupdate=func.now())) - diff --git a/backend/app/models/business.py b/backend/app/models/business.py deleted file mode 100644 index 96abe85..0000000 --- a/backend/app/models/business.py +++ /dev/null @@ -1,58 +0,0 @@ -from sqlmodel import SQLModel, Field, Column, Relationship -from datetime import datetime -from typing import Optional, List, TYPE_CHECKING -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - -if TYPE_CHECKING: - from app.models.coupon import Coupon - -class Business(SQLModel, table=True): - """Business record for local partners.""" - - __tablename__ = "businesses" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - name: str - address: Optional[str] = None - phone: Optional[str] = None - image_url: Optional[str] = None - social_media: Optional[str] = None - category: Optional[str] = None - latitude: Optional[float] = None - longitude: Optional[float] = None - area: Optional[str] = Field(default="Boquete") - - # Relationship to coupons - coupons: List["Coupon"] = Relationship(back_populates="business") - - created_at: Optional[datetime] = Field( - default=None, - sa_column=Column(DateTime(timezone=True), server_default=func.now()) - ) - updated_at: Optional[datetime] = Field( - default=None, - sa_column=Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) - ) - -class BusinessCreate(SQLModel): - name: str - address: Optional[str] = None - phone: Optional[str] = None - image_url: Optional[str] = None - social_media: Optional[str] = None - category: Optional[str] = None - latitude: Optional[float] = None - longitude: Optional[float] = None - area: Optional[str] = "Boquete" - -class BusinessUpdate(SQLModel): - name: Optional[str] = None - address: Optional[str] = None - phone: Optional[str] = None - image_url: Optional[str] = None - social_media: Optional[str] = None - category: Optional[str] = None - latitude: Optional[float] = None - longitude: Optional[float] = None - area: Optional[str] = None diff --git a/backend/app/models/coupon.py b/backend/app/models/coupon.py deleted file mode 100644 index 4aa8b46..0000000 --- a/backend/app/models/coupon.py +++ /dev/null @@ -1,79 +0,0 @@ -from sqlmodel import SQLModel, Field, Column, Relationship -from datetime import datetime -from typing import Optional, TYPE_CHECKING -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - -if TYPE_CHECKING: - from app.models.business import Business - -class Coupon(SQLModel, table=True): - """Coupon record for promotions.""" - - __tablename__ = "coupons" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - business_id: Optional[UUID] = Field(default=None, foreign_key="businesses.id") - title: str = Field(index=True) - description: Optional[str] = None - - # Relationship to business - business: Optional["Business"] = Relationship(back_populates="coupons") - business_name: Optional[str] = None - business_address: Optional[str] = None - business_phone: Optional[str] = None - image_url: Optional[str] = None - social_media: Optional[str] = None - terms: Optional[str] = None - discount_percentage: Optional[int] = None - discount_amount: Optional[float] = None - category: Optional[str] = None - valid_from: Optional[datetime] = Field( - sa_column=Column(DateTime(timezone=True), nullable=True) - ) - valid_until: Optional[datetime] = Field( - sa_column=Column(DateTime(timezone=True), nullable=True) - ) - is_active: bool = Field(default=True) - created_at: Optional[datetime] = Field( - default=None, - sa_column=Column(DateTime(timezone=True), server_default=func.now()) - ) - updated_at: Optional[datetime] = Field( - default=None, - sa_column=Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) - ) - -class CouponCreate(SQLModel): - title: str - business_id: Optional[UUID] = None - description: Optional[str] = None - business_name: Optional[str] = None - business_address: Optional[str] = None - business_phone: Optional[str] = None - image_url: Optional[str] = None - social_media: Optional[str] = None - terms: Optional[str] = None - discount_percentage: Optional[int] = None - discount_amount: Optional[float] = None - category: Optional[str] = None - valid_from: Optional[datetime] = None - valid_until: Optional[datetime] = None - is_active: Optional[bool] = True - -class CouponUpdate(SQLModel): - title: Optional[str] = None - business_id: Optional[UUID] = None - description: Optional[str] = None - business_name: Optional[str] = None - business_address: Optional[str] = None - business_phone: Optional[str] = None - image_url: Optional[str] = None - social_media: Optional[str] = None - terms: Optional[str] = None - discount_percentage: Optional[int] = None - discount_amount: Optional[float] = None - category: Optional[str] = None - valid_from: Optional[datetime] = None - valid_until: Optional[datetime] = None - is_active: Optional[bool] = None diff --git a/backend/app/models/favorite.py b/backend/app/models/favorite.py deleted file mode 100644 index e344b5c..0000000 --- a/backend/app/models/favorite.py +++ /dev/null @@ -1,31 +0,0 @@ -from sqlmodel import SQLModel, Field -from datetime import datetime -from typing import Optional -from uuid import UUID, uuid4 - -class Favorite(SQLModel, table=True): - __tablename__ = "favorites" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - user_id: UUID = Field(foreign_key="users.id", index=True) - - # Type of favorite: 'coupon', 'business', 'taxi', 'route' - item_type: str = Field(index=True) - item_id: str = Field(index=True) - - # Optional metadata - item_name: Optional[str] = None - item_image: Optional[str] = None - - created_at: datetime = Field(default_factory=datetime.utcnow) - - class Config: - json_schema_extra = { - "example": { - "user_id": "user-123", - "item_type": "coupon", - "item_id": "coupon-456", - "item_name": "50% descuento en restaurante", - "item_image": "/uploads/coupon.jpg" - } - } diff --git a/backend/app/models/report.py b/backend/app/models/report.py deleted file mode 100644 index 4fb2c39..0000000 --- a/backend/app/models/report.py +++ /dev/null @@ -1,27 +0,0 @@ -from sqlmodel import SQLModel, Field, Relationship -from typing import Optional, TYPE_CHECKING -if TYPE_CHECKING: - from app.models.user import User -from uuid import UUID, uuid4 -from datetime import datetime -from sqlalchemy import Column, DateTime, func -from enum import Enum - -class ReportStatus(str, Enum): - PENDING = "pending" - RESOLVED = "resolved" - ARCHIVED = "archived" - -class Report(SQLModel, table=True): - __tablename__ = "reports" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - user_id: Optional[UUID] = Field(default=None, foreign_key="users.id") - message: str - status: ReportStatus = Field(default=ReportStatus.PENDING) - created_at: Optional[datetime] = Field( - sa_column=Column(DateTime, server_default=func.now()) - ) - - # Relationships - user: Optional["User"] = Relationship() diff --git a/backend/app/models/route.py b/backend/app/models/route.py deleted file mode 100644 index 06aa14d..0000000 --- a/backend/app/models/route.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Route model.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime -from typing import Optional -from enum import Enum -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - - -class RouteStatus(str, Enum): - """Route status enumeration.""" - ACTIVE = "ACTIVE" - INACTIVE = "INACTIVE" - MAINTENANCE = "MAINTENANCE" - - -class Route(SQLModel, table=True): - """Route model representing a bus route.""" - - __tablename__ = "routes" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - name: str = Field(unique=True, index=True) - description: Optional[str] = None - origin_city: str - destination_city: str - color: str = Field(default="#FEE715") - direction: str = Field(default="outbound") - distance_km: Optional[float] = None - estimated_duration_minutes: Optional[int] = None - average_speed_kmh: Optional[float] = None - status: RouteStatus = RouteStatus.ACTIVE - created_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now())) - updated_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now(), onupdate=func.now())) - diff --git a/backend/app/models/route_stop.py b/backend/app/models/route_stop.py deleted file mode 100644 index d235e4f..0000000 --- a/backend/app/models/route_stop.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Route stop junction model.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime -from typing import Optional -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - - -class RouteStop(SQLModel, table=True): - """Route stop junction table connecting routes to their stops.""" - - __tablename__ = "route_stops" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - route_id: UUID = Field(foreign_key="routes.id") - stop_id: UUID = Field(foreign_key="bus_stops.id") - stop_order: int - travel_time_minutes: Optional[int] = None - stop_delay_minutes: int = 0 - is_pickup_point: bool = True - is_dropoff_point: bool = True - created_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now())) - diff --git a/backend/app/models/shuttle.py b/backend/app/models/shuttle.py deleted file mode 100644 index 450aa00..0000000 --- a/backend/app/models/shuttle.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Shuttle model for intercity and tourist trips.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime -from typing import Optional -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - - -class Shuttle(SQLModel, table=True): - """Model representing an intercity shuttle or tourist trip.""" - - __tablename__ = "shuttles" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - route_name: str = Field(index=True) # e.g. "Boquete - Santa Catalina" - description: Optional[str] = None - origin: str = Field(index=True) - destination: str = Field(index=True) - vehicle_type: str # Private Bus, Private Car, Van - company_name: Optional[str] = None # e.g. "Chiriqui Transfers" - trip_type: str = "one_way" # one_way, round_trip, both - price_per_person: Optional[float] = None - price_private_trip: Optional[float] = None - estimated_duration: str # e.g. "4.5 hours" - departure_times: Optional[str] = None # e.g. "Every Day at 8:00 AM" - contact_whatsapp: str - phone_number: Optional[str] = None - english_speaking: bool = Field(default=False) - image_url: Optional[str] = None - is_active: bool = Field(default=True) - created_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now())) - updated_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now(), onupdate=func.now())) diff --git a/backend/app/models/taxi.py b/backend/app/models/taxi.py deleted file mode 100644 index 29f9f22..0000000 --- a/backend/app/models/taxi.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Taxi model.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime -from typing import Optional -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func - - -class Taxi(SQLModel, table=True): - """Taxi model representing an authorized taxi.""" - - __tablename__ = "taxis_v2" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - owner_name: str - phone_number: str - license_plate: str = Field(unique=True, index=True) - cooperative: Optional[str] = None - corregimiento: str = Field(index=True) - shift: str = "day" # day, night, 24h - rating: float = Field(default=5.0) - english_speaking: bool = Field(default=False) - image_url: Optional[str] = None - is_active: bool = Field(default=True) - created_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now())) - updated_at: Optional[datetime] = Field(sa_column=Column(DateTime, server_default=func.now(), onupdate=func.now())) diff --git a/backend/app/models/telemetry.py b/backend/app/models/telemetry.py deleted file mode 100644 index 2c4f81d..0000000 --- a/backend/app/models/telemetry.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Telemetry model for real-time tracking.""" -from sqlmodel import SQLModel, Field, Column -from datetime import datetime -from typing import Optional -from uuid import UUID, uuid4 -from sqlalchemy import DateTime, func -from enum import Enum - -class VehicleStatus(str, Enum): - ACTIVE = "active" - OFFLINE = "offline" - BREAK = "break" - -class Telemetry(SQLModel, table=True): - """Telemetry record for a driver's vehicle.""" - - __tablename__ = "telemetry" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - user_id: UUID = Field(foreign_key="users.id", index=True) - latitude: float - longitude: float - speed: Optional[float] = None - heading: Optional[float] = None - status: VehicleStatus = Field(default=VehicleStatus.ACTIVE) - timestamp: datetime = Field( - sa_column=Column(DateTime, server_default=func.now(), index=True) - ) - -class TelemetryCreate(SQLModel): - latitude: float - longitude: float - speed: Optional[float] = None - heading: Optional[float] = None - status: VehicleStatus = VehicleStatus.ACTIVE diff --git a/backend/app/models/user.py b/backend/app/models/user.py deleted file mode 100644 index 4fbf903..0000000 --- a/backend/app/models/user.py +++ /dev/null @@ -1,59 +0,0 @@ -"""User and DriverProfile models.""" -from sqlmodel import SQLModel, Field, Relationship -from typing import Optional -from enum import Enum -from uuid import UUID, uuid4 -from datetime import datetime -from sqlalchemy import Column, DateTime, func - - -class UserRole(str, Enum): - ADMIN = "ADMIN" - PASSENGER = "PASSENGER" - DRIVER = "DRIVER" - PROMOTER = "PROMOTER" - - -class VehicleType(str, Enum): - TAXI = "taxi" - BUS = "bus" - - -class User(SQLModel, table=True): - __tablename__ = "users" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - email: str = Field(unique=True, index=True) - hashed_password: str - full_name: str = Field(index=True) - role: UserRole = Field(default=UserRole.PASSENGER) - is_active: bool = Field(default=True) - is_verified: bool = Field(default=False) # For drivers/admins verification - profile_photo_url: Optional[str] = None - created_at: Optional[datetime] = Field( - sa_column=Column(DateTime, server_default=func.now()) - ) - - # Relationships - driver_profile: Optional["DriverProfile"] = Relationship( - back_populates="user", sa_relationship_kwargs={"uselist": False} - ) - - -class DriverProfile(SQLModel, table=True): - __tablename__ = "driver_profiles" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - user_id: UUID = Field(foreign_key="users.id") - cedula: str - vehicle_type: VehicleType - license_plate: str - photo_url: Optional[str] = None - vehicle_photo_url: Optional[str] = None - cooperative_name: Optional[str] = None # Specifically for Bus - shift: Optional[str] = None # For Taxi schedules (e.g. "Dia,Noche") - payment_methods: Optional[str] = None # e.g. "Efectivo,Yappi" - speaks_english: bool = Field(default=False) - - # Relationship - user: User = Relationship(back_populates="driver_profile") diff --git a/backend/app/models/user_coupon.py b/backend/app/models/user_coupon.py deleted file mode 100644 index df14ec5..0000000 --- a/backend/app/models/user_coupon.py +++ /dev/null @@ -1,49 +0,0 @@ -"""UserCoupon model for tracking claimed coupons.""" -from sqlmodel import SQLModel, Field, Relationship -from datetime import datetime -from typing import Optional, TYPE_CHECKING -from uuid import UUID, uuid4 -from sqlalchemy import Column, DateTime, func, String -from enum import Enum - -if TYPE_CHECKING: - from app.models.user import User - from app.models.coupon import Coupon - -class UserCouponStatus(str, Enum): - CLAIMED = "claimed" - REDEEMED = "redeemed" - EXPIRED = "expired" - -class UserCoupon(SQLModel, table=True): - __tablename__ = "user_coupons" - - id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) - user_id: UUID = Field(foreign_key="users.id") - coupon_id: UUID = Field(foreign_key="coupons.id") - - status: UserCouponStatus = Field(default=UserCouponStatus.CLAIMED) - redemption_code: str = Field( - sa_column=Column(String, unique=True, index=True) - ) - - claimed_at: datetime = Field( - sa_column=Column(DateTime(timezone=True), server_default=func.now()) - ) - redeemed_at: Optional[datetime] = Field( - sa_column=Column(DateTime(timezone=True), nullable=True) - ) - - # Relationships - user: "User" = Relationship() - coupon: "Coupon" = Relationship() - -class UserCouponRead(SQLModel): - id: UUID - user_id: UUID - coupon_id: UUID - status: UserCouponStatus - redemption_code: str - claimed_at: datetime - redeemed_at: Optional[datetime] - coupon: Optional["Coupon"] = None diff --git a/backend/app/schemas/__init__.py b/backend/app/schemas/__init__.py deleted file mode 100644 index cc4b794..0000000 --- a/backend/app/schemas/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Pydantic schemas for request/response validation.""" - diff --git a/backend/app/schemas/bus_stop.py b/backend/app/schemas/bus_stop.py deleted file mode 100644 index 59d98fd..0000000 --- a/backend/app/schemas/bus_stop.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Bus stop schemas.""" -from pydantic import BaseModel, field_serializer -from typing import Optional -from datetime import datetime -from uuid import UUID -from app.models.bus_stop import StopType - - -class BusStopBase(BaseModel): - """Base bus stop schema.""" - name: str - latitude: float - longitude: float - city: str - address: Optional[str] = None - stop_type: StopType = StopType.REGULAR - has_shelter: bool = False - has_seating: bool = False - is_accessible: bool = False - stop_order: Optional[int] = None - - -class BusStopCreate(BusStopBase): - """Schema for creating a bus stop.""" - pass - - -class BusStopUpdate(BaseModel): - """Schema for updating a bus stop.""" - name: Optional[str] = None - latitude: Optional[float] = None - longitude: Optional[float] = None - city: Optional[str] = None - address: Optional[str] = None - stop_type: Optional[StopType] = None - has_shelter: Optional[bool] = None - has_seating: Optional[bool] = None - is_accessible: Optional[bool] = None - - -class BusStopResponse(BusStopBase): - """Schema for bus stop response.""" - id: UUID - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None - - @field_serializer('id') - def serialize_id(self, value: UUID) -> str: - return str(value) - - class Config: - from_attributes = True - diff --git a/backend/app/schemas/report.py b/backend/app/schemas/report.py deleted file mode 100644 index ae6fe5e..0000000 --- a/backend/app/schemas/report.py +++ /dev/null @@ -1,22 +0,0 @@ -from pydantic import BaseModel -from typing import Optional -from uuid import UUID -from datetime import datetime -from app.models.report import ReportStatus - -class ReportCreate(BaseModel): - message: str - -class ReportUpdate(BaseModel): - status: ReportStatus - -class ReportResponse(BaseModel): - id: UUID - user_id: Optional[UUID] = None - user_name: Optional[str] = None - message: str - status: ReportStatus - created_at: datetime - - class Config: - from_attributes = True diff --git a/backend/app/schemas/route.py b/backend/app/schemas/route.py deleted file mode 100644 index 7d9f2f9..0000000 --- a/backend/app/schemas/route.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Route schemas.""" -from pydantic import BaseModel, field_serializer -from typing import Optional -from datetime import datetime -from uuid import UUID -from app.models.route import RouteStatus - - -class RouteBase(BaseModel): - """Base route schema.""" - name: str - description: Optional[str] = None - origin_city: str - destination_city: str - color: Optional[str] = "#FEE715" - direction: Optional[str] = "outbound" - distance_km: Optional[float] = None - estimated_duration_minutes: Optional[int] = None - average_speed_kmh: Optional[float] = None - status: RouteStatus = RouteStatus.ACTIVE - - -class RouteCreate(RouteBase): - """Schema for creating a route.""" - pass - - -class RouteUpdate(BaseModel): - """Schema for updating a route.""" - name: Optional[str] = None - description: Optional[str] = None - origin_city: Optional[str] = None - destination_city: Optional[str] = None - color: Optional[str] = None - direction: Optional[str] = None - distance_km: Optional[float] = None - estimated_duration_minutes: Optional[int] = None - average_speed_kmh: Optional[float] = None - status: Optional[RouteStatus] = None - - -class RouteResponse(RouteBase): - """Schema for route response.""" - id: UUID - created_at: Optional[datetime] = None - updated_at: Optional[datetime] = None - - @field_serializer('id') - def serialize_id(self, value: UUID) -> str: - return str(value) - - class Config: - from_attributes = True diff --git a/backend/app/schemas/route_stop.py b/backend/app/schemas/route_stop.py deleted file mode 100644 index 731f7b2..0000000 --- a/backend/app/schemas/route_stop.py +++ /dev/null @@ -1,21 +0,0 @@ -from pydantic import BaseModel -from typing import Optional -from uuid import UUID - -class RouteStopBase(BaseModel): - stop_id: UUID - stop_order: Optional[int] = None - travel_time_minutes: Optional[int] = None - stop_delay_minutes: int = 0 - is_pickup_point: Optional[bool] = True - is_dropoff_point: Optional[bool] = True - -class RouteStopCreate(RouteStopBase): - pass - -class RouteStopUpdate(BaseModel): - stop_order: Optional[int] = None - travel_time_minutes: Optional[int] = None - stop_delay_minutes: Optional[int] = None - is_pickup_point: Optional[bool] = None - is_dropoff_point: Optional[bool] = None diff --git a/backend/app/schemas/shuttle.py b/backend/app/schemas/shuttle.py deleted file mode 100644 index db45cca..0000000 --- a/backend/app/schemas/shuttle.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Shuttle schemas.""" -from typing import Optional -from uuid import UUID -from pydantic import BaseModel - -class ShuttleBase(BaseModel): - route_name: str - description: Optional[str] = None - origin: str - destination: str - vehicle_type: str - company_name: Optional[str] = None - trip_type: str = "one_way" - price_per_person: Optional[float] = None - price_private_trip: Optional[float] = None - estimated_duration: str - departure_times: Optional[str] = None - contact_whatsapp: str - image_url: Optional[str] = None - is_active: bool = True - -class ShuttleCreate(ShuttleBase): - pass - -class ShuttleUpdate(BaseModel): - route_name: Optional[str] = None - description: Optional[str] = None - origin: Optional[str] = None - destination: Optional[str] = None - vehicle_type: Optional[str] = None - company_name: Optional[str] = None - trip_type: Optional[str] = None - price_per_person: Optional[float] = None - price_private_trip: Optional[float] = None - estimated_duration: Optional[str] = None - departure_times: Optional[str] = None - contact_whatsapp: Optional[str] = None - image_url: Optional[str] = None - is_active: Optional[bool] = None - -class ShuttleRead(ShuttleBase): - id: UUID - - class Config: - from_attributes = True diff --git a/backend/app/schemas/user.py b/backend/app/schemas/user.py deleted file mode 100644 index 73d3999..0000000 --- a/backend/app/schemas/user.py +++ /dev/null @@ -1,65 +0,0 @@ -"""User and Auth schemas.""" -from pydantic import BaseModel, EmailStr -from typing import Optional -from uuid import UUID -from app.models.user import UserRole, VehicleType - - -class UserBase(BaseModel): - email: EmailStr - full_name: str - profile_photo_url: Optional[str] = None - - -class UserUpdate(BaseModel): - full_name: Optional[str] = None - password: Optional[str] = None - profile_photo_url: Optional[str] = None - - -class PassengerCreate(UserBase): - password: str - - -class DriverProfileBase(BaseModel): - cedula: str - vehicle_type: VehicleType - license_plate: str - cooperative_name: Optional[str] = None - - -class DriverCreate(UserBase): - password: str - cedula: str - vehicle_type: VehicleType - license_plate: str - cooperative_name: Optional[str] = None - # Photos will be handled via UploadFile in FastAPI, not in the Pydantic schema for JSON data - - -class UserResponse(UserBase): - id: UUID - role: UserRole - is_active: bool - is_verified: bool - - class Config: - from_attributes = True - - -class LoginRequest(BaseModel): - email: str - password: str - keep_session: bool = False - - -class GoogleLoginRequest(BaseModel): - id_token: str - - -class Token(BaseModel): - access_token: str - token_type: str - role: str - full_name: str - profile_photo_url: Optional[str] = None diff --git a/backend/app/services/__init__.py b/backend/app/services/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/app/services/image_handler.py b/backend/app/services/image_handler.py deleted file mode 100644 index 458fa7a..0000000 --- a/backend/app/services/image_handler.py +++ /dev/null @@ -1,79 +0,0 @@ -import os -import shutil -from uuid import uuid4 -from fastapi import UploadFile -from typing import Optional -from datetime import datetime -from sqlmodel import Session, select -from app.models.coupon import Coupon - -# Use absolute path relative to THIS file's location (app/services/image_handler.py) -# Going up 3 levels: services -> app -> backend -> uploads -_BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -UPLOAD_BASE = os.path.join(_BASE_DIR, "uploads") - - -def save_image(image: UploadFile, subfolder: str) -> str: - """Saves an image to the local filesystem and returns its relative URL.""" - upload_dir = os.path.join(UPLOAD_BASE, subfolder) - os.makedirs(upload_dir, exist_ok=True) - - # Generate unique filename - ext = os.path.splitext(image.filename or "")[1].lower() - if not ext or ext not in ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.avif']: - ext = ".jpg" # Default extension if missing or invalid - - filename = f"{uuid4()}{ext}" - path = os.path.join(upload_dir, filename) - - # Reset file pointer to start before reading - image.file.seek(0) - - # Save file - with open(path, "wb") as buffer: - shutil.copyfileobj(image.file, buffer) - - print(f"DEBUG: Saved image to {path}") - return f"/uploads/{subfolder}/{filename}" - - -def delete_image(image_url: Optional[str]): - """Deletes an image from the filesystem if it's stored locally.""" - if not image_url: - return - - # We only delete if it points to our local uploads folder - if image_url.startswith("/uploads/"): - # Build absolute path - relative = image_url.lstrip("/") # e.g. "uploads/businesses/uuid.jpg" - file_path = os.path.join(_BASE_DIR, relative) - if os.path.exists(file_path): - try: - os.remove(file_path) - print(f"DEBUG: Deleted file {file_path}") - except Exception as e: - print(f"ERROR: Failed to delete {file_path}: {e}") - else: - print(f"DEBUG: File not found for deletion: {file_path}") - - -def cleanup_expired_coupons(session: Session): - """Finds and deletes expired coupons and their associated images.""" - try: - now = datetime.now() - # Coupons where valid_until is passed - statement = select(Coupon).where(Coupon.valid_until < now) - expired = session.exec(statement).all() - - count = 0 - for coupon in expired: - if coupon.image_url: - delete_image(coupon.image_url) - session.delete(coupon) - count += 1 - - if count > 0: - session.commit() - print(f"DEBUG: Cleaned up {count} expired coupons and their images.") - except Exception as e: - print(f"ERROR: Cleanup failed: {e}") diff --git a/backend/check_db.py b/backend/check_db.py deleted file mode 100644 index 9042860..0000000 --- a/backend/check_db.py +++ /dev/null @@ -1,19 +0,0 @@ -from app.core.database import engine -from sqlmodel import Session, select -from app.models.favorite import Favorite -from app.models.user import User - -def check_db(): - with Session(engine) as session: - favorites = session.exec(select(Favorite)).all() - print(f"Total favorites: {len(favorites)}") - for f in favorites: - print(f"User: {f.user_id}, Type: {f.item_type}, ID: {f.item_id}, Name: {f.item_name}") - - users = session.exec(select(User)).all() - print(f"Total users: {len(users)}") - for u in users: - print(f"User ID: {u.id}, Email: {u.email}, Role: {u.role}") - -if __name__ == "__main__": - check_db() diff --git a/backend/check_db_async.py b/backend/check_db_async.py deleted file mode 100644 index dd069fa..0000000 --- a/backend/check_db_async.py +++ /dev/null @@ -1,25 +0,0 @@ -import asyncio -import asyncpg - -async def check_db(): - creds = [ - ("sibu", "sibu", "sibu"), - ("postgres", "postgres", "postgres"), - ("postgres", "postgres", "sibu"), - ("postgres", "", "postgres"), - ("sibu", "", "sibu"), - ] - - for user, pw, db in creds: - url = f"postgresql://{user}:{pw}@localhost:5432/{db}" - print(f"Testing {url}...") - try: - conn = await asyncpg.connect(url, timeout=5) - print(f"!!! SUCCESS with {url} !!!") - await conn.close() - return - except Exception as e: - print(f"Failed: {type(e).__name__}: {e}") - -if __name__ == "__main__": - asyncio.run(check_db()) diff --git a/backend/create_admin.py b/backend/create_admin.py deleted file mode 100644 index e510baf..0000000 --- a/backend/create_admin.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Script to create a default admin user.""" -from sqlmodel import Session, select -from app.core.database import engine -from app.models.user import User, UserRole -from app.core.security import get_password_hash -from app.core.config import settings - -def create_admin(): - with Session(engine) as session: - # Check if admin already exists - admin = session.exec(select(User).where(User.email == "admin@sibu.com")).first() - if admin: - print("Admin already exists.") - return - - new_admin = User( - email="admin@sibu.com", - full_name="Administrator", - hashed_password=get_password_hash(settings.admin_password), - role=UserRole.ADMIN, - is_verified=True - ) - session.add(new_admin) - session.commit() - print("Admin user created successfully!") - -if __name__ == "__main__": - create_admin() diff --git a/backend/create_promo_user.py b/backend/create_promo_user.py deleted file mode 100644 index 970e6d0..0000000 --- a/backend/create_promo_user.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -import os -from sqlmodel import Session, select - -# Add parent directory to path to import app -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -from app.core.database import engine -from app.models.user import User, UserRole -from app.core.security import get_password_hash - -def create_promo_user(): - email = "promo@gmail.com" - password = "promo" - full_name = "Promociones SIBU" - - with Session(engine) as session: - # Check if user already exists - statement = select(User).where(User.email == email) - user = session.exec(statement).first() - - if user: - print(f"User {email} already exists.") - # Update role to PROMOTER if necessary - if user.role != UserRole.PROMOTER: - user.role = UserRole.PROMOTER - session.add(user) - session.commit() - print(f"Updated user {email} role to PROMOTER.") - return - - # Create new user - new_user = User( - email=email, - hashed_password=get_password_hash(password), - full_name=full_name, - role=UserRole.PROMOTER.value, - is_active=True, - is_verified=True - ) - - session.add(new_user) - session.commit() - print(f"User {email} created successfully.") - -if __name__ == "__main__": - create_promo_user() diff --git a/backend/database_export.json b/backend/database_export.json deleted file mode 100644 index f22095c..0000000 --- a/backend/database_export.json +++ /dev/null @@ -1,6289 +0,0 @@ -{ - "routes": [ - { - "id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "name": "Boquete>David", - "description": "Ruta desde Boquete hacia David con paradas principales", - "origin_city": "Boquete", - "destination_city": "David", - "distance_km": 38.5, - "estimated_duration_minutes": 45, - "status": "active" - }, - { - "id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "name": "David>Boquete", - "description": "Ruta desde David hacia Boquete con paradas principales", - "origin_city": "David", - "destination_city": "Boquete", - "distance_km": 38.5, - "estimated_duration_minutes": 45, - "status": "active" - }, - { - "id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "name": "Palmira>David", - "description": "Ruta desde Palmira hacia David", - "origin_city": "Palmira", - "destination_city": "David", - "distance_km": 25.2, - "estimated_duration_minutes": 35, - "status": "active" - }, - { - "id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "name": "David>Palmira", - "description": "Ruta desde David hacia Palmira", - "origin_city": "David", - "destination_city": "Palmira", - "distance_km": 25.2, - "estimated_duration_minutes": 35, - "status": "active" - }, - { - "id": "6239c83b-7466-476f-be54-df33977fc32e", - "name": "Caldera>David", - "description": "Ruta desde Caldera hacia David", - "origin_city": "Caldera", - "destination_city": "David", - "distance_km": 42.8, - "estimated_duration_minutes": 50, - "status": "active" - }, - { - "id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "name": "David>Caldera", - "description": "Ruta desde David hacia Caldera", - "origin_city": "David", - "destination_city": "Caldera", - "distance_km": 42.8, - "estimated_duration_minutes": 50, - "status": "active" - } - ], - "bus_stops": [ - { - "id": "12fc09fc-5e48-4c54-b414-4133f0f12a37", - "name": "Parada Principal 1", - "latitude": 8.6589562, - "longitude": -82.442055, - "city": "Ruta Caldera-David", - "address": "Parada Principal 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "39274b2b-7d5a-4c6e-b3e9-4f05a66f1c7e", - "name": "Parada 18", - "latitude": 8.5746042, - "longitude": -82.4212994, - "city": "Ruta Palmira-David", - "address": "Parada 18", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "46588013-d616-4eae-8e50-c98bf38e050f", - "name": "Parada 22", - "latitude": 8.5472523, - "longitude": -82.419091, - "city": "Ruta Palmira-David", - "address": "Parada 22", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "506e4aff-1cb6-47e9-a85f-3dafd2d49308", - "name": "Parada Principal 4", - "latitude": 8.4445818, - "longitude": -82.4221416, - "city": "Ruta Palmira-David", - "address": "Parada Principal 4", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "51043828-726d-4245-a975-59723eb2f08f", - "name": "Parada 34", - "latitude": 8.4759182, - "longitude": -82.4202329, - "city": "Ruta Palmira-David", - "address": "Parada 34", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "05baf1ef-af1d-4f76-8027-2482b37b8c37", - "name": "Parada 31", - "latitude": 8.4978514, - "longitude": -82.4254706, - "city": "Ruta Palmira-David", - "address": "Parada 31", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "10a60237-1189-49d6-8da3-54893f849212", - "name": "Intersección 5", - "latitude": 8.5259111, - "longitude": -82.4219091, - "city": "Ruta Palmira-David", - "address": "Intersección 5", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "1d74e1ef-e488-4fc9-9df8-9c88f007e204", - "name": "Parada 13", - "latitude": 8.6006107, - "longitude": -82.4211566, - "city": "Ruta Palmira-David", - "address": "Parada 13", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "2050bc76-6534-4b6b-891f-33fe3bac8407", - "name": "Parada 21", - "latitude": 8.5516692, - "longitude": -82.4189188, - "city": "Ruta Palmira-David", - "address": "Parada 21", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "29c3fa50-965a-47fc-9aa9-5216593fd863", - "name": "Parada 36", - "latitude": 8.4552106, - "longitude": -82.4207317, - "city": "Ruta Palmira-David", - "address": "Parada 36", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "2c2ba744-3c20-4485-aca4-22b00b4f622f", - "name": "Parada 8", - "latitude": 8.6234797, - "longitude": -82.4254989, - "city": "Ruta Palmira-David", - "address": "Parada 8", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "2c669c57-a164-4437-8114-85a7ec8b4e3c", - "name": "Intersección 7", - "latitude": 8.475465, - "longitude": -82.4204772, - "city": "Ruta Palmira-David", - "address": "Intersección 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "2e00b45d-9c28-4aac-b895-546f213e3309", - "name": "Parada 27", - "latitude": 8.5116647, - "longitude": -82.4237289, - "city": "Ruta Palmira-David", - "address": "Parada 27", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "2f17114c-6bfc-45bf-a436-ed64860df62e", - "name": "Parada 29", - "latitude": 8.5080045, - "longitude": -82.4242084, - "city": "Ruta Palmira-David", - "address": "Parada 29", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "3386ad96-9012-472f-a756-9093c602a416", - "name": "Parada 32", - "latitude": 8.4948946, - "longitude": -82.4254776, - "city": "Ruta Palmira-David", - "address": "Parada 32", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "2a03ba34-5483-4783-bb78-e8c92c200fbe", - "name": "Parada 58", - "latitude": 8.5097514, - "longitude": -82.4239683, - "city": "Ruta Caldera-David", - "address": "Parada 58", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "4d182cbe-c108-46ed-a9b3-4b6cdef33aa9", - "name": "Parada 64", - "latitude": 8.4759182, - "longitude": -82.4202329, - "city": "Ruta Caldera-David", - "address": "Parada 64", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "51e94d40-56fb-4842-8cfe-8b76c46aa13b", - "name": "Parada 59", - "latitude": 8.5080045, - "longitude": -82.4242084, - "city": "Ruta Caldera-David", - "address": "Parada 59", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "53d8b9b6-ef59-439e-97a5-39dacac56a24", - "name": "Parada 52", - "latitude": 8.5472523, - "longitude": -82.419091, - "city": "Ruta Caldera-David", - "address": "Parada 52", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "5433c8d0-002a-45f0-a17a-c4fcf84e5169", - "name": "Parada 62", - "latitude": 8.4948946, - "longitude": -82.4254776, - "city": "Ruta Caldera-David", - "address": "Parada 62", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "6d4aa16d-5683-48b1-8507-b0aba05d4aaa", - "name": "Parada 53", - "latitude": 8.5344038, - "longitude": -82.420778, - "city": "Ruta Caldera-David", - "address": "Parada 53", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "6eabfea4-f0e8-4f8d-b97f-bc8febb39344", - "name": "Parada 68", - "latitude": 8.450325, - "longitude": -82.4213788, - "city": "Ruta Caldera-David", - "address": "Parada 68", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "6eb8d5e3-4319-40d3-bd16-e3383cb113af", - "name": "Parada 67", - "latitude": 8.4521084, - "longitude": -82.4211461, - "city": "Ruta Caldera-David", - "address": "Parada 67", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "707c8544-533f-4e42-8767-0490170cb083", - "name": "Parada 56", - "latitude": 8.520598, - "longitude": -82.4225716, - "city": "Ruta Caldera-David", - "address": "Parada 56", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8085a65b-18fd-439d-8fa6-760b3b26ea55", - "name": "Parada 63", - "latitude": 8.4919557, - "longitude": -82.4251941, - "city": "Ruta Caldera-David", - "address": "Parada 63", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "81644bb0-0afb-4cd0-8496-f066a4bd1701", - "name": "Parada Principal 5", - "latitude": 8.5584545, - "longitude": -82.4151901, - "city": "Ruta Caldera-David", - "address": "Parada Principal 5", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "89d0f353-8316-4c22-ab4e-1006121ee23a", - "name": "Parada 66", - "latitude": 8.4552106, - "longitude": -82.4207317, - "city": "Ruta Caldera-David", - "address": "Parada 66", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8db9b2c9-769b-4ec6-aae7-8a43ef99b9bc", - "name": "Parada 57", - "latitude": 8.5116647, - "longitude": -82.4237289, - "city": "Ruta Caldera-David", - "address": "Parada 57", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "9c9a32d7-1bef-4824-95db-3761b4688111", - "name": "Intersección 13", - "latitude": 8.475465, - "longitude": -82.4204772, - "city": "Ruta Caldera-David", - "address": "Intersección 13", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "a364477b-c104-4ec5-bc4e-67bc04d4fd84", - "name": "Parada 61", - "latitude": 8.4978514, - "longitude": -82.4254706, - "city": "Ruta Caldera-David", - "address": "Parada 61", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "b5c4dbb3-3225-462e-b865-79216d8564f4", - "name": "Parada 51", - "latitude": 8.5516692, - "longitude": -82.4189188, - "city": "Ruta Caldera-David", - "address": "Parada 51", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "b64f9a9a-0568-476f-b229-403e6a4cf448", - "name": "Parada Principal 7", - "latitude": 8.4445818, - "longitude": -82.4221416, - "city": "Ruta Caldera-David", - "address": "Parada Principal 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "bd0f3e38-f7f4-4d8f-a9d3-33191468a58d", - "name": "Parada 69", - "latitude": 8.4462536, - "longitude": -82.4213439, - "city": "Ruta Caldera-David", - "address": "Parada 69", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "d3773f11-9393-40ab-9295-9305412d16ce", - "name": "Intersección 11", - "latitude": 8.5259111, - "longitude": -82.4219091, - "city": "Ruta Caldera-David", - "address": "Intersección 11", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "d5af00b9-9f40-4afd-a67f-abf98a06ed6a", - "name": "Parada 71", - "latitude": 8.4426552, - "longitude": -82.42181, - "city": "Ruta Caldera-David", - "address": "Parada 71", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "dee5dc1b-5101-43f1-a322-b59cfdd18ed1", - "name": "Parada 73", - "latitude": 8.4357775, - "longitude": -82.4210319, - "city": "Ruta Caldera-David", - "address": "Parada 73", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "e51839b2-1bb8-47c6-ab80-224cd5f17cb7", - "name": "Parada 72", - "latitude": 8.4388768, - "longitude": -82.4220722, - "city": "Ruta Caldera-David", - "address": "Parada 72", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "eef5ca98-8a8d-42a6-9616-e3cabc7fcf0b", - "name": "Parada 54", - "latitude": 8.5322854, - "longitude": -82.421057, - "city": "Ruta Caldera-David", - "address": "Parada 54", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f475143d-f78b-4b27-87d9-5a8867673695", - "name": "Parada Principal 6", - "latitude": 8.5040506, - "longitude": -82.4246805, - "city": "Ruta Caldera-David", - "address": "Parada Principal 6", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "c9c1378e-19de-4730-9590-844df9bab1e5", - "name": "Centro de David", - "latitude": 8.4194, - "longitude": -82.4255, - "city": "David", - "address": "Parque Cervantes", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "20b52f70-0b6f-4932-a71e-4cb179a88f38", - "name": "Hospital Chiriquí", - "latitude": 8.4156, - "longitude": -82.4289, - "city": "David", - "address": "Complejo Hospitalario", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "0d277d0c-1069-45df-805c-ce59ef2dfd23", - "name": "Chiriquí Mall", - "latitude": 8.4089, - "longitude": -82.4178, - "city": "David", - "address": "Centro Comercial", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "c0c28ce0-88fa-4d01-a4e9-530101b35990", - "name": "Escuela de Palmira", - "latitude": 8.3567, - "longitude": -82.3598, - "city": "Palmira", - "address": "Zona Escolar", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "752e1079-4ae3-4345-8a03-05d58c63388a", - "name": "Centro de Caldera", - "latitude": 8.2478, - "longitude": -81.7198, - "city": "Caldera", - "address": "Centro del Pueblo", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "0666a01b-0055-4b3a-9756-5053690cfae5", - "name": "Terminal de David", - "latitude": 8.4334255, - "longitude": -82.4231136, - "city": "Ruta Boquete-David", - "address": "Terminal de David", - "stop_type": "terminal", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "3d73312c-eba3-43d1-ba3d-2381cfe6abd8", - "name": "Parada 56", - "latitude": 8.4445115, - "longitude": -82.4221416, - "city": "Ruta Boquete-David", - "address": "Parada 56", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "926d4e83-1f08-4504-95e3-71f4d2c9666c", - "name": "Parada 49", - "latitude": 8.4919557, - "longitude": -82.4251941, - "city": "Ruta Boquete-David", - "address": "Parada 49", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "4d7a3281-563a-491d-bbde-3a5fc4b87198", - "name": "Terminal de David", - "latitude": 8.4334255, - "longitude": -82.4231136, - "city": "Ruta Caldera-David", - "address": "Terminal de David", - "stop_type": "terminal", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "089afec3-6911-4c41-9d12-223b8607c4a9", - "name": "Parada 34", - "latitude": 8.5746042, - "longitude": -82.4212994, - "city": "Ruta Boquete-David", - "address": "Parada 34", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "0948094e-1132-4a94-8873-4fbbb9bd25e5", - "name": "Parada 6", - "latitude": 8.7275817, - "longitude": -82.4348154, - "city": "Ruta Boquete-David", - "address": "Parada 6", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "0b5970c0-343f-4c9d-972e-1ec6926f9807", - "name": "Parada 22", - "latitude": 8.643388, - "longitude": -82.4345935, - "city": "Ruta Boquete-David", - "address": "Parada 22", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "0b660dd6-e935-4be8-b470-eea9bf995c75", - "name": "Parada 51", - "latitude": 8.475465, - "longitude": -82.4204772, - "city": "Ruta Boquete-David", - "address": "Parada 51", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "18dabf19-4f52-4d92-be42-6bd3623b4f06", - "name": "Parada 17", - "latitude": 8.6874249, - "longitude": -82.4510803, - "city": "Ruta Boquete-David", - "address": "Parada 17", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "24428491-2b6a-4ac0-9ca5-17df33138a18", - "name": "Parada 11", - "latitude": 8.7179038, - "longitude": -82.440164, - "city": "Ruta Boquete-David", - "address": "Parada 11", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "2802d866-56d1-4200-9c41-402cc967f35b", - "name": "Intersección 5", - "latitude": 8.6202619, - "longitude": -82.4239767, - "city": "Ruta Boquete-David", - "address": "Intersección 5", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "00a14099-a862-455f-abfa-c2ec1489ab70", - "name": "Parada 17", - "latitude": 8.6171078, - "longitude": -82.4232463, - "city": "Ruta Caldera-David", - "address": "Parada 17", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "21f322a7-ac14-4144-abad-7e7f2502eef6", - "name": "Parada 22", - "latitude": 8.5912165, - "longitude": -82.4217292, - "city": "Ruta Caldera-David", - "address": "Parada 22", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "2b2e6858-be6d-4f18-a3a2-92373cfd9a9d", - "name": "Parada 2", - "latitude": 8.6585931, - "longitude": -82.3713713, - "city": "Ruta Caldera-David", - "address": "Parada 2", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "3d769def-cf21-4560-be21-13b828aafe54", - "name": "Parada 3", - "latitude": 8.6565684, - "longitude": -82.3751424, - "city": "Ruta Caldera-David", - "address": "Parada 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "682705d5-5413-4bd3-a31c-144832e7ec96", - "name": "Parada 9", - "latitude": 8.6677249, - "longitude": -82.4464655, - "city": "Ruta Caldera-David", - "address": "Parada 9", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "69c374a2-a062-4b28-8308-6aff793cd631", - "name": "Intersección 3", - "latitude": 8.6233007, - "longitude": -82.425637, - "city": "Ruta Caldera-David", - "address": "Intersección 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "77f80a0a-450c-42c3-bb8a-b9a3b6e5758d", - "name": "Parada 6", - "latitude": 8.6660748, - "longitude": -82.4257239, - "city": "Ruta Caldera-David", - "address": "Parada 6", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "788abd79-3d4b-4810-a5c0-7d8fec3d1a27", - "name": "Parada 11", - "latitude": 8.657646, - "longitude": -82.441363, - "city": "Ruta Caldera-David", - "address": "Parada 11", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "7db160e3-05b2-4778-baee-789cea0f0bfd", - "name": "Parada 4", - "latitude": 8.6559353, - "longitude": -82.3772655, - "city": "Ruta Caldera-David", - "address": "Parada 4", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8ba33c36-303a-4182-8e08-065c2961e05d", - "name": "Parada 16", - "latitude": 8.6201558, - "longitude": -82.4242288, - "city": "Ruta Caldera-David", - "address": "Parada 16", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "9bdf297b-6312-43fa-b945-bfaa01fd49bc", - "name": "Parada 19", - "latitude": 8.6102291, - "longitude": -82.4228095, - "city": "Ruta Caldera-David", - "address": "Parada 19", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "9d9ffbcc-b4d8-427b-b5a3-add1c25f66a7", - "name": "Parada Principal 2", - "latitude": 8.6005179, - "longitude": -82.4214315, - "city": "Ruta Caldera-David", - "address": "Parada Principal 2", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a20332a5-08f3-46f4-9dfd-f27e5539469e", - "name": "Parada 1", - "latitude": 8.659617, - "longitude": -82.3693378, - "city": "Ruta Caldera-David", - "address": "Parada 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "b321b88d-5032-4383-85e1-ec99c3e3cb3f", - "name": "Parada 12", - "latitude": 8.6471196, - "longitude": -82.4365581, - "city": "Ruta Caldera-David", - "address": "Parada 12", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "b95c7990-65ac-40db-bb49-b99ed3b9d8dd", - "name": "Parada 18", - "latitude": 8.6144144, - "longitude": -82.4230377, - "city": "Ruta Caldera-David", - "address": "Parada 18", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "bd2f01ab-0406-4b6d-b4c5-052f8915fc30", - "name": "Parada 14", - "latitude": 8.6277337, - "longitude": -82.4276677, - "city": "Ruta Caldera-David", - "address": "Parada 14", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "d86649cc-7286-46c3-933c-168716d1b304", - "name": "Parada 13", - "latitude": 8.6431851, - "longitude": -82.4347209, - "city": "Ruta Caldera-David", - "address": "Parada 13", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "dc3e0510-7cdd-4521-8dc2-6181120b4f26", - "name": "Intersección 1", - "latitude": 8.6528035, - "longitude": -82.3823114, - "city": "Ruta Caldera-David", - "address": "Intersección 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "decf0e21-7488-4dc1-b5b6-9997e2437403", - "name": "Parada 21", - "latitude": 8.5986961, - "longitude": -82.4203193, - "city": "Ruta Caldera-David", - "address": "Parada 21", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "df528e47-8fc2-49b7-81db-3c8f4f7a176a", - "name": "Puerto de Caldera", - "latitude": 8.6623636, - "longitude": -82.3643095, - "city": "Ruta Caldera-David", - "address": "Puerto de Caldera", - "stop_type": "terminal", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "edfb904e-66be-4a8d-80f7-3a30403d3fca", - "name": "Parada 7", - "latitude": 8.6668357, - "longitude": -82.4271414, - "city": "Ruta Caldera-David", - "address": "Parada 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "f7317833-9adc-40c0-9132-5c66c1822210", - "name": "Parada 8", - "latitude": 8.667541, - "longitude": -82.4288313, - "city": "Ruta Caldera-David", - "address": "Parada 8", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "0512d2ed-abc0-4f95-b39f-515eac489d27", - "name": "Parada 31", - "latitude": 8.667541, - "longitude": -82.4288313, - "city": "Ruta Caldera-David", - "address": "Parada 31", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "156ce6b5-1683-4654-aab5-17e6d55547e8", - "name": "Parada 27", - "latitude": 8.6559353, - "longitude": -82.3772655, - "city": "Ruta Caldera-David", - "address": "Parada 27", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "1fb1faef-ae69-4875-8598-7839e6268741", - "name": "Parada 46", - "latitude": 8.5842058, - "longitude": -82.4229429, - "city": "Ruta Caldera-David", - "address": "Parada 46", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "267afc65-88a6-4ac1-9be5-46d22bfec4d5", - "name": "Parada 34", - "latitude": 8.6577004, - "longitude": -82.4411605, - "city": "Ruta Caldera-David", - "address": "Parada 34", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f30ed3ab-b629-4320-b254-32d4d8341ee6", - "name": "Intersección 3", - "latitude": 8.6969771, - "longitude": -82.4484517, - "city": "Ruta Boquete-David", - "address": "Intersección 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "f38abc02-65e0-4a35-b19e-474359d7477e", - "name": "Parada 26", - "latitude": 8.6169195, - "longitude": -82.4229218, - "city": "Ruta Boquete-David", - "address": "Parada 26", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f63e9060-33e9-4263-9023-f37d0e848260", - "name": "Parada 12", - "latitude": 8.7165669, - "longitude": -82.4408624, - "city": "Ruta Boquete-David", - "address": "Parada 12", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "fa9a49ee-146f-4ed2-8473-cc17da8dcab2", - "name": "Parada 13", - "latitude": 8.7139392, - "longitude": -82.4423294, - "city": "Ruta Boquete-David", - "address": "Parada 13", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "fb9882db-bb01-46ad-bbb1-5cb8cf4f78f2", - "name": "Parada 8", - "latitude": 8.7248711, - "longitude": -82.4363221, - "city": "Ruta Boquete-David", - "address": "Parada 8", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "29819fa8-f25e-4cb5-b142-c65a6f11baa9", - "name": "Parada 29", - "latitude": 8.6660748, - "longitude": -82.4257239, - "city": "Ruta Caldera-David", - "address": "Parada 29", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "3211b00c-4c3a-41e9-a560-794d77c1cfab", - "name": "Parada 42", - "latitude": 8.610253, - "longitude": -82.4225976, - "city": "Ruta Caldera-David", - "address": "Parada 42", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8265275c-8f02-487b-a8d2-4a33a04515d2", - "name": "Parada 16", - "latitude": 8.5842058, - "longitude": -82.4229429, - "city": "Ruta Palmira-David", - "address": "Parada 16", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "83f03e06-bb17-41ef-9760-565f7c6b7905", - "name": "Parada 12", - "latitude": 8.610253, - "longitude": -82.4225976, - "city": "Ruta Palmira-David", - "address": "Parada 12", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "848e3f5c-0500-4ffa-a92f-5f56a339fda2", - "name": "Parada 41", - "latitude": 8.4426552, - "longitude": -82.42181, - "city": "Ruta Palmira-David", - "address": "Parada 41", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "85b7e107-6d21-44cf-84c9-ddef2be9bbdb", - "name": "Parada 28", - "latitude": 8.5097514, - "longitude": -82.4239683, - "city": "Ruta Palmira-David", - "address": "Parada 28", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8b26bd01-f59e-40d4-9f5b-91eb86ae9d0f", - "name": "Parada Principal 3", - "latitude": 8.5040506, - "longitude": -82.4246805, - "city": "Ruta Palmira-David", - "address": "Parada Principal 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8b5246b1-c4cb-4435-85a3-0330ac8db62e", - "name": "Parada 38", - "latitude": 8.450325, - "longitude": -82.4213788, - "city": "Ruta Palmira-David", - "address": "Parada 38", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "9740fe20-cde6-467f-8de4-174426fcbc7f", - "name": "Parada 7", - "latitude": 8.627808, - "longitude": -82.4274531, - "city": "Ruta Palmira-David", - "address": "Parada 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "9cc2dd3d-59fd-4a5f-a24e-c52082625190", - "name": "Parada 2", - "latitude": 8.6678999, - "longitude": -82.4462348, - "city": "Ruta Palmira-David", - "address": "Parada 2", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a324ca30-9831-48ce-a5cc-cfcf21d91ee0", - "name": "Intersección 1", - "latitude": 8.6472681, - "longitude": -82.4363596, - "city": "Ruta Palmira-David", - "address": "Intersección 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "a5704227-9658-4118-8566-19d7b5827fc6", - "name": "Parada 19", - "latitude": 8.565803, - "longitude": -82.4162278, - "city": "Ruta Palmira-David", - "address": "Parada 19", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "acea0a34-f564-4f30-b97d-445c5c2f3864", - "name": "Centro de Palmira", - "latitude": 8.6960095, - "longitude": -82.4488575, - "city": "Ruta Palmira-David", - "address": "Centro de Palmira", - "stop_type": "terminal", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "bf949ab0-c554-41ab-a852-917b6aed4251", - "name": "Parada 1", - "latitude": 8.6874249, - "longitude": -82.4510803, - "city": "Ruta Palmira-David", - "address": "Parada 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "c01ee146-0148-4e5d-bff3-3db389de1dd8", - "name": "Parada Principal 2", - "latitude": 8.5584545, - "longitude": -82.4151901, - "city": "Ruta Palmira-David", - "address": "Parada Principal 2", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "d20f93f6-f187-47d3-b46a-9f067ca71258", - "name": "Parada 39", - "latitude": 8.4462536, - "longitude": -82.4213439, - "city": "Ruta Palmira-David", - "address": "Parada 39", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "d649e756-a1a7-4b07-80a1-7040cffc5567", - "name": "Parada 3", - "latitude": 8.6588979, - "longitude": -82.4417667, - "city": "Ruta Palmira-David", - "address": "Parada 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "d8e82b75-e2a3-47f7-ab91-299282456076", - "name": "Parada 14", - "latitude": 8.5983885, - "longitude": -82.4200162, - "city": "Ruta Palmira-David", - "address": "Parada 14", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "d99779b3-07e4-4a53-bd87-1d3dec150346", - "name": "Parada 24", - "latitude": 8.5322854, - "longitude": -82.421057, - "city": "Ruta Palmira-David", - "address": "Parada 24", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "378993ec-7689-475c-8f4a-21177bbf6b73", - "name": "Parada 33", - "latitude": 8.6588979, - "longitude": -82.4417667, - "city": "Ruta Caldera-David", - "address": "Parada 33", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "37f0aeff-4345-4429-9c39-1a95be47d19f", - "name": "Parada 36", - "latitude": 8.643388, - "longitude": -82.4345935, - "city": "Ruta Caldera-David", - "address": "Parada 36", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "432d38b5-4ef5-4ca0-ad06-cbb98abfcdc1", - "name": "Parada 37", - "latitude": 8.627808, - "longitude": -82.4274531, - "city": "Ruta Caldera-David", - "address": "Parada 37", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "595f2ffe-2ab7-4cdb-9e49-087b3dddd12e", - "name": "Parada 24", - "latitude": 8.6596151, - "longitude": -82.3693519, - "city": "Ruta Caldera-David", - "address": "Parada 24", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "5ac77ca0-882f-41be-b434-f95731b4f947", - "name": "Parada 49", - "latitude": 8.565803, - "longitude": -82.4162278, - "city": "Ruta Caldera-David", - "address": "Parada 49", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5b8ed1ee-43fe-4bf2-8baf-ba7fb046bb16", - "name": "Parada 39", - "latitude": 8.6202619, - "longitude": -82.4239767, - "city": "Ruta Caldera-David", - "address": "Parada 39", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5c1bdc42-ab43-42a1-a257-66e547df75ff", - "name": "Intersección 5", - "latitude": 8.6585719, - "longitude": -82.3713712, - "city": "Ruta Caldera-David", - "address": "Intersección 5", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "54a34108-7928-4ec9-944c-5bcf33d59147", - "name": "Intersección 3", - "latitude": 8.5914154, - "longitude": -82.4213832, - "city": "Ruta Palmira-David", - "address": "Intersección 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "54d3e908-e2c6-4a8c-90e3-694daefea995", - "name": "Parada 11", - "latitude": 8.6144011, - "longitude": -82.4228017, - "city": "Ruta Palmira-David", - "address": "Parada 11", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "6ca67be5-7084-46ad-940d-277caeaebb9e", - "name": "Parada 4", - "latitude": 8.6577004, - "longitude": -82.4411605, - "city": "Ruta Palmira-David", - "address": "Parada 4", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "78017d28-3996-4820-a033-034e7a20c9bf", - "name": "Parada 23", - "latitude": 8.5344038, - "longitude": -82.420778, - "city": "Ruta Palmira-David", - "address": "Parada 23", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "54a8ce58-a383-48f2-8c58-d3c32c4878ef", - "name": "Parada 39", - "latitude": 8.5344038, - "longitude": -82.420778, - "city": "Ruta Boquete-David", - "address": "Parada 39", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5669e724-da62-42cc-8250-6d645d460e7b", - "name": "Intersección 11", - "latitude": 8.4462536, - "longitude": -82.4213439, - "city": "Ruta Boquete-David", - "address": "Intersección 11", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "56d12752-cb1e-448e-a54c-ac4ceb5b85c9", - "name": "Parada 4", - "latitude": 8.7321499, - "longitude": -82.4336354, - "city": "Ruta Boquete-David", - "address": "Parada 4", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "5966ddf4-4ad1-47c0-962d-20d4a19438fc", - "name": "Parada 27", - "latitude": 8.6144011, - "longitude": -82.4228017, - "city": "Ruta Boquete-David", - "address": "Parada 27", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5eff88c8-be0a-40a6-81b7-050b0e660b2a", - "name": "Parada 41", - "latitude": 8.5259111, - "longitude": -82.4219091, - "city": "Ruta Boquete-David", - "address": "Parada 41", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "652426c4-ba01-4191-8969-88701ad482a6", - "name": "Terminal de Boquete", - "latitude": 8.7520024, - "longitude": -82.4318432, - "city": "Ruta Boquete-David", - "address": "Terminal de Boquete", - "stop_type": "terminal", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "680fb194-6f56-4f12-8042-4e97b477019c", - "name": "Parada 54", - "latitude": 8.450325, - "longitude": -82.4213788, - "city": "Ruta Boquete-David", - "address": "Parada 54", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "70cb67c0-3ff5-45ce-812a-f996e0a7f44d", - "name": "Parada 21", - "latitude": 8.6472681, - "longitude": -82.4363596, - "city": "Ruta Boquete-David", - "address": "Parada 21", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "71ce16ce-5aa5-4e39-a7fe-fa3272e75e41", - "name": "Parada 9", - "latitude": 8.7218976, - "longitude": -82.4379503, - "city": "Ruta Boquete-David", - "address": "Parada 9", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "2bf338e4-3cf0-4815-aaa5-7e4aa4774863", - "name": "Parada 57", - "latitude": 8.4426552, - "longitude": -82.42181, - "city": "Ruta Boquete-David", - "address": "Parada 57", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "30349a8c-65f4-481e-acd2-510efe0bbe78", - "name": "Parada 32", - "latitude": 8.5842058, - "longitude": -82.4229429, - "city": "Ruta Boquete-David", - "address": "Parada 32", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "33f07c2b-1618-482d-92c7-8d56c0e44960", - "name": "Parada 43", - "latitude": 8.5116647, - "longitude": -82.4237289, - "city": "Ruta Boquete-David", - "address": "Parada 43", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "358461df-1b48-4527-a457-f94277b47c60", - "name": "Parada 24", - "latitude": 8.6234797, - "longitude": -82.4254989, - "city": "Ruta Boquete-David", - "address": "Parada 24", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "35f25575-b799-4167-b94c-912c66e525ce", - "name": "Parada 52", - "latitude": 8.4552106, - "longitude": -82.4207317, - "city": "Ruta Boquete-David", - "address": "Parada 52", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "39e8a80a-cb67-464f-99e0-4c55602abc14", - "name": "Parada 48", - "latitude": 8.4948946, - "longitude": -82.4254776, - "city": "Ruta Boquete-David", - "address": "Parada 48", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "39fc64f7-4630-4197-a0ca-436c18a6cc8a", - "name": "Intersección 9", - "latitude": 8.5080045, - "longitude": -82.4242084, - "city": "Ruta Boquete-David", - "address": "Intersección 9", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "3f34c52b-28f6-4afb-8284-7e287322e5bf", - "name": "Parada 23", - "latitude": 8.627808, - "longitude": -82.4274531, - "city": "Ruta Boquete-David", - "address": "Parada 23", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "41bbb27f-5ee0-41a1-9cc4-98f491977023", - "name": "Parada 33", - "latitude": 8.5785467, - "longitude": -82.4231551, - "city": "Ruta Boquete-David", - "address": "Parada 33", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "447d004f-2952-4a7d-becf-3502f3bb43f8", - "name": "Parada Principal 3", - "latitude": 8.5983885, - "longitude": -82.4200162, - "city": "Ruta Boquete-David", - "address": "Parada Principal 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "46b43a9d-a71d-4276-9252-86a143def245", - "name": "Parada 1", - "latitude": 8.7500574, - "longitude": -82.4320427, - "city": "Ruta Boquete-David", - "address": "Parada 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5250f47d-3885-4566-ad93-25d8a223e25b", - "name": "Parada 53", - "latitude": 8.4521084, - "longitude": -82.4211461, - "city": "Ruta Boquete-David", - "address": "Parada 53", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "ffbe020d-97cb-4552-800a-1979bebcf3f9", - "name": "Parada 17", - "latitude": 8.5785467, - "longitude": -82.4231551, - "city": "Ruta Palmira-David", - "address": "Parada 17", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5dda8c4c-1134-4bef-a4d5-08de4234ccea", - "name": "Intersección 9", - "latitude": 8.5914154, - "longitude": -82.4213832, - "city": "Ruta Caldera-David", - "address": "Intersección 9", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "5e276d2f-6d8c-4e29-b14f-2088acb32ea0", - "name": "Parada Principal 4", - "latitude": 8.6169195, - "longitude": -82.4229218, - "city": "Ruta Caldera-David", - "address": "Parada Principal 4", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "62ba8246-ead0-49ad-ae56-e76afd35765e", - "name": "Parada 23", - "latitude": 8.6623761, - "longitude": -82.3642991, - "city": "Ruta Caldera-David", - "address": "Parada 23", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "6837aea7-cf79-4fc5-9530-9a7d02db7662", - "name": "Parada 47", - "latitude": 8.5785467, - "longitude": -82.4231551, - "city": "Ruta Caldera-David", - "address": "Parada 47", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "6ed29cc6-f1ad-407a-b27c-2a45ef50d506", - "name": "Parada 41", - "latitude": 8.6144011, - "longitude": -82.4228017, - "city": "Ruta Caldera-David", - "address": "Parada 41", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "817b72ba-d4e6-4cc5-814c-7055dbcbeba5", - "name": "Parada 43", - "latitude": 8.6006107, - "longitude": -82.4211566, - "city": "Ruta Caldera-David", - "address": "Parada 43", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "a1d2c520-d8dd-45e8-ad6e-16c1f8ecfe08", - "name": "Parada 26", - "latitude": 8.6565959, - "longitude": -82.3751945, - "city": "Ruta Caldera-David", - "address": "Parada 26", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a1df2b63-5a62-41fd-9f32-4c947d153d07", - "name": "Parada 32", - "latitude": 8.6678999, - "longitude": -82.4462348, - "city": "Ruta Caldera-David", - "address": "Parada 32", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a7996b81-206d-49af-bb42-e167f4f96a0a", - "name": "Parada Principal 3", - "latitude": 8.6668438, - "longitude": -82.4271677, - "city": "Ruta Caldera-David", - "address": "Parada Principal 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "bc19ef7d-7379-413e-bb2f-f32f224b0c64", - "name": "Parada 44", - "latitude": 8.5983885, - "longitude": -82.4200162, - "city": "Ruta Caldera-David", - "address": "Parada 44", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "bf4a14b1-2c0a-4405-8653-9a7ad24cd9ba", - "name": "Intersección 7", - "latitude": 8.6472681, - "longitude": -82.4363596, - "city": "Ruta Caldera-David", - "address": "Intersección 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "e2246bb6-1f69-4550-9239-fca81114892c", - "name": "Terminal de David", - "latitude": 8.4334255, - "longitude": -82.4231136, - "city": "Ruta Palmira-David", - "address": "Terminal de David", - "stop_type": "terminal", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "ea305b8a-bffe-42b1-948e-72c9dbc6752d", - "name": "Parada 26", - "latitude": 8.520598, - "longitude": -82.4225716, - "city": "Ruta Palmira-David", - "address": "Parada 26", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "ecc0d404-bf6e-4266-bccd-4050e54a442a", - "name": "Parada 9", - "latitude": 8.6202619, - "longitude": -82.4239767, - "city": "Ruta Palmira-David", - "address": "Parada 9", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "efb5c05b-d52c-4030-aa82-960e41894ec3", - "name": "Parada Principal 1", - "latitude": 8.6169195, - "longitude": -82.4229218, - "city": "Ruta Palmira-David", - "address": "Parada Principal 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f184de4f-a708-4464-91a5-53e836c342fb", - "name": "Parada 42", - "latitude": 8.4388768, - "longitude": -82.4220722, - "city": "Ruta Palmira-David", - "address": "Parada 42", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f374aad0-549f-4754-859d-10465229c5fa", - "name": "Parada 6", - "latitude": 8.643388, - "longitude": -82.4345935, - "city": "Ruta Palmira-David", - "address": "Parada 6", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f42e378e-d63a-4747-aea9-1dfd179d9864", - "name": "Parada 33", - "latitude": 8.4919557, - "longitude": -82.4251941, - "city": "Ruta Palmira-David", - "address": "Parada 33", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "f6d8d3d7-7209-40ad-bf35-7cf9cb4de1d3", - "name": "Parada 43", - "latitude": 8.4357775, - "longitude": -82.4210319, - "city": "Ruta Palmira-David", - "address": "Parada 43", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "f6fc1c86-5b7e-4e83-86b1-4b999a33a2ba", - "name": "Parada 37", - "latitude": 8.4521084, - "longitude": -82.4211461, - "city": "Ruta Palmira-David", - "address": "Parada 37", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "84761977-665d-4b96-8c6b-766e7c8c779d", - "name": "Parada Principal 1", - "latitude": 8.7197081, - "longitude": -82.4391483, - "city": "Ruta Boquete-David", - "address": "Parada Principal 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "88e91734-fe05-4187-890f-b37c7c3d70ef", - "name": "Parada 59", - "latitude": 8.4357775, - "longitude": -82.4210319, - "city": "Ruta Boquete-David", - "address": "Parada 59", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "8a40a5a0-acee-49e3-b07d-3923128e4908", - "name": "Parada 18", - "latitude": 8.6678999, - "longitude": -82.4462348, - "city": "Ruta Boquete-David", - "address": "Parada 18", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "8e538436-3fba-478c-be7e-36d79e4c8e34", - "name": "Parada 29", - "latitude": 8.6006107, - "longitude": -82.4211566, - "city": "Ruta Boquete-David", - "address": "Parada 29", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "91d641eb-5564-4f8f-957e-aa2851078d98", - "name": "Intersección 1", - "latitude": 8.729323, - "longitude": -82.4340776, - "city": "Ruta Boquete-David", - "address": "Intersección 1", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "9412a5db-85b7-4eb4-b51e-1052c84de4f6", - "name": "Parada 46", - "latitude": 8.5040506, - "longitude": -82.4246805, - "city": "Ruta Boquete-David", - "address": "Parada 46", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "945f6bd5-5795-49d5-a874-b063e9611b5a", - "name": "Parada 31", - "latitude": 8.5914154, - "longitude": -82.4213832, - "city": "Ruta Boquete-David", - "address": "Parada 31", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "96d1c7d3-a6a7-4b56-9cb4-6f23260bf0a7", - "name": "Parada 38", - "latitude": 8.5472523, - "longitude": -82.419091, - "city": "Ruta Boquete-David", - "address": "Parada 38", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "9a773cda-fc7b-4020-8605-5a85b04a1049", - "name": "Parada 16", - "latitude": 8.6960095, - "longitude": -82.4488575, - "city": "Ruta Boquete-David", - "address": "Parada 16", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a23339b9-25b1-4219-b27e-ab153e2efcd7", - "name": "Parada Principal 2", - "latitude": 8.6577004, - "longitude": -82.4411605, - "city": "Ruta Boquete-David", - "address": "Parada Principal 2", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a37b73a8-9436-4c57-bf84-83b51659ae0f", - "name": "Parada 58", - "latitude": 8.4388768, - "longitude": -82.4220722, - "city": "Ruta Boquete-David", - "address": "Parada 58", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a48906a3-459e-40cf-b3c7-06aa1261b75e", - "name": "Parada 42", - "latitude": 8.520598, - "longitude": -82.4225716, - "city": "Ruta Boquete-David", - "address": "Parada 42", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "a8c62a6a-edf4-48ee-8fa7-6af9cf0165ed", - "name": "Parada 14", - "latitude": 8.7122196, - "longitude": -82.4433471, - "city": "Ruta Boquete-David", - "address": "Parada 14", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "ad214625-1468-4bf5-bf8c-ef4c27d64c38", - "name": "Parada 19", - "latitude": 8.6588979, - "longitude": -82.4417667, - "city": "Ruta Boquete-David", - "address": "Parada 19", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "ad39742d-5cc3-4288-a5ce-ec4fa132ae47", - "name": "Parada 7", - "latitude": 8.7255787, - "longitude": -82.4359451, - "city": "Ruta Boquete-David", - "address": "Parada 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "b8eec28f-3d45-4a65-9bfc-6df0a6f525bd", - "name": "Parada 28", - "latitude": 8.610253, - "longitude": -82.4225976, - "city": "Ruta Boquete-David", - "address": "Parada 28", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "c78c5f09-92da-4b82-a1db-c9e686c178b1", - "name": "Parada 3", - "latitude": 8.7382538, - "longitude": -82.4330994, - "city": "Ruta Boquete-David", - "address": "Parada 3", - "stop_type": "regular", - "has_shelter": true, - "has_seating": false, - "is_accessible": false - }, - { - "id": "d20c75b9-605f-4aa9-b6f6-da9244f00bbd", - "name": "Parada 36", - "latitude": 8.5584545, - "longitude": -82.4151901, - "city": "Ruta Boquete-David", - "address": "Parada 36", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "d68fa99a-5e46-4db2-bc90-527addb6570b", - "name": "Intersección 7", - "latitude": 8.565803, - "longitude": -82.4162278, - "city": "Ruta Boquete-David", - "address": "Intersección 7", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "d982f3fc-8dca-4450-b932-7a975b6a6a86", - "name": "Parada 44", - "latitude": 8.5097514, - "longitude": -82.4239683, - "city": "Ruta Boquete-David", - "address": "Parada 44", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "d9e3cda5-b5d1-4c16-a51b-532cdcb9904f", - "name": "Parada Principal 5", - "latitude": 8.4759182, - "longitude": -82.4202329, - "city": "Ruta Boquete-David", - "address": "Parada Principal 5", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "e1fb75a6-2e2a-44f0-adcf-cae892b5976b", - "name": "Parada 37", - "latitude": 8.5516692, - "longitude": -82.4189188, - "city": "Ruta Boquete-David", - "address": "Parada 37", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "e6aa65fd-a2cb-4c83-b237-bc4ed6c31f57", - "name": "Parada 47", - "latitude": 8.4978514, - "longitude": -82.4254706, - "city": "Ruta Boquete-David", - "address": "Parada 47", - "stop_type": "regular", - "has_shelter": false, - "has_seating": false, - "is_accessible": false - }, - { - "id": "e7c404fe-6db7-4fa8-be3c-d20bfaea30b4", - "name": "Parada 2", - "latitude": 8.7451912, - "longitude": -82.4324671, - "city": "Ruta Boquete-David", - "address": "Parada 2", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "f10f4c8a-d04c-4ebe-a46d-ae3532867a4a", - "name": "Parada Principal 4", - "latitude": 8.5322854, - "longitude": -82.421057, - "city": "Ruta Boquete-David", - "address": "Parada Principal 4", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "d57a03ef-26ae-49b8-b0ab-a24701fecf8c", - "name": "Parada 38", - "latitude": 8.6234797, - "longitude": -82.4254989, - "city": "Ruta Caldera-David", - "address": "Parada 38", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - }, - { - "id": "dd5b1ddb-80ca-4709-801a-dd8376df0b4e", - "name": "Parada 48", - "latitude": 8.5746042, - "longitude": -82.4212994, - "city": "Ruta Caldera-David", - "address": "Parada 48", - "stop_type": "regular", - "has_shelter": true, - "has_seating": true, - "is_accessible": false - }, - { - "id": "eb875940-9aa6-42bc-bc9a-15fce44c4287", - "name": "Parada 28", - "latitude": 8.6528035, - "longitude": -82.3823114, - "city": "Ruta Caldera-David", - "address": "Parada 28", - "stop_type": "regular", - "has_shelter": false, - "has_seating": true, - "is_accessible": false - } - ], - "route_stops": [ - { - "id": "281d3e37-c5d8-4710-9d1e-308f3453d44e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "652426c4-ba01-4191-8969-88701ad482a6", - "stop_order": 1, - "travel_time_minutes": 0, - "is_pickup_point": true, - "is_dropoff_point": false - }, - { - "id": "08b9bc6e-4f72-4122-9f4e-7b038ca6e687", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "46b43a9d-a71d-4276-9252-86a143def245", - "stop_order": 2, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e2f76f37-3c62-4cc1-9098-599f88337a1e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "e7c404fe-6db7-4fa8-be3c-d20bfaea30b4", - "stop_order": 3, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a6061938-57da-46db-9000-971504a48b0a", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "c78c5f09-92da-4b82-a1db-c9e686c178b1", - "stop_order": 4, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8732e3df-6a2c-44c3-a03c-69bc5769cefa", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "56d12752-cb1e-448e-a54c-ac4ceb5b85c9", - "stop_order": 5, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "173009e1-9d74-40a1-bf2c-0015269c89f8", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "91d641eb-5564-4f8f-957e-aa2851078d98", - "stop_order": 6, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0af9b5d1-bff9-4360-bd8a-e4f148740299", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "0948094e-1132-4a94-8873-4fbbb9bd25e5", - "stop_order": 7, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7703f2b7-4890-411c-b470-12e834599d10", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "ad39742d-5cc3-4288-a5ce-ec4fa132ae47", - "stop_order": 8, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "08942c5e-f013-4e31-9a43-c4d732d27639", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "fb9882db-bb01-46ad-bbb1-5cb8cf4f78f2", - "stop_order": 9, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1c4b1cf7-4ae2-44be-a403-736867e67de2", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "71ce16ce-5aa5-4e39-a7fe-fa3272e75e41", - "stop_order": 10, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "52d35382-4a4a-41df-ba12-dbec55c71a88", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "84761977-665d-4b96-8c6b-766e7c8c779d", - "stop_order": 11, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4b27892c-9c33-47ec-9748-845e69906ff8", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "24428491-2b6a-4ac0-9ca5-17df33138a18", - "stop_order": 12, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a475a846-8fec-4637-a0f2-f94fa4ddd612", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "f63e9060-33e9-4263-9023-f37d0e848260", - "stop_order": 13, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "db92b367-286c-4eb9-b9c1-3f03a5c698de", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "fa9a49ee-146f-4ed2-8473-cc17da8dcab2", - "stop_order": 14, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "fa8e01c5-fa22-46c0-8e95-1fc7198cf945", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "a8c62a6a-edf4-48ee-8fa7-6af9cf0165ed", - "stop_order": 15, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8e94bd85-6b1f-403d-9644-85ac55766a61", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "f30ed3ab-b629-4320-b254-32d4d8341ee6", - "stop_order": 16, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "73f8ff26-b697-454b-9676-3f10dbd188a6", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "9a773cda-fc7b-4020-8605-5a85b04a1049", - "stop_order": 17, - "travel_time_minutes": 12, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "05133946-6e25-467b-968b-e32bd8cc79bc", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "18dabf19-4f52-4d92-be42-6bd3623b4f06", - "stop_order": 18, - "travel_time_minutes": 13, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "2a8da84d-e86d-4fa4-8694-fcb08a0879f4", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "8a40a5a0-acee-49e3-b07d-3923128e4908", - "stop_order": 19, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "24515c35-093e-4c05-9bda-69fbcf67c499", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "ad214625-1468-4bf5-bf8c-ef4c27d64c38", - "stop_order": 20, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6d6adb3a-f5c6-4007-924f-87f7588f897c", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "a23339b9-25b1-4219-b27e-ab153e2efcd7", - "stop_order": 21, - "travel_time_minutes": 15, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a2f86e11-36d4-4ddd-b90e-74097d304a8d", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "70cb67c0-3ff5-45ce-812a-f996e0a7f44d", - "stop_order": 22, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "08899511-5226-416a-943e-7986b177023c", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "0b5970c0-343f-4c9d-972e-1ec6926f9807", - "stop_order": 23, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1a410e57-8480-4a3b-894c-d9f63375a35d", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "3f34c52b-28f6-4afb-8284-7e287322e5bf", - "stop_order": 24, - "travel_time_minutes": 17, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9c03a3ac-2e09-499e-b48d-7026a3540766", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "358461df-1b48-4527-a457-f94277b47c60", - "stop_order": 25, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "47c6027c-699d-4896-ac8e-54b1a28cbe09", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "2802d866-56d1-4200-9c41-402cc967f35b", - "stop_order": 26, - "travel_time_minutes": 19, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ff46774d-8a81-4097-af03-13a75c238f9d", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "f38abc02-65e0-4a35-b19e-474359d7477e", - "stop_order": 27, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e4ada674-e31c-4a31-9f69-fc37e24b64c3", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "5966ddf4-4ad1-47c0-962d-20d4a19438fc", - "stop_order": 28, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "13ef03ee-b61c-41a3-8b8a-787bd38559a4", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "b8eec28f-3d45-4a65-9bfc-6df0a6f525bd", - "stop_order": 29, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "cbc678f5-1fba-4bfb-bf10-b6fa9bc1df35", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "8e538436-3fba-478c-be7e-36d79e4c8e34", - "stop_order": 30, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1f5e8d8b-66c8-4e61-8f22-de48c2cb5818", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "447d004f-2952-4a7d-becf-3502f3bb43f8", - "stop_order": 31, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ebd08d80-010e-4c62-b573-a0d4c6a17a3e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "945f6bd5-5795-49d5-a874-b063e9611b5a", - "stop_order": 32, - "travel_time_minutes": 23, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "00918509-4224-46ee-b95a-e4165774f845", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "30349a8c-65f4-481e-acd2-510efe0bbe78", - "stop_order": 33, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "251204a4-320c-4381-b6fd-18b9f3ad78a6", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "41bbb27f-5ee0-41a1-9cc4-98f491977023", - "stop_order": 34, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a1afe18b-13f5-49d1-b609-043c15a4dc52", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "089afec3-6911-4c41-9d12-223b8607c4a9", - "stop_order": 35, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "92280e9a-471d-41d7-8c2e-1db53c3d6e02", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "d68fa99a-5e46-4db2-bc90-527addb6570b", - "stop_order": 36, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0c01730f-51a1-4a5b-853e-9a0ee013116a", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "d20c75b9-605f-4aa9-b6f6-da9244f00bbd", - "stop_order": 37, - "travel_time_minutes": 27, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "cb6fe554-c75d-466b-9131-2391f7affeec", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "e1fb75a6-2e2a-44f0-adcf-cae892b5976b", - "stop_order": 38, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "dd598d69-a92c-45ba-aca7-190a26e68585", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "96d1c7d3-a6a7-4b56-9cb4-6f23260bf0a7", - "stop_order": 39, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "84a5c5c8-0bd6-434a-84d4-fdd84c14e814", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "54a8ce58-a383-48f2-8c58-d3c32c4878ef", - "stop_order": 40, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0893e0f3-99f6-4991-b52c-c7b43de0dfd9", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "f10f4c8a-d04c-4ebe-a46d-ae3532867a4a", - "stop_order": 41, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ae52818c-6e01-43f6-850a-192ff9c5c63d", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "5eff88c8-be0a-40a6-81b7-050b0e660b2a", - "stop_order": 42, - "travel_time_minutes": 31, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "aaedccb2-6be4-4cdc-ae06-9f2174f48332", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "a48906a3-459e-40cf-b3c7-06aa1261b75e", - "stop_order": 43, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "593880f8-9c08-4859-bf44-eef3994cb489", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "33f07c2b-1618-482d-92c7-8d56c0e44960", - "stop_order": 44, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e251768a-4c8b-4bff-9f75-4060903925df", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "d982f3fc-8dca-4450-b932-7a975b6a6a86", - "stop_order": 45, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "919e2b4e-adaa-4563-8a9c-2828fdc1d1c3", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "39fc64f7-4630-4197-a0ca-436c18a6cc8a", - "stop_order": 46, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8a61c4d4-615e-4ba0-83e8-c82a9f4f7fcf", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "9412a5db-85b7-4eb4-b51e-1052c84de4f6", - "stop_order": 47, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ddb356fa-96bb-4507-beea-f075b162b02f", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "e6aa65fd-a2cb-4c83-b237-bc4ed6c31f57", - "stop_order": 48, - "travel_time_minutes": 35, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "590233ee-cb70-4b96-a595-3254922329d5", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "39e8a80a-cb67-464f-99e0-4c55602abc14", - "stop_order": 49, - "travel_time_minutes": 36, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "55f18100-eef3-4767-8678-46327c0fab69", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "926d4e83-1f08-4504-95e3-71f4d2c9666c", - "stop_order": 50, - "travel_time_minutes": 37, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "aafcf22c-f520-4697-8f59-7022e23f5dba", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "d9e3cda5-b5d1-4c16-a51b-532cdcb9904f", - "stop_order": 51, - "travel_time_minutes": 38, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8e71cb61-3edf-47b0-80d5-1d57d4967ab1", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "0b660dd6-e935-4be8-b470-eea9bf995c75", - "stop_order": 52, - "travel_time_minutes": 38, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d6a494fe-186f-4e1a-8e0c-2aba2dee882b", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "35f25575-b799-4167-b94c-912c66e525ce", - "stop_order": 53, - "travel_time_minutes": 39, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6ee4cb94-c79a-476b-9469-478276bbc262", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "5250f47d-3885-4566-ad93-25d8a223e25b", - "stop_order": 54, - "travel_time_minutes": 40, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8a8cdcc0-7705-46ae-bf0c-f7323d71dc20", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "680fb194-6f56-4f12-8042-4e97b477019c", - "stop_order": 55, - "travel_time_minutes": 40, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "77b9b2f4-99d9-4e23-8bf0-c6ed1e46a858", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "5669e724-da62-42cc-8250-6d645d460e7b", - "stop_order": 56, - "travel_time_minutes": 41, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "40bee8e1-1a3d-4362-ba72-489dadbf30b7", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "3d73312c-eba3-43d1-ba3d-2381cfe6abd8", - "stop_order": 57, - "travel_time_minutes": 42, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "158cb1af-3ec3-49f4-a09e-ed429d0f183e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "2bf338e4-3cf0-4815-aaa5-7e4aa4774863", - "stop_order": 58, - "travel_time_minutes": 43, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c71f7a0b-3a45-47c7-9809-1bee28c98e0b", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "a37b73a8-9436-4c57-bf84-83b51659ae0f", - "stop_order": 59, - "travel_time_minutes": 44, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "83504dd0-735f-4c4e-ae4e-914493df53a2", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "88e91734-fe05-4187-890f-b37c7c3d70ef", - "stop_order": 60, - "travel_time_minutes": 44, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "da6ba1e4-1c6c-46f6-a804-7da926c59a4d", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "stop_id": "0666a01b-0055-4b3a-9756-5053690cfae5", - "stop_order": 61, - "travel_time_minutes": 45, - "is_pickup_point": false, - "is_dropoff_point": true - }, - { - "id": "54fb3bc8-91fc-49c3-a3ee-56332f02db0c", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "0666a01b-0055-4b3a-9756-5053690cfae5", - "stop_order": 1, - "travel_time_minutes": 0, - "is_pickup_point": true, - "is_dropoff_point": false - }, - { - "id": "c486e012-c302-41fc-994a-1e974a40acbf", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "88e91734-fe05-4187-890f-b37c7c3d70ef", - "stop_order": 2, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a68b6117-c2ba-41bd-b368-23a1ac49f1d0", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "a37b73a8-9436-4c57-bf84-83b51659ae0f", - "stop_order": 3, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e6d3e0df-be20-4870-83c4-30bb5f2fcbba", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "2bf338e4-3cf0-4815-aaa5-7e4aa4774863", - "stop_order": 4, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "2c4855f4-9b23-490f-97bd-57a2042937c7", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "3d73312c-eba3-43d1-ba3d-2381cfe6abd8", - "stop_order": 5, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "2a33abbe-3cff-43e8-b092-6f0430b40ab3", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "5669e724-da62-42cc-8250-6d645d460e7b", - "stop_order": 6, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "69f84717-5cea-4d25-9291-6bd300a3b2b1", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "680fb194-6f56-4f12-8042-4e97b477019c", - "stop_order": 7, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e312db59-3f06-44c5-9a99-750b8a53f6c5", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "5250f47d-3885-4566-ad93-25d8a223e25b", - "stop_order": 8, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "193e4784-808a-4331-bb28-7f72f15734d5", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "35f25575-b799-4167-b94c-912c66e525ce", - "stop_order": 9, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "59bbab1d-9057-4c42-a178-dfb5233dc569", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "0b660dd6-e935-4be8-b470-eea9bf995c75", - "stop_order": 10, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f60b09ee-e405-4258-a85e-8f6982108831", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "d9e3cda5-b5d1-4c16-a51b-532cdcb9904f", - "stop_order": 11, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7d92cc3d-5e74-4f3c-b63a-9d4fa8d0cae2", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "926d4e83-1f08-4504-95e3-71f4d2c9666c", - "stop_order": 12, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a4322707-6a6a-4897-b06d-c2769f924d51", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "39e8a80a-cb67-464f-99e0-4c55602abc14", - "stop_order": 13, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "69577aef-8a7b-4f48-bc9b-5d69367f33c1", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "e6aa65fd-a2cb-4c83-b237-bc4ed6c31f57", - "stop_order": 14, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "2587bece-63b7-45a1-acec-bcc11625945d", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "9412a5db-85b7-4eb4-b51e-1052c84de4f6", - "stop_order": 15, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1a5038fe-e950-47e4-9b5a-c0e63b2d8194", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "39fc64f7-4630-4197-a0ca-436c18a6cc8a", - "stop_order": 16, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "58001e32-564c-4d46-b2db-c0cea747fea5", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "d982f3fc-8dca-4450-b932-7a975b6a6a86", - "stop_order": 17, - "travel_time_minutes": 12, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "20df10e1-b28d-4c0a-a267-0dda9c684b74", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "33f07c2b-1618-482d-92c7-8d56c0e44960", - "stop_order": 18, - "travel_time_minutes": 13, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bbbfeef4-644e-46fd-8ea7-aa758a92f8f5", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "a48906a3-459e-40cf-b3c7-06aa1261b75e", - "stop_order": 19, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5f2f2775-90d1-47a1-86bb-55ed02ad120b", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "5eff88c8-be0a-40a6-81b7-050b0e660b2a", - "stop_order": 20, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "86d2c6e4-28cf-4a92-b9b2-988b53da0497", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "f10f4c8a-d04c-4ebe-a46d-ae3532867a4a", - "stop_order": 21, - "travel_time_minutes": 15, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e689531f-733b-4b40-9787-f0f07946a3e3", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "54a8ce58-a383-48f2-8c58-d3c32c4878ef", - "stop_order": 22, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "63ec3fff-7d77-4674-96ef-fa709b3cf495", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "96d1c7d3-a6a7-4b56-9cb4-6f23260bf0a7", - "stop_order": 23, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "216fc222-5e2f-4159-965d-2c6ccf623ffa", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "e1fb75a6-2e2a-44f0-adcf-cae892b5976b", - "stop_order": 24, - "travel_time_minutes": 17, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7648107d-3462-41ba-af42-f6126eb3cffc", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "d20c75b9-605f-4aa9-b6f6-da9244f00bbd", - "stop_order": 25, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d1138ec3-d249-494f-a8d7-dde68b5a3ae0", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "d68fa99a-5e46-4db2-bc90-527addb6570b", - "stop_order": 26, - "travel_time_minutes": 19, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "428892ee-831a-44eb-b682-143e65054976", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "089afec3-6911-4c41-9d12-223b8607c4a9", - "stop_order": 27, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c280c81e-3a48-4d8f-869a-cb1be5664354", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "41bbb27f-5ee0-41a1-9cc4-98f491977023", - "stop_order": 28, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "cd154d0a-52cc-406c-969e-471e0c6d8d88", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "30349a8c-65f4-481e-acd2-510efe0bbe78", - "stop_order": 29, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "327ca1bf-3f9d-4c06-951b-97ce2acd9c23", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "945f6bd5-5795-49d5-a874-b063e9611b5a", - "stop_order": 30, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "62408a8d-1d76-4342-81e1-94724681a012", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "447d004f-2952-4a7d-becf-3502f3bb43f8", - "stop_order": 31, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a9c7a30c-01d3-4e54-85b4-315f6cd7ea31", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "8e538436-3fba-478c-be7e-36d79e4c8e34", - "stop_order": 32, - "travel_time_minutes": 23, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4a25eeec-d9da-46c9-a0c7-770bc1370a78", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "b8eec28f-3d45-4a65-9bfc-6df0a6f525bd", - "stop_order": 33, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8b987eb6-58ec-4662-bdec-e7c62b165183", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "5966ddf4-4ad1-47c0-962d-20d4a19438fc", - "stop_order": 34, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "98e0bf42-2ecb-40a2-86fa-196f4f665b73", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "f38abc02-65e0-4a35-b19e-474359d7477e", - "stop_order": 35, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4ae17ff0-35b6-4661-9f89-d6fa562c930c", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "2802d866-56d1-4200-9c41-402cc967f35b", - "stop_order": 36, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3a2761e7-16b6-41b1-93d4-c0d57ee3c8f3", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "358461df-1b48-4527-a457-f94277b47c60", - "stop_order": 37, - "travel_time_minutes": 27, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "68a20bcc-16d8-4a23-81ba-2acb43a9a207", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "3f34c52b-28f6-4afb-8284-7e287322e5bf", - "stop_order": 38, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f1bb95eb-f854-4824-88d6-e37fdc650a74", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "0b5970c0-343f-4c9d-972e-1ec6926f9807", - "stop_order": 39, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "92c28a32-d98c-4460-8059-0ba509ab4b86", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "70cb67c0-3ff5-45ce-812a-f996e0a7f44d", - "stop_order": 40, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c7ac4aea-e135-412c-92e4-cc6e83021f4b", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "a23339b9-25b1-4219-b27e-ab153e2efcd7", - "stop_order": 41, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "33ffba62-52cd-4c3a-95de-d2d6c00f93d9", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "ad214625-1468-4bf5-bf8c-ef4c27d64c38", - "stop_order": 42, - "travel_time_minutes": 31, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "69980dac-a9a8-4176-b447-31a5897f5af7", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "8a40a5a0-acee-49e3-b07d-3923128e4908", - "stop_order": 43, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "033b499a-f230-4dc1-b238-cae8603d426d", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "18dabf19-4f52-4d92-be42-6bd3623b4f06", - "stop_order": 44, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9304f892-6284-4953-ae6b-97f2cb67b58b", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "9a773cda-fc7b-4020-8605-5a85b04a1049", - "stop_order": 45, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "91605791-55c8-47dd-a0a3-a93a2c056a67", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "f30ed3ab-b629-4320-b254-32d4d8341ee6", - "stop_order": 46, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "14bc2c19-79da-496f-bca5-a7ce1a27e971", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "a8c62a6a-edf4-48ee-8fa7-6af9cf0165ed", - "stop_order": 47, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a842a9ff-7a17-4bba-968e-bb0c8c8b025d", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "fa9a49ee-146f-4ed2-8473-cc17da8dcab2", - "stop_order": 48, - "travel_time_minutes": 35, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e6f4e6a9-7313-4f9c-a1cd-6fb2ead4c237", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "f63e9060-33e9-4263-9023-f37d0e848260", - "stop_order": 49, - "travel_time_minutes": 36, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0a2133ae-5c49-42d2-9f68-e3e7eec2940a", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "24428491-2b6a-4ac0-9ca5-17df33138a18", - "stop_order": 50, - "travel_time_minutes": 37, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "84f800a8-cb26-4dd7-92fe-0c7d15da48e2", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "84761977-665d-4b96-8c6b-766e7c8c779d", - "stop_order": 51, - "travel_time_minutes": 38, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7048aedb-582c-43de-bdb8-4ac64bc31b3a", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "71ce16ce-5aa5-4e39-a7fe-fa3272e75e41", - "stop_order": 52, - "travel_time_minutes": 38, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "263c965d-7642-4321-9b15-d0817fc0d8af", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "fb9882db-bb01-46ad-bbb1-5cb8cf4f78f2", - "stop_order": 53, - "travel_time_minutes": 39, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3b21fa68-c803-4a98-8272-5c82898a22f9", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "ad39742d-5cc3-4288-a5ce-ec4fa132ae47", - "stop_order": 54, - "travel_time_minutes": 40, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1543a78c-9a1a-4ab9-b54f-d09ff392d7d4", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "0948094e-1132-4a94-8873-4fbbb9bd25e5", - "stop_order": 55, - "travel_time_minutes": 40, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3d0ba9c4-3984-48b0-89cb-310d58ad6432", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "91d641eb-5564-4f8f-957e-aa2851078d98", - "stop_order": 56, - "travel_time_minutes": 41, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e1560397-833b-404b-b172-e6631717674e", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "56d12752-cb1e-448e-a54c-ac4ceb5b85c9", - "stop_order": 57, - "travel_time_minutes": 42, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b7586595-7097-4ff3-9916-e64f648cf7ed", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "c78c5f09-92da-4b82-a1db-c9e686c178b1", - "stop_order": 58, - "travel_time_minutes": 43, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "59ca2ca0-ed6d-4e6e-934e-d8324e0e09f0", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "e7c404fe-6db7-4fa8-be3c-d20bfaea30b4", - "stop_order": 59, - "travel_time_minutes": 44, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "18d2add6-3520-41f3-85ce-fcb9d5bc6949", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "46b43a9d-a71d-4276-9252-86a143def245", - "stop_order": 60, - "travel_time_minutes": 44, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ec559ba3-b578-4ae4-9135-2dc944488883", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "stop_id": "652426c4-ba01-4191-8969-88701ad482a6", - "stop_order": 61, - "travel_time_minutes": 45, - "is_pickup_point": false, - "is_dropoff_point": true - }, - { - "id": "64600b26-45b0-495e-91ae-e5cb057187c2", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "acea0a34-f564-4f30-b97d-445c5c2f3864", - "stop_order": 1, - "travel_time_minutes": 0, - "is_pickup_point": true, - "is_dropoff_point": false - }, - { - "id": "813ef96e-b65e-4767-aa26-f73c344dc6f6", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "bf949ab0-c554-41ab-a852-917b6aed4251", - "stop_order": 2, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3b452131-5ad0-4d59-a338-84067208b76c", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "9cc2dd3d-59fd-4a5f-a24e-c52082625190", - "stop_order": 3, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ec087680-65f4-4ffb-96e3-10bf8f94e7df", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "d649e756-a1a7-4b07-80a1-7040cffc5567", - "stop_order": 4, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9402b299-9972-4ff1-89d4-fb9e69093006", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "6ca67be5-7084-46ad-940d-277caeaebb9e", - "stop_order": 5, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5b0a4333-e711-427b-a487-e1c376c646e7", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "a324ca30-9831-48ce-a5cc-cfcf21d91ee0", - "stop_order": 6, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f01061b2-49cd-4854-89ba-e1202a3744a6", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "f374aad0-549f-4754-859d-10465229c5fa", - "stop_order": 7, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "73e79d5b-5deb-493d-8ec8-c324e64ba3be", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "9740fe20-cde6-467f-8de4-174426fcbc7f", - "stop_order": 8, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "24217a9b-274a-4f01-b642-42e2eb84a1e4", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "2c2ba744-3c20-4485-aca4-22b00b4f622f", - "stop_order": 9, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8470dfcd-52a5-4be3-9759-a1a0aee5c8d8", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "ecc0d404-bf6e-4266-bccd-4050e54a442a", - "stop_order": 10, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "88dbba33-a750-471a-8406-5310b885bc3a", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "efb5c05b-d52c-4030-aa82-960e41894ec3", - "stop_order": 11, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8a2a6814-bcc9-4a9d-ab33-37114b67b487", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "54d3e908-e2c6-4a8c-90e3-694daefea995", - "stop_order": 12, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "383dd3f7-01d6-49b2-8cdf-1a4bfcb68d23", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "83f03e06-bb17-41ef-9760-565f7c6b7905", - "stop_order": 13, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "60a9d682-2ce2-4aa4-ab87-71b323d936e7", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "1d74e1ef-e488-4fc9-9df8-9c88f007e204", - "stop_order": 14, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5a124a60-d234-4820-a8fb-fbe166643bf6", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "d8e82b75-e2a3-47f7-ab91-299282456076", - "stop_order": 15, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c5348c24-b6b2-436a-8ae4-0b3098ca2dfd", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "54a34108-7928-4ec9-944c-5bcf33d59147", - "stop_order": 16, - "travel_time_minutes": 12, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c1d46723-3519-4a81-b30c-efa65a92f14f", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "8265275c-8f02-487b-a8d2-4a33a04515d2", - "stop_order": 17, - "travel_time_minutes": 13, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "db089592-1d25-402b-98e9-4abee7287879", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "ffbe020d-97cb-4552-800a-1979bebcf3f9", - "stop_order": 18, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "57a8d0f5-13cf-46c1-a818-4b357b7f5507", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "39274b2b-7d5a-4c6e-b3e9-4f05a66f1c7e", - "stop_order": 19, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "eac471a3-1a53-4e5f-961f-9bda41ddac5f", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "a5704227-9658-4118-8566-19d7b5827fc6", - "stop_order": 20, - "travel_time_minutes": 15, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "984e0ee0-7bd5-4157-a518-b1764cb2be7e", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "c01ee146-0148-4e5d-bff3-3db389de1dd8", - "stop_order": 21, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a7049fe3-9c97-4d15-b125-89dcd8fd1cd3", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "2050bc76-6534-4b6b-891f-33fe3bac8407", - "stop_order": 22, - "travel_time_minutes": 17, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0ab1bdd8-c747-4cd0-a6f9-d777c3826b56", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "46588013-d616-4eae-8e50-c98bf38e050f", - "stop_order": 23, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "29c9e433-5117-4cca-a69a-6a77c1a948b1", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "78017d28-3996-4820-a033-034e7a20c9bf", - "stop_order": 24, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "215d76f9-5b09-4569-a929-f530860ed0ab", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "d99779b3-07e4-4a53-bd87-1d3dec150346", - "stop_order": 25, - "travel_time_minutes": 19, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "48c687da-76c5-4e28-9430-0e942ee5749c", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "10a60237-1189-49d6-8da3-54893f849212", - "stop_order": 26, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7edc917a-1ae8-41a4-a760-e82fe63551bc", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "ea305b8a-bffe-42b1-948e-72c9dbc6752d", - "stop_order": 27, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c569be54-9c39-491f-bdd7-2d6ee26b992b", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "2e00b45d-9c28-4aac-b895-546f213e3309", - "stop_order": 28, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "54b5d14a-9e09-425c-a16e-2b50cf9031ea", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "85b7e107-6d21-44cf-84c9-ddef2be9bbdb", - "stop_order": 29, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "15a28767-cc9e-4cc5-ba35-2e74109fc91b", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "2f17114c-6bfc-45bf-a436-ed64860df62e", - "stop_order": 30, - "travel_time_minutes": 23, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "464976dd-b464-4e8b-babc-eb2e4956d959", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "8b26bd01-f59e-40d4-9f5b-91eb86ae9d0f", - "stop_order": 31, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3fd2b90e-c8e6-456e-8b4b-df03fb735ebc", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "05baf1ef-af1d-4f76-8027-2482b37b8c37", - "stop_order": 32, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8ca2b24b-955d-4b99-bc46-c1066a1fb4f8", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "3386ad96-9012-472f-a756-9093c602a416", - "stop_order": 33, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "08f88b06-bd47-4086-80d3-2865617567ec", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "f42e378e-d63a-4747-aea9-1dfd179d9864", - "stop_order": 34, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "be179291-b8f5-4f1d-b96c-1c9062afefd0", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "51043828-726d-4245-a975-59723eb2f08f", - "stop_order": 35, - "travel_time_minutes": 27, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0add64d7-e0b2-41a8-a35c-b191968ded6d", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "2c669c57-a164-4437-8114-85a7ec8b4e3c", - "stop_order": 36, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "869ba5c9-e983-4f89-b9ff-1eb5c528dc09", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "29c3fa50-965a-47fc-9aa9-5216593fd863", - "stop_order": 37, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6da8511e-676a-4589-8bf7-afe36b097524", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "f6fc1c86-5b7e-4e83-86b1-4b999a33a2ba", - "stop_order": 38, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "92ac7431-f834-4c23-b437-1d4553a2fff7", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "8b5246b1-c4cb-4435-85a3-0330ac8db62e", - "stop_order": 39, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "dbaa05fd-6fb2-4c2b-8d6e-5842de1d981a", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "d20f93f6-f187-47d3-b46a-9f067ca71258", - "stop_order": 40, - "travel_time_minutes": 31, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5a5158d3-357f-43ab-a66b-34120d7106d2", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "506e4aff-1cb6-47e9-a85f-3dafd2d49308", - "stop_order": 41, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c2055b1c-1984-4bb2-a549-74e26a4b8898", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "848e3f5c-0500-4ffa-a92f-5f56a339fda2", - "stop_order": 42, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9ea82cc3-4520-4c53-992c-0ac675b616ef", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "f184de4f-a708-4464-91a5-53e836c342fb", - "stop_order": 43, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7344deb2-ef5c-49b2-ba01-87e3372758ed", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "f6d8d3d7-7209-40ad-bf35-7cf9cb4de1d3", - "stop_order": 44, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "45cc1d36-85e1-4ed4-8fce-255001bcb553", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "stop_id": "e2246bb6-1f69-4550-9239-fca81114892c", - "stop_order": 45, - "travel_time_minutes": 35, - "is_pickup_point": false, - "is_dropoff_point": true - }, - { - "id": "d9acb914-7424-459f-a859-0b72a60941e7", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "e2246bb6-1f69-4550-9239-fca81114892c", - "stop_order": 1, - "travel_time_minutes": 0, - "is_pickup_point": true, - "is_dropoff_point": false - }, - { - "id": "e98a3ab9-8aea-4a03-9776-b29d0864f003", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "f6d8d3d7-7209-40ad-bf35-7cf9cb4de1d3", - "stop_order": 2, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "94cbe537-e347-4f39-94c5-d68bdbf48175", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "f184de4f-a708-4464-91a5-53e836c342fb", - "stop_order": 3, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0646bdff-cf05-4862-943b-a2fcf53dc7b7", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "848e3f5c-0500-4ffa-a92f-5f56a339fda2", - "stop_order": 4, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c5e3328d-66b4-424c-9c44-d5a30a5f330e", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "506e4aff-1cb6-47e9-a85f-3dafd2d49308", - "stop_order": 5, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "19197507-dd9b-4f72-9a9f-8973edb720dd", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "d20f93f6-f187-47d3-b46a-9f067ca71258", - "stop_order": 6, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6a030255-5ad7-434d-8c8a-6eb4c446add5", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "8b5246b1-c4cb-4435-85a3-0330ac8db62e", - "stop_order": 7, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a662a795-c7b5-4d4d-8a97-74a920debe48", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "f6fc1c86-5b7e-4e83-86b1-4b999a33a2ba", - "stop_order": 8, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bcc02be5-3367-4073-849c-31cabe13859b", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "29c3fa50-965a-47fc-9aa9-5216593fd863", - "stop_order": 9, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f139fd48-0a4f-4d2a-89f4-4da24affe170", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "2c669c57-a164-4437-8114-85a7ec8b4e3c", - "stop_order": 10, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3a4e3e07-a564-49d1-86a1-832de7b4b541", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "51043828-726d-4245-a975-59723eb2f08f", - "stop_order": 11, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b014cb7b-c161-4011-84f4-98734cdd7537", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "f42e378e-d63a-4747-aea9-1dfd179d9864", - "stop_order": 12, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b9a55fcf-5ada-4090-bba8-ffc677909964", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "3386ad96-9012-472f-a756-9093c602a416", - "stop_order": 13, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5ce7bc61-e303-4ab9-8125-571e87e9781c", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "05baf1ef-af1d-4f76-8027-2482b37b8c37", - "stop_order": 14, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1a6e86a3-4b90-42bf-a624-6f52fd418390", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "8b26bd01-f59e-40d4-9f5b-91eb86ae9d0f", - "stop_order": 15, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b19bb52f-62fb-4f47-9493-7045f3515dc8", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "2f17114c-6bfc-45bf-a436-ed64860df62e", - "stop_order": 16, - "travel_time_minutes": 12, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7c6a12cb-810f-4d4d-8ced-b01e5631eed3", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "85b7e107-6d21-44cf-84c9-ddef2be9bbdb", - "stop_order": 17, - "travel_time_minutes": 13, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "69440fb0-7b75-4d01-b4fb-4afb6f6d85b6", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "2e00b45d-9c28-4aac-b895-546f213e3309", - "stop_order": 18, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "df989498-e8b0-4be1-bdeb-215ac3e41a90", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "ea305b8a-bffe-42b1-948e-72c9dbc6752d", - "stop_order": 19, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b212d570-0cf8-4dbb-80b8-08262781ee87", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "10a60237-1189-49d6-8da3-54893f849212", - "stop_order": 20, - "travel_time_minutes": 15, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4ea0a1e7-dead-4950-822f-4583876403c6", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "d99779b3-07e4-4a53-bd87-1d3dec150346", - "stop_order": 21, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9360bb9f-4c89-4bd5-b14a-157fba8863d2", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "78017d28-3996-4820-a033-034e7a20c9bf", - "stop_order": 22, - "travel_time_minutes": 17, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "24a8dbc4-d283-476b-b116-84a5a70f7d2e", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "46588013-d616-4eae-8e50-c98bf38e050f", - "stop_order": 23, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a5272eb7-7080-439a-b575-2c98df33a21c", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "2050bc76-6534-4b6b-891f-33fe3bac8407", - "stop_order": 24, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a305ff8a-21e3-48f8-b4bf-547a81cf7641", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "c01ee146-0148-4e5d-bff3-3db389de1dd8", - "stop_order": 25, - "travel_time_minutes": 19, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "73e04970-0e3c-4493-a53a-f1797f33b406", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "a5704227-9658-4118-8566-19d7b5827fc6", - "stop_order": 26, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f9bc7728-ea67-4180-bbff-b67a6e96ac24", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "39274b2b-7d5a-4c6e-b3e9-4f05a66f1c7e", - "stop_order": 27, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bb8645a3-eb06-4737-ac73-edd5efb12eaa", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "ffbe020d-97cb-4552-800a-1979bebcf3f9", - "stop_order": 28, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "95f17382-e59e-427c-b480-d1d265b2c5f1", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "8265275c-8f02-487b-a8d2-4a33a04515d2", - "stop_order": 29, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a5807270-c93f-4c3d-a7b3-0625df63ac98", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "54a34108-7928-4ec9-944c-5bcf33d59147", - "stop_order": 30, - "travel_time_minutes": 23, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8f546591-3a0d-4fc3-b9ce-753fac21eeca", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "d8e82b75-e2a3-47f7-ab91-299282456076", - "stop_order": 31, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3a413ece-bee3-4390-b9fd-723cc50731d8", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "1d74e1ef-e488-4fc9-9df8-9c88f007e204", - "stop_order": 32, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "fde83d90-5112-47ad-988e-1b4057aab718", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "83f03e06-bb17-41ef-9760-565f7c6b7905", - "stop_order": 33, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9d564d04-3512-4f9d-9b1b-71da74ef03c4", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "54d3e908-e2c6-4a8c-90e3-694daefea995", - "stop_order": 34, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7602f0be-d6a2-413d-99ac-4b0fc5146d53", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "efb5c05b-d52c-4030-aa82-960e41894ec3", - "stop_order": 35, - "travel_time_minutes": 27, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d0dbee33-97ed-4ebe-ab98-a70bca089756", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "ecc0d404-bf6e-4266-bccd-4050e54a442a", - "stop_order": 36, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "901af916-f2d8-45d6-a954-385a73a842c0", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "2c2ba744-3c20-4485-aca4-22b00b4f622f", - "stop_order": 37, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7b05884d-91f1-4232-abc1-46eb7fd979ae", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "9740fe20-cde6-467f-8de4-174426fcbc7f", - "stop_order": 38, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8b83735b-734e-45c8-9224-35c6f334fb83", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "f374aad0-549f-4754-859d-10465229c5fa", - "stop_order": 39, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bfc2ec3d-ec28-43e7-8135-b24d6a9a95b7", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "a324ca30-9831-48ce-a5cc-cfcf21d91ee0", - "stop_order": 40, - "travel_time_minutes": 31, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "96d5075d-7e03-42bd-a614-7a083eb4e57c", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "6ca67be5-7084-46ad-940d-277caeaebb9e", - "stop_order": 41, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "821d2091-3524-46e8-9bb2-0c2dfe6407cc", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "d649e756-a1a7-4b07-80a1-7040cffc5567", - "stop_order": 42, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a02bbeea-c1ba-41f5-965b-cd45878ff1b2", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "9cc2dd3d-59fd-4a5f-a24e-c52082625190", - "stop_order": 43, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5a0cd1c2-342f-4e0a-8f3f-6e6b6595ec42", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "bf949ab0-c554-41ab-a852-917b6aed4251", - "stop_order": 44, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "736c0cdd-a006-4f59-93e6-39141d0057fa", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "stop_id": "acea0a34-f564-4f30-b97d-445c5c2f3864", - "stop_order": 45, - "travel_time_minutes": 35, - "is_pickup_point": false, - "is_dropoff_point": true - }, - { - "id": "4e6dfd56-6289-4c39-aedd-91744d6d4a87", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "df528e47-8fc2-49b7-81db-3c8f4f7a176a", - "stop_order": 1, - "travel_time_minutes": 0, - "is_pickup_point": true, - "is_dropoff_point": false - }, - { - "id": "12a62ee0-7a8d-478b-b46e-dfed67b694d2", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "a20332a5-08f3-46f4-9dfd-f27e5539469e", - "stop_order": 2, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ee472ee3-369b-4f73-a9b7-c9a2273a4ced", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "2b2e6858-be6d-4f18-a3a2-92373cfd9a9d", - "stop_order": 3, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9b940c14-eafb-4828-b229-bb69f545afa0", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "3d769def-cf21-4560-be21-13b828aafe54", - "stop_order": 4, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "844d8a44-ccae-416a-9dcd-70e534b90a70", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "7db160e3-05b2-4778-baee-789cea0f0bfd", - "stop_order": 5, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "92b8cbaf-e535-422e-86f4-20ef3c894d8e", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "dc3e0510-7cdd-4521-8dc2-6181120b4f26", - "stop_order": 6, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c0d4dfbe-a906-4f1f-a297-fff89848222b", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "77f80a0a-450c-42c3-bb8a-b9a3b6e5758d", - "stop_order": 7, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e074ae1c-ab6d-4d13-8661-83d40ded2572", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "edfb904e-66be-4a8d-80f7-3a30403d3fca", - "stop_order": 8, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "2a63249a-ec32-4e62-959a-a443e5d1e411", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "f7317833-9adc-40c0-9132-5c66c1822210", - "stop_order": 9, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4ca0296c-8355-44d5-9225-cf4b3644ea2a", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "682705d5-5413-4bd3-a31c-144832e7ec96", - "stop_order": 10, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1475a34e-c191-4c17-a454-929f079c55a4", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "12fc09fc-5e48-4c54-b414-4133f0f12a37", - "stop_order": 11, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "383afdbe-9762-4dbd-a40a-73599f02f632", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "788abd79-3d4b-4810-a5c0-7d8fec3d1a27", - "stop_order": 12, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5dff3e99-877f-43f0-afbc-1724053f1daf", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "b321b88d-5032-4383-85e1-ec99c3e3cb3f", - "stop_order": 13, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bc25980c-cf12-4c4c-8140-8ba70dfae63e", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "d86649cc-7286-46c3-933c-168716d1b304", - "stop_order": 14, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "42474af8-0d23-4bc8-a7dd-3f911e39b126", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "bd2f01ab-0406-4b6d-b4c5-052f8915fc30", - "stop_order": 15, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5fd56e3f-a279-41e8-b5f1-f35df0a188f6", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "69c374a2-a062-4b28-8308-6aff793cd631", - "stop_order": 16, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ffd7c23e-88a9-4170-923b-4da8364f420d", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "8ba33c36-303a-4182-8e08-065c2961e05d", - "stop_order": 17, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b6e7ca9a-d283-48da-9d05-22f227cd3b91", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "00a14099-a862-455f-abfa-c2ec1489ab70", - "stop_order": 18, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a8b8160f-05a7-4b3f-b885-c7df70eee448", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "b95c7990-65ac-40db-bb49-b99ed3b9d8dd", - "stop_order": 19, - "travel_time_minutes": 12, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f2c517da-b460-41e9-8700-bd0cf18eeeb6", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "9bdf297b-6312-43fa-b945-bfaa01fd49bc", - "stop_order": 20, - "travel_time_minutes": 13, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c5c0e36f-adbe-42d0-a4fa-7ffbd99b8c04", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "9d9ffbcc-b4d8-427b-b5a3-add1c25f66a7", - "stop_order": 21, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f683c590-e253-4de2-bbfd-827ee8c10420", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "decf0e21-7488-4dc1-b5b6-9997e2437403", - "stop_order": 22, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1792516f-91b4-4f79-9db7-3668b2c0a6aa", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "21f322a7-ac14-4144-abad-7e7f2502eef6", - "stop_order": 23, - "travel_time_minutes": 15, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f310cd1d-5c8d-47fd-8c96-0db603f11e35", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "62ba8246-ead0-49ad-ae56-e76afd35765e", - "stop_order": 24, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "09ae1d88-db5e-43a4-98b9-66de5b526904", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "595f2ffe-2ab7-4cdb-9e49-087b3dddd12e", - "stop_order": 25, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "05a610e7-0ac7-4632-b5f3-369c28c5f290", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "5c1bdc42-ab43-42a1-a257-66e547df75ff", - "stop_order": 26, - "travel_time_minutes": 17, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "dc827719-19ff-41b7-b650-f992c58389a1", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "a1d2c520-d8dd-45e8-ad6e-16c1f8ecfe08", - "stop_order": 27, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "cf7db02c-12e2-49c0-9bce-4a4fa3fa6fce", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "156ce6b5-1683-4654-aab5-17e6d55547e8", - "stop_order": 28, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "47ac6b3b-a8fa-4c9e-ad72-95684e28e705", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "eb875940-9aa6-42bc-bc9a-15fce44c4287", - "stop_order": 29, - "travel_time_minutes": 19, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "cc6a53d6-de2a-4790-ba50-4bfa47609de9", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "29819fa8-f25e-4cb5-b142-c65a6f11baa9", - "stop_order": 30, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8dbed868-528d-4271-95e1-911470868362", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "a7996b81-206d-49af-bb42-e167f4f96a0a", - "stop_order": 31, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "97e04e23-26d2-4c67-8792-cc9dfef5cadb", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "0512d2ed-abc0-4f95-b39f-515eac489d27", - "stop_order": 32, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "affbeb64-0c86-41c7-bd38-7098fc1a1ca3", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "a1df2b63-5a62-41fd-9f32-4c947d153d07", - "stop_order": 33, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0c86c7fb-c6dd-43b5-a905-de12577a47a7", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "378993ec-7689-475c-8f4a-21177bbf6b73", - "stop_order": 34, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "eb4eafe8-e8bb-4b9c-8265-fb171381fdfd", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "267afc65-88a6-4ac1-9be5-46d22bfec4d5", - "stop_order": 35, - "travel_time_minutes": 23, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "178771b0-4678-4cb7-a1bd-e506a5d83524", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "bf4a14b1-2c0a-4405-8653-9a7ad24cd9ba", - "stop_order": 36, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "90cd836e-d866-4c60-8827-ba3e9b430b8d", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "37f0aeff-4345-4429-9c39-1a95be47d19f", - "stop_order": 37, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "34c07e23-aa0a-4ebc-9da8-b8e838c58b15", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "432d38b5-4ef5-4ca0-ad06-cbb98abfcdc1", - "stop_order": 38, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "38f667d6-147b-449a-8998-80f5ab304c1b", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "d57a03ef-26ae-49b8-b0ab-a24701fecf8c", - "stop_order": 39, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "08ee6f99-b6d9-43eb-9dcc-26290fd4bb30", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "5b8ed1ee-43fe-4bf2-8baf-ba7fb046bb16", - "stop_order": 40, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bacacc7e-088b-43d4-b08b-9e4a407430ba", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "5e276d2f-6d8c-4e29-b14f-2088acb32ea0", - "stop_order": 41, - "travel_time_minutes": 27, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "8467712d-c44d-4172-b10a-1e588412b9ba", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "6ed29cc6-f1ad-407a-b27c-2a45ef50d506", - "stop_order": 42, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f231886a-8d28-47bc-bf9d-f1db1fb3b9c1", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "3211b00c-4c3a-41e9-a560-794d77c1cfab", - "stop_order": 43, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f87556ae-19e9-4c5a-85a0-1517a7b06711", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "817b72ba-d4e6-4cc5-814c-7055dbcbeba5", - "stop_order": 44, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c48175d3-c97a-4002-bbdb-de91edaff067", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "bc19ef7d-7379-413e-bb2f-f32f224b0c64", - "stop_order": 45, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0e3411f6-9042-4f07-bc7f-a0524b181f3d", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "5dda8c4c-1134-4bef-a4d5-08de4234ccea", - "stop_order": 46, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "97c11d8e-5387-4e79-8686-46c47a6a0298", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "1fb1faef-ae69-4875-8598-7839e6268741", - "stop_order": 47, - "travel_time_minutes": 31, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "14fb8350-a855-4890-a6e7-a553ce69025b", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "6837aea7-cf79-4fc5-9530-9a7d02db7662", - "stop_order": 48, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ea36dfaf-67f6-43f8-a91f-b4db930d1d0f", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "dd5b1ddb-80ca-4709-801a-dd8376df0b4e", - "stop_order": 49, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d6d83cf5-b78c-45d9-a761-ba5d26481d24", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "5ac77ca0-882f-41be-b434-f95731b4f947", - "stop_order": 50, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e21054ec-a1ed-4d9b-8405-62636fa755e2", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "81644bb0-0afb-4cd0-8496-f066a4bd1701", - "stop_order": 51, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6d5fb8de-439a-4fda-bf85-fda5fe1677f7", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "b5c4dbb3-3225-462e-b865-79216d8564f4", - "stop_order": 52, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "be504510-197a-4e0d-9baf-fd8955473991", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "53d8b9b6-ef59-439e-97a5-39dacac56a24", - "stop_order": 53, - "travel_time_minutes": 35, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6f1d2ce9-9724-428a-bb70-b16097fa06bb", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "6d4aa16d-5683-48b1-8507-b0aba05d4aaa", - "stop_order": 54, - "travel_time_minutes": 36, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1c9a87ed-8524-4959-8b24-b1f29e4f4e05", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "eef5ca98-8a8d-42a6-9616-e3cabc7fcf0b", - "stop_order": 55, - "travel_time_minutes": 36, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1761fa9b-1d45-4a4d-a61d-7a210b6f9f6c", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "d3773f11-9393-40ab-9295-9305412d16ce", - "stop_order": 56, - "travel_time_minutes": 37, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "686874e4-059b-4577-ac90-58ebf9ca5a8f", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "707c8544-533f-4e42-8767-0490170cb083", - "stop_order": 57, - "travel_time_minutes": 38, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "11df87fd-40e6-498b-9c20-c209c755a35b", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "8db9b2c9-769b-4ec6-aae7-8a43ef99b9bc", - "stop_order": 58, - "travel_time_minutes": 39, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7a7a64ed-53ba-46ee-9689-76d512e081b6", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "2a03ba34-5483-4783-bb78-e8c92c200fbe", - "stop_order": 59, - "travel_time_minutes": 39, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7257f268-9e62-4302-b283-8d36955163f5", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "51e94d40-56fb-4842-8cfe-8b76c46aa13b", - "stop_order": 60, - "travel_time_minutes": 40, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "fda1ea1f-1463-4e40-97c1-556b1a1ee19b", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "f475143d-f78b-4b27-87d9-5a8867673695", - "stop_order": 61, - "travel_time_minutes": 41, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c336fcef-5a81-4071-a62a-dad7c33ec4a2", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "a364477b-c104-4ec5-bc4e-67bc04d4fd84", - "stop_order": 62, - "travel_time_minutes": 41, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "22695f50-4277-4ccb-9d85-4aae20fc1c24", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "5433c8d0-002a-45f0-a17a-c4fcf84e5169", - "stop_order": 63, - "travel_time_minutes": 42, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "04b93678-21cb-4d0d-ba30-fef1adf1d119", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "8085a65b-18fd-439d-8fa6-760b3b26ea55", - "stop_order": 64, - "travel_time_minutes": 43, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1d32e452-7aba-43bd-8ee2-dd30f2aeced4", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "4d182cbe-c108-46ed-a9b3-4b6cdef33aa9", - "stop_order": 65, - "travel_time_minutes": 43, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d8327617-fd83-4773-9d32-713c7d8b61bc", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "9c9a32d7-1bef-4824-95db-3761b4688111", - "stop_order": 66, - "travel_time_minutes": 44, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "41cda481-6922-4388-852e-04daec13baf9", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "89d0f353-8316-4c22-ab4e-1006121ee23a", - "stop_order": 67, - "travel_time_minutes": 45, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f1904d87-ff86-47a9-b069-37650bfa28cb", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "6eb8d5e3-4319-40d3-bd16-e3383cb113af", - "stop_order": 68, - "travel_time_minutes": 45, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ef5ababa-732b-4266-9e94-111abfd18507", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "6eabfea4-f0e8-4f8d-b97f-bc8febb39344", - "stop_order": 69, - "travel_time_minutes": 46, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "59061c03-d384-4692-b02d-05d6a52323fe", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "bd0f3e38-f7f4-4d8f-a9d3-33191468a58d", - "stop_order": 70, - "travel_time_minutes": 47, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "afb309cf-cab8-4f31-91ee-ec855aaa7e4b", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "b64f9a9a-0568-476f-b229-403e6a4cf448", - "stop_order": 71, - "travel_time_minutes": 47, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c8be7cb8-3656-40b6-9845-a5e1a88e26b8", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "d5af00b9-9f40-4afd-a67f-abf98a06ed6a", - "stop_order": 72, - "travel_time_minutes": 48, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d97a9cf9-13a2-44de-8926-ca3990052bae", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "e51839b2-1bb8-47c6-ab80-224cd5f17cb7", - "stop_order": 73, - "travel_time_minutes": 49, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a94f30c4-04de-4de7-a03f-9b40b0a3afa9", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "dee5dc1b-5101-43f1-a322-b59cfdd18ed1", - "stop_order": 74, - "travel_time_minutes": 49, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9c5cfd61-fdc6-4272-8fdb-38a5d9e619f1", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "stop_id": "4d7a3281-563a-491d-bbde-3a5fc4b87198", - "stop_order": 75, - "travel_time_minutes": 50, - "is_pickup_point": false, - "is_dropoff_point": true - }, - { - "id": "258a8516-933a-4cb3-b40a-a430eee73559", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "4d7a3281-563a-491d-bbde-3a5fc4b87198", - "stop_order": 1, - "travel_time_minutes": 0, - "is_pickup_point": true, - "is_dropoff_point": false - }, - { - "id": "373a098c-e318-47ce-9931-51046a1c5217", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "dee5dc1b-5101-43f1-a322-b59cfdd18ed1", - "stop_order": 2, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "864d71b2-ff11-4bad-933f-29f6a97ef370", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "e51839b2-1bb8-47c6-ab80-224cd5f17cb7", - "stop_order": 3, - "travel_time_minutes": 1, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "6f053bf0-3c04-4681-9f51-848612c1e960", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "d5af00b9-9f40-4afd-a67f-abf98a06ed6a", - "stop_order": 4, - "travel_time_minutes": 2, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e49f2814-5931-40ae-b12d-7ad0e9d7084b", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "b64f9a9a-0568-476f-b229-403e6a4cf448", - "stop_order": 5, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5d593fa4-4b1a-4b4d-ba74-e6c3da027b3c", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "bd0f3e38-f7f4-4d8f-a9d3-33191468a58d", - "stop_order": 6, - "travel_time_minutes": 3, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d163adbf-23c7-40c0-af57-9d27c59708f6", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "6eabfea4-f0e8-4f8d-b97f-bc8febb39344", - "stop_order": 7, - "travel_time_minutes": 4, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b55ee303-39b4-4ee9-a9f2-47c3b3a54542", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "6eb8d5e3-4319-40d3-bd16-e3383cb113af", - "stop_order": 8, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ea2c7c28-464c-4663-9d60-e3321ee85c0b", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "89d0f353-8316-4c22-ab4e-1006121ee23a", - "stop_order": 9, - "travel_time_minutes": 5, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "941e2806-439f-415a-a28e-0eed58898122", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "9c9a32d7-1bef-4824-95db-3761b4688111", - "stop_order": 10, - "travel_time_minutes": 6, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "d7af2db8-5877-408f-989b-105193b6c2b6", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "4d182cbe-c108-46ed-a9b3-4b6cdef33aa9", - "stop_order": 11, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "938cac27-9e25-47fe-8b50-512803fde9ca", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "8085a65b-18fd-439d-8fa6-760b3b26ea55", - "stop_order": 12, - "travel_time_minutes": 7, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e551a79c-5824-4c41-b89a-8591be00fe0a", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "5433c8d0-002a-45f0-a17a-c4fcf84e5169", - "stop_order": 13, - "travel_time_minutes": 8, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "429cf47c-3ec8-4915-a8fb-9b5d37f8d6d5", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "a364477b-c104-4ec5-bc4e-67bc04d4fd84", - "stop_order": 14, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ba7912bc-8be9-4208-a187-7160b44273c5", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "f475143d-f78b-4b27-87d9-5a8867673695", - "stop_order": 15, - "travel_time_minutes": 9, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "02cfbb56-398e-4e7a-ab3d-903171dcfa4c", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "51e94d40-56fb-4842-8cfe-8b76c46aa13b", - "stop_order": 16, - "travel_time_minutes": 10, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "fdb900e4-86d4-454f-9511-2fa79c5fe7c1", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "2a03ba34-5483-4783-bb78-e8c92c200fbe", - "stop_order": 17, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e7addc81-c341-4eda-88c9-e5ef43aea618", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "8db9b2c9-769b-4ec6-aae7-8a43ef99b9bc", - "stop_order": 18, - "travel_time_minutes": 11, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "c4ed723f-95fb-46b9-bc8c-39644d57258c", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "707c8544-533f-4e42-8767-0490170cb083", - "stop_order": 19, - "travel_time_minutes": 12, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0e9da61b-5f4d-44cf-9758-f132afd8c6fa", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "d3773f11-9393-40ab-9295-9305412d16ce", - "stop_order": 20, - "travel_time_minutes": 13, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5b38fb80-790e-4751-bfb4-152ff6c4aac8", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "eef5ca98-8a8d-42a6-9616-e3cabc7fcf0b", - "stop_order": 21, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ca16d9c2-c06e-4f0c-b586-8bfe8f305849", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "6d4aa16d-5683-48b1-8507-b0aba05d4aaa", - "stop_order": 22, - "travel_time_minutes": 14, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3b33a5ed-0f98-4023-81f0-30bda766bd95", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "53d8b9b6-ef59-439e-97a5-39dacac56a24", - "stop_order": 23, - "travel_time_minutes": 15, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5260f42f-e343-4663-a74b-63e407d42ca8", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "b5c4dbb3-3225-462e-b865-79216d8564f4", - "stop_order": 24, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e98e6a53-3707-4897-8d6e-d55c1bde2717", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "81644bb0-0afb-4cd0-8496-f066a4bd1701", - "stop_order": 25, - "travel_time_minutes": 16, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "362170d6-3e9c-47cf-a0be-4cce6d2312d0", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "5ac77ca0-882f-41be-b434-f95731b4f947", - "stop_order": 26, - "travel_time_minutes": 17, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "ba739e90-abb2-4927-8d03-35919327b5df", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "dd5b1ddb-80ca-4709-801a-dd8376df0b4e", - "stop_order": 27, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f4b14b85-dea1-4019-bdbc-f9e436a2e436", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "6837aea7-cf79-4fc5-9530-9a7d02db7662", - "stop_order": 28, - "travel_time_minutes": 18, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "638c48b0-bc3d-4b1a-8bf4-6ecb648b5774", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "1fb1faef-ae69-4875-8598-7839e6268741", - "stop_order": 29, - "travel_time_minutes": 19, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "fff0824c-ace1-44b2-9d43-bff70fd8e90e", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "5dda8c4c-1134-4bef-a4d5-08de4234ccea", - "stop_order": 30, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "eeaa31fc-cbb0-4093-9869-b30da64d7861", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "bc19ef7d-7379-413e-bb2f-f32f224b0c64", - "stop_order": 31, - "travel_time_minutes": 20, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b8a7480c-1478-4e2f-9fdc-e5b2b5492469", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "817b72ba-d4e6-4cc5-814c-7055dbcbeba5", - "stop_order": 32, - "travel_time_minutes": 21, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3e692c61-5f88-47e8-8662-82d64c1d4586", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "3211b00c-4c3a-41e9-a560-794d77c1cfab", - "stop_order": 33, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "999f5a81-792d-4195-b58e-b8a255c2353f", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "6ed29cc6-f1ad-407a-b27c-2a45ef50d506", - "stop_order": 34, - "travel_time_minutes": 22, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "f1afd36a-ca22-475a-a592-cf6f81235e33", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "5e276d2f-6d8c-4e29-b14f-2088acb32ea0", - "stop_order": 35, - "travel_time_minutes": 23, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "275d363c-b1b1-4265-a3f9-3f949488cd56", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "5b8ed1ee-43fe-4bf2-8baf-ba7fb046bb16", - "stop_order": 36, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "99a24a1b-1f3e-41d2-ac58-e60e0127e5b2", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "d57a03ef-26ae-49b8-b0ab-a24701fecf8c", - "stop_order": 37, - "travel_time_minutes": 24, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "22623c6f-ab26-471f-9b7b-2698618c7607", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "432d38b5-4ef5-4ca0-ad06-cbb98abfcdc1", - "stop_order": 38, - "travel_time_minutes": 25, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "de9e5953-d878-4cd7-abff-e4ac91813bb6", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "37f0aeff-4345-4429-9c39-1a95be47d19f", - "stop_order": 39, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "bb489cc1-ec9c-4653-a4d8-079395f29101", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "bf4a14b1-2c0a-4405-8653-9a7ad24cd9ba", - "stop_order": 40, - "travel_time_minutes": 26, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4bb95694-26d6-4a4d-adfc-c4ae7e9a0224", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "267afc65-88a6-4ac1-9be5-46d22bfec4d5", - "stop_order": 41, - "travel_time_minutes": 27, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0eaa6919-3a72-49bb-90a5-7d7763e97cce", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "378993ec-7689-475c-8f4a-21177bbf6b73", - "stop_order": 42, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "0a189b6d-0185-48b2-9fce-cf8c78297b26", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "a1df2b63-5a62-41fd-9f32-4c947d153d07", - "stop_order": 43, - "travel_time_minutes": 28, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "877ad958-2479-444a-bdd3-ac288b66c27f", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "0512d2ed-abc0-4f95-b39f-515eac489d27", - "stop_order": 44, - "travel_time_minutes": 29, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "3033319b-18a8-4184-baac-1e70e05506b4", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "a7996b81-206d-49af-bb42-e167f4f96a0a", - "stop_order": 45, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7fce0679-a7ce-4d24-b433-4d8e8ed6a774", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "29819fa8-f25e-4cb5-b142-c65a6f11baa9", - "stop_order": 46, - "travel_time_minutes": 30, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "964926d6-5fe5-4de8-804a-f7465d3e465a", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "eb875940-9aa6-42bc-bc9a-15fce44c4287", - "stop_order": 47, - "travel_time_minutes": 31, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5cdd9bc7-2686-44cc-8563-fff31ca6e970", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "156ce6b5-1683-4654-aab5-17e6d55547e8", - "stop_order": 48, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4e3e345a-742a-475d-a744-9bf2d6c5df2b", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "a1d2c520-d8dd-45e8-ad6e-16c1f8ecfe08", - "stop_order": 49, - "travel_time_minutes": 32, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e46388df-e524-4285-87b6-6bb3ae11a673", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "5c1bdc42-ab43-42a1-a257-66e547df75ff", - "stop_order": 50, - "travel_time_minutes": 33, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5a50a68b-9c80-4db2-8322-a911cf6f1369", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "595f2ffe-2ab7-4cdb-9e49-087b3dddd12e", - "stop_order": 51, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "50c223d3-6e8d-4042-89eb-719bd1d2bd68", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "62ba8246-ead0-49ad-ae56-e76afd35765e", - "stop_order": 52, - "travel_time_minutes": 34, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7f069c66-ae6c-4df8-918e-b02d3f50f8cf", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "21f322a7-ac14-4144-abad-7e7f2502eef6", - "stop_order": 53, - "travel_time_minutes": 35, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "a9395d0c-66c3-4111-96a8-262e76555bc8", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "decf0e21-7488-4dc1-b5b6-9997e2437403", - "stop_order": 54, - "travel_time_minutes": 36, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "1e96fe36-4b24-4183-b3c4-c8ef93d333bb", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "9d9ffbcc-b4d8-427b-b5a3-add1c25f66a7", - "stop_order": 55, - "travel_time_minutes": 36, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "4d080c8f-d04d-4a51-81d1-101c0bd3459a", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "9bdf297b-6312-43fa-b945-bfaa01fd49bc", - "stop_order": 56, - "travel_time_minutes": 37, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "edcad09e-8a8d-4e46-821c-7d0b5c71f07d", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "b95c7990-65ac-40db-bb49-b99ed3b9d8dd", - "stop_order": 57, - "travel_time_minutes": 38, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5d42197a-0ae0-4261-902f-e4753610de9d", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "00a14099-a862-455f-abfa-c2ec1489ab70", - "stop_order": 58, - "travel_time_minutes": 39, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "9d2a7393-6f6a-436b-a02a-7ee8296317ab", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "8ba33c36-303a-4182-8e08-065c2961e05d", - "stop_order": 59, - "travel_time_minutes": 39, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "67468d15-bd25-476a-b232-d1a87dcb0d8f", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "69c374a2-a062-4b28-8308-6aff793cd631", - "stop_order": 60, - "travel_time_minutes": 40, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "03686c4a-fc1b-435c-b1f3-6eb45e808542", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "bd2f01ab-0406-4b6d-b4c5-052f8915fc30", - "stop_order": 61, - "travel_time_minutes": 41, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "b5eebeaf-4658-4d0f-9ab8-6983279de444", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "d86649cc-7286-46c3-933c-168716d1b304", - "stop_order": 62, - "travel_time_minutes": 41, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7685a0db-d788-4d8c-b79a-4b5da5d066d9", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "b321b88d-5032-4383-85e1-ec99c3e3cb3f", - "stop_order": 63, - "travel_time_minutes": 42, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5bc005d2-465c-4733-9d05-543a87688cf6", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "788abd79-3d4b-4810-a5c0-7d8fec3d1a27", - "stop_order": 64, - "travel_time_minutes": 43, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7c82e7bd-ceba-4886-a084-7c535f4796d2", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "12fc09fc-5e48-4c54-b414-4133f0f12a37", - "stop_order": 65, - "travel_time_minutes": 43, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "76372ddd-6328-40fa-9ebd-72bdd660804f", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "682705d5-5413-4bd3-a31c-144832e7ec96", - "stop_order": 66, - "travel_time_minutes": 44, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "5fa95113-116e-40c6-b5ca-dc83d2a8023a", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "f7317833-9adc-40c0-9132-5c66c1822210", - "stop_order": 67, - "travel_time_minutes": 45, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "860759b2-df9c-41f2-b81a-1e0b447f1478", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "edfb904e-66be-4a8d-80f7-3a30403d3fca", - "stop_order": 68, - "travel_time_minutes": 45, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "31f206f8-a07f-4857-9630-fceef1b49267", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "77f80a0a-450c-42c3-bb8a-b9a3b6e5758d", - "stop_order": 69, - "travel_time_minutes": 46, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e21e7a46-b815-4afa-9d09-17c21b00d17c", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "dc3e0510-7cdd-4521-8dc2-6181120b4f26", - "stop_order": 70, - "travel_time_minutes": 47, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "acb46a63-95ad-413e-b376-718c531529bd", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "7db160e3-05b2-4778-baee-789cea0f0bfd", - "stop_order": 71, - "travel_time_minutes": 47, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "52cc6f5f-5443-481d-9f2f-4fd93580c421", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "3d769def-cf21-4560-be21-13b828aafe54", - "stop_order": 72, - "travel_time_minutes": 48, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "7939c8c6-699c-4135-8189-82ac36aa4fd5", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "2b2e6858-be6d-4f18-a3a2-92373cfd9a9d", - "stop_order": 73, - "travel_time_minutes": 49, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "53d8963c-7d0e-42bc-bd44-b006b7b8940d", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "a20332a5-08f3-46f4-9dfd-f27e5539469e", - "stop_order": 74, - "travel_time_minutes": 49, - "is_pickup_point": true, - "is_dropoff_point": true - }, - { - "id": "e2516b00-e44a-4fe4-9e0d-ae052c7c0db8", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "stop_id": "df528e47-8fc2-49b7-81db-3c8f4f7a176a", - "stop_order": 75, - "travel_time_minutes": 50, - "is_pickup_point": false, - "is_dropoff_point": true - } - ], - "bus_schedules": [ - { - "id": "4ab51885-5e69-41ad-80e8-74ffb1446338", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "05:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "88c4b540-eec0-4948-967e-41f5f200b95f", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "05:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "e1efe773-f9b1-41c0-bda7-0f7bf94d339b", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "06:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "303827d6-4210-42b7-b353-b9b4cc2e3ee3", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "06:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "a971f604-87c6-42f9-808c-485ef5f7b109", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "07:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "93c18109-201b-4cda-8d96-156a21da23a9", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "07:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "39ac5d46-84ca-44bc-b2b0-753f3a52971a", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "08:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "820617ce-2d44-4b60-b4e9-83fae67070e0", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "08:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "dfd3d868-2f87-4cd4-bb30-f9cc27786a92", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "09:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "7487516d-6cf0-4a85-b23e-27feb49b2d5e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "09:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "da8fa30f-1e11-4774-aed2-0c960a47bb00", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "10:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "c518d7de-7bcd-43e4-98a4-f6b6b4c6e6a5", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "10:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "b606ac3f-4885-4a0e-aeb6-a3715821c5a3", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "11:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "57d7be12-b9cb-4ad7-98d2-99d3fe23a264", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "11:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "b926b555-edc0-4c1c-bd5c-51b98109bdb2", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "12:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "83499fdf-0869-4672-9d1c-5564f86dc645", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "12:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "bde3c4ab-17ac-4140-86bd-f8d6f6bf3830", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "13:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "bd8f31fc-1675-47b9-9eea-01343ac360e7", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "13:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "2c7240de-0bc5-4ad8-a9c7-4698ef9989bb", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "14:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "04ddf718-d351-4afa-bd8f-db8f05454306", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "14:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "22ce8dca-a458-47af-906a-3e1293918233", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "15:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "84e15f6e-18a7-421d-8710-6eca3b84b0c9", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "15:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "c618abdc-eb9c-4841-aa84-de21d9820680", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "16:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "debce970-370c-474f-b086-033e7d1bb965", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "16:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "4ef788ad-bbd2-4230-8b1b-173d93fab456", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "17:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "fbd17c0d-72a0-4c02-8871-f7a6c7b9738e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "17:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "2e2ae907-09be-4545-ab6d-b00adbb7c124", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "18:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "174db71b-88d3-4926-ad53-debad2bdff2d", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "18:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "dff2adc6-b831-4e66-90dd-f009948b0a59", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "19:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "a1baee98-806a-42bb-9de1-0c711f9534de", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "19:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "c934be3b-cf25-4d87-890c-edfb53f89c4e", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "20:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "b979cb68-26a3-4f3a-ab85-be6d01bb777c", - "route_id": "944457a8-7edd-42f4-9ff6-8018f4ec7e9c", - "departure_time": "20:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "3a283d3f-1814-4007-a631-15732b0f9c11", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "05:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "3fe2df15-e4bf-44a2-903a-5deb2e18d504", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "06:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "a630f498-c6c4-4615-900c-42380a931dd5", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "06:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "36374993-931e-4108-8b69-22efbbc4da8d", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "07:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "2a048752-22b7-4d27-a642-257868c7f18e", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "07:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "118c4c13-03ea-49c0-9cc6-71d21279f309", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "08:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "25d00814-c510-4c43-a6f5-3a46fec307e6", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "08:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "50d7fd10-efe7-43ac-9208-7b09d8603b49", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "09:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "4f4b2afe-5584-452b-a732-18211aac0263", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "09:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "242bc4ea-c92b-4253-8e41-677102c14708", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "10:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "c8292a79-2cca-44e7-8897-c7516719cc74", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "10:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "89061b10-496f-4616-b4e4-9e7e6b0f5de2", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "11:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "a12829ff-cb03-43b4-aa40-73586b4a8fef", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "11:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "9e8156b5-c28b-43e3-bfb5-29e9f4536669", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "12:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "4928d538-1be7-4a86-83a3-4c4382d2ce33", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "12:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "5febdf1c-6375-42ba-9afe-3ab493115e56", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "13:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "a8b000fb-6d0a-4619-a61c-365735af795d", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "13:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "bfd684a7-0db5-4a75-b536-be380cd851e8", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "14:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "c759e6df-fc6a-4d6c-a3dc-8ffb98daabf8", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "14:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "b73e213a-6641-4ff9-9d7b-f105432e341f", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "15:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "81a66279-6eb6-4569-896c-1c6cb22e3043", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "15:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "ba82c476-25bd-4130-85a4-b8a7f435850b", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "16:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "d7b8b222-1c6b-4260-8048-da0356386f9b", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "16:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "b561a6fe-38df-4fd3-88cc-524f7ca50f05", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "17:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "afd7718f-9e93-49c7-a084-4d37fae01ff5", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "17:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "e32c504f-6d9a-431e-b195-d5f0a5989137", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "18:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "1eebae65-4277-4c65-81e4-bdc910fe1cf4", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "18:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "241115a8-a212-41b2-a761-8977ed4aa9df", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "19:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "10df12fc-dfc2-4ea4-a652-d67683f0f1ea", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "19:00:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "61e7d41c-e6c5-48b0-8d63-503395380310", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "20:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "bc8c40f4-159b-43a4-a78a-3555cd477bf1", - "route_id": "5da1dfb6-760a-4f59-aa5b-667149eb9ae6", - "departure_time": "20:30:00", - "frequency_minutes": 30, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "d81e730b-eb8c-4996-9d5d-fbe500ccdfe1", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "departure_time": "06:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "3cebb658-80c4-4f17-885c-36ff3530b4b4", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "departure_time": "07:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "fa3320f4-e237-49fa-812e-89f1956e60c8", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "departure_time": "08:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "6b5f2351-2bc8-48cf-93c0-77706d811c5b", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "departure_time": "12:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "5cdd8930-d26e-4362-8cd0-39bf5cc64d2b", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "departure_time": "17:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "86df144c-299d-4622-9ccb-e17c213e7b72", - "route_id": "27ef54e9-196f-478f-ba56-9d46c0949098", - "departure_time": "18:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "717c6d4c-0a56-44d1-b1bc-88d850fbe577", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "departure_time": "08:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "137ef5a1-0e2a-4dfb-b51d-151aeaacbd6d", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "departure_time": "14:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "f5bcd221-439c-4e0a-adb2-c915b9ea96cd", - "route_id": "22dc631f-1f8c-4a34-9f3e-1dc450d9be9a", - "departure_time": "18:00:00", - "frequency_minutes": 60, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "b0fb43f1-e784-4a61-b756-f0a8d2dc99f8", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "departure_time": "05:30:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "c6d3e0fe-c45e-45c1-b547-e298f2cdd1a3", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "departure_time": "06:15:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "82418469-1006-409a-adf0-6b0dfe820174", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "departure_time": "07:00:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "3912cd14-9e3f-4d5b-bfa4-2459f2b6d3df", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "departure_time": "07:45:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "d38b3a5d-d63d-47ab-a15f-7c3d2c861751", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "departure_time": "16:00:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "6d2384f4-dea2-45ce-824d-015276233f0a", - "route_id": "6239c83b-7466-476f-be54-df33977fc32e", - "departure_time": "17:00:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "7bd76de1-b769-4ea3-9983-478b536aa4d6", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "departure_time": "09:00:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "bb10d088-7b96-4757-b73f-fc915aa0fd42", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "departure_time": "15:00:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - }, - { - "id": "4a2d2f5d-e2f9-41a7-95a0-4bffff86d152", - "route_id": "9d315fa5-f87e-4737-8013-9fe2617ffb23", - "departure_time": "18:30:00", - "frequency_minutes": 45, - "schedule_type": "weekday", - "is_active": true, - "notes": null - } - ] -} \ No newline at end of file diff --git a/backend/docker-entrypoint.sh b/backend/docker-entrypoint.sh deleted file mode 100644 index c3047d8..0000000 --- a/backend/docker-entrypoint.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -set -e - -echo "Starting application startup sequence..." - -# Run migrations -echo "Running database migrations..." -uv run alembic upgrade head - -# Optionally run seeders if RUN_SEEDERS environment variable is set -if [ "${RUN_SEEDERS:-false}" = "true" ]; then - echo "Running database seeders..." - uv run python -m app.core.seed -else - echo "Skipping seeders (set RUN_SEEDERS=true to enable)" -fi - -# Start the application -echo "Starting FastAPI application..." -exec "$@" - diff --git a/backend/get_remote_users.py b/backend/get_remote_users.py deleted file mode 100644 index 11ce160..0000000 --- a/backend/get_remote_users.py +++ /dev/null @@ -1,40 +0,0 @@ -import requests - -def get_vertexdc_users(): - api_url = "https://api.sibu.vertexdc.com" - login_data = { - "email": "admin@sibu.com", - "password": "admin", - "keep_session": True - } - - print(f"Logging in to {api_url}/api/auth/login...") - try: - response = requests.post(f"{api_url}/api/auth/login", json=login_data) - if response.status_code != 200: - print(f"Login failed: {response.status_code} - {response.text}") - return - - token_data = response.json() - token = token_data.get("access_token") - print("Login successful!") - - headers = {"Authorization": f"Bearer {token}"} - - # Try to search for '@' to get all users or use search with empty string if allowed - print("Fetching users via /api/users/search?email=...") - search_response = requests.get(f"{api_url}/api/users/search", params={"email": ""}, headers=headers) - - if search_response.status_code == 200: - users = search_response.json() - print(f"Found {len(users)} users:") - for u in users: - print(f"- {u['full_name']} ({u['email']}) Role: {u['role']}") - else: - print(f"Search failed: {search_response.status_code} - {search_response.text}") - - except Exception as e: - print(f"Error: {e}") - -if __name__ == "__main__": - get_vertexdc_users() diff --git a/backend/get_remote_users_db.py b/backend/get_remote_users_db.py deleted file mode 100644 index 5333077..0000000 --- a/backend/get_remote_users_db.py +++ /dev/null @@ -1,21 +0,0 @@ -from sqlmodel import Session, select, create_engine -from app.models.user import User - -def get_remote_users(): - # Trying the IP of api.sibu.vertexdc.com - url = "postgresql+psycopg2://sibu:xajqcG2nYUoLXCBQYYYN7U23AZp2JWZNmDwo9ivrp6RnwcUcANPfhVXy2AM7J0sm@74.208.39.48:5432/sibu" - print(f"Attempting to connect to: {url}") - try: - engine = create_engine(url, connect_args={'connect_timeout': 5}) - with Session(engine) as session: - print("Connection successful! Fetching users...") - statement = select(User) - users = session.exec(statement).all() - print(f"Found {len(users)} users:") - for u in users: - print(f"- {u.full_name} ({u.email}) [Role: {u.role}]") - except Exception as e: - print(f"Connection failed: {e}") - -if __name__ == "__main__": - get_remote_users() diff --git a/backend/get_remote_users_urllib.py b/backend/get_remote_users_urllib.py deleted file mode 100644 index 30c39d3..0000000 --- a/backend/get_remote_users_urllib.py +++ /dev/null @@ -1,43 +0,0 @@ -import urllib.request -import json -import ssl - -def get_vertexdc_users(): - api_url = "https://api.sibu.vertexdc.com" - login_data = json.dumps({ - "email": "admin@sibu.com", - "password": "admin", - "keep_session": True - }).encode('utf-8') - - # Bypass SSL verification if needed (not recommended but for quick dev check) - ctx = ssl.create_default_context() - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - - print(f"Logging in to {api_url}/api/auth/login...") - try: - req = urllib.request.Request(f"{api_url}/api/auth/login", data=login_data, headers={'Content-Type': 'application/json'}) - with urllib.request.urlopen(req, context=ctx) as response: - token_data = json.loads(response.read().decode('utf-8')) - token = token_data.get("access_token") - print("Login successful!") - - headers = {"Authorization": f"Bearer {token}"} - - print("Fetching users via /api/users/search?email=...") - # Search with an empty string to get all users - search_url = f"{api_url}/api/users/search?email=" - req_search = urllib.request.Request(search_url, headers=headers) - - with urllib.request.urlopen(req_search, context=ctx) as response: - users = json.loads(response.read().decode('utf-8')) - print(f"Found {len(users)} users:") - for u in users: - print(f"- {u['full_name']} ({u['email']}) Role: {u['role']}") - - except Exception as e: - print(f"Error: {e}") - -if __name__ == "__main__": - get_vertexdc_users() diff --git a/backend/get_remote_users_v2.py b/backend/get_remote_users_v2.py deleted file mode 100644 index b0f8e70..0000000 --- a/backend/get_remote_users_v2.py +++ /dev/null @@ -1,55 +0,0 @@ -import urllib.request -import json -import ssl - -def get_vertexdc_users_via_api(): - api_url = "https://api.sibu.vertexdc.com" - # Admin credentials the user gave me - login_data = json.dumps({ - "email": "admin@sibu.com", - "password": "admin", - "keep_session": True - }).encode('utf-8') - - ctx = ssl.create_default_context() - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - - print(f"Attempting login to {api_url}/api/auth/login...") - try: - req = urllib.request.Request(f"{api_url}/api/auth/login", data=login_data, headers={'Content-Type': 'application/json'}) - with urllib.request.urlopen(req, context=ctx) as response: - token_data = json.loads(response.read().decode('utf-8')) - token = token_data.get("access_token") - print("Login successful!") - - headers = {"Authorization": f"Bearer {token}"} - - # Try different search terms to find users - search_terms = ["@", ".com", "admin", "promo", "usuario"] - all_users = {} - - for term in search_terms: - print(f"Searching for users matching '{term}'...") - search_url = f"{api_url}/api/users/search?email={term}" - req_search = urllib.request.Request(search_url, headers=headers) - try: - with urllib.request.urlopen(req_search, context=ctx) as response: - users = json.loads(response.read().decode('utf-8')) - for u in users: - all_users[u['email']] = u - except Exception as e: - print(f"Search for '{term}' failed: {e}") - - if all_users: - print(f"\n✅ Found {len(all_users)} users on VertexDC:") - for email, u in all_users.items(): - print(f"- {u['full_name']} ({email}) [Role: {u['role']}]") - else: - print("\n❌ No users found via API search.") - - except Exception as e: - print(f"Critical error: {e}") - -if __name__ == "__main__": - get_vertexdc_users_via_api() diff --git a/backend/init_db.py b/backend/init_db.py deleted file mode 100644 index 346dcd8..0000000 --- a/backend/init_db.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Script to initialize database and create all tables.""" -from app.core.database import init_db - -if __name__ == "__main__": - print("Creating database tables...") - init_db() - print("Database tables created successfully!") diff --git a/backend/inject_routes.py b/backend/inject_routes.py deleted file mode 100644 index 110f20f..0000000 --- a/backend/inject_routes.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -Script de emergencia: Inyectar rutas directamente en la BD de producción -Ejecutar desde el servidor Render o con acceso directo a la BD. - -USO: python inject_routes.py -""" -import os -import sys - -# Añadir el path del backend -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -from sqlmodel import Session, create_engine, select, SQLModel -from app.models.route import Route, RouteStatus -from app.core.config import settings - -# Rutas de bus más importantes de Boquete / Chiriquí -SAMPLE_ROUTES = [ - { - "name": "Boquete - David", - "origin_city": "Boquete", - "destination_city": "David", - "color": "#FEE715", - "direction": "outbound", - "distance_km": 38.0, - "estimated_duration_minutes": 55, - "average_speed_kmh": 40.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "David - Boquete", - "origin_city": "David", - "destination_city": "Boquete", - "color": "#FEE715", - "direction": "inbound", - "distance_km": 38.0, - "estimated_duration_minutes": 55, - "average_speed_kmh": 40.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "Boquete - Caldera", - "origin_city": "Boquete", - "destination_city": "Caldera", - "color": "#4CAF50", - "direction": "outbound", - "distance_km": 22.0, - "estimated_duration_minutes": 35, - "average_speed_kmh": 38.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "Caldera - Boquete", - "origin_city": "Caldera", - "destination_city": "Boquete", - "color": "#4CAF50", - "direction": "inbound", - "distance_km": 22.0, - "estimated_duration_minutes": 35, - "average_speed_kmh": 38.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "David - Paso Canoas", - "origin_city": "David", - "destination_city": "Paso Canoas", - "color": "#2196F3", - "direction": "outbound", - "distance_km": 52.0, - "estimated_duration_minutes": 70, - "average_speed_kmh": 45.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "David - Cerro Punta", - "origin_city": "David", - "destination_city": "Cerro Punta", - "color": "#9C27B0", - "direction": "outbound", - "distance_km": 75.0, - "estimated_duration_minutes": 100, - "average_speed_kmh": 45.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "David - Volcán", - "origin_city": "David", - "destination_city": "Volcán", - "color": "#FF5722", - "direction": "outbound", - "distance_km": 62.0, - "estimated_duration_minutes": 85, - "average_speed_kmh": 44.0, - "status": RouteStatus.ACTIVE, - }, - { - "name": "Boquete - Dolega", - "origin_city": "Boquete", - "destination_city": "Dolega", - "color": "#00BCD4", - "direction": "outbound", - "distance_km": 28.0, - "estimated_duration_minutes": 40, - "average_speed_kmh": 42.0, - "status": RouteStatus.ACTIVE, - }, -] - - -def inject_routes(): - db_url = settings.get_database_url - engine = create_engine(db_url, echo=True) - - with Session(engine) as session: - inserted = 0 - skipped = 0 - - for route_data in SAMPLE_ROUTES: - # Verificar si ya existe - existing = session.exec( - select(Route).where(Route.name == route_data["name"]) - ).first() - - if existing: - print(f" [SKIP] Ya existe: {route_data['name']}") - skipped += 1 - continue - - route = Route(**route_data) - session.add(route) - print(f" [ADD] {route_data['name']} ({route_data['origin_city']} → {route_data['destination_city']})") - inserted += 1 - - session.commit() - print(f"\n✅ Listo: {inserted} rutas insertadas, {skipped} ya existían.") - - -if __name__ == "__main__": - print("🚌 Inyectando rutas de bus en producción...\n") - inject_routes() diff --git a/backend/inspect_db.py b/backend/inspect_db.py deleted file mode 100644 index 7d58b89..0000000 --- a/backend/inspect_db.py +++ /dev/null @@ -1,15 +0,0 @@ -from sqlalchemy import inspect -from app.core.database import engine - -def inspect_db(): - inspector = inspect(engine) - if 'favorites' in inspector.get_table_names(): - print("Table 'favorites' exists.") - columns = inspector.get_columns('favorites') - for column in columns: - print(f"Column: {column['name']}, Type: {column['type']}") - else: - print("Table 'favorites' does NOT exist.") - -if __name__ == "__main__": - inspect_db() diff --git a/backend/list_paths.py b/backend/list_paths.py deleted file mode 100644 index c05e277..0000000 --- a/backend/list_paths.py +++ /dev/null @@ -1,12 +0,0 @@ -import json - -try: - with open("vertexdc_openapi.json", "r", encoding="utf-16") as f: - data = json.load(f) -except Exception: - with open("vertexdc_openapi.json", "r", encoding="utf-8") as f: - data = json.load(f) - -print("Paths found in OpenAPI:") -for path in sorted(data.get("paths", {}).keys()): - print(f"- {path}") diff --git a/backend/main.py b/backend/main.py deleted file mode 100644 index 1022e2a..0000000 --- a/backend/main.py +++ /dev/null @@ -1,6 +0,0 @@ -def main(): - print("Hello from sibu-backend!") - - -if __name__ == "__main__": - main() diff --git a/backend/migrate_taxis.py b/backend/migrate_taxis.py deleted file mode 100644 index 61c78dc..0000000 --- a/backend/migrate_taxis.py +++ /dev/null @@ -1,25 +0,0 @@ -from app.core.database import engine -from sqlalchemy import text, inspect - -def migrate(): - with engine.connect() as conn: - inspector = inspect(engine) - columns = [c['name'] for c in inspector.get_columns('taxis')] - - if 'rating' not in columns: - print("Adding column rating...") - conn.execute(text("ALTER TABLE taxis ADD COLUMN rating FLOAT DEFAULT 5.0")) - - if 'english_speaking' not in columns: - print("Adding column english_speaking...") - conn.execute(text("ALTER TABLE taxis ADD COLUMN english_speaking BOOLEAN DEFAULT FALSE")) - - if 'image_url' not in columns: - print("Adding column image_url...") - conn.execute(text("ALTER TABLE taxis ADD COLUMN image_url VARCHAR")) - - conn.commit() - print("Migration completed!") - -if __name__ == "__main__": - migrate() diff --git a/backend/parse_openapi.py b/backend/parse_openapi.py deleted file mode 100644 index 15429af..0000000 --- a/backend/parse_openapi.py +++ /dev/null @@ -1,8 +0,0 @@ -import json - -with open("vertexdc_openapi.json", "r") as f: - data = json.load(f) - -for path in data.get("paths", {}): - if "/api/users" in path: - print(path) diff --git a/backend/parse_openapi_v2.py b/backend/parse_openapi_v2.py deleted file mode 100644 index 1d74753..0000000 --- a/backend/parse_openapi_v2.py +++ /dev/null @@ -1,16 +0,0 @@ -import json - -with open("vertexdc_openapi.json", "r", encoding="utf-16" if "\xFF\xFE" in open("vertexdc_openapi.json", "rb").read(2).decode("latin-1", errors="ignore") else "utf-8") as f: - try: - content = f.read() - # Clean potential BOM or leading spaces - content = content.strip() - data = json.loads(content) - for path in data.get("paths", {}): - if "/api/users" in path: - print(path) - except Exception as e: - print(f"Error parsing JSON: {e}") - # Let's print the first 100 chars to see what's wrong - f.seek(0) - print(f"Start of file: {f.read(100)!r}") diff --git a/backend/pyproject.toml b/backend/pyproject.toml deleted file mode 100644 index 9f1c532..0000000 --- a/backend/pyproject.toml +++ /dev/null @@ -1,21 +0,0 @@ -[project] -name = "sibu-backend" -version = "0.1.0" -description = "Add your description here" -requires-python = ">=3.13" -dependencies = [ - "alembic>=1.17.2", - "asyncpg>=0.31.0", - "bcrypt>=5.0.0", - "fastapi[standard]>=0.123.0", - "firebase-admin>=7.1.0", - "passlib>=1.7.4", - "psycopg2-binary>=2.9.11", - "pydantic-settings[dotenv]>=2.12.0", - "python-dotenv>=1.2.1", - "python-jose[cryptography]>=3.5.0", - "python-multipart>=0.0.20", - "ruff>=0.14.10", - "sqlmodel>=0.0.27", - "supabase>=2.24.0", -] diff --git a/backend/reset_favorites.py b/backend/reset_favorites.py deleted file mode 100644 index fb535c5..0000000 --- a/backend/reset_favorites.py +++ /dev/null @@ -1,13 +0,0 @@ -from app.core.database import engine -from app.models.favorite import Favorite - -def reset_favorites(): - # Only drop favorites table - print("Dropping favorites table...") - Favorite.__table__.drop(engine, checkfirst=True) - print("Creating favorites table...") - Favorite.__table__.create(engine) - print("Done.") - -if __name__ == "__main__": - reset_favorites() diff --git a/backend/seed_promos.py b/backend/seed_promos.py deleted file mode 100644 index 19ff5ff..0000000 --- a/backend/seed_promos.py +++ /dev/null @@ -1,106 +0,0 @@ -import sys -import os -from sqlmodel import Session, select - -# Add parent directory to path to import app -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -from app.core.database import engine -from app.models.business import Business -from app.models.coupon import Coupon - -def seed_promos(): - with Session(engine) as session: - # 1. Check if we already have these businesses - biz_name = "Pizzeria El Centro" - biz = session.exec(select(Business).where(Business.name == biz_name)).first() - - if not biz: - biz = Business( - name=biz_name, - category="Restaurante", - address="Calle Central, David", - phone="775-1234", - latitude=8.4272, - longitude=-82.4300, - image_url="/uploads/businesses/pizzeria.jpg" - ) - session.add(biz) - session.commit() - session.refresh(biz) - print(f"Created business: {biz_name}") - else: - # Update coords if needed - biz.latitude = 8.4272 - biz.longitude = -82.4300 - session.add(biz) - session.commit() - print(f"Updated business: {biz_name}") - - # 2. Add a coupon for this business - coupon_title = "Pizzas 2x1 Martes" - coupon = session.exec(select(Coupon).where(Coupon.title == coupon_title)).first() - - if not coupon: - coupon = Coupon( - title=coupon_title, - business_id=biz.id, - business_name=biz.name, - business_address=biz.address, - description="Lleva 2 pizzas al precio de 1 todos los martes.", - category="Restaurante", - discount_percentage=50, - is_active=True, - image_url=biz.image_url - ) - session.add(coupon) - session.commit() - print(f"Created coupon: {coupon_title}") - - # 3. Add second business - biz_name2 = "Heladeria Glacial" - biz2 = session.exec(select(Business).where(Business.name == biz_name2)).first() - - if not biz2: - biz2 = Business( - name=biz_name2, - category="Restaurante", - address="Plaza Terronal, David", - phone="774-5678", - latitude=8.4350, - longitude=-82.4250, - image_url="/uploads/businesses/icecream.jpg" - ) - session.add(biz2) - session.commit() - session.refresh(biz2) - print(f"Created business: {biz_name2}") - else: - biz2.latitude = 8.4350 - biz2.longitude = -82.4250 - session.add(biz2) - session.commit() - print(f"Updated business: {biz_name2}") - - # 4. Add a coupon for second business - coupon_title2 = "30% en Helados" - coupon2 = session.exec(select(Coupon).where(Coupon.title == coupon_title2)).first() - - if not coupon2: - coupon2 = Coupon( - title=coupon_title2, - business_id=biz2.id, - business_name=biz2.name, - business_address=biz2.address, - description="30% de descuento en el segundo helado.", - category="Restaurante", - discount_percentage=30, - is_active=True, - image_url=biz2.image_url - ) - session.add(coupon2) - session.commit() - print(f"Created coupon: {coupon_title2}") - -if __name__ == "__main__": - seed_promos() diff --git a/backend/seed_shuttles.py b/backend/seed_shuttles.py deleted file mode 100644 index 842143e..0000000 --- a/backend/seed_shuttles.py +++ /dev/null @@ -1,84 +0,0 @@ -from app.core.database import engine, init_db -from app.models.shuttle import Shuttle -from sqlmodel import Session, select -import uuid - -def seed_shuttles(): - # Ensure table exists - init_db() - - shuttles_data = [ - { - 'route_name': 'Boquete > Santa Catalina', - 'origin': 'Boquete', - 'destination': 'Santa Catalina', - 'vehicle_type': 'Mini Van Compartida', - 'company_name': 'Chiriqui Transfers', - 'trip_type': 'one_way', - 'price_per_person': 35.0, - 'price_private_trip': 180.0, - 'estimated_duration': '4.5 horas', - 'departure_times': 'Todos los días 8:00 AM', - 'contact_whatsapp': '+50760000000', - 'description': 'Viaje directo desde el centro de Boquete hasta Santa Catalina. Ideal para surfistas y turistas.', - 'is_active': True - }, - { - 'route_name': 'Boquete > Bocas del Toro', - 'origin': 'Boquete', - 'destination': 'Bocas del Toro', - 'vehicle_type': 'Mini Van + Bote', - 'company_name': 'Hello Panama Tours', - 'trip_type': 'one_way', - 'price_per_person': 30.0, - 'price_private_trip': 150.0, - 'estimated_duration': '3.5 horas', - 'departure_times': 'Diario 8:00 AM / 12:00 PM', - 'contact_whatsapp': '+50760000000', - 'description': 'Incluye transporte terrestre hasta Almirante y el bote taxi hacia Isla Colón.', - 'is_active': True - }, - { - 'route_name': 'Boquete > Las Lajas', - 'origin': 'Boquete', - 'destination': 'Las Lajas', - 'vehicle_type': 'Vehículo Privado', - 'company_name': 'Express Boquete', - 'trip_type': 'both', - 'price_per_person': 20.0, - 'price_private_trip': 100.0, - 'estimated_duration': '2 horas', - 'departure_times': 'Bajo demanda', - 'contact_whatsapp': '+50760000000', - 'description': 'Transporte directo a la playa de Las Lajas. Regreso incluido opcional.', - 'is_active': True - }, - { - 'route_name': 'Boquete > Puerto Armuelles', - 'origin': 'Boquete', - 'destination': 'Puerto Armuelles', - 'vehicle_type': 'Sedán Privado', - 'company_name': 'Taxi Chiriqui', - 'trip_type': 'one_way', - 'price_per_person': 25.0, - 'price_private_trip': 120.0, - 'estimated_duration': '2.5 horas', - 'departure_times': 'Bajo demanda', - 'contact_whatsapp': '+50760000000', - 'description': 'Viaje cómodo y seguro hacia el puerto y las playas del sur.', - 'is_active': True - } - ] - - with Session(engine) as session: - for data in shuttles_data: - statement = select(Shuttle).where(Shuttle.route_name == data['route_name']) - existing = session.exec(statement).first() - if not existing: - shuttle = Shuttle(**data) - session.add(shuttle) - session.commit() - print(f"✅ Inserted shuttles successfully!") - -if __name__ == "__main__": - seed_shuttles() diff --git a/backend/seed_taxis.py b/backend/seed_taxis.py deleted file mode 100644 index a0d83c7..0000000 --- a/backend/seed_taxis.py +++ /dev/null @@ -1,82 +0,0 @@ -from app.core.database import engine -from sqlalchemy import text -import uuid - -def seed_taxis(): - taxis_data = [ - { - 'id': str(uuid.uuid4()), - 'owner_name': 'Taxi Volcán Express', - 'phone_number': '+507 771-3344', - 'license_plate': 'CHI-1234', - 'cooperative': 'Cooperativa Boquete', - 'corregimiento': 'Boquete', - 'shift': 'dia', - 'rating': 4.5, - 'english_speaking': True, - 'is_active': True - }, - { - 'id': str(uuid.uuid4()), - 'owner_name': 'Taxi Taroe Boquete', - 'phone_number': '+507 722-8890', - 'license_plate': 'CHI-5678', - 'cooperative': 'Cooperativa Boquete', - 'corregimiento': 'David - Boquete', - 'shift': 'tarde', - 'rating': 5.0, - 'english_speaking': True, - 'is_active': True - }, - { - 'id': str(uuid.uuid4()), - 'owner_name': 'Taxi Aeropuerto Express', - 'phone_number': '+507 788-9900', - 'license_plate': 'CHI-9012', - 'cooperative': None, - 'corregimiento': 'Aeropuerto - Boquete', - 'shift': 'dia', - 'rating': 4.8, - 'english_speaking': True, - 'is_active': True - }, - { - 'id': str(uuid.uuid4()), - 'owner_name': 'Taxi Nocturno Boquete', - 'phone_number': '+507 755-4433', - 'license_plate': 'CHI-3456', - 'cooperative': 'Cooperativa Boquete', - 'corregimiento': 'Boquete - David', - 'shift': 'noche', - 'rating': 4.2, - 'english_speaking': False, - 'is_active': True - }, - { - 'id': str(uuid.uuid4()), - 'owner_name': 'Taxi Local Boquete', - 'phone_number': '+507 766-5544', - 'license_plate': 'CHI-7890', - 'cooperative': None, - 'corregimiento': 'Boquete', - 'shift': 'tarde', - 'rating': 4.7, - 'english_speaking': False, - 'is_active': True - } - ] - - with engine.connect() as conn: - for taxi in taxis_data: - conn.execute(text(""" - INSERT INTO taxis (id, owner_name, phone_number, license_plate, cooperative, - corregimiento, shift, rating, english_speaking, is_active) - VALUES (:id, :owner_name, :phone_number, :license_plate, :cooperative, - :corregimiento, :shift, :rating, :english_speaking, :is_active) - ON CONFLICT (license_plate) DO NOTHING - """), taxi) - conn.commit() - print(f"✅ Inserted {len(taxis_data)} taxis successfully!") - -if __name__ == "__main__": - seed_taxis() diff --git a/backend/seed_test_data.py b/backend/seed_test_data.py deleted file mode 100644 index f498110..0000000 --- a/backend/seed_test_data.py +++ /dev/null @@ -1,58 +0,0 @@ -from sqlmodel import Session -from app.core.database import engine -from app.models.business import Business -from app.models.coupon import Coupon -from datetime import datetime, timedelta -import random - -def seed_data(): - with Session(engine) as session: - # 5 Tourist Spots (Businesses) - categories = ["Restaurante", "Area Turistica", "Bebidas", "Viajes de Turismo"] - - tourist_spots = [ - {"name": "Finca El Explorador", "area": "Boquete", "lat": 8.7845, "lng": -82.4350}, - {"name": "Cascada San Ramón", "area": "Boquete", "lat": 8.8120, "lng": -82.4650}, - {"name": "Balneario Majagua", "area": "Dolega", "lat": 8.5550, "lng": -82.4210}, - {"name": "Parque Miguel de Cervantes", "area": "David", "lat": 8.4275, "lng": -82.4285}, - {"name": "Cangilones de Gualaca", "area": "Dolega", "lat": 8.5230, "lng": -82.3120} - ] - - created_businesses = [] - for spot in tourist_spots: - biz = Business( - name=spot["name"], - address=f"Cerca de {spot['name']}, sector {spot['area']}", - phone=f"6{random.randint(1000000, 9999999)}", - category=random.choice(categories), - area=spot["area"], - latitude=spot["lat"], - longitude=spot["lng"] - ) - session.add(biz) - session.flush() # To get the ID - created_businesses.append(biz) - - # 5 Coupons (Offers) - for i in range(5): - biz = random.choice(created_businesses) - coupon = Coupon( - title=f"Oferta Especial {i+1} - {biz.name}", - description=f"¡Aprovecha esta increíble oferta en {biz.name}! Solo por tiempo limitado.", - business_id=biz.id, - business_name=biz.name, - business_address=biz.address, - business_phone=biz.phone, - category=biz.category, - discount_percentage=random.randint(10, 50), - valid_from=datetime.now().isoformat(), - valid_until=(datetime.now() + timedelta(days=30)).isoformat(), - is_active=True - ) - session.add(coupon) - - session.commit() - print("Successfully seeded 5 tourist spots and 5 offers.") - -if __name__ == "__main__": - seed_data() diff --git a/backend/seed_tourist_spots.py b/backend/seed_tourist_spots.py deleted file mode 100644 index d5e90e8..0000000 --- a/backend/seed_tourist_spots.py +++ /dev/null @@ -1,70 +0,0 @@ -from sqlmodel import Session, select -from app.core.database import engine -from app.models.business import Business - -def seed_tourist_spots(): - spots = [ - { - "name": "Mi Jardín es Su Jardín", - "category": "Area Turistica", - "address": "Entrada de Boquete", - "phone": "+507 720-1234", - "latitude": 8.7770, - "longitude": -82.4330, - "social_media": "@jardin_boquete", - "image_url": "/uploads/mijardin.jpg" - }, - { - "name": "Boquete Brewing Company", - "category": "Bebidas", - "address": "Calle Principal, Boquete", - "phone": "+507 720-5678", - "latitude": 8.7760, - "longitude": -82.4350, - "social_media": "@boquetebrewing", - "image_url": "/uploads/brewing.jpg" - }, - { - "name": "CEFATI - Info Turística", - "category": "Area Turistica", - "address": "Bajo Boquete", - "phone": "+507 720-9999", - "latitude": 8.7690, - "longitude": -82.4300, - "social_media": "@turismoboquete", - "image_url": "/uploads/cefati.jpg" - }, - { - "name": "Kotowa Coffee House", - "category": "Restaurante", - "address": "Plaza Los Delfines", - "phone": "+507 720-4444", - "latitude": 8.7775, - "longitude": -82.4325, - "social_media": "@kotowacoffee", - "image_url": "/uploads/kotowa.jpg" - }, - { - "name": "Biblioteca de Boquete", - "category": "Area Turistica", - "address": "Av. Central", - "phone": "+507 720-1111", - "latitude": 8.7765, - "longitude": -82.4310, - "social_media": "@biblio_boquete", - "image_url": "/uploads/biblioteca.jpg" - } - ] - - with Session(engine) as session: - for spot_data in spots: - # Check if exists - existing = session.exec(select(Business).where(Business.name == spot_data["name"])).first() - if not existing: - business = Business(**spot_data) - session.add(business) - session.commit() - print("Tourist spots seeded successfully!") - -if __name__ == "__main__": - seed_tourist_spots() diff --git a/backend/seed_users.py b/backend/seed_users.py deleted file mode 100644 index c4438db..0000000 --- a/backend/seed_users.py +++ /dev/null @@ -1,95 +0,0 @@ -from sqlmodel import Session, select -from app.core.database import engine -from app.models.user import User, UserRole, DriverProfile, VehicleType -from app.models.telemetry import Telemetry, VehicleStatus -from app.core.security import get_password_hash -from datetime import datetime - -def seed_users(): - users_to_create = [ - { - "email": "admin@sibu.com", - "password": "admin", - "full_name": "Administrador Sistema", - "role": UserRole.ADMIN - }, - { - "email": "promo@sibu.com", - "password": "promo", - "full_name": "Promotor de Negocios", - "role": UserRole.PROMOTER - }, - { - "email": "usuario@sibu.com", - "password": "usuario", - "full_name": "Usuario Pasajero", - "role": UserRole.PASSENGER - }, - { - "email": "conductor@sibu.com", - "password": "conductor", - "full_name": "Juan Perez (Conductor)", - "role": UserRole.DRIVER - } - ] - - with Session(engine) as session: - for u_data in users_to_create: - existing = session.exec(select(User).where(User.email == u_data["email"])).first() - if existing: - print(f"User {u_data['email']} already exists. Updating password and role.") - existing.hashed_password = get_password_hash(u_data["password"]) - existing.role = u_data["role"] - session.add(existing) - session.commit() - session.refresh(existing) - user = existing - else: - user = User( - email=u_data["email"], - full_name=u_data["full_name"], - hashed_password=get_password_hash(u_data["password"]), - role=u_data["role"], - is_active=True, - is_verified=True - ) - session.add(user) - session.commit() - session.refresh(user) - print(f"Created user: {u_data['email']}") - - # If it's a driver, ensure they have a profile - if user.role == UserRole.DRIVER: - profile = session.exec(select(DriverProfile).where(DriverProfile.user_id == user.id)).first() - if not profile: - profile = DriverProfile( - user_id=user.id, - cedula="8-000-0000", - vehicle_type=VehicleType.BUS, - license_plate="BUS-1234", - cooperative_name="Cooperativa David-Boquete", - shift="Mañana", - speaks_english=True - ) - session.add(profile) - print(f"Created driver profile for {user.email}") - - # Add sample telemetry for the driver (near David/Boquete area) - # David coordinates approx: 8.43, -82.43 - telemetry = Telemetry( - user_id=user.id, - latitude=8.435, - longitude=-82.428, - status=VehicleStatus.ACTIVE, - speed=0.0, - heading=0.0, - timestamp=datetime.utcnow() - ) - session.add(telemetry) - print(f"Added sample telemetry for driver {user.email}") - - session.commit() - print("User seeding completed successfully.") - -if __name__ == "__main__": - seed_users() diff --git a/backend/setup_db.py b/backend/setup_db.py deleted file mode 100644 index bc842ef..0000000 --- a/backend/setup_db.py +++ /dev/null @@ -1,24 +0,0 @@ -import asyncio -import asyncpg - -async def setup_db(): - try: - # Connect to default postgres DB - conn = await asyncpg.connect("postgresql://postgres:postgres@localhost:5432/postgres") - - # Check if sibu exists - dbs = await conn.fetch("SELECT datname FROM pg_database WHERE datname = 'sibu'") - if not dbs: - print("Creating database 'sibu'...") - # We can't run CREATE DATABASE inside a transaction - await conn.execute("CREATE DATABASE sibu") - print("Database 'sibu' created!") - else: - print("Database 'sibu' already exists.") - - await conn.close() - except Exception as e: - print(f"Error: {e}") - -if __name__ == "__main__": - asyncio.run(setup_db()) diff --git a/backend/test_db_fix.py b/backend/test_db_fix.py deleted file mode 100644 index 42313f2..0000000 --- a/backend/test_db_fix.py +++ /dev/null @@ -1,20 +0,0 @@ -from sqlmodel import Session, create_engine, text -from app.core.config import settings - -def test_conn(): - url = settings.database_url.replace("+asyncpg", "+psycopg2") - # Try adding .supabase.co if it's missing the dot - if "ggo08co8sokggcc040o800c4" in url and "supabase.co" not in url: - url = url.replace("ggo08co8sokggcc040o800c4", "db.ggo08co8sokggcc040o800c4.supabase.co") - - print(f"Testing URL: {url}") - try: - engine = create_engine(url) - with Session(engine) as session: - session.exec(text("SELECT 1")) - print("Connection successful!") - except Exception as e: - print(f"Connection failed: {e}") - -if __name__ == "__main__": - test_conn() diff --git a/backend/uv.lock b/backend/uv.lock deleted file mode 100644 index fd24e3b..0000000 --- a/backend/uv.lock +++ /dev/null @@ -1,1980 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.13" -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version < '3.14'", -] - -[[package]] -name = "alembic" -version = "1.17.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mako" }, - { name = "sqlalchemy" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064, upload-time = "2025-11-14T20:35:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554, upload-time = "2025-11-14T20:35:05.699Z" }, -] - -[[package]] -name = "annotated-doc" -version = "0.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/16/ce/8a777047513153587e5434fd752e89334ac33e379aa3497db860eeb60377/anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0", size = 228266, upload-time = "2025-11-28T23:37:38.911Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362, upload-time = "2025-11-28T23:36:57.897Z" }, -] - -[[package]] -name = "asyncpg" -version = "0.31.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cc/d18065ce2380d80b1bcce927c24a2642efd38918e33fd724bc4bca904877/asyncpg-0.31.0.tar.gz", hash = "sha256:c989386c83940bfbd787180f2b1519415e2d3d6277a70d9d0f0145ac73500735", size = 993667, upload-time = "2025-11-24T23:27:00.812Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/11/97b5c2af72a5d0b9bc3fa30cd4b9ce22284a9a943a150fdc768763caf035/asyncpg-0.31.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c204fab1b91e08b0f47e90a75d1b3c62174dab21f670ad6c5d0f243a228f015b", size = 661111, upload-time = "2025-11-24T23:26:04.467Z" }, - { url = "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:54a64f91839ba59008eccf7aad2e93d6e3de688d796f35803235ea1c4898ae1e", size = 636928, upload-time = "2025-11-24T23:26:05.944Z" }, - { url = "https://files.pythonhosted.org/packages/2e/fc/9e3486fb2bbe69d4a867c0b76d68542650a7ff1574ca40e84c3111bb0c6e/asyncpg-0.31.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0e0822b1038dc7253b337b0f3f676cadc4ac31b126c5d42691c39691962e403", size = 3424067, upload-time = "2025-11-24T23:26:07.957Z" }, - { url = "https://files.pythonhosted.org/packages/12/c6/8c9d076f73f07f995013c791e018a1cd5f31823c2a3187fc8581706aa00f/asyncpg-0.31.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bef056aa502ee34204c161c72ca1f3c274917596877f825968368b2c33f585f4", size = 3518156, upload-time = "2025-11-24T23:26:09.591Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3b/60683a0baf50fbc546499cfb53132cb6835b92b529a05f6a81471ab60d0c/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0bfbcc5b7ffcd9b75ab1558f00db2ae07db9c80637ad1b2469c43df79d7a5ae2", size = 3319636, upload-time = "2025-11-24T23:26:11.168Z" }, - { url = "https://files.pythonhosted.org/packages/50/dc/8487df0f69bd398a61e1792b3cba0e47477f214eff085ba0efa7eac9ce87/asyncpg-0.31.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22bc525ebbdc24d1261ecbf6f504998244d4e3be1721784b5f64664d61fbe602", size = 3472079, upload-time = "2025-11-24T23:26:13.164Z" }, - { url = "https://files.pythonhosted.org/packages/13/a1/c5bbeeb8531c05c89135cb8b28575ac2fac618bcb60119ee9696c3faf71c/asyncpg-0.31.0-cp313-cp313-win32.whl", hash = "sha256:f890de5e1e4f7e14023619399a471ce4b71f5418cd67a51853b9910fdfa73696", size = 527606, upload-time = "2025-11-24T23:26:14.78Z" }, - { url = "https://files.pythonhosted.org/packages/91/66/b25ccb84a246b470eb943b0107c07edcae51804912b824054b3413995a10/asyncpg-0.31.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc5f2fa9916f292e5c5c8b2ac2813763bcd7f58e130055b4ad8a0531314201ab", size = 596569, upload-time = "2025-11-24T23:26:16.189Z" }, - { url = "https://files.pythonhosted.org/packages/3c/36/e9450d62e84a13aea6580c83a47a437f26c7ca6fa0f0fd40b6670793ea30/asyncpg-0.31.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f6b56b91bb0ffc328c4e3ed113136cddd9deefdf5f79ab448598b9772831df44", size = 660867, upload-time = "2025-11-24T23:26:17.631Z" }, - { url = "https://files.pythonhosted.org/packages/82/4b/1d0a2b33b3102d210439338e1beea616a6122267c0df459ff0265cd5807a/asyncpg-0.31.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:334dec28cf20d7f5bb9e45b39546ddf247f8042a690bff9b9573d00086e69cb5", size = 638349, upload-time = "2025-11-24T23:26:19.689Z" }, - { url = "https://files.pythonhosted.org/packages/41/aa/e7f7ac9a7974f08eff9183e392b2d62516f90412686532d27e196c0f0eeb/asyncpg-0.31.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98cc158c53f46de7bb677fd20c417e264fc02b36d901cc2a43bd6cb0dc6dbfd2", size = 3410428, upload-time = "2025-11-24T23:26:21.275Z" }, - { url = "https://files.pythonhosted.org/packages/6f/de/bf1b60de3dede5c2731e6788617a512bc0ebd9693eac297ee74086f101d7/asyncpg-0.31.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9322b563e2661a52e3cdbc93eed3be7748b289f792e0011cb2720d278b366ce2", size = 3471678, upload-time = "2025-11-24T23:26:23.627Z" }, - { url = "https://files.pythonhosted.org/packages/46/78/fc3ade003e22d8bd53aaf8f75f4be48f0b460fa73738f0391b9c856a9147/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19857a358fc811d82227449b7ca40afb46e75b33eb8897240c3839dd8b744218", size = 3313505, upload-time = "2025-11-24T23:26:25.235Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e9/73eb8a6789e927816f4705291be21f2225687bfa97321e40cd23055e903a/asyncpg-0.31.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ba5f8886e850882ff2c2ace5732300e99193823e8107e2c53ef01c1ebfa1e85d", size = 3434744, upload-time = "2025-11-24T23:26:26.944Z" }, - { url = "https://files.pythonhosted.org/packages/08/4b/f10b880534413c65c5b5862f79b8e81553a8f364e5238832ad4c0af71b7f/asyncpg-0.31.0-cp314-cp314-win32.whl", hash = "sha256:cea3a0b2a14f95834cee29432e4ddc399b95700eb1d51bbc5bfee8f31fa07b2b", size = 532251, upload-time = "2025-11-24T23:26:28.404Z" }, - { url = "https://files.pythonhosted.org/packages/d3/2d/7aa40750b7a19efa5d66e67fc06008ca0f27ba1bd082e457ad82f59aba49/asyncpg-0.31.0-cp314-cp314-win_amd64.whl", hash = "sha256:04d19392716af6b029411a0264d92093b6e5e8285ae97a39957b9a9c14ea72be", size = 604901, upload-time = "2025-11-24T23:26:30.34Z" }, - { url = "https://files.pythonhosted.org/packages/ce/fe/b9dfe349b83b9dee28cc42360d2c86b2cdce4cb551a2c2d27e156bcac84d/asyncpg-0.31.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bdb957706da132e982cc6856bb2f7b740603472b54c3ebc77fe60ea3e57e1bd2", size = 702280, upload-time = "2025-11-24T23:26:32Z" }, - { url = "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6d11b198111a72f47154fa03b85799f9be63701e068b43f84ac25da0bda9cb31", size = 682931, upload-time = "2025-11-24T23:26:33.572Z" }, - { url = "https://files.pythonhosted.org/packages/a6/45/6009040da85a1648dd5bc75b3b0a062081c483e75a1a29041ae63a0bf0dc/asyncpg-0.31.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18c83b03bc0d1b23e6230f5bf8d4f217dc9bc08644ce0502a9d91dc9e634a9c7", size = 3581608, upload-time = "2025-11-24T23:26:35.638Z" }, - { url = "https://files.pythonhosted.org/packages/7e/06/2e3d4d7608b0b2b3adbee0d0bd6a2d29ca0fc4d8a78f8277df04e2d1fd7b/asyncpg-0.31.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e009abc333464ff18b8f6fd146addffd9aaf63e79aa3bb40ab7a4c332d0c5e9e", size = 3498738, upload-time = "2025-11-24T23:26:37.275Z" }, - { url = "https://files.pythonhosted.org/packages/7d/aa/7d75ede780033141c51d83577ea23236ba7d3a23593929b32b49db8ed36e/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3b1fbcb0e396a5ca435a8826a87e5c2c2cc0c8c68eb6fadf82168056b0e53a8c", size = 3401026, upload-time = "2025-11-24T23:26:39.423Z" }, - { url = "https://files.pythonhosted.org/packages/ba/7a/15e37d45e7f7c94facc1e9148c0e455e8f33c08f0b8a0b1deb2c5171771b/asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8df714dba348efcc162d2adf02d213e5fab1bd9f557e1305633e851a61814a7a", size = 3429426, upload-time = "2025-11-24T23:26:41.032Z" }, - { url = "https://files.pythonhosted.org/packages/13/d5/71437c5f6ae5f307828710efbe62163974e71237d5d46ebd2869ea052d10/asyncpg-0.31.0-cp314-cp314t-win32.whl", hash = "sha256:1b41f1afb1033f2b44f3234993b15096ddc9cd71b21a42dbd87fc6a57b43d65d", size = 614495, upload-time = "2025-11-24T23:26:42.659Z" }, - { url = "https://files.pythonhosted.org/packages/3c/d7/8fb3044eaef08a310acfe23dae9a8e2e07d305edc29a53497e52bc76eca7/asyncpg-0.31.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bd4107bb7cdd0e9e65fae66a62afd3a249663b844fa34d479f6d5b3bef9c04c3", size = 706062, upload-time = "2025-11-24T23:26:44.086Z" }, -] - -[[package]] -name = "bcrypt" -version = "5.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/36/3329e2518d70ad8e2e5817d5a4cac6bba05a47767ec416c7d020a965f408/bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd", size = 25386, upload-time = "2025-09-25T19:50:47.829Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/85/3e65e01985fddf25b64ca67275bb5bdb4040bd1a53b66d355c6c37c8a680/bcrypt-5.0.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f3c08197f3039bec79cee59a606d62b96b16669cff3949f21e74796b6e3cd2be", size = 481806, upload-time = "2025-09-25T19:49:05.102Z" }, - { url = "https://files.pythonhosted.org/packages/44/dc/01eb79f12b177017a726cbf78330eb0eb442fae0e7b3dfd84ea2849552f3/bcrypt-5.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:200af71bc25f22006f4069060c88ed36f8aa4ff7f53e67ff04d2ab3f1e79a5b2", size = 268626, upload-time = "2025-09-25T19:49:06.723Z" }, - { url = "https://files.pythonhosted.org/packages/8c/cf/e82388ad5959c40d6afd94fb4743cc077129d45b952d46bdc3180310e2df/bcrypt-5.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:baade0a5657654c2984468efb7d6c110db87ea63ef5a4b54732e7e337253e44f", size = 271853, upload-time = "2025-09-25T19:49:08.028Z" }, - { url = "https://files.pythonhosted.org/packages/ec/86/7134b9dae7cf0efa85671651341f6afa695857fae172615e960fb6a466fa/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c58b56cdfb03202b3bcc9fd8daee8e8e9b6d7e3163aa97c631dfcfcc24d36c86", size = 269793, upload-time = "2025-09-25T19:49:09.727Z" }, - { url = "https://files.pythonhosted.org/packages/cc/82/6296688ac1b9e503d034e7d0614d56e80c5d1a08402ff856a4549cb59207/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bfd2a34de661f34d0bda43c3e4e79df586e4716ef401fe31ea39d69d581ef23", size = 289930, upload-time = "2025-09-25T19:49:11.204Z" }, - { url = "https://files.pythonhosted.org/packages/d1/18/884a44aa47f2a3b88dd09bc05a1e40b57878ecd111d17e5bba6f09f8bb77/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ed2e1365e31fc73f1825fa830f1c8f8917ca1b3ca6185773b349c20fd606cec2", size = 272194, upload-time = "2025-09-25T19:49:12.524Z" }, - { url = "https://files.pythonhosted.org/packages/0e/8f/371a3ab33c6982070b674f1788e05b656cfbf5685894acbfef0c65483a59/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:83e787d7a84dbbfba6f250dd7a5efd689e935f03dd83b0f919d39349e1f23f83", size = 269381, upload-time = "2025-09-25T19:49:14.308Z" }, - { url = "https://files.pythonhosted.org/packages/b1/34/7e4e6abb7a8778db6422e88b1f06eb07c47682313997ee8a8f9352e5a6f1/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:137c5156524328a24b9fac1cb5db0ba618bc97d11970b39184c1d87dc4bf1746", size = 271750, upload-time = "2025-09-25T19:49:15.584Z" }, - { url = "https://files.pythonhosted.org/packages/c0/1b/54f416be2499bd72123c70d98d36c6cd61a4e33d9b89562c22481c81bb30/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:38cac74101777a6a7d3b3e3cfefa57089b5ada650dce2baf0cbdd9d65db22a9e", size = 303757, upload-time = "2025-09-25T19:49:17.244Z" }, - { url = "https://files.pythonhosted.org/packages/13/62/062c24c7bcf9d2826a1a843d0d605c65a755bc98002923d01fd61270705a/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d8d65b564ec849643d9f7ea05c6d9f0cd7ca23bdd4ac0c2dbef1104ab504543d", size = 306740, upload-time = "2025-09-25T19:49:18.693Z" }, - { url = "https://files.pythonhosted.org/packages/d5/c8/1fdbfc8c0f20875b6b4020f3c7dc447b8de60aa0be5faaf009d24242aec9/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:741449132f64b3524e95cd30e5cd3343006ce146088f074f31ab26b94e6c75ba", size = 334197, upload-time = "2025-09-25T19:49:20.523Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c1/8b84545382d75bef226fbc6588af0f7b7d095f7cd6a670b42a86243183cd/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:212139484ab3207b1f0c00633d3be92fef3c5f0af17cad155679d03ff2ee1e41", size = 352974, upload-time = "2025-09-25T19:49:22.254Z" }, - { url = "https://files.pythonhosted.org/packages/10/a6/ffb49d4254ed085e62e3e5dd05982b4393e32fe1e49bb1130186617c29cd/bcrypt-5.0.0-cp313-cp313t-win32.whl", hash = "sha256:9d52ed507c2488eddd6a95bccee4e808d3234fa78dd370e24bac65a21212b861", size = 148498, upload-time = "2025-09-25T19:49:24.134Z" }, - { url = "https://files.pythonhosted.org/packages/48/a9/259559edc85258b6d5fc5471a62a3299a6aa37a6611a169756bf4689323c/bcrypt-5.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f6984a24db30548fd39a44360532898c33528b74aedf81c26cf29c51ee47057e", size = 145853, upload-time = "2025-09-25T19:49:25.702Z" }, - { url = "https://files.pythonhosted.org/packages/2d/df/9714173403c7e8b245acf8e4be8876aac64a209d1b392af457c79e60492e/bcrypt-5.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9fffdb387abe6aa775af36ef16f55e318dcda4194ddbf82007a6f21da29de8f5", size = 139626, upload-time = "2025-09-25T19:49:26.928Z" }, - { url = "https://files.pythonhosted.org/packages/f8/14/c18006f91816606a4abe294ccc5d1e6f0e42304df5a33710e9e8e95416e1/bcrypt-5.0.0-cp314-cp314t-macosx_10_12_universal2.whl", hash = "sha256:4870a52610537037adb382444fefd3706d96d663ac44cbb2f37e3919dca3d7ef", size = 481862, upload-time = "2025-09-25T19:49:28.365Z" }, - { url = "https://files.pythonhosted.org/packages/67/49/dd074d831f00e589537e07a0725cf0e220d1f0d5d8e85ad5bbff251c45aa/bcrypt-5.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48f753100931605686f74e27a7b49238122aa761a9aefe9373265b8b7aa43ea4", size = 268544, upload-time = "2025-09-25T19:49:30.39Z" }, - { url = "https://files.pythonhosted.org/packages/f5/91/50ccba088b8c474545b034a1424d05195d9fcbaaf802ab8bfe2be5a4e0d7/bcrypt-5.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70aadb7a809305226daedf75d90379c397b094755a710d7014b8b117df1ebbf", size = 271787, upload-time = "2025-09-25T19:49:32.144Z" }, - { url = "https://files.pythonhosted.org/packages/aa/e7/d7dba133e02abcda3b52087a7eea8c0d4f64d3e593b4fffc10c31b7061f3/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:744d3c6b164caa658adcb72cb8cc9ad9b4b75c7db507ab4bc2480474a51989da", size = 269753, upload-time = "2025-09-25T19:49:33.885Z" }, - { url = "https://files.pythonhosted.org/packages/33/fc/5b145673c4b8d01018307b5c2c1fc87a6f5a436f0ad56607aee389de8ee3/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a28bc05039bdf3289d757f49d616ab3efe8cf40d8e8001ccdd621cd4f98f4fc9", size = 289587, upload-time = "2025-09-25T19:49:35.144Z" }, - { url = "https://files.pythonhosted.org/packages/27/d7/1ff22703ec6d4f90e62f1a5654b8867ef96bafb8e8102c2288333e1a6ca6/bcrypt-5.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7f277a4b3390ab4bebe597800a90da0edae882c6196d3038a73adf446c4f969f", size = 272178, upload-time = "2025-09-25T19:49:36.793Z" }, - { url = "https://files.pythonhosted.org/packages/c8/88/815b6d558a1e4d40ece04a2f84865b0fef233513bd85fd0e40c294272d62/bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:79cfa161eda8d2ddf29acad370356b47f02387153b11d46042e93a0a95127493", size = 269295, upload-time = "2025-09-25T19:49:38.164Z" }, - { url = "https://files.pythonhosted.org/packages/51/8c/e0db387c79ab4931fc89827d37608c31cc57b6edc08ccd2386139028dc0d/bcrypt-5.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a5393eae5722bcef046a990b84dff02b954904c36a194f6cfc817d7dca6c6f0b", size = 271700, upload-time = "2025-09-25T19:49:39.917Z" }, - { url = "https://files.pythonhosted.org/packages/06/83/1570edddd150f572dbe9fc00f6203a89fc7d4226821f67328a85c330f239/bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f4c94dec1b5ab5d522750cb059bb9409ea8872d4494fd152b53cca99f1ddd8c", size = 334034, upload-time = "2025-09-25T19:49:41.227Z" }, - { url = "https://files.pythonhosted.org/packages/c9/f2/ea64e51a65e56ae7a8a4ec236c2bfbdd4b23008abd50ac33fbb2d1d15424/bcrypt-5.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0cae4cb350934dfd74c020525eeae0a5f79257e8a201c0c176f4b84fdbf2a4b4", size = 352766, upload-time = "2025-09-25T19:49:43.08Z" }, - { url = "https://files.pythonhosted.org/packages/d7/d4/1a388d21ee66876f27d1a1f41287897d0c0f1712ef97d395d708ba93004c/bcrypt-5.0.0-cp314-cp314t-win32.whl", hash = "sha256:b17366316c654e1ad0306a6858e189fc835eca39f7eb2cafd6aaca8ce0c40a2e", size = 152449, upload-time = "2025-09-25T19:49:44.971Z" }, - { url = "https://files.pythonhosted.org/packages/3f/61/3291c2243ae0229e5bca5d19f4032cecad5dfb05a2557169d3a69dc0ba91/bcrypt-5.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:92864f54fb48b4c718fc92a32825d0e42265a627f956bc0361fe869f1adc3e7d", size = 149310, upload-time = "2025-09-25T19:49:46.162Z" }, - { url = "https://files.pythonhosted.org/packages/3e/89/4b01c52ae0c1a681d4021e5dd3e45b111a8fb47254a274fa9a378d8d834b/bcrypt-5.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dd19cf5184a90c873009244586396a6a884d591a5323f0e8a5922560718d4993", size = 143761, upload-time = "2025-09-25T19:49:47.345Z" }, - { url = "https://files.pythonhosted.org/packages/84/29/6237f151fbfe295fe3e074ecc6d44228faa1e842a81f6d34a02937ee1736/bcrypt-5.0.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:fc746432b951e92b58317af8e0ca746efe93e66555f1b40888865ef5bf56446b", size = 494553, upload-time = "2025-09-25T19:49:49.006Z" }, - { url = "https://files.pythonhosted.org/packages/45/b6/4c1205dde5e464ea3bd88e8742e19f899c16fa8916fb8510a851fae985b5/bcrypt-5.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c2388ca94ffee269b6038d48747f4ce8df0ffbea43f31abfa18ac72f0218effb", size = 275009, upload-time = "2025-09-25T19:49:50.581Z" }, - { url = "https://files.pythonhosted.org/packages/3b/71/427945e6ead72ccffe77894b2655b695ccf14ae1866cd977e185d606dd2f/bcrypt-5.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:560ddb6ec730386e7b3b26b8b4c88197aaed924430e7b74666a586ac997249ef", size = 278029, upload-time = "2025-09-25T19:49:52.533Z" }, - { url = "https://files.pythonhosted.org/packages/17/72/c344825e3b83c5389a369c8a8e58ffe1480b8a699f46c127c34580c4666b/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d79e5c65dcc9af213594d6f7f1fa2c98ad3fc10431e7aa53c176b441943efbdd", size = 275907, upload-time = "2025-09-25T19:49:54.709Z" }, - { url = "https://files.pythonhosted.org/packages/0b/7e/d4e47d2df1641a36d1212e5c0514f5291e1a956a7749f1e595c07a972038/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2b732e7d388fa22d48920baa267ba5d97cca38070b69c0e2d37087b381c681fd", size = 296500, upload-time = "2025-09-25T19:49:56.013Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c3/0ae57a68be2039287ec28bc463b82e4b8dc23f9d12c0be331f4782e19108/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0c8e093ea2532601a6f686edbc2c6b2ec24131ff5c52f7610dd64fa4553b5464", size = 278412, upload-time = "2025-09-25T19:49:57.356Z" }, - { url = "https://files.pythonhosted.org/packages/45/2b/77424511adb11e6a99e3a00dcc7745034bee89036ad7d7e255a7e47be7d8/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5b1589f4839a0899c146e8892efe320c0fa096568abd9b95593efac50a87cb75", size = 275486, upload-time = "2025-09-25T19:49:59.116Z" }, - { url = "https://files.pythonhosted.org/packages/43/0a/405c753f6158e0f3f14b00b462d8bca31296f7ecfc8fc8bc7919c0c7d73a/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:89042e61b5e808b67daf24a434d89bab164d4de1746b37a8d173b6b14f3db9ff", size = 277940, upload-time = "2025-09-25T19:50:00.869Z" }, - { url = "https://files.pythonhosted.org/packages/62/83/b3efc285d4aadc1fa83db385ec64dcfa1707e890eb42f03b127d66ac1b7b/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e3cf5b2560c7b5a142286f69bde914494b6d8f901aaa71e453078388a50881c4", size = 310776, upload-time = "2025-09-25T19:50:02.393Z" }, - { url = "https://files.pythonhosted.org/packages/95/7d/47ee337dacecde6d234890fe929936cb03ebc4c3a7460854bbd9c97780b8/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f632fd56fc4e61564f78b46a2269153122db34988e78b6be8b32d28507b7eaeb", size = 312922, upload-time = "2025-09-25T19:50:04.232Z" }, - { url = "https://files.pythonhosted.org/packages/d6/3a/43d494dfb728f55f4e1cf8fd435d50c16a2d75493225b54c8d06122523c6/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:801cad5ccb6b87d1b430f183269b94c24f248dddbbc5c1f78b6ed231743e001c", size = 341367, upload-time = "2025-09-25T19:50:05.559Z" }, - { url = "https://files.pythonhosted.org/packages/55/ab/a0727a4547e383e2e22a630e0f908113db37904f58719dc48d4622139b5c/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3cf67a804fc66fc217e6914a5635000259fbbbb12e78a99488e4d5ba445a71eb", size = 359187, upload-time = "2025-09-25T19:50:06.916Z" }, - { url = "https://files.pythonhosted.org/packages/1b/bb/461f352fdca663524b4643d8b09e8435b4990f17fbf4fea6bc2a90aa0cc7/bcrypt-5.0.0-cp38-abi3-win32.whl", hash = "sha256:3abeb543874b2c0524ff40c57a4e14e5d3a66ff33fb423529c88f180fd756538", size = 153752, upload-time = "2025-09-25T19:50:08.515Z" }, - { url = "https://files.pythonhosted.org/packages/41/aa/4190e60921927b7056820291f56fc57d00d04757c8b316b2d3c0d1d6da2c/bcrypt-5.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:35a77ec55b541e5e583eb3436ffbbf53b0ffa1fa16ca6782279daf95d146dcd9", size = 150881, upload-time = "2025-09-25T19:50:09.742Z" }, - { url = "https://files.pythonhosted.org/packages/54/12/cd77221719d0b39ac0b55dbd39358db1cd1246e0282e104366ebbfb8266a/bcrypt-5.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:cde08734f12c6a4e28dc6755cd11d3bdfea608d93d958fffbe95a7026ebe4980", size = 144931, upload-time = "2025-09-25T19:50:11.016Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ba/2af136406e1c3839aea9ecadc2f6be2bcd1eff255bd451dd39bcf302c47a/bcrypt-5.0.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0c418ca99fd47e9c59a301744d63328f17798b5947b0f791e9af3c1c499c2d0a", size = 495313, upload-time = "2025-09-25T19:50:12.309Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ee/2f4985dbad090ace5ad1f7dd8ff94477fe089b5fab2040bd784a3d5f187b/bcrypt-5.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddb4e1500f6efdd402218ffe34d040a1196c072e07929b9820f363a1fd1f4191", size = 275290, upload-time = "2025-09-25T19:50:13.673Z" }, - { url = "https://files.pythonhosted.org/packages/e4/6e/b77ade812672d15cf50842e167eead80ac3514f3beacac8902915417f8b7/bcrypt-5.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7aeef54b60ceddb6f30ee3db090351ecf0d40ec6e2abf41430997407a46d2254", size = 278253, upload-time = "2025-09-25T19:50:15.089Z" }, - { url = "https://files.pythonhosted.org/packages/36/c4/ed00ed32f1040f7990dac7115f82273e3c03da1e1a1587a778d8cea496d8/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f0ce778135f60799d89c9693b9b398819d15f1921ba15fe719acb3178215a7db", size = 276084, upload-time = "2025-09-25T19:50:16.699Z" }, - { url = "https://files.pythonhosted.org/packages/e7/c4/fa6e16145e145e87f1fa351bbd54b429354fd72145cd3d4e0c5157cf4c70/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a71f70ee269671460b37a449f5ff26982a6f2ba493b3eabdd687b4bf35f875ac", size = 297185, upload-time = "2025-09-25T19:50:18.525Z" }, - { url = "https://files.pythonhosted.org/packages/24/b4/11f8a31d8b67cca3371e046db49baa7c0594d71eb40ac8121e2fc0888db0/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8429e1c410b4073944f03bd778a9e066e7fad723564a52ff91841d278dfc822", size = 278656, upload-time = "2025-09-25T19:50:19.809Z" }, - { url = "https://files.pythonhosted.org/packages/ac/31/79f11865f8078e192847d2cb526e3fa27c200933c982c5b2869720fa5fce/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:edfcdcedd0d0f05850c52ba3127b1fce70b9f89e0fe5ff16517df7e81fa3cbb8", size = 275662, upload-time = "2025-09-25T19:50:21.567Z" }, - { url = "https://files.pythonhosted.org/packages/d4/8d/5e43d9584b3b3591a6f9b68f755a4da879a59712981ef5ad2a0ac1379f7a/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:611f0a17aa4a25a69362dcc299fda5c8a3d4f160e2abb3831041feb77393a14a", size = 278240, upload-time = "2025-09-25T19:50:23.305Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/44590e3fc158620f680a978aafe8f87a4c4320da81ed11552f0323aa9a57/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:db99dca3b1fdc3db87d7c57eac0c82281242d1eabf19dcb8a6b10eb29a2e72d1", size = 311152, upload-time = "2025-09-25T19:50:24.597Z" }, - { url = "https://files.pythonhosted.org/packages/5f/85/e4fbfc46f14f47b0d20493669a625da5827d07e8a88ee460af6cd9768b44/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5feebf85a9cefda32966d8171f5db7e3ba964b77fdfe31919622256f80f9cf42", size = 313284, upload-time = "2025-09-25T19:50:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/25/ae/479f81d3f4594456a01ea2f05b132a519eff9ab5768a70430fa1132384b1/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3ca8a166b1140436e058298a34d88032ab62f15aae1c598580333dc21d27ef10", size = 341643, upload-time = "2025-09-25T19:50:28.02Z" }, - { url = "https://files.pythonhosted.org/packages/df/d2/36a086dee1473b14276cd6ea7f61aef3b2648710b5d7f1c9e032c29b859f/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:61afc381250c3182d9078551e3ac3a41da14154fbff647ddf52a769f588c4172", size = 359698, upload-time = "2025-09-25T19:50:31.347Z" }, - { url = "https://files.pythonhosted.org/packages/c0/f6/688d2cd64bfd0b14d805ddb8a565e11ca1fb0fd6817175d58b10052b6d88/bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683", size = 153725, upload-time = "2025-09-25T19:50:34.384Z" }, - { url = "https://files.pythonhosted.org/packages/9f/b9/9d9a641194a730bda138b3dfe53f584d61c58cd5230e37566e83ec2ffa0d/bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2", size = 150912, upload-time = "2025-09-25T19:50:35.69Z" }, - { url = "https://files.pythonhosted.org/packages/27/44/d2ef5e87509158ad2187f4dd0852df80695bb1ee0cfe0a684727b01a69e0/bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927", size = 144953, upload-time = "2025-09-25T19:50:37.32Z" }, -] - -[[package]] -name = "cachecontrol" -version = "0.14.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "msgpack" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2d/f6/c972b32d80760fb79d6b9eeb0b3010a46b89c0b23cf6329417ff7886cd22/cachecontrol-0.14.4.tar.gz", hash = "sha256:e6220afafa4c22a47dd0badb319f84475d79108100d04e26e8542ef7d3ab05a1", size = 16150, upload-time = "2025-11-14T04:32:13.138Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/79/c45f2d53efe6ada1110cf6f9fca095e4ff47a0454444aefdde6ac4789179/cachecontrol-0.14.4-py3-none-any.whl", hash = "sha256:b7ac014ff72ee199b5f8af1de29d60239954f223e948196fa3d84adaffc71d2b", size = 22247, upload-time = "2025-11-14T04:32:11.733Z" }, -] - -[[package]] -name = "certifi" -version = "2025.11.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, -] - -[[package]] -name = "cffi" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, - { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, - { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, - { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, - { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, - { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, - { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, - { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, - { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, - { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, - { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, - { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, - { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, - { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, - { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, - { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, - { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, - { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, - { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, - { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, - { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, - { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, - { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, - { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, - { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, -] - -[[package]] -name = "click" -version = "8.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cryptography" -version = "46.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, - { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, - { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, - { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, - { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, - { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, - { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, - { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, - { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, - { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, - { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, - { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, - { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, - { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, - { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, - { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, - { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, - { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, - { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, - { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, - { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, - { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, - { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, - { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, - { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, - { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, - { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, - { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, - { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, - { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, - { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, - { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, -] - -[[package]] -name = "deprecation" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5a/d3/8ae2869247df154b64c1884d7346d412fed0c49df84db635aab2d1c40e62/deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff", size = 173788, upload-time = "2020-04-20T14:23:38.738Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/c3/253a89ee03fc9b9682f1541728eb66db7db22148cd94f89ab22528cd1e1b/deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a", size = 11178, upload-time = "2020-04-20T14:23:36.581Z" }, -] - -[[package]] -name = "dnspython" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, -] - -[[package]] -name = "ecdsa" -version = "0.19.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/1f/924e3caae75f471eae4b26bd13b698f6af2c44279f67af317439c2f4c46a/ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61", size = 201793, upload-time = "2025-03-13T11:52:43.25Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a3/460c57f094a4a165c84a1341c373b0a4f5ec6ac244b998d5021aade89b77/ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3", size = 150607, upload-time = "2025-03-13T11:52:41.757Z" }, -] - -[[package]] -name = "email-validator" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, -] - -[[package]] -name = "fastapi" -version = "0.123.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-doc" }, - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/c7/d3956d7c2da2b66188eacc8db0919635b28313a30334dd78cba4c366caf0/fastapi-0.123.0.tar.gz", hash = "sha256:1410678b3c44418245eec85088b15140d894074b86e66061017e2b492c09b138", size = 347702, upload-time = "2025-11-30T14:49:17.848Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/17/62c82beab6536ea72576f90b84a3dbe6bcceb88d3d46afc4d05c376f0231/fastapi-0.123.0-py3-none-any.whl", hash = "sha256:cb56e69e874afa897bd3416c8a3dbfdae1730d0a308d4c63303f3f4b44136ae4", size = 110865, upload-time = "2025-11-30T14:49:16.164Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.16" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/75/9407a6b452be4c988feacec9c9d2f58d8f315162a6c7258d5a649d933ebe/fastapi_cli-0.0.16.tar.gz", hash = "sha256:e8a2a1ecf7a4e062e3b2eec63ae34387d1e142d4849181d936b23c4bdfe29073", size = 19447, upload-time = "2025-11-10T19:01:07.856Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/43/678528c19318394320ee43757648d5e0a8070cf391b31f69d931e5c840d2/fastapi_cli-0.0.16-py3-none-any.whl", hash = "sha256:addcb6d130b5b9c91adbbf3f2947fe115991495fdb442fe3e51b5fc6327df9f4", size = 12312, upload-time = "2025-11-10T19:01:06.728Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "fastapi-cloud-cli" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cloud-cli" -version = "0.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fastar" }, - { name = "httpx" }, - { name = "pydantic", extra = ["email"] }, - { name = "rich-toolkit" }, - { name = "rignore" }, - { name = "sentry-sdk" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/27/6c/32527a1fd7eee91dd0c52bbe6b7c21e3272b24beb436b142b2c9c01f922d/fastapi_cloud_cli-0.5.2.tar.gz", hash = "sha256:34d04ffadb2562c3ebb39e6f5a599c47353750f75a2ef0a2d9c1442ed09f3308", size = 30744, upload-time = "2025-11-25T11:06:14.583Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/29/5b46612e48589df93cbd9a77fe35a36315937386f7ecc0f1d7b9b10ad0ca/fastapi_cloud_cli-0.5.2-py3-none-any.whl", hash = "sha256:783ab5e41baf8afcbbfb7e513ac5bdf7376202053b8bf2d158a38978dba1ca69", size = 23218, upload-time = "2025-11-25T11:06:13.215Z" }, -] - -[[package]] -name = "fastar" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/a5/79ecba3646e22d03eef1a66fb7fc156567213e2e4ab9faab3bbd4489e483/fastar-0.8.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a3253a06845462ca2196024c7a18f5c0ba4de1532ab1c4bad23a40b332a06a6a", size = 706112, upload-time = "2025-11-26T02:34:39.237Z" }, - { url = "https://files.pythonhosted.org/packages/0a/03/4f883bce878218a8676c2d7ca09b50c856a5470bb3b7f63baf9521ea6995/fastar-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5cbeb3ebfa0980c68ff8b126295cc6b208ccd81b638aebc5a723d810a7a0e5d2", size = 628954, upload-time = "2025-11-26T02:34:23.705Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f1/892e471f156b03d10ba48ace9384f5a896702a54506137462545f38e40b8/fastar-0.8.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1c0d5956b917daac77d333d48b3f0f3ff927b8039d5b32d8125462782369f761", size = 868685, upload-time = "2025-11-26T02:33:53.077Z" }, - { url = "https://files.pythonhosted.org/packages/39/ba/e24915045852e30014ec6840446975c03f4234d1c9270394b51d3ad18394/fastar-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27b404db2b786b65912927ce7f3790964a4bcbde42cdd13091b82a89cd655e1c", size = 765044, upload-time = "2025-11-26T02:32:48.187Z" }, - { url = "https://files.pythonhosted.org/packages/14/2c/1aa11ac21a99984864c2fca4994e094319ff3a2046e7a0343c39317bd5b9/fastar-0.8.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0902fc89dcf1e7f07b8563032a4159fe2b835e4c16942c76fd63451d0e5f76a3", size = 764322, upload-time = "2025-11-26T02:33:03.859Z" }, - { url = "https://files.pythonhosted.org/packages/ba/f0/4b91902af39fe2d3bae7c85c6d789586b9fbcf618d7fdb3d37323915906d/fastar-0.8.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:069347e2f0f7a8b99bbac8cd1bc0e06c7b4a31dc964fc60d84b95eab3d869dc1", size = 931016, upload-time = "2025-11-26T02:33:19.902Z" }, - { url = "https://files.pythonhosted.org/packages/c9/97/8fc43a5a9c0a2dc195730f6f7a0f367d171282cd8be2511d0e87c6d2dad0/fastar-0.8.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd135306f6bfe9a835918280e0eb440b70ab303e0187d90ab51ca86e143f70d", size = 821308, upload-time = "2025-11-26T02:33:34.664Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e9/058615b63a7fd27965e8c5966f393ed0c169f7ff5012e1674f21684de3ba/fastar-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d06d6897f43c27154b5f2d0eb930a43a81b7eec73f6f0b0114814d4a10ab38", size = 821171, upload-time = "2025-11-26T02:34:08.498Z" }, - { url = "https://files.pythonhosted.org/packages/ca/cf/69e16a17961570a755c37ffb5b5aa7610d2e77807625f537989da66f2a9d/fastar-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a922f8439231fa0c32b15e8d70ff6d415619b9d40492029dabbc14a0c53b5f18", size = 986227, upload-time = "2025-11-26T02:34:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/fb/83/2100192372e59b56f4ace37d7d9cabda511afd71b5febad1643d1c334271/fastar-0.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a739abd51eb766384b4caff83050888e80cd75bbcfec61e6d1e64875f94e4a40", size = 1039395, upload-time = "2025-11-26T02:35:12.166Z" }, - { url = "https://files.pythonhosted.org/packages/75/15/cdd03aca972f55872efbb7cf7540c3fa7b97a75d626303a3ea46932163dc/fastar-0.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5a65f419d808b23ac89d5cd1b13a2f340f15bc5d1d9af79f39fdb77bba48ff1b", size = 1044766, upload-time = "2025-11-26T02:35:29.62Z" }, - { url = "https://files.pythonhosted.org/packages/3d/29/945e69e4e2652329ace545999334ec31f1431fbae3abb0105587e11af2ae/fastar-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7bb2ae6c0cce58f0db1c9f20495e7557cca2c1ee9c69bbd90eafd54f139171c5", size = 994740, upload-time = "2025-11-26T02:35:47.887Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5d/dbfe28f8cd1eb484bba0c62e5259b2cf6fea229d6ef43e05c06b5a78c034/fastar-0.8.0-cp313-cp313-win32.whl", hash = "sha256:b28753e0d18a643272597cb16d39f1053842aa43131ad3e260c03a2417d38401", size = 455990, upload-time = "2025-11-26T02:36:28.502Z" }, - { url = "https://files.pythonhosted.org/packages/e1/01/e965740bd36e60ef4c5aa2cbe42b6c4eb1dc3551009238a97c2e5e96bd23/fastar-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:620e5d737dce8321d49a5ebb7997f1fd0047cde3512082c27dc66d6ac8c1927a", size = 490227, upload-time = "2025-11-26T02:36:14.363Z" }, - { url = "https://files.pythonhosted.org/packages/dd/10/c99202719b83e5249f26902ae53a05aea67d840eeb242019322f20fc171c/fastar-0.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:c4c4bd08df563120cd33e854fe0a93b81579e8571b11f9b7da9e84c37da2d6b6", size = 461078, upload-time = "2025-11-26T02:36:04.94Z" }, - { url = "https://files.pythonhosted.org/packages/96/4a/9573b87a0ef07580ed111e7230259aec31bb33ca3667963ebee77022ec61/fastar-0.8.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:50b36ce654ba44b0e13fae607ae17ee6e1597b69f71df1bee64bb8328d881dfc", size = 706041, upload-time = "2025-11-26T02:34:40.638Z" }, - { url = "https://files.pythonhosted.org/packages/4a/19/f95444a1d4f375333af49300aa75ee93afa3335c0e40fda528e460ed859c/fastar-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:63a892762683d7ab00df0227d5ea9677c62ff2cde9b875e666c0be569ed940f3", size = 628617, upload-time = "2025-11-26T02:34:24.893Z" }, - { url = "https://files.pythonhosted.org/packages/b3/c9/b51481b38b7e3f16ef2b9e233b1a3623386c939d745d6e41bbd389eaae30/fastar-0.8.0-cp314-cp314-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4ae6a145c1bff592644bde13f2115e0239f4b7babaf506d14e7d208483cf01a5", size = 869299, upload-time = "2025-11-26T02:33:54.274Z" }, - { url = "https://files.pythonhosted.org/packages/bf/02/3ba1267ee5ba7314e29c431cf82eaa68586f2c40cdfa08be3632b7d07619/fastar-0.8.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ae0ff7c0a1c7e1428404b81faee8aebef466bfd0be25bfe4dabf5d535c68741", size = 764667, upload-time = "2025-11-26T02:32:49.606Z" }, - { url = "https://files.pythonhosted.org/packages/1b/84/bf33530fd015b5d7c2cc69e0bce4a38d736754a6955487005aab1af6adcd/fastar-0.8.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dbfd87dbd217b45c898b2dbcd0169aae534b2c1c5cbe3119510881f6a5ac8ef5", size = 763993, upload-time = "2025-11-26T02:33:05.782Z" }, - { url = "https://files.pythonhosted.org/packages/da/e0/9564d24e7cea6321a8d921c6d2a457044a476ef197aa4708e179d3d97f0d/fastar-0.8.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5abd99fcba83ef28c8fe6ae2927edc79053db43a0457a962ed85c9bf150d37", size = 930153, upload-time = "2025-11-26T02:33:21.53Z" }, - { url = "https://files.pythonhosted.org/packages/35/b1/6f57fcd8d6e192cfebf97e58eb27751640ad93784c857b79039e84387b51/fastar-0.8.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91d4c685620c3a9d6b5ae091dbabab4f98b20049b7ecc7976e19cc9016c0d5d6", size = 821177, upload-time = "2025-11-26T02:33:35.839Z" }, - { url = "https://files.pythonhosted.org/packages/b3/78/9e004ea9f3aa7466f5ddb6f9518780e1d2f0ed3ca55f093632982598bace/fastar-0.8.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f77c2f2cad76e9dc7b6701297adb1eba87d0485944b416fc2ccf5516c01219a3", size = 820652, upload-time = "2025-11-26T02:34:09.776Z" }, - { url = "https://files.pythonhosted.org/packages/42/95/b604ed536544005c9f1aee7c4c74b00150db3d8d535cd8232dc20f947063/fastar-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e7f07c4a3dada7757a8fc430a5b4a29e6ef696d2212747213f57086ffd970316", size = 985961, upload-time = "2025-11-26T02:34:56.401Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7b/fa9d4d96a5d494bdb8699363bb9de8178c0c21a02e1d89cd6f913d127018/fastar-0.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:90c0c3fe55105c0aed8a83135dbdeb31e683455dbd326a1c48fa44c378b85616", size = 1039316, upload-time = "2025-11-26T02:35:13.807Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f9/8462789243bc3f33e8401378ec6d54de4e20cfa60c96a0e15e3e9d1389bb/fastar-0.8.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fb9ee51e5bffe0dab3d3126d3a4fac8d8f7235cedcb4b8e74936087ce1c157f3", size = 1045028, upload-time = "2025-11-26T02:35:31.079Z" }, - { url = "https://files.pythonhosted.org/packages/a5/71/9abb128777e616127194b509e98fcda3db797d76288c1a8c23dd22afc14f/fastar-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e380b1e8d30317f52406c43b11e98d11e1d68723bbd031e18049ea3497b59a6d", size = 994677, upload-time = "2025-11-26T02:35:49.391Z" }, - { url = "https://files.pythonhosted.org/packages/de/c1/b81b3f194853d7ad232a67a1d768f5f51a016f165cfb56cb31b31bbc6177/fastar-0.8.0-cp314-cp314-win32.whl", hash = "sha256:1c4ffc06e9c4a8ca498c07e094670d8d8c0d25b17ca6465b9774da44ea997ab1", size = 456687, upload-time = "2025-11-26T02:36:30.205Z" }, - { url = "https://files.pythonhosted.org/packages/cb/87/9e0cd4768a98181d56f0cdbab2363404cc15deb93f4aad3b99cd2761bbaa/fastar-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:5517a8ad4726267c57a3e0e2a44430b782e00b230bf51c55b5728e758bb3a692", size = 490578, upload-time = "2025-11-26T02:36:16.218Z" }, - { url = "https://files.pythonhosted.org/packages/aa/1e/580a76cf91847654f2ad6520e956e93218f778540975bc4190d363f709e2/fastar-0.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:58030551046ff4a8616931e52a36c83545ff05996db5beb6e0cd2b7e748aa309", size = 461473, upload-time = "2025-11-26T02:36:06.373Z" }, - { url = "https://files.pythonhosted.org/packages/58/4c/bdb5c6efe934f68708529c8c9d4055ebef5c4be370621966438f658b29bd/fastar-0.8.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:1e7d29b6bfecb29db126a08baf3c04a5ab667f6cea2b7067d3e623a67729c4a6", size = 705570, upload-time = "2025-11-26T02:34:42.01Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/f01ac7e71d5a37621bd13598a26e948a12b85ca8042f7ee1a0a8c9f59cda/fastar-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:05eb7b96940f9526b485f1d0b02393839f0f61cac4b1f60024984f8b326d2640", size = 627761, upload-time = "2025-11-26T02:34:26.152Z" }, - { url = "https://files.pythonhosted.org/packages/06/45/6df0ecda86ea9d2e95053c1a655d153dee55fc121b6e13ea6d1e246a50b6/fastar-0.8.0-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:619352d8ac011794e2345c462189dc02ba634750d23cd9d86a9267dd71b1f278", size = 869414, upload-time = "2025-11-26T02:33:55.618Z" }, - { url = "https://files.pythonhosted.org/packages/b2/72/486421f5a8c0c377cc82e7a50c8a8ea899a6ec2aa72bde8f09fb667a2dc8/fastar-0.8.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74ebfecef3fe6d7a90355fac1402fd30636988332a1d33f3e80019a10782bb24", size = 763863, upload-time = "2025-11-26T02:32:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/d4/64/39f654dbb41a3867fb1f2c8081c014d8f1d32ea10585d84cacbef0b32995/fastar-0.8.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2975aca5a639e26a3ab0d23b4b0628d6dd6d521146c3c11486d782be621a35aa", size = 763065, upload-time = "2025-11-26T02:33:07.274Z" }, - { url = "https://files.pythonhosted.org/packages/4e/bd/c011a34fb3534c4c3301f7c87c4ffd7e47f6113c904c092ddc8a59a303ea/fastar-0.8.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afc438eaed8ff0dcdd9308268be5cb38c1db7e94c3ccca7c498ca13a4a4535a3", size = 930530, upload-time = "2025-11-26T02:33:23.117Z" }, - { url = "https://files.pythonhosted.org/packages/55/9d/aa6e887a7033c571b1064429222bbe09adc9a3c1e04f3d1788ba5838ebd5/fastar-0.8.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ced0a5399cc0a84a858ef0a31ca2d0c24d3bbec4bcda506a9192d8119f3590a", size = 820572, upload-time = "2025-11-26T02:33:37.542Z" }, - { url = "https://files.pythonhosted.org/packages/ad/9c/7a3a2278a1052e1a5d98646de7c095a00cffd2492b3b84ce730e2f1cd93a/fastar-0.8.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec9b23da8c4c039da3fe2e358973c66976a0c8508aa06d6626b4403cb5666c19", size = 820649, upload-time = "2025-11-26T02:34:11.108Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d38edc1f4438cd047e56137c26d94783ffade42e1b3bde620ccf17b771ef/fastar-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:dfba078fcd53478032fd0ceed56960ec6b7ff0511cfc013a8a3a4307e3a7bac4", size = 985653, upload-time = "2025-11-26T02:34:57.884Z" }, - { url = "https://files.pythonhosted.org/packages/69/d9/2147d0c19757e165cd62d41cec3f7b38fad2ad68ab784978b5f81716c7ea/fastar-0.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ade56c94c14be356d295fecb47a3fcd473dd43a8803ead2e2b5b9e58feb6dcfa", size = 1038140, upload-time = "2025-11-26T02:35:15.778Z" }, - { url = "https://files.pythonhosted.org/packages/7f/1d/ec4c717ffb8a308871e9602ec3197d957e238dc0227127ac573ec9bca952/fastar-0.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e48d938f9366db5e59441728f70b7f6c1ccfab7eff84f96f9b7e689b07786c52", size = 1045195, upload-time = "2025-11-26T02:35:32.865Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/637334dc8c8f3bb391388b064ae13f0ad9402bc5a6c3e77b8887d0c31921/fastar-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:79c441dc1482ff51a54fb3f57ae6f7bb3d2cff88fa2cc5d196c519f8aab64a56", size = 994686, upload-time = "2025-11-26T02:35:51.392Z" }, - { url = "https://files.pythonhosted.org/packages/c9/e2/dfa19a4b260b8ab3581b7484dcb80c09b25324f4daa6b6ae1c7640d1607a/fastar-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:187f61dc739afe45ac8e47ed7fd1adc45d52eac110cf27d579155720507d6fbe", size = 455767, upload-time = "2025-11-26T02:36:34.758Z" }, - { url = "https://files.pythonhosted.org/packages/51/47/df65c72afc1297797b255f90c4778b5d6f1f0f80282a134d5ab610310ed9/fastar-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:40e9d763cf8bf85ce2fa256e010aa795c0fe3d3bd1326d5c3084e6ce7857127e", size = 489971, upload-time = "2025-11-26T02:36:22.081Z" }, - { url = "https://files.pythonhosted.org/packages/85/11/0aa8455af26f0ae89e42be67f3a874255ee5d7f0f026fc86e8d56f76b428/fastar-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e59673307b6a08210987059a2bdea2614fe26e3335d0e5d1a3d95f49a05b1418", size = 460467, upload-time = "2025-11-26T02:36:07.978Z" }, -] - -[[package]] -name = "firebase-admin" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachecontrol" }, - { name = "google-api-core", extra = ["grpc"], marker = "platform_python_implementation != 'PyPy'" }, - { name = "google-cloud-firestore", marker = "platform_python_implementation != 'PyPy'" }, - { name = "google-cloud-storage" }, - { name = "httpx", extra = ["http2"] }, - { name = "pyjwt", extra = ["crypto"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/aa/41/859f78701761bed7abdb8a7c050819c654dad17f96c658dcdf263d5a9641/firebase_admin-7.1.0.tar.gz", hash = "sha256:a163014a4368c43f7efa409948065f8856b51bd2ae5d82c24586e546d5fd4a26", size = 194786, upload-time = "2025-07-31T20:36:39.512Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/16/eb9bf44cdc7af0317a70ae770ad4170b9fcfbb660ac32806742506be1246/firebase_admin-7.1.0-py3-none-any.whl", hash = "sha256:1913e783b7ad56f891e1aca86e6fdde6a8ec49b7a920dd451da155e8647506c8", size = 137140, upload-time = "2025-07-31T20:36:38.266Z" }, -] - -[[package]] -name = "google-api-core" -version = "2.30.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "googleapis-common-protos" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/22/98/586ec94553b569080caef635f98a3723db36a38eac0e3d7eb3ea9d2e4b9a/google_api_core-2.30.0.tar.gz", hash = "sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b", size = 176959, upload-time = "2026-02-18T20:28:11.926Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/27/09c33d67f7e0dcf06d7ac17d196594e66989299374bfb0d4331d1038e76b/google_api_core-2.30.0-py3-none-any.whl", hash = "sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5", size = 173288, upload-time = "2026-02-18T20:28:10.367Z" }, -] - -[package.optional-dependencies] -grpc = [ - { name = "grpcio" }, - { name = "grpcio-status" }, -] - -[[package]] -name = "google-auth" -version = "2.48.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, - { name = "pyasn1-modules" }, - { name = "rsa" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0c/41/242044323fbd746615884b1c16639749e73665b718209946ebad7ba8a813/google_auth-2.48.0.tar.gz", hash = "sha256:4f7e706b0cd3208a3d940a19a822c37a476ddba5450156c3e6624a71f7c841ce", size = 326522, upload-time = "2026-01-26T19:22:47.157Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/1d/d6466de3a5249d35e832a52834115ca9d1d0de6abc22065f049707516d47/google_auth-2.48.0-py3-none-any.whl", hash = "sha256:2e2a537873d449434252a9632c28bfc268b0adb1e53f9fb62afc5333a975903f", size = 236499, upload-time = "2026-01-26T19:22:45.099Z" }, -] - -[[package]] -name = "google-cloud-core" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, -] - -[[package]] -name = "google-cloud-firestore" -version = "2.23.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/9c/ec28ca4ec88fa89e41366316cf92c037feaa2c4200aa5d9da69fe011d2f6/google_cloud_firestore-2.23.0.tar.gz", hash = "sha256:a9cffba7cdc6101111d6d54cde22d521c98f9e7d415e67486b137fa16f06aa03", size = 615238, upload-time = "2026-01-14T23:50:54.574Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/99/2a627c8ea7ae72a686dda8bf2b79747362b425c237d2729eb76bcee55a25/google_cloud_firestore-2.23.0-py3-none-any.whl", hash = "sha256:19f2326cb466b0d52aed9fabbd89758be431f6ce18c422966cfdb8326b424314", size = 411195, upload-time = "2026-01-14T23:50:52.825Z" }, -] - -[[package]] -name = "google-cloud-storage" -version = "3.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "google-crc32c" }, - { name = "google-resumable-media" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f7/b1/4f0798e88285b50dfc60ed3a7de071def538b358db2da468c2e0deecbb40/google_cloud_storage-3.9.0.tar.gz", hash = "sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc", size = 17298544, upload-time = "2026-02-02T13:36:34.119Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/0b/816a6ae3c9fd096937d2e5f9670558908811d57d59ddf69dd4b83b326fd1/google_cloud_storage-3.9.0-py3-none-any.whl", hash = "sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066", size = 321324, upload-time = "2026-02-02T13:36:32.271Z" }, -] - -[[package]] -name = "google-crc32c" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, - { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, - { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, - { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301, upload-time = "2025-12-16T00:24:48.527Z" }, - { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868, upload-time = "2025-12-16T00:48:12.163Z" }, - { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload-time = "2025-12-16T00:40:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload-time = "2025-12-16T00:40:27.028Z" }, - { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload-time = "2025-12-16T00:35:23.142Z" }, -] - -[[package]] -name = "google-resumable-media" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-crc32c" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, -] - -[[package]] -name = "googleapis-common-protos" -version = "1.72.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, -] - -[[package]] -name = "greenlet" -version = "3.2.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, - { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, - { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, - { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, - { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, - { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, - { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, - { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" }, - { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, - { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, - { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, - { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, - { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, - { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" }, - { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, -] - -[[package]] -name = "grpcio" -version = "1.78.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1f/de/de568532d9907552700f80dcec38219d8d298ad9e71f5e0a095abaf2761e/grpcio-1.78.1.tar.gz", hash = "sha256:27c625532d33ace45d57e775edf1982e183ff8641c72e4e91ef7ba667a149d72", size = 12835760, upload-time = "2026-02-20T01:16:10.869Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/72/754754639cfd16ad04619e1435a518124b2d858e5752225376f9285d4c51/grpcio-1.78.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:2b7ad2981550ce999e25ce3f10c8863f718a352a2fd655068d29ea3fd37b4907", size = 5919437, upload-time = "2026-02-20T01:14:29.403Z" }, - { url = "https://files.pythonhosted.org/packages/5c/84/6267d1266f8bc335d3a8b7ccf981be7de41e3ed8bd3a49e57e588212b437/grpcio-1.78.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:409bfe22220889b9906739910a0ee4c197a967c21b8dd14b4b06dd477f8819ce", size = 11803701, upload-time = "2026-02-20T01:14:32.624Z" }, - { url = "https://files.pythonhosted.org/packages/f3/56/c9098e8b920a54261cd605bbb040de0cde1ca4406102db0aa2c0b11d1fb4/grpcio-1.78.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:34b6cb16f4b67eeb5206250dc5b4d5e8e3db939535e58efc330e4c61341554bd", size = 6479416, upload-time = "2026-02-20T01:14:35.926Z" }, - { url = "https://files.pythonhosted.org/packages/86/cf/5d52024371ee62658b7ed72480200524087528844ec1b65265bbcd31c974/grpcio-1.78.1-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:39d21fd30d38a5afb93f0e2e71e2ec2bd894605fb75d41d5a40060c2f98f8d11", size = 7174087, upload-time = "2026-02-20T01:14:39.98Z" }, - { url = "https://files.pythonhosted.org/packages/31/e6/5e59551afad4279e27335a6d60813b8aa3ae7b14fb62cea1d329a459c118/grpcio-1.78.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09fbd4bcaadb6d8604ed1504b0bdf7ac18e48467e83a9d930a70a7fefa27e862", size = 6692881, upload-time = "2026-02-20T01:14:42.466Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/940062de2d14013c02f51b079eb717964d67d46f5d44f22038975c9d9576/grpcio-1.78.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:db681513a1bdd879c0b24a5a6a70398da5eaaba0e077a306410dc6008426847a", size = 7269092, upload-time = "2026-02-20T01:14:45.826Z" }, - { url = "https://files.pythonhosted.org/packages/09/87/9db657a4b5f3b15560ec591db950bc75a1a2f9e07832578d7e2b23d1a7bd/grpcio-1.78.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f81816faa426da461e9a597a178832a351d6f1078102590a4b32c77d251b71eb", size = 8252037, upload-time = "2026-02-20T01:14:48.57Z" }, - { url = "https://files.pythonhosted.org/packages/e2/37/b980e0265479ec65e26b6e300a39ceac33ecb3f762c2861d4bac990317cf/grpcio-1.78.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffbb760df1cd49e0989f9826b2fd48930700db6846ac171eaff404f3cfbe5c28", size = 7695243, upload-time = "2026-02-20T01:14:51.376Z" }, - { url = "https://files.pythonhosted.org/packages/98/46/5fc42c100ab702fa1ea41a75c890c563c3f96432b4a287d5a6369654f323/grpcio-1.78.1-cp313-cp313-win32.whl", hash = "sha256:1a56bf3ee99af5cf32d469de91bf5de79bdac2e18082b495fc1063ea33f4f2d0", size = 4065329, upload-time = "2026-02-20T01:14:53.952Z" }, - { url = "https://files.pythonhosted.org/packages/b0/da/806d60bb6611dfc16cf463d982bd92bd8b6bd5f87dfac66b0a44dfe20995/grpcio-1.78.1-cp313-cp313-win_amd64.whl", hash = "sha256:8991c2add0d8505178ff6c3ae54bd9386279e712be82fa3733c54067aae9eda1", size = 4797637, upload-time = "2026-02-20T01:14:57.276Z" }, - { url = "https://files.pythonhosted.org/packages/96/3a/2d2ec4d2ce2eb9d6a2b862630a0d9d4ff4239ecf1474ecff21442a78612a/grpcio-1.78.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:d101fe49b1e0fb4a7aa36ed0c3821a0f67a5956ef572745452d2cd790d723a3f", size = 5920256, upload-time = "2026-02-20T01:15:00.23Z" }, - { url = "https://files.pythonhosted.org/packages/9c/92/dccb7d087a1220ed358753945230c1ddeeed13684b954cb09db6758f1271/grpcio-1.78.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:5ce1855e8cfc217cdf6bcfe0cf046d7cf81ddcc3e6894d6cfd075f87a2d8f460", size = 11813749, upload-time = "2026-02-20T01:15:03.312Z" }, - { url = "https://files.pythonhosted.org/packages/ef/47/c20e87f87986da9998f30f14776ce27e61f02482a3a030ffe265089342c6/grpcio-1.78.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd26048d066b51f39fe9206e2bcc2cea869a5e5b2d13c8d523f4179193047ebd", size = 6488739, upload-time = "2026-02-20T01:15:14.349Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c2/088bd96e255133d7d87c3eed0d598350d16cde1041bdbe2bb065967aaf91/grpcio-1.78.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4b8d7fda614cf2af0f73bbb042f3b7fee2ecd4aea69ec98dbd903590a1083529", size = 7173096, upload-time = "2026-02-20T01:15:17.687Z" }, - { url = "https://files.pythonhosted.org/packages/60/ce/168db121073a03355ce3552b3b1f790b5ded62deffd7d98c5f642b9d3d81/grpcio-1.78.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:656a5bd142caeb8b1efe1fe0b4434ecc7781f44c97cfc7927f6608627cf178c0", size = 6693861, upload-time = "2026-02-20T01:15:20.911Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d0/90b30ec2d9425215dd56922d85a90babbe6ee7e8256ba77d866b9c0d3aba/grpcio-1.78.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:99550e344482e3c21950c034f74668fccf8a546d50c1ecb4f717543bbdc071ba", size = 7278083, upload-time = "2026-02-20T01:15:23.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fb/73f9ba0b082bcd385d46205095fd9c917754685885b28fce3741e9f54529/grpcio-1.78.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8f27683ca68359bd3f0eb4925824d71e538f84338b3ae337ead2ae43977d7541", size = 8252546, upload-time = "2026-02-20T01:15:26.517Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/6a89ea3cb5db6c3d9ed029b0396c49f64328c0cf5d2630ffeed25711920a/grpcio-1.78.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a40515b69ac50792f9b8ead260f194ba2bb3285375b6c40c7ff938f14c3df17d", size = 7696289, upload-time = "2026-02-20T01:15:29.718Z" }, - { url = "https://files.pythonhosted.org/packages/3d/05/63a7495048499ef437b4933d32e59b7f737bd5368ad6fb2479e2bd83bf2c/grpcio-1.78.1-cp314-cp314-win32.whl", hash = "sha256:2c473b54ef1618f4fb85e82ff4994de18143b74efc088b91b5a935a3a45042ba", size = 4142186, upload-time = "2026-02-20T01:15:32.786Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ce/adfe7e5f701d503be7778291757452e3fab6b19acf51917c79f5d1cf7f8a/grpcio-1.78.1-cp314-cp314-win_amd64.whl", hash = "sha256:e2a6b33d1050dce2c6f563c5caf7f7cbeebf7fba8cde37ffe3803d50526900d1", size = 4932000, upload-time = "2026-02-20T01:15:36.127Z" }, -] - -[[package]] -name = "grpcio-status" -version = "1.78.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/73/be/0a88b27a058d3a640bbe42e2b4e1323a19cabcedaeab1b3a44af231777e9/grpcio_status-1.78.1.tar.gz", hash = "sha256:47e7fa903549c5881344f1cba23c814b5f69d09233541036eb25642d32497c8e", size = 13814, upload-time = "2026-02-20T01:21:50.761Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/dd/08819a8108753e8b2a89aab259d7301dba696ebc581a307a3cd4bb786b57/grpcio_status-1.78.1-py3-none-any.whl", hash = "sha256:5f6660b99063f918b7f84d99cab68084aeb0dd09949e1224a6073026cea6820c", size = 14525, upload-time = "2026-02-20T01:21:35.793Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "h2" -version = "4.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" }, -] - -[[package]] -name = "hpack" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, - { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, - { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, - { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, - { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, - { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, - { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, - { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, - { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, - { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, - { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, - { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, - { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, - { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[package.optional-dependencies] -http2 = [ - { name = "h2" }, -] - -[[package]] -name = "hyperframe" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, -] - -[[package]] -name = "idna" -version = "3.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "mako" -version = "1.3.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "4.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, - { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, - { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, - { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, - { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, - { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, - { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, - { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, - { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, - { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, - { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, - { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, - { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, - { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, - { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, - { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, - { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, - { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, - { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, - { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, - { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, - { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, - { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, - { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, - { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, - { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, - { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, - { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "msgpack" -version = "1.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, - { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, - { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, - { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, - { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, - { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, - { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, - { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, - { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, - { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, - { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, - { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, - { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, - { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, - { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, - { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, - { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, - { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, -] - -[[package]] -name = "multidict" -version = "6.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, - { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, - { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, - { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, - { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, - { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, - { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, - { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, - { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, - { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, - { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, - { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, - { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, - { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, - { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, - { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, - { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, - { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, - { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, - { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, - { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, - { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, - { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, - { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, - { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, - { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, - { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, - { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, - { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, - { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, - { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, - { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, - { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, - { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, - { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, - { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, - { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, - { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, - { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, - { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, - { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, - { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, - { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, - { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, - { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, - { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, - { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, - { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, - { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, - { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, - { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, - { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, - { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, - { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, - { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, - { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, - { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, - { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, - { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "passlib" -version = "1.7.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/06/9da9ee59a67fae7761aab3ccc84fa4f3f33f125b370f1ccdb915bf967c11/passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04", size = 689844, upload-time = "2020-10-08T19:00:52.121Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", size = 525554, upload-time = "2020-10-08T19:00:49.856Z" }, -] - -[[package]] -name = "postgrest" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deprecation" }, - { name = "httpx", extra = ["http2"] }, - { name = "pydantic" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/2a/5d956bbf12dbf3b3fef7dce416a702eebf1fdce2b64c5fe3091e57f67e1b/postgrest-2.24.0.tar.gz", hash = "sha256:2b19a9f44ac06bea8f9fc936f6a609a66a4b3ce10e87f88ff59935e64a97578c", size = 13681, upload-time = "2025-11-07T17:08:11.108Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/b2/78d588d5acd1cc195bbbc26e9810a75371fdfd47489a653df4476867f220/postgrest-2.24.0-py3-none-any.whl", hash = "sha256:2127b7ff70c3e917791c17d4adfe36d1b721d5999eeda9d4ad3862d1bb6d15ae", size = 21581, upload-time = "2025-11-07T17:08:09.789Z" }, -] - -[[package]] -name = "propcache" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, - { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, - { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, - { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, - { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, - { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, - { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, - { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, - { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, - { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, - { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, - { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, - { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, - { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, - { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, - { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, - { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, - { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, - { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, - { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, - { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, - { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, - { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, - { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, - { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, - { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, - { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, - { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, - { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, - { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, - { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, - { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, - { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, - { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, - { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, - { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, - { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, - { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, - { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, - { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, - { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, - { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, - { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, - { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, - { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, - { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, -] - -[[package]] -name = "proto-plus" -version = "1.27.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929, upload-time = "2026-02-02T17:34:49.035Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/79/ac273cbbf744691821a9cca88957257f41afe271637794975ca090b9588b/proto_plus-1.27.1-py3-none-any.whl", hash = "sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc", size = 50480, upload-time = "2026-02-02T17:34:47.339Z" }, -] - -[[package]] -name = "protobuf" -version = "6.33.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, - { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" }, - { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, - { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, - { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, -] - -[[package]] -name = "psycopg2-binary" -version = "2.9.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/6c/8767aaa597ba424643dc87348c6f1754dd9f48e80fdc1b9f7ca5c3a7c213/psycopg2-binary-2.9.11.tar.gz", hash = "sha256:b6aed9e096bf63f9e75edf2581aa9a7e7186d97ab5c177aa6c87797cd591236c", size = 379620, upload-time = "2025-10-10T11:14:48.041Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/a8/a2709681b3ac11b0b1786def10006b8995125ba268c9a54bea6f5ae8bd3e/psycopg2_binary-2.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8fb3db325435d34235b044b199e56cdf9ff41223a4b9752e8576465170bb38c", size = 3756572, upload-time = "2025-10-10T11:12:32.873Z" }, - { url = "https://files.pythonhosted.org/packages/62/e1/c2b38d256d0dafd32713e9f31982a5b028f4a3651f446be70785f484f472/psycopg2_binary-2.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:366df99e710a2acd90efed3764bb1e28df6c675d33a7fb40df9b7281694432ee", size = 3864529, upload-time = "2025-10-10T11:12:36.791Z" }, - { url = "https://files.pythonhosted.org/packages/11/32/b2ffe8f3853c181e88f0a157c5fb4e383102238d73c52ac6d93a5c8bffe6/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c55b385daa2f92cb64b12ec4536c66954ac53654c7f15a203578da4e78105c0", size = 4411242, upload-time = "2025-10-10T11:12:42.388Z" }, - { url = "https://files.pythonhosted.org/packages/10/04/6ca7477e6160ae258dc96f67c371157776564679aefd247b66f4661501a2/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c0377174bf1dd416993d16edc15357f6eb17ac998244cca19bc67cdc0e2e5766", size = 4468258, upload-time = "2025-10-10T11:12:48.654Z" }, - { url = "https://files.pythonhosted.org/packages/3c/7e/6a1a38f86412df101435809f225d57c1a021307dd0689f7a5e7fe83588b1/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6ff3335ce08c75afaed19e08699e8aacf95d4a260b495a4a8545244fe2ceb3", size = 4166295, upload-time = "2025-10-10T11:12:52.525Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7d/c07374c501b45f3579a9eb761cbf2604ddef3d96ad48679112c2c5aa9c25/psycopg2_binary-2.9.11-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84011ba3109e06ac412f95399b704d3d6950e386b7994475b231cf61eec2fc1f", size = 3983133, upload-time = "2025-10-30T02:55:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/82/56/993b7104cb8345ad7d4516538ccf8f0d0ac640b1ebd8c754a7b024e76878/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba34475ceb08cccbdd98f6b46916917ae6eeb92b5ae111df10b544c3a4621dc4", size = 3652383, upload-time = "2025-10-10T11:12:56.387Z" }, - { url = "https://files.pythonhosted.org/packages/2d/ac/eaeb6029362fd8d454a27374d84c6866c82c33bfc24587b4face5a8e43ef/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b31e90fdd0f968c2de3b26ab014314fe814225b6c324f770952f7d38abf17e3c", size = 3298168, upload-time = "2025-10-10T11:13:00.403Z" }, - { url = "https://files.pythonhosted.org/packages/2b/39/50c3facc66bded9ada5cbc0de867499a703dc6bca6be03070b4e3b65da6c/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d526864e0f67f74937a8fce859bd56c979f5e2ec57ca7c627f5f1071ef7fee60", size = 3044712, upload-time = "2025-10-30T02:55:27.975Z" }, - { url = "https://files.pythonhosted.org/packages/9c/8e/b7de019a1f562f72ada81081a12823d3c1590bedc48d7d2559410a2763fe/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04195548662fa544626c8ea0f06561eb6203f1984ba5b4562764fbeb4c3d14b1", size = 3347549, upload-time = "2025-10-10T11:13:03.971Z" }, - { url = "https://files.pythonhosted.org/packages/80/2d/1bb683f64737bbb1f86c82b7359db1eb2be4e2c0c13b947f80efefa7d3e5/psycopg2_binary-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:efff12b432179443f54e230fdf60de1f6cc726b6c832db8701227d089310e8aa", size = 2714215, upload-time = "2025-10-10T11:13:07.14Z" }, - { url = "https://files.pythonhosted.org/packages/64/12/93ef0098590cf51d9732b4f139533732565704f45bdc1ffa741b7c95fb54/psycopg2_binary-2.9.11-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:92e3b669236327083a2e33ccfa0d320dd01b9803b3e14dd986a4fc54aa00f4e1", size = 3756567, upload-time = "2025-10-10T11:13:11.885Z" }, - { url = "https://files.pythonhosted.org/packages/7c/a9/9d55c614a891288f15ca4b5209b09f0f01e3124056924e17b81b9fa054cc/psycopg2_binary-2.9.11-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e0deeb03da539fa3577fcb0b3f2554a97f7e5477c246098dbb18091a4a01c16f", size = 3864755, upload-time = "2025-10-10T11:13:17.727Z" }, - { url = "https://files.pythonhosted.org/packages/13/1e/98874ce72fd29cbde93209977b196a2edae03f8490d1bd8158e7f1daf3a0/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b52a3f9bb540a3e4ec0f6ba6d31339727b2950c9772850d6545b7eae0b9d7c5", size = 4411646, upload-time = "2025-10-10T11:13:24.432Z" }, - { url = "https://files.pythonhosted.org/packages/5a/bd/a335ce6645334fb8d758cc358810defca14a1d19ffbc8a10bd38a2328565/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:db4fd476874ccfdbb630a54426964959e58da4c61c9feba73e6094d51303d7d8", size = 4468701, upload-time = "2025-10-10T11:13:29.266Z" }, - { url = "https://files.pythonhosted.org/packages/44/d6/c8b4f53f34e295e45709b7568bf9b9407a612ea30387d35eb9fa84f269b4/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47f212c1d3be608a12937cc131bd85502954398aaa1320cb4c14421a0ffccf4c", size = 4166293, upload-time = "2025-10-10T11:13:33.336Z" }, - { url = "https://files.pythonhosted.org/packages/4b/e0/f8cc36eadd1b716ab36bb290618a3292e009867e5c97ce4aba908cb99644/psycopg2_binary-2.9.11-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e35b7abae2b0adab776add56111df1735ccc71406e56203515e228a8dc07089f", size = 3983184, upload-time = "2025-10-30T02:55:32.483Z" }, - { url = "https://files.pythonhosted.org/packages/53/3e/2a8fe18a4e61cfb3417da67b6318e12691772c0696d79434184a511906dc/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fcf21be3ce5f5659daefd2b3b3b6e4727b028221ddc94e6c1523425579664747", size = 3652650, upload-time = "2025-10-10T11:13:38.181Z" }, - { url = "https://files.pythonhosted.org/packages/76/36/03801461b31b29fe58d228c24388f999fe814dfc302856e0d17f97d7c54d/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9bd81e64e8de111237737b29d68039b9c813bdf520156af36d26819c9a979e5f", size = 3298663, upload-time = "2025-10-10T11:13:44.878Z" }, - { url = "https://files.pythonhosted.org/packages/97/77/21b0ea2e1a73aa5fa9222b2a6b8ba325c43c3a8d54272839c991f2345656/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:32770a4d666fbdafab017086655bcddab791d7cb260a16679cc5a7338b64343b", size = 3044737, upload-time = "2025-10-30T02:55:35.69Z" }, - { url = "https://files.pythonhosted.org/packages/67/69/f36abe5f118c1dca6d3726ceae164b9356985805480731ac6712a63f24f0/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3cb3a676873d7506825221045bd70e0427c905b9c8ee8d6acd70cfcbd6e576d", size = 3347643, upload-time = "2025-10-10T11:13:53.499Z" }, - { url = "https://files.pythonhosted.org/packages/e1/36/9c0c326fe3a4227953dfb29f5d0c8ae3b8eb8c1cd2967aa569f50cb3c61f/psycopg2_binary-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:4012c9c954dfaccd28f94e84ab9f94e12df76b4afb22331b1f0d3154893a6316", size = 2803913, upload-time = "2025-10-10T11:13:57.058Z" }, -] - -[[package]] -name = "pyasn1" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, -] - -[[package]] -name = "pyasn1-modules" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, -] - -[[package]] -name = "pycparser" -version = "2.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, -] - -[[package]] -name = "pydantic" -version = "2.12.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, -] - -[package.optional-dependencies] -email = [ - { name = "email-validator" }, -] - -[[package]] -name = "pydantic-core" -version = "2.41.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, - { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, - { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, - { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, - { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, - { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, - { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, - { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, - { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, - { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, - { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, - { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, - { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, - { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, - { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, - { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, - { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, - { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, - { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, - { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, - { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, - { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, - { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, - { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, - { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, - { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, - { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, - { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] - -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - -[package.optional-dependencies] -crypto = [ - { name = "cryptography" }, -] - -[[package]] -name = "python-dotenv" -version = "1.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, -] - -[[package]] -name = "python-jose" -version = "3.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ecdsa" }, - { name = "pyasn1" }, - { name = "rsa" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" }, -] - -[package.optional-dependencies] -cryptography = [ - { name = "cryptography" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, -] - -[[package]] -name = "realtime" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/3b/0a85238e57842fbcda7a090e76459e59d21e0f339da9dda71c8c5efa1a0c/realtime-2.24.0.tar.gz", hash = "sha256:eaf6e2d298473ffb093c25f1ed12f479cb095ae7a59df699bbea9f11c68a087a", size = 18536, upload-time = "2025-11-07T17:08:13.113Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/08/1ab54f258a9afe1b0064f2ef2421975ea0065d9a0c970ce87f0933eae118/realtime-2.24.0-py3-none-any.whl", hash = "sha256:fd1b335caf178deaf99c7deae99498c9b820ebfc10522e44ad8c341121d1f230", size = 22139, upload-time = "2025-11-07T17:08:12.019Z" }, -] - -[[package]] -name = "requests" -version = "2.32.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, -] - -[[package]] -name = "rich" -version = "14.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.17.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/d0/8f8de36e1abf8339b497ce700dd7251ca465ffca4a1976969b0eaeb596fb/rich_toolkit-0.17.0.tar.gz", hash = "sha256:17ca7a32e613001aa0945ddea27a246f6de01dfc4c12403254c057a8ee542977", size = 187955, upload-time = "2025-11-27T11:10:24.863Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/42/ef2ed40699567661d03b0b511ac46cf6cee736de8f3666819c12d6d20696/rich_toolkit-0.17.0-py3-none-any.whl", hash = "sha256:06fb47a5c5259d6b480287cd38aff5f551b6e1a307f90ed592453dd360e4e71e", size = 31412, upload-time = "2025-11-27T11:10:23.847Z" }, -] - -[[package]] -name = "rignore" -version = "0.7.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/8a/a4078f6e14932ac7edb171149c481de29969d96ddee3ece5dc4c26f9e0c3/rignore-0.7.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2bdab1d31ec9b4fb1331980ee49ea051c0d7f7bb6baa28b3125ef03cdc48fdaf", size = 883057, upload-time = "2025-11-05T20:42:42.741Z" }, - { url = "https://files.pythonhosted.org/packages/f9/8f/f8daacd177db4bf7c2223bab41e630c52711f8af9ed279be2058d2fe4982/rignore-0.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90f0a00ce0c866c275bf888271f1dc0d2140f29b82fcf33cdbda1e1a6af01010", size = 820150, upload-time = "2025-11-05T20:42:26.545Z" }, - { url = "https://files.pythonhosted.org/packages/36/31/b65b837e39c3f7064c426754714ac633b66b8c2290978af9d7f513e14aa9/rignore-0.7.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ad295537041dc2ed4b540fb1a3906bd9ede6ccdad3fe79770cd89e04e3c73c", size = 897406, upload-time = "2025-11-05T20:40:53.854Z" }, - { url = "https://files.pythonhosted.org/packages/ca/58/1970ce006c427e202ac7c081435719a076c478f07b3a23f469227788dc23/rignore-0.7.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f782dbd3a65a5ac85adfff69e5c6b101285ef3f845c3a3cae56a54bebf9fe116", size = 874050, upload-time = "2025-11-05T20:41:08.922Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/eb45db9f90137329072a732273be0d383cb7d7f50ddc8e0bceea34c1dfdf/rignore-0.7.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65cece3b36e5b0826d946494734c0e6aaf5a0337e18ff55b071438efe13d559e", size = 1167835, upload-time = "2025-11-05T20:41:24.997Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f1/6f1d72ddca41a64eed569680587a1236633587cc9f78136477ae69e2c88a/rignore-0.7.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e4bb66c13cd7602dc8931822c02dfbbd5252015c750ac5d6152b186f0a8be0", size = 941945, upload-time = "2025-11-05T20:41:40.628Z" }, - { url = "https://files.pythonhosted.org/packages/48/6f/2f178af1c1a276a065f563ec1e11e7a9e23d4996fd0465516afce4b5c636/rignore-0.7.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297e500c15766e196f68aaaa70e8b6db85fa23fdc075b880d8231fdfba738cd7", size = 959067, upload-time = "2025-11-05T20:42:11.09Z" }, - { url = "https://files.pythonhosted.org/packages/5b/db/423a81c4c1e173877c7f9b5767dcaf1ab50484a94f60a0b2ed78be3fa765/rignore-0.7.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a07084211a8d35e1a5b1d32b9661a5ed20669970b369df0cf77da3adea3405de", size = 984438, upload-time = "2025-11-05T20:41:55.443Z" }, - { url = "https://files.pythonhosted.org/packages/31/eb/c4f92cc3f2825d501d3c46a244a671eb737fc1bcf7b05a3ecd34abb3e0d7/rignore-0.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:181eb2a975a22256a1441a9d2f15eb1292839ea3f05606620bd9e1938302cf79", size = 1078365, upload-time = "2025-11-05T21:40:15.148Z" }, - { url = "https://files.pythonhosted.org/packages/26/09/99442f02794bd7441bfc8ed1c7319e890449b816a7493b2db0e30af39095/rignore-0.7.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7bbcdc52b5bf9f054b34ce4af5269df5d863d9c2456243338bc193c28022bd7b", size = 1139066, upload-time = "2025-11-05T21:40:32.771Z" }, - { url = "https://files.pythonhosted.org/packages/2c/88/bcfc21e520bba975410e9419450f4b90a2ac8236b9a80fd8130e87d098af/rignore-0.7.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f2e027a6da21a7c8c0d87553c24ca5cc4364def18d146057862c23a96546238e", size = 1118036, upload-time = "2025-11-05T21:40:49.646Z" }, - { url = "https://files.pythonhosted.org/packages/e2/25/d37215e4562cda5c13312636393aea0bafe38d54d4e0517520a4cc0753ec/rignore-0.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee4a18b82cbbc648e4aac1510066682fe62beb5dc88e2c67c53a83954e541360", size = 1127550, upload-time = "2025-11-05T21:41:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/dc/76/a264ab38bfa1620ec12a8ff1c07778da89e16d8c0f3450b0333020d3d6dc/rignore-0.7.6-cp313-cp313-win32.whl", hash = "sha256:a7d7148b6e5e95035d4390396895adc384d37ff4e06781a36fe573bba7c283e5", size = 646097, upload-time = "2025-11-05T21:41:53.201Z" }, - { url = "https://files.pythonhosted.org/packages/62/44/3c31b8983c29ea8832b6082ddb1d07b90379c2d993bd20fce4487b71b4f4/rignore-0.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:b037c4b15a64dced08fc12310ee844ec2284c4c5c1ca77bc37d0a04f7bff386e", size = 726170, upload-time = "2025-11-05T21:41:38.131Z" }, - { url = "https://files.pythonhosted.org/packages/aa/41/e26a075cab83debe41a42661262f606166157df84e0e02e2d904d134c0d8/rignore-0.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:e47443de9b12fe569889bdbe020abe0e0b667516ee2ab435443f6d0869bd2804", size = 656184, upload-time = "2025-11-05T21:41:27.396Z" }, - { url = "https://files.pythonhosted.org/packages/9a/b9/1f5bd82b87e5550cd843ceb3768b4a8ef274eb63f29333cf2f29644b3d75/rignore-0.7.6-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:8e41be9fa8f2f47239ded8920cc283699a052ac4c371f77f5ac017ebeed75732", size = 882632, upload-time = "2025-11-05T20:42:44.063Z" }, - { url = "https://files.pythonhosted.org/packages/e9/6b/07714a3efe4a8048864e8a5b7db311ba51b921e15268b17defaebf56d3db/rignore-0.7.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6dc1e171e52cefa6c20e60c05394a71165663b48bca6c7666dee4f778f2a7d90", size = 820760, upload-time = "2025-11-05T20:42:27.885Z" }, - { url = "https://files.pythonhosted.org/packages/ac/0f/348c829ea2d8d596e856371b14b9092f8a5dfbb62674ec9b3f67e4939a9d/rignore-0.7.6-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce2268837c3600f82ab8db58f5834009dc638ee17103582960da668963bebc5", size = 899044, upload-time = "2025-11-05T20:40:55.336Z" }, - { url = "https://files.pythonhosted.org/packages/f0/30/2e1841a19b4dd23878d73edd5d82e998a83d5ed9570a89675f140ca8b2ad/rignore-0.7.6-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:690a3e1b54bfe77e89c4bacb13f046e642f8baadafc61d68f5a726f324a76ab6", size = 874144, upload-time = "2025-11-05T20:41:10.195Z" }, - { url = "https://files.pythonhosted.org/packages/c2/bf/0ce9beb2e5f64c30e3580bef09f5829236889f01511a125f98b83169b993/rignore-0.7.6-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09d12ac7a0b6210c07bcd145007117ebd8abe99c8eeb383e9e4673910c2754b2", size = 1168062, upload-time = "2025-11-05T20:41:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/b9/8b/571c178414eb4014969865317da8a02ce4cf5241a41676ef91a59aab24de/rignore-0.7.6-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a2b2b74a8c60203b08452479b90e5ce3dbe96a916214bc9eb2e5af0b6a9beb0", size = 942542, upload-time = "2025-11-05T20:41:41.838Z" }, - { url = "https://files.pythonhosted.org/packages/19/62/7a3cf601d5a45137a7e2b89d10c05b5b86499190c4b7ca5c3c47d79ee519/rignore-0.7.6-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fc5a531ef02131e44359419a366bfac57f773ea58f5278c2cdd915f7d10ea94", size = 958739, upload-time = "2025-11-05T20:42:12.463Z" }, - { url = "https://files.pythonhosted.org/packages/5f/1f/4261f6a0d7caf2058a5cde2f5045f565ab91aa7badc972b57d19ce58b14e/rignore-0.7.6-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7a1f77d9c4cd7e76229e252614d963442686bfe12c787a49f4fe481df49e7a9", size = 984138, upload-time = "2025-11-05T20:41:56.775Z" }, - { url = "https://files.pythonhosted.org/packages/2b/bf/628dfe19c75e8ce1f45f7c248f5148b17dfa89a817f8e3552ab74c3ae812/rignore-0.7.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ead81f728682ba72b5b1c3d5846b011d3e0174da978de87c61645f2ed36659a7", size = 1079299, upload-time = "2025-11-05T21:40:16.639Z" }, - { url = "https://files.pythonhosted.org/packages/af/a5/be29c50f5c0c25c637ed32db8758fdf5b901a99e08b608971cda8afb293b/rignore-0.7.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:12ffd50f520c22ffdabed8cd8bfb567d9ac165b2b854d3e679f4bcaef11a9441", size = 1139618, upload-time = "2025-11-05T21:40:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/2a/40/3c46cd7ce4fa05c20b525fd60f599165e820af66e66f2c371cd50644558f/rignore-0.7.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e5a16890fbe3c894f8ca34b0fcacc2c200398d4d46ae654e03bc9b3dbf2a0a72", size = 1117626, upload-time = "2025-11-05T21:40:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/8c/b9/aea926f263b8a29a23c75c2e0d8447965eb1879d3feb53cfcf84db67ed58/rignore-0.7.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3abab3bf99e8a77488ef6c7c9a799fac22224c28fe9f25cc21aa7cc2b72bfc0b", size = 1128144, upload-time = "2025-11-05T21:41:09.169Z" }, - { url = "https://files.pythonhosted.org/packages/a4/f6/0d6242f8d0df7f2ecbe91679fefc1f75e7cd2072cb4f497abaab3f0f8523/rignore-0.7.6-cp314-cp314-win32.whl", hash = "sha256:eeef421c1782953c4375aa32f06ecae470c1285c6381eee2a30d2e02a5633001", size = 646385, upload-time = "2025-11-05T21:41:55.105Z" }, - { url = "https://files.pythonhosted.org/packages/d5/38/c0dcd7b10064f084343d6af26fe9414e46e9619c5f3224b5272e8e5d9956/rignore-0.7.6-cp314-cp314-win_amd64.whl", hash = "sha256:6aeed503b3b3d5af939b21d72a82521701a4bd3b89cd761da1e7dc78621af304", size = 725738, upload-time = "2025-11-05T21:41:39.736Z" }, - { url = "https://files.pythonhosted.org/packages/d9/7a/290f868296c1ece914d565757ab363b04730a728b544beb567ceb3b2d96f/rignore-0.7.6-cp314-cp314-win_arm64.whl", hash = "sha256:104f215b60b3c984c386c3e747d6ab4376d5656478694e22c7bd2f788ddd8304", size = 656008, upload-time = "2025-11-05T21:41:29.028Z" }, - { url = "https://files.pythonhosted.org/packages/ca/d2/3c74e3cd81fe8ea08a8dcd2d755c09ac2e8ad8fe409508904557b58383d3/rignore-0.7.6-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bb24a5b947656dd94cb9e41c4bc8b23cec0c435b58be0d74a874f63c259549e8", size = 882835, upload-time = "2025-11-05T20:42:45.443Z" }, - { url = "https://files.pythonhosted.org/packages/77/61/a772a34b6b63154877433ac2d048364815b24c2dd308f76b212c408101a2/rignore-0.7.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b1e33c9501cefe24b70a1eafd9821acfd0ebf0b35c3a379430a14df089993e3", size = 820301, upload-time = "2025-11-05T20:42:29.226Z" }, - { url = "https://files.pythonhosted.org/packages/71/30/054880b09c0b1b61d17eeb15279d8bf729c0ba52b36c3ada52fb827cbb3c/rignore-0.7.6-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bec3994665a44454df86deb762061e05cd4b61e3772f5b07d1882a8a0d2748d5", size = 897611, upload-time = "2025-11-05T20:40:56.475Z" }, - { url = "https://files.pythonhosted.org/packages/1e/40/b2d1c169f833d69931bf232600eaa3c7998ba4f9a402e43a822dad2ea9f2/rignore-0.7.6-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26cba2edfe3cff1dfa72bddf65d316ddebf182f011f2f61538705d6dbaf54986", size = 873875, upload-time = "2025-11-05T20:41:11.561Z" }, - { url = "https://files.pythonhosted.org/packages/55/59/ca5ae93d83a1a60e44b21d87deb48b177a8db1b85e82fc8a9abb24a8986d/rignore-0.7.6-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffa86694fec604c613696cb91e43892aa22e1fec5f9870e48f111c603e5ec4e9", size = 1167245, upload-time = "2025-11-05T20:41:28.29Z" }, - { url = "https://files.pythonhosted.org/packages/a5/52/cf3dce392ba2af806cba265aad6bcd9c48bb2a6cb5eee448d3319f6e505b/rignore-0.7.6-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48efe2ed95aa8104145004afb15cdfa02bea5cdde8b0344afeb0434f0d989aa2", size = 941750, upload-time = "2025-11-05T20:41:43.111Z" }, - { url = "https://files.pythonhosted.org/packages/ec/be/3f344c6218d779395e785091d05396dfd8b625f6aafbe502746fcd880af2/rignore-0.7.6-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dcae43eb44b7f2457fef7cc87f103f9a0013017a6f4e62182c565e924948f21", size = 958896, upload-time = "2025-11-05T20:42:13.784Z" }, - { url = "https://files.pythonhosted.org/packages/c9/34/d3fa71938aed7d00dcad87f0f9bcb02ad66c85d6ffc83ba31078ce53646a/rignore-0.7.6-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2cd649a7091c0dad2f11ef65630d30c698d505cbe8660dd395268e7c099cc99f", size = 983992, upload-time = "2025-11-05T20:41:58.022Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/52a697158e9920705bdbd0748d59fa63e0f3233fb92e9df9a71afbead6ca/rignore-0.7.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42de84b0289d478d30ceb7ae59023f7b0527786a9a5b490830e080f0e4ea5aeb", size = 1078181, upload-time = "2025-11-05T21:40:18.151Z" }, - { url = "https://files.pythonhosted.org/packages/ac/65/aa76dbcdabf3787a6f0fd61b5cc8ed1e88580590556d6c0207960d2384bb/rignore-0.7.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:875a617e57b53b4acbc5a91de418233849711c02e29cc1f4f9febb2f928af013", size = 1139232, upload-time = "2025-11-05T21:40:35.966Z" }, - { url = "https://files.pythonhosted.org/packages/08/44/31b31a49b3233c6842acc1c0731aa1e7fb322a7170612acf30327f700b44/rignore-0.7.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8703998902771e96e49968105207719f22926e4431b108450f3f430b4e268b7c", size = 1117349, upload-time = "2025-11-05T21:40:53.013Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ae/1b199a2302c19c658cf74e5ee1427605234e8c91787cfba0015f2ace145b/rignore-0.7.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:602ef33f3e1b04c1e9a10a3c03f8bc3cef2d2383dcc250d309be42b49923cabc", size = 1127702, upload-time = "2025-11-05T21:41:10.881Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d3/18210222b37e87e36357f7b300b7d98c6dd62b133771e71ae27acba83a4f/rignore-0.7.6-cp314-cp314t-win32.whl", hash = "sha256:c1d8f117f7da0a4a96a8daef3da75bc090e3792d30b8b12cfadc240c631353f9", size = 647033, upload-time = "2025-11-05T21:42:00.095Z" }, - { url = "https://files.pythonhosted.org/packages/3e/87/033eebfbee3ec7d92b3bb1717d8f68c88e6fc7de54537040f3b3a405726f/rignore-0.7.6-cp314-cp314t-win_amd64.whl", hash = "sha256:ca36e59408bec81de75d307c568c2d0d410fb880b1769be43611472c61e85c96", size = 725647, upload-time = "2025-11-05T21:41:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/79/62/b88e5879512c55b8ee979c666ee6902adc4ed05007226de266410ae27965/rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896", size = 656035, upload-time = "2025-11-05T21:41:31.13Z" }, -] - -[[package]] -name = "rsa" -version = "4.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, -] - -[[package]] -name = "ruff" -version = "0.14.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/08/52232a877978dd8f9cf2aeddce3e611b40a63287dfca29b6b8da791f5e8d/ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4", size = 5859763, upload-time = "2025-12-18T19:28:57.98Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/01/933704d69f3f05ee16ef11406b78881733c186fe14b6a46b05cfcaf6d3b2/ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49", size = 13527080, upload-time = "2025-12-18T19:29:25.642Z" }, - { url = "https://files.pythonhosted.org/packages/df/58/a0349197a7dfa603ffb7f5b0470391efa79ddc327c1e29c4851e85b09cc5/ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f", size = 13797320, upload-time = "2025-12-18T19:29:02.571Z" }, - { url = "https://files.pythonhosted.org/packages/7b/82/36be59f00a6082e38c23536df4e71cdbc6af8d7c707eade97fcad5c98235/ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d", size = 12918434, upload-time = "2025-12-18T19:28:51.202Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/45c62a7f7e34da92a25804f813ebe05c88aa9e0c25e5cb5a7d23dd7450e3/ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77", size = 13371961, upload-time = "2025-12-18T19:29:04.991Z" }, - { url = "https://files.pythonhosted.org/packages/40/31/a5906d60f0405f7e57045a70f2d57084a93ca7425f22e1d66904769d1628/ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a", size = 13275629, upload-time = "2025-12-18T19:29:21.381Z" }, - { url = "https://files.pythonhosted.org/packages/3e/60/61c0087df21894cf9d928dc04bcd4fb10e8b2e8dca7b1a276ba2155b2002/ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f", size = 14029234, upload-time = "2025-12-18T19:29:00.132Z" }, - { url = "https://files.pythonhosted.org/packages/44/84/77d911bee3b92348b6e5dab5a0c898d87084ea03ac5dc708f46d88407def/ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935", size = 15449890, upload-time = "2025-12-18T19:28:53.573Z" }, - { url = "https://files.pythonhosted.org/packages/e9/36/480206eaefa24a7ec321582dda580443a8f0671fdbf6b1c80e9c3e93a16a/ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e", size = 15123172, upload-time = "2025-12-18T19:29:23.453Z" }, - { url = "https://files.pythonhosted.org/packages/5c/38/68e414156015ba80cef5473d57919d27dfb62ec804b96180bafdeaf0e090/ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d", size = 14460260, upload-time = "2025-12-18T19:29:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/b3/19/9e050c0dca8aba824d67cc0db69fb459c28d8cd3f6855b1405b3f29cc91d/ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f", size = 14229978, upload-time = "2025-12-18T19:29:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/51/eb/e8dd1dd6e05b9e695aa9dd420f4577debdd0f87a5ff2fedda33c09e9be8c/ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f", size = 14338036, upload-time = "2025-12-18T19:29:09.184Z" }, - { url = "https://files.pythonhosted.org/packages/6a/12/f3e3a505db7c19303b70af370d137795fcfec136d670d5de5391e295c134/ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d", size = 13264051, upload-time = "2025-12-18T19:29:13.431Z" }, - { url = "https://files.pythonhosted.org/packages/08/64/8c3a47eaccfef8ac20e0484e68e0772013eb85802f8a9f7603ca751eb166/ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405", size = 13283998, upload-time = "2025-12-18T19:29:06.994Z" }, - { url = "https://files.pythonhosted.org/packages/12/84/534a5506f4074e5cc0529e5cd96cfc01bb480e460c7edf5af70d2bcae55e/ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60", size = 13601891, upload-time = "2025-12-18T19:28:55.811Z" }, - { url = "https://files.pythonhosted.org/packages/0d/1e/14c916087d8598917dbad9b2921d340f7884824ad6e9c55de948a93b106d/ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830", size = 14336660, upload-time = "2025-12-18T19:29:16.531Z" }, - { url = "https://files.pythonhosted.org/packages/f2/1c/d7b67ab43f30013b47c12b42d1acd354c195351a3f7a1d67f59e54227ede/ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6", size = 13196187, upload-time = "2025-12-18T19:29:19.006Z" }, - { url = "https://files.pythonhosted.org/packages/fb/9c/896c862e13886fae2af961bef3e6312db9ebc6adc2b156fe95e615dee8c1/ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154", size = 14661283, upload-time = "2025-12-18T19:29:30.16Z" }, - { url = "https://files.pythonhosted.org/packages/74/31/b0e29d572670dca3674eeee78e418f20bdf97fa8aa9ea71380885e175ca0/ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6", size = 13729839, upload-time = "2025-12-18T19:28:48.636Z" }, -] - -[[package]] -name = "sentry-sdk" -version = "2.46.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/c140a5837649e2bf2ec758494fde1d9a016c76777eab64e75ef38d685bbb/sentry_sdk-2.46.0.tar.gz", hash = "sha256:91821a23460725734b7741523021601593f35731808afc0bb2ba46c27b8acd91", size = 374761, upload-time = "2025-11-24T09:34:13.932Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/b6/ce7c502a366f4835b1f9c057753f6989a92d3c70cbadb168193f5fb7499b/sentry_sdk-2.46.0-py2.py3-none-any.whl", hash = "sha256:4eeeb60198074dff8d066ea153fa6f241fef1668c10900ea53a4200abc8da9b1", size = 406266, upload-time = "2025-11-24T09:34:12.114Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sibu-backend" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "alembic" }, - { name = "asyncpg" }, - { name = "bcrypt" }, - { name = "fastapi", extra = ["standard"] }, - { name = "firebase-admin" }, - { name = "passlib" }, - { name = "psycopg2-binary" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "python-jose", extra = ["cryptography"] }, - { name = "python-multipart" }, - { name = "ruff" }, - { name = "sqlmodel" }, - { name = "supabase" }, -] - -[package.metadata] -requires-dist = [ - { name = "alembic", specifier = ">=1.17.2" }, - { name = "asyncpg", specifier = ">=0.31.0" }, - { name = "bcrypt", specifier = ">=5.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.123.0" }, - { name = "firebase-admin", specifier = ">=7.1.0" }, - { name = "passlib", specifier = ">=1.7.4" }, - { name = "psycopg2-binary", specifier = ">=2.9.11" }, - { name = "pydantic-settings", extras = ["dotenv"], specifier = ">=2.12.0" }, - { name = "python-dotenv", specifier = ">=1.2.1" }, - { name = "python-jose", extras = ["cryptography"], specifier = ">=3.5.0" }, - { name = "python-multipart", specifier = ">=0.0.20" }, - { name = "ruff", specifier = ">=0.14.10" }, - { name = "sqlmodel", specifier = ">=0.0.27" }, - { name = "supabase", specifier = ">=2.24.0" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "sqlalchemy" -version = "2.0.44" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/d3/c67077a2249fdb455246e6853166360054c331db4613cda3e31ab1cadbef/sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1", size = 2135479, upload-time = "2025-10-10T16:03:37.671Z" }, - { url = "https://files.pythonhosted.org/packages/2b/91/eabd0688330d6fd114f5f12c4f89b0d02929f525e6bf7ff80aa17ca802af/sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", size = 2123212, upload-time = "2025-10-10T16:03:41.755Z" }, - { url = "https://files.pythonhosted.org/packages/b0/bb/43e246cfe0e81c018076a16036d9b548c4cc649de241fa27d8d9ca6f85ab/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", size = 3255353, upload-time = "2025-10-10T15:35:31.221Z" }, - { url = "https://files.pythonhosted.org/packages/b9/96/c6105ed9a880abe346b64d3b6ddef269ddfcab04f7f3d90a0bf3c5a88e82/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", size = 3260222, upload-time = "2025-10-10T15:43:50.124Z" }, - { url = "https://files.pythonhosted.org/packages/44/16/1857e35a47155b5ad927272fee81ae49d398959cb749edca6eaa399b582f/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", size = 3189614, upload-time = "2025-10-10T15:35:32.578Z" }, - { url = "https://files.pythonhosted.org/packages/88/ee/4afb39a8ee4fc786e2d716c20ab87b5b1fb33d4ac4129a1aaa574ae8a585/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", size = 3226248, upload-time = "2025-10-10T15:43:51.862Z" }, - { url = "https://files.pythonhosted.org/packages/32/d5/0e66097fc64fa266f29a7963296b40a80d6a997b7ac13806183700676f86/sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", size = 2101275, upload-time = "2025-10-10T15:03:26.096Z" }, - { url = "https://files.pythonhosted.org/packages/03/51/665617fe4f8c6450f42a6d8d69243f9420f5677395572c2fe9d21b493b7b/sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", size = 2127901, upload-time = "2025-10-10T15:03:27.548Z" }, - { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" }, -] - -[[package]] -name = "sqlmodel" -version = "0.0.27" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "sqlalchemy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/90/5a/693d90866233e837d182da76082a6d4c2303f54d3aaaa5c78e1238c5d863/sqlmodel-0.0.27.tar.gz", hash = "sha256:ad1227f2014a03905aef32e21428640848ac09ff793047744a73dfdd077ff620", size = 118053, upload-time = "2025-10-08T16:39:11.938Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/92/c35e036151fe53822893979f8a13e6f235ae8191f4164a79ae60a95d66aa/sqlmodel-0.0.27-py3-none-any.whl", hash = "sha256:667fe10aa8ff5438134668228dc7d7a08306f4c5c4c7e6ad3ad68defa0e7aa49", size = 29131, upload-time = "2025-10-08T16:39:10.917Z" }, -] - -[[package]] -name = "starlette" -version = "0.50.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, -] - -[[package]] -name = "storage3" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deprecation" }, - { name = "httpx", extra = ["http2"] }, - { name = "pydantic" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/10/eb/4743955292d59f8e5408103aa2c3bb2d219c955099481e26a878ba3bbdef/storage3-2.24.0.tar.gz", hash = "sha256:4f26d2866ef6eb9349570e2ec70657e7e3cc884f419c58e64d99317891013743", size = 9764, upload-time = "2025-11-07T17:08:15.419Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/9a/9915392e8028c55556ed90f30d71e703fca49d6e4b129f1934e83c27de77/storage3-2.24.0-py3-none-any.whl", hash = "sha256:189364923c3a3279af863f2e5170700eddd45c7d861bbd360aebc40b6361f1a7", size = 19159, upload-time = "2025-11-07T17:08:14.001Z" }, -] - -[[package]] -name = "strenum" -version = "0.4.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/ad/430fb60d90e1d112a62ff57bdd1f286ec73a2a0331272febfddd21f330e1/StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff", size = 23384, upload-time = "2023-06-29T22:02:58.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/69/297302c5f5f59c862faa31e6cb9a4cd74721cd1e052b38e464c5b402df8b/StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659", size = 8851, upload-time = "2023-06-29T22:02:56.947Z" }, -] - -[[package]] -name = "supabase" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httpx" }, - { name = "postgrest" }, - { name = "realtime" }, - { name = "storage3" }, - { name = "supabase-auth" }, - { name = "supabase-functions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/c0/9a8f8b808450ab28642ca96f384b8071749524ff533db261e47941e228e3/supabase-2.24.0.tar.gz", hash = "sha256:9a1c0a56cc1c1caea4fc78354fd81b764f73bc4cd86932920be8ad9f127bc5ca", size = 9565, upload-time = "2025-11-07T17:08:17.415Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/67/f89c2104687dd7b9f375dd2fff8f5ffd63afbb0285df2d8fa96ebfb7b99e/supabase-2.24.0-py3-none-any.whl", hash = "sha256:44adea019a0964529a3021f45f25c15e719dff8e5d726634644df789eb23f64f", size = 16441, upload-time = "2025-11-07T17:08:16.096Z" }, -] - -[[package]] -name = "supabase-auth" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httpx", extra = ["http2"] }, - { name = "pydantic" }, - { name = "pyjwt", extra = ["crypto"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/be/2a/f3ec5d6c6dbac41e3e8848b34410e8a71efa879a151dcb5cc89258f3a004/supabase_auth-2.24.0.tar.gz", hash = "sha256:8b3ed605ce8cfa308e88620ccf9dc42c8780270353968e4b49853fe9a7849ec9", size = 38794, upload-time = "2025-11-07T17:08:19.847Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/57/c3696af055b3b43a9864d1dd6c0472023d61163dbee223e7deae7e81de2d/supabase_auth-2.24.0-py3-none-any.whl", hash = "sha256:9229d1d13cd21abc082ed81602226d4f8d03422f3e73d22412f55f24c374bc6f", size = 48019, upload-time = "2025-11-07T17:08:18.356Z" }, -] - -[[package]] -name = "supabase-functions" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httpx", extra = ["http2"] }, - { name = "strenum" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ff/c8/6b07d8e938bd44616304b573787f9d7033aae7f908ef60e0bc66805d56e3/supabase_functions-2.24.0.tar.gz", hash = "sha256:d98777b6433c2d916f135906685b73460f26e16a3d0c167dda0ae03e1a1f9b59", size = 4524, upload-time = "2025-11-07T17:08:21.805Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/da/d49051453766dbfdb5a086eebed7d3cb1814b6ff64ab6a90fd14edc13d46/supabase_functions-2.24.0-py3-none-any.whl", hash = "sha256:b93d79ffc446cb96faf03be550b6991847394064feec3ebf21954d3aff836d11", size = 8471, upload-time = "2025-11-07T17:08:20.943Z" }, -] - -[[package]] -name = "typer" -version = "0.20.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8f/28/7c85c8032b91dbe79725b6f17d2fffc595dff06a35c7a30a37bef73a1ab4/typer-0.20.0.tar.gz", hash = "sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37", size = 106492, upload-time = "2025-10-20T17:03:49.445Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/64/7713ffe4b5983314e9d436a90d5bd4f63b6054e2aca783a3cfc44cb95bbf/typer-0.20.0-py3-none-any.whl", hash = "sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a", size = 47028, upload-time = "2025-10-20T17:03:47.617Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, -] - -[[package]] -name = "urllib3" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.38.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef4688ca63bdb2fdf113ca0a3be33f94488f2cadb690b0cf/uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d", size = 80605, upload-time = "2025-10-18T13:46:44.63Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.22.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, - { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, - { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, - { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, - { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, - { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, - { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, - { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, - { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, - { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, - { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, - { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, - { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, - { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, - { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, - { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, - { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, - { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, - { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, - { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, - { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, - { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, - { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, - { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, - { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, - { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, - { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, - { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, - { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, - { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, - { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, - { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, - { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, - { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, - { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, - { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, - { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, - { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, - { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, - { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, - { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, - { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, - { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, - { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, - { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, - { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "yarl" -version = "1.22.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, - { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, - { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, - { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, - { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, - { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, - { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, - { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, - { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, - { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, - { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, - { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, - { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, - { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, - { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, - { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, - { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, - { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, - { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, - { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, - { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, - { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, - { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, - { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, - { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, - { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, - { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, - { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, - { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, - { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, - { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, - { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, - { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, - { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, - { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, - { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, -] diff --git a/backend/vertexdc_openapi.json b/backend/vertexdc_openapi.json deleted file mode 100644 index 803e09a448a9dae668688c0a6aa010671e6ba575..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38210 zcmeI5TTdOy5y$5_Qoh3x$wMM}*Bd8KdGk$KE4yn8a9%8gFks9s1_C&{R^+dqq<&qe zsOp)X%Nb@dhm4Sy<(%p6>gwu$UAyPM|M_>dQJq!i)nRp7?aA+B`TMW(@6XlO)t}_w zH}d}vUFiKwyO*2>9o3(-p=IzujDVDK9kQD z)#K`wJgI#iNbAdLU!FOZXYCp7PoG<)F)yT@_kUh}tlrAV$I@~kt-40LtUk#IS2E6r z<(U7H|G$vWlpY;R=c#l3oMwBTXnrrx*?b?$CvfMXv_2CG=+nPFlE1F5pJm2J%WvPv zr+JH=G{U9y@j-s}g<*F-K^d2a<=tPZJzXbkvPB_v(}Ltk3?#a87L*!{aYZ@DL};p)$s)Gn$&$h;1O>tN0zasEU&^+!RYerX0x4wIZ8 zR#AG}B-(jmGW}1HLgevE@a#tH2wQ;CF6iqY%3 ze{asc`aUxbDu@13J(3^WEnPVF50N-D(m|3u({;~<-=OiuQf}{#{Cq1~dRsJciS9_X zBM34D%I}K=p|8O+IP)f1121LAq7&Z>zg`IsK=Yr|%nxK2u^*8(_&|#tkwE?_m&=;< zq4evTY&Y@tb862{G(BXt$W;2aAHiJPE@X}%)RC+_IOxV?2H_RblJK5HoP&f=w|3+{+??}V$nVpdyIYD7RR>s7M*oE zJ+_@A(~u~a&MikC?|C&8itUVNGjgD@y4LkeMy_qIuu3y>7&rK>ayw0wn;7(gcx<-Y z$!wj;-;MW2*^bGxqb@V$xYqshCAX4XomZvYgznLG z_bCl?W&|dtZ`{z|@MNs*M%3R>r5^LQSk=w!xfth&SRQfy^Y`dBcWY&}^5_JX6k<2|}S@+h(AJLYSo7uul)j5Gf_2{& z)HR}$r>Ftbl{D1clwM0r?FqM^Y&O%Rv)HxxQtI(C8mA*4(OJD=a}h*cJJ-(Afv8@NoVA<$wZt@ zsm9}ecy1fj*s8IdgQflL{?8nhQ(hR#OzRa`uU$I3%ab$>HU;7-u8zSvYpJn8_4~Av ztci8w>d98awTOS_*%_z62CBh^R+g=oFBA2&TYKwL#XjR1xtg(D7~?VMZs@8k)15ce zYKmUx7$nKtgC|V{nXcCC=BRRa;zjF)Q|)#pei+}D>^7wJuG*nda?K8%?M%ETv(#rh zvw5bdEFLT_S(9<+@@y@j0{kVt?wfPiwu;wj>;G zs~4K&zT+NvWel4{05gaMwXX8;4bYu@5 z31_+UNGpW7X$>x{FJ89Ks|`6X#oIU*jmC`)>pb_ZFpsvm&RW8(ul2~YvyQr!vyJVU zI_HVo*n47O6Cr#kmd9B_HEa*Ht-W@xY-?NFjiqf-s+|2U^a@IJ-EHU;IBMG%yMey? z`8D(3v25=0J#fy8P0<@_S3c6P-ULjcXiJj?7-P;a%L} zwu{Zy(LG$+qnpB4PCKa{@A7@^$wgX)gXEiI^9(!DN?eX{>bIaF^Y_6giQFd=i_Z_X z4qu6HvsUc(uGNT7a}Jp?_hpBSTb)SpZtBbE&+n|eU#q1ELKLNbZ>+6ajQzSVr8zu{ zQsx!frah5&Zjt3yWjqCM9b*v9m@qoQ_qXP>_w(dwqK@|3pPrvrX?4!u zR@DBnaOogvb8go(nwSML!C8LK0^Fn`(j;*Ex<5k=G8p8Y^hQ0k8;;T^R0bPG@8u~X zV0d#>&S-41yt?%WRY@|xP5p6-B=4_Gm1kLW&72y&6Do@!e?hM>P@XkQNMJnwkCd|?cjS8f%>yjCU*6BY|MSe~zRWzz zmEIDf6}NeYRJoEZE5dXvJqUHn4u+iV)gWvXF_C8-TGOhYyigEy&M zh~;ekper<6`jzxd9sr8~G#aBxqwl~CR*w_4ifv@SZLGULlXyNL&P3-DE#BL=30%I) za@nVw4IS|Y(I=kSM{jS4z3ca>yM<7<1@!)ysP(AT+X3kjPwrm zMEmK-g1dWyS`Jh8j z(5hT?`J(vC)KpN>W*Ta``&s($FxNd0eZ9W>S)OGSk6pu|98`&J&-wLp*iLfTyLpVu zIez52po9#sWR>DOey}){y1b|1ahfJ&JH?nw`|Ndm@=5wegJ=cYJiDaNBSp%`d?x)o zsoO2>(VsD11G5`rO(CHr3sbp;7jnGJ(eH+M*EkLkx3k_Ba{H%6-*qhI2lxf2`Hl5* z^HFt%^?pm^qYJ>7Q<*7mhxl7>iZg%I>Wt6-@wVcAXo!DmqYo%7iB#>w|QGD z@;IZ2JcCiBYXe0}yRIAgD(CuG`_OS}E6JqwYC1cQ2N8#_SKl_Z)o`?RtfQAU6fjy; zCfj!HP7$YlemM?%pR0JiJR7aM`t8~7^ZK}VAsRmGfLRAL{i<09%sL={Yw$Q70G7@X z?id$_BksShL##eVW#dfL;>dlFFQeaG%K9{YQ{#@)_7~SaTvv44HGRH&hWRd>vY>Ve z`~QvnH@B~J&R9Ir>f%!@bF-uQUVRCxSH^a~x~}Kg2=5BXY3$>R&rP%b_)B`1s?klY zg?mvY`-c(9`semne~jRA+0ITn594PuqxDfJR&-*vb z@93`+@mSPX!;ksWKG}AX2c?TQ)o2c}%?oor!(*yqKDEvv#~_n^tM=($TYPivy-5iz z89n!OzFGQO8n@-`_SBz(=~|<&;}7@Rr;3GZ?DkclXCZI8K9j$xRc_1UQz_zaT-P~K z!^gfnlbOG}6SI1jQMB5;ZloA}j%iARW2QY7b*o8CR|L?hnb9Xk!O@hw zt%Nv8d4+yG^y!ZR)e#A47!xTqsUeotj#?^f>xNE|>h;2(p?QV6ebI*o$`OBRRjlv` zn%YPGatgY5-QZX${XulKR|j>~n668f;kGz8O?Kk8s0D+N7|_k_{5h-9ME0rhf6i)n zR-+{4Q)fDcAmGi>KgV_RIZ7GP_L@7q53QL*){dm2lA3+2c+J7N_iZ-B_VwABVcxTO z^%jlLGc)Q_a%N8b3vwXwybZHClp8s)X+aB4-H=n|y>e|4i6({pJkdA;?=4lUP)`FA zJ!y+V#B;U%5eK3yc6LSINor?uhjFj2`yYq?^sTMdpK5*Pqn|WSP1zh-35`d%&W2O< zv3#bCWLEP~xn>h4#$KA5Dz^Yjy*`(n z46g8&-|3{u){7Bs);hY$Ygu;sB*mn>em}HVE`v%YCoiQAU2leXB$1Q6e&~sClXZ;o zzQ{{*)OK&fBk2+9-wDp0$y<|sgk}wqN+@Wr=b!A^Iu5*+u}>1EM1qMrai4`!o8M!> MobBhg)o-f*0Vl;AegFUf diff --git a/frontend/src/firebaseConfig.ts b/frontend/src/firebaseConfig.ts deleted file mode 100644 index 6f77cfb..0000000 --- a/frontend/src/firebaseConfig.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { initializeApp } from 'firebase/app'; -import { - getAuth, - GoogleAuthProvider, - signInWithPopup, - signInWithRedirect, - getRedirectResult -} from 'firebase/auth'; - -const firebaseConfig = { - apiKey: "AIzaSyAG8nmGLHYmXGkl018NjW2sMcIiutM4ne0", - authDomain: "sibu2-0-transport-2026.firebaseapp.com", - projectId: "sibu2-0-transport-2026", - storageBucket: "sibu2-0-transport-2026.firebasestorage.app", - messagingSenderId: "1015760260932", - appId: "1:1015760260932:web:5657b544bc8099ab54d111" -}; - -const app = initializeApp(firebaseConfig); -export const auth = getAuth(app); -export const googleProvider = new GoogleAuthProvider(); -googleProvider.setCustomParameters({ - prompt: 'select_account' -}); - -// Detect if the user is on a mobile device -const isMobile = () => { - return /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test(navigator.userAgent); -}; - -/** - * Signs in with Google. - * - Uses signInWithPopup on desktop (fast, no page reload) - * - Uses signInWithRedirect on mobile (avoids popup blocking on mobile browsers) - */ -export const signInWithGoogle = async (): Promise<{ user: any; token: string }> => { - try { - if (isMobile()) { - console.log("DEBUG: Intentando signInWithRedirect..."); - await signInWithRedirect(auth, googleProvider); - // On mobile, the page reloads, so we return a promise that doesn't resolve - // here as the app will re-initialize on the callback URL. - return new Promise(() => { }); - } else { - console.log("DEBUG: Intentando signInWithPopup..."); - const result = await signInWithPopup(auth, googleProvider); - const token = await result.user.getIdToken(true); // Force refresh to get fresh token - return { user: result.user, token }; - } - } catch (error: any) { - console.error("DEBUG: Error al iniciar Google:", error); - throw error; - } -}; - -/** - * Call this once when the app loads (e.g., in AuthView.vue) to - * handle the result from a Google redirect login on mobile. - */ -export const getGoogleRedirectResult = async (): Promise<{ user: any; token: string } | null> => { - try { - const result = await getRedirectResult(auth); - if (result && result.user) { - const token = await result.user.getIdToken(true); - console.log("DEBUG: Redirect result obtained for:", result.user.email); - return { user: result.user, token }; - } - return null; - } catch (error: any) { - console.error("DEBUG: Error en getRedirectResult:", error); - // Throw the error so the UI can catch it and show a message - throw error; - } -}; diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index dd3f93b..5704dc3 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -1,171 +1,188 @@ /** Vue Router configuration */ import { createRouter, createWebHistory } from 'vue-router' +import { supabase } from '@/supabase' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ - // ─── Vistas Públicas Core (cargadas en el chunk principal) ─────────── + // ─── Vistas Públicas Core ─────────────────────────────────────────── { path: '/', name: 'splash', - component: () => import(/* webpackChunkName: "splash" */ '@/views/SplashScreen.vue'), + component: () => import('@/views/SplashScreen.vue'), }, { path: '/map', name: 'map', - component: () => import(/* webpackChunkName: "map" */ '@/views/MapView.vue'), + component: () => import('@/views/MapView.vue'), }, { path: '/login', name: 'auth', - component: () => import(/* webpackChunkName: "auth" */ '@/views/AuthView.vue'), + component: () => import('@/views/AuthView.vue'), }, - // ─── Vistas de Transporte (chunk: transport) ───────────────────────── + // ─── Vistas de Transporte ──────────────────────────────────────────── { path: '/routes', name: 'routes', - component: () => import(/* webpackChunkName: "transport" */ '@/views/RoutesView.vue'), + component: () => import('@/views/RoutesView.vue'), }, { path: '/schedules', name: 'schedules', - component: () => import(/* webpackChunkName: "transport" */ '@/views/SchedulesView.vue'), + component: () => import('@/views/SchedulesView.vue'), }, { path: '/bus-stop/:id', name: 'bus-stop-details', - component: () => import(/* webpackChunkName: "transport" */ '@/views/BusStopDetailsView.vue'), + component: () => import('@/views/BusStopDetailsView.vue'), }, { path: '/taxi', name: 'taxi', - component: () => import(/* webpackChunkName: "transport" */ '@/views/TaxiView.vue'), + component: () => import('@/views/TaxiView.vue'), }, - // ─── Vistas de Descubrir (chunk: discover) ─────────────────────────── + // ─── Vistas de Descubrir ───────────────────────────────────────────── { path: '/discover', name: 'discover', - component: () => import(/* webpackChunkName: "discover" */ '@/views/DiscoverView.vue'), + component: () => import('@/views/DiscoverView.vue'), }, { path: '/business/:id', name: 'business-details', - component: () => import(/* webpackChunkName: "discover" */ '@/views/BusinessDetailsView.vue'), + component: () => import('@/views/BusinessDetailsView.vue'), }, { path: '/coupons', name: 'coupons', - component: () => import(/* webpackChunkName: "discover" */ '@/views/CouponsView.vue'), + component: () => import('@/views/CouponsView.vue'), }, - // ─── Vistas de Usuario (chunk: user) ───────────────────────────────── + // ─── Vistas de Usuario ─────────────────────────────────────────────── { path: '/favorites', name: 'favorites', - component: () => import(/* webpackChunkName: "user" */ '@/views/FavoritesView.vue'), + component: () => import('@/views/FavoritesView.vue'), }, { path: '/profile', name: 'profile', - component: () => import(/* webpackChunkName: "user" */ '@/views/ProfileView.vue'), + component: () => import('@/views/ProfileView.vue'), meta: { requiresAuth: true } }, - // ─── Vistas de Admin (chunk: admin — solo carga para admins) ───────── + // ─── Vistas de Admin ───────────────────────────────────────────────── { path: '/admin', name: 'admin-panel', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminPanel.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminPanel.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/bus-stops', name: 'admin-bus-stops', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminBusStops.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminBusStops.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/routes', name: 'admin-routes', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminRoutes.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminRoutes.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/reports', name: 'admin-reports', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminReports.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminReports.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/schedules', name: 'admin-schedules', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminSchedules.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminSchedules.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/drivers', name: 'admin-drivers', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminDrivers.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminDrivers.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/analytics', name: 'admin-analytics', - component: () => import(/* webpackChunkName: "admin" */ '@/views/StrategicAnalytics.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/StrategicAnalytics.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/taxis', name: 'admin-taxis', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminTaxis.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminTaxis.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, { path: '/admin/shuttles', name: 'admin-shuttles', - component: () => import(/* webpackChunkName: "admin" */ '@/views/AdminShuttles.vue'), - meta: { requiresAuth: true, role: 'admin' } + component: () => import('@/views/AdminShuttles.vue'), + meta: { requiresAuth: true, role: 'ADMIN' } }, - // ─── Vistas de Roles Especiales (chunk: roles) ─────────────────────── + // ─── Vistas de Roles Especiales ────────────────────────────────────── { path: '/promoter', name: 'promoter-dashboard', - component: () => import(/* webpackChunkName: "roles" */ '@/views/PromoterDashboard.vue'), + component: () => import('@/views/PromoterDashboard.vue'), meta: { requiresAuth: true, role: ['PROMOTER', 'ADMIN'] } }, { path: '/driver', name: 'driver-dashboard', - component: () => import(/* webpackChunkName: "roles" */ '@/views/DriverDashboard.vue'), + component: () => import('@/views/DriverDashboard.vue'), meta: { requiresAuth: true, role: ['DRIVER', 'ADMIN'] } }, ], }) -router.beforeEach((to, _from, next) => { - const token = localStorage.getItem('auth_token') - const role = localStorage.getItem('user_role')?.toUpperCase() - - if (to.meta.requiresAuth && !token) { - next('/login') - } else if (to.meta.role) { - const allowedRoles = Array.isArray(to.meta.role) ? to.meta.role : [to.meta.role] - const hasAccess = allowedRoles.some(r => r.toUpperCase() === role) - - if (!hasAccess) { - if (role === 'ADMIN') next('/admin') - else if (role === 'DRIVER') next('/driver') - else if (role === 'PROMOTER') next('/promoter') - else next('/map') - } else { - next() - } - } else { - next() +router.beforeEach(async (to, _from, next) => { + // Rutas públicas: siempre pasan sin verificación + if (!to.meta.requiresAuth && !to.meta.role) { + return next() } + + // Leer sesión activa de Supabase (sustituye el viejo localStorage) + const { data: { session } } = await supabase.auth.getSession() + + // Ruta protegida sin sesión → redirige a login + if (to.meta.requiresAuth && !session) { + return next('/login') + } + + // Ruta con restricción de rol → verificar en la BD + if (to.meta.role && session) { + const { data: profile } = await supabase + .from('users') + .select('role') + .eq('id', session.user.id) + .single() + + const userRole = profile?.role?.toUpperCase() || 'PASSENGER' + const allowedRoles = Array.isArray(to.meta.role) + ? (to.meta.role as string[]).map(r => r.toUpperCase()) + : [(to.meta.role as string).toUpperCase()] + + if (!allowedRoles.includes(userRole)) { + // Redirigir a la vista correcta según su rol real + if (userRole === 'ADMIN') return next('/admin') + else if (userRole === 'DRIVER') return next('/driver') + else if (userRole === 'PROMOTER') return next('/promoter') + else return next('/map') + } + } + + next() }) export default router diff --git a/frontend/src/services/analyticsService.ts b/frontend/src/services/analyticsService.ts index 1111c7e..cd2668e 100644 --- a/frontend/src/services/analyticsService.ts +++ b/frontend/src/services/analyticsService.ts @@ -1,22 +1,9 @@ -import { apiClient } from './apiClient' - -export interface AnalyticsEvent { - event_name: 'app_open' | 'screen_view' | 'route_selected' | 'stop_selected' | 'schedule_viewed' | 'reminder_created' | 'promo_view' | 'promo_click' | 'taxi_view' | 'taxi_click' | 'shuttle_view' | 'shuttle_contact' | 'business_view' | 'business_contact' | 'login' | 'sign_up' - screen_name?: string - item_id?: string - properties?: Record -} - +/** analyticsService — stub. Analytics via Supabase can be implemented in v3 */ export const analyticsService = { - logEvent(event: AnalyticsEvent) { - // Log asynchronously without awaiting to avoid blocking UI - apiClient.post('/api/analytics/event', event).catch(error => { - console.warn('Analytics capture failed:', error) - }) + logEvent(_event: { event_name: string; properties?: Record }) { + // no-op }, - - async getStats() { - const response = await apiClient.get('/api/analytics/dashboard/stats') - return response.data + async getDashboardStats() { + return null } } diff --git a/frontend/src/services/apiClient.ts b/frontend/src/services/apiClient.ts deleted file mode 100644 index 39f61bd..0000000 --- a/frontend/src/services/apiClient.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** Base API client for making HTTP requests to the backend */ -import axios from 'axios' - -export const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000' - -const client = axios.create({ - baseURL: API_URL, - headers: { - 'Content-Type': 'application/json', - }, - timeout: 60000, -}) - -// Request interceptor -client.interceptors.request.use( - (config) => { - const token = localStorage.getItem('auth_token') - if (token) { - config.headers.Authorization = `Bearer ${token}` - } - return config - }, - (error) => { - return Promise.reject(error) - } -) - -// Response interceptor -client.interceptors.response.use( - (response) => response, - (error) => { - if (error.response) { - console.error('API Error:', error.response.status, error.response.data) - // Si el token expiró o es inválido, limpiar sesión y redirigir al login - if (error.response.status === 401) { - const currentPath = window.location.pathname - // Solo redirigir si no estamos ya en la página de login - if (!currentPath.includes('/auth') && !currentPath.includes('/login')) { - localStorage.removeItem('auth_token') - localStorage.removeItem('user_role') - localStorage.removeItem('user_name') - localStorage.removeItem('profile_photo_url') - // Redirigir al login con mensaje - window.location.href = '/auth?reason=session_expired' - } - } - } else if (error.request) { - // La solicitud fue hecha pero no hubo respuesta (timeout, servidor dormido, etc.) - console.error('Network Error: No response from server', error.message) - } - return Promise.reject(error) - } -) - -export const apiClient = client -export default apiClient diff --git a/frontend/src/services/favoritesService.ts b/frontend/src/services/favoritesService.ts index c1685be..d6c3671 100644 --- a/frontend/src/services/favoritesService.ts +++ b/frontend/src/services/favoritesService.ts @@ -1,13 +1,18 @@ /** Service for favorite-related API calls */ -import { apiClient } from './apiClient' +import { supabase } from '@/supabase' import type { Favorite } from '@/types' export const favoritesService = { /** Get all favorites for the current user */ async getMyFavorites(itemType?: string): Promise { - const params = itemType ? { item_type: itemType } : {} - const response = await apiClient.get('/api/favorites', { params }) - return response.data + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) return [] + + let query = supabase.from('favorites').select('*').eq('user_id', userData.user.id) + if (itemType) query = query.eq('item_type', itemType) + const { data, error } = await query + if (error) throw new Error(error.message) + return data as Favorite[] }, /** Add a new favorite */ @@ -17,39 +22,53 @@ export const favoritesService = { itemName?: string, itemImage?: string ): Promise { - const response = await apiClient.post('/api/favorites', { + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) throw new Error('Not authenticated') + + const { data, error } = await supabase.from('favorites').insert([{ + user_id: userData.user.id, item_type: itemType, item_id: itemId, item_name: itemName, item_image: itemImage - }) - return response.data + }]).select().single() + if (error) throw new Error(error.message) + return data as Favorite }, /** Remove a favorite by type and ID */ async removeFavorite(itemType: string, itemId: string): Promise { - await apiClient.delete(`/api/favorites/${itemType}/${itemId}`) + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) throw new Error('Not authenticated') + + const { error } = await supabase.from('favorites') + .delete() + .eq('user_id', userData.user.id) + .eq('item_type', itemType) + .eq('item_id', itemId) + if (error) throw new Error(error.message) }, - /** Remove a favorite by favorite ID (legacy support) */ + /** Remove a favorite by favorite ID */ async removeFavoriteById(favoriteId: string): Promise { - // This requires finding the favorite first to get type and id - const favorites = await this.getMyFavorites() - const favorite = favorites.find(f => f.id === favoriteId) - if (favorite) { - await this.removeFavorite(favorite.item_type, favorite.item_id) - } + const { error } = await supabase.from('favorites').delete().eq('id', favoriteId) + if (error) throw new Error(error.message) }, /** Check if an item is favorited */ async checkFavorite(itemType: string, itemId: string): Promise { try { - const response = await apiClient.get<{ is_favorite: boolean }>( - `/api/favorites/check/${itemType}/${itemId}` - ) - return response.data.is_favorite - } catch (error) { - console.error('Error checking favorite:', error) + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) return false + + const { data } = await supabase.from('favorites') + .select('id') + .eq('user_id', userData.user.id) + .eq('item_type', itemType) + .eq('item_id', itemId) + .single() + return !!data + } catch { return false } }, @@ -62,7 +81,6 @@ export const favoritesService = { itemImage?: string ): Promise { const isFavorite = await this.checkFavorite(itemType, itemId) - if (isFavorite) { await this.removeFavorite(itemType, itemId) return false diff --git a/frontend/src/services/reportsService.ts b/frontend/src/services/reportsService.ts index 4204496..7059e91 100644 --- a/frontend/src/services/reportsService.ts +++ b/frontend/src/services/reportsService.ts @@ -1,28 +1,17 @@ -import { apiClient } from './apiClient'; - -export interface Report { - id: string; - user_id?: string; - user_name?: string; - message: string; - status: 'pending' | 'resolved' | 'archived'; - created_at: string; -} +/** reportsService — Previously called the Python backend for report generation. + * Reports are now generated directly from Supabase queries in the AdminReports view. */ +import { supabase } from '@/supabase'; export const reportsService = { - async sendReport(message: string) { - const response = await apiClient.post('/api/reports', { message }); - return response.data; + async getRoutesReport() { + const { data, error } = await supabase.from('routes').select('*') + if (error) throw new Error(error.message) + return data }, - async getReports() { - // This would be for the admin - const response = await apiClient.get('/api/reports'); - return response.data; - }, - - async updateReportStatus(reportId: string, status: string) { - const response = await apiClient.patch(`/api/reports/${reportId}`, { status }); - return response.data; + async getUsersReport() { + const { data, error } = await supabase.from('users').select('id, email, role, created_at, is_active') + if (error) throw new Error(error.message) + return data } -}; +} diff --git a/frontend/src/services/schedulesService.ts b/frontend/src/services/schedulesService.ts index 8531090..42ef5ca 100644 --- a/frontend/src/services/schedulesService.ts +++ b/frontend/src/services/schedulesService.ts @@ -1,32 +1,44 @@ -import { apiClient } from './apiClient'; +import { supabase } from '@/supabase'; export const schedulesService = { async getRouteSchedules(routeId: string, onlyPublished = true) { - const response = await apiClient.get('/api/schedules', { - params: { route_id: routeId, only_published: onlyPublished } - }); - return response.data; + let query = supabase.from('bus_schedules').select('*').eq('route_id', routeId) + if (onlyPublished) query = query.eq('is_published', true) + const { data, error } = await query + if (error) throw new Error(error.message) + return data }, async getStopSchedules(stopId: string, onlyPublished = true) { - const response = await apiClient.get('/api/schedules', { - params: { stop_id: stopId, only_published: onlyPublished } - }); - return response.data; + // Get routes passing through this stop, then get their schedules + const { data: routeStops, error: rsError } = await supabase + .from('route_stops').select('route_id').eq('stop_id', stopId) + if (rsError) throw new Error(rsError.message) + + const routeIds = (routeStops || []).map((rs: any) => rs.route_id) + if (routeIds.length === 0) return [] + + let query = supabase.from('bus_schedules').select('*').in('route_id', routeIds) + if (onlyPublished) query = query.eq('is_published', true) + const { data, error } = await query + if (error) throw new Error(error.message) + return data }, async createSchedule(scheduleData: any) { - const response = await apiClient.post('/api/schedules', scheduleData); - return response.data; + const { data, error } = await supabase.from('bus_schedules').insert([scheduleData]).select().single() + if (error) throw new Error(error.message) + return data }, async updateSchedule(scheduleId: string, updateData: any) { - const response = await apiClient.put(`/api/schedules/${scheduleId}`, updateData); - return response.data; + const { data, error } = await supabase.from('bus_schedules').update(updateData).eq('id', scheduleId).select().single() + if (error) throw new Error(error.message) + return data }, async deleteSchedule(scheduleId: string) { - const response = await apiClient.delete(`/api/schedules/${scheduleId}`); - return response.data; + const { error } = await supabase.from('bus_schedules').delete().eq('id', scheduleId) + if (error) throw new Error(error.message) } }; diff --git a/frontend/src/services/telemetryService.ts b/frontend/src/services/telemetryService.ts index ff2c652..fa54303 100644 --- a/frontend/src/services/telemetryService.ts +++ b/frontend/src/services/telemetryService.ts @@ -1,32 +1,14 @@ -import { apiClient } from './apiClient' - -export interface TelemetryData { - latitude: number - longitude: number - speed?: number - heading?: number - status?: 'active' | 'offline' | 'break' -} - -export interface ActiveUnit { - user_id: string - full_name: string - latitude: number - longitude: number - speed?: number - heading?: number - timestamp: string - vehicle_type: string - license_plate: string -} +import { supabase } from '@/supabase'; +/** telemetryService — Previously sent GPS data to the Python backend. + * Now it's a no-op stub since we don't have a custom backend. + * Realtime GPS tracking can be implemented via Supabase Realtime in the future. */ export const telemetryService = { - async sendTelemetry(data: TelemetryData) { - return await apiClient.post('/api/telemetry', data) + async sendLocation(_data: any) { + // No-op: telemetry via Supabase Realtime can be implemented in v3 + return null }, - - async getActiveUnits(): Promise { - const response = await apiClient.get('/api/telemetry/active') - return response.data + async getDriverLocation(_driverId: string) { + return null } } diff --git a/frontend/src/services/usersService.ts b/frontend/src/services/usersService.ts index 8da9c67..7c7a0c4 100644 --- a/frontend/src/services/usersService.ts +++ b/frontend/src/services/usersService.ts @@ -1,27 +1,35 @@ -import { apiClient } from './apiClient'; +import { supabase } from '@/supabase'; export const usersService = { async searchUsers(email: string) { - const response = await apiClient.get('/api/users/search', { - params: { email } - }); - return response.data; + const { data, error } = await supabase.from('users').select('*').ilike('email', `%${email}%`) + if (error) throw new Error(error.message) + return data }, async getUserDetails(userId: string) { - const response = await apiClient.get(`/api/users/${userId}`); - return response.data; + const { data, error } = await supabase.from('users').select('*').eq('id', userId).single() + if (error) throw new Error(error.message) + return data }, async getPendingDrivers() { - const response = await apiClient.get('/api/users/pending-drivers'); - return response.data; + const { data, error } = await supabase + .from('driver_profiles') + .select('*, user:users(*)') + .eq('users.is_verified', false) + if (error) throw new Error(error.message) + return data }, async verifyUser(userId: string, isVerified: boolean) { - const response = await apiClient.post(`/api/users/${userId}/verify`, null, { - params: { is_verified: isVerified } - }); - return response.data; + const { data, error } = await supabase + .from('users') + .update({ is_verified: isVerified }) + .eq('id', userId) + .select() + .single() + if (error) throw new Error(error.message) + return data } }; diff --git a/frontend/src/stores/favorites.ts b/frontend/src/stores/favorites.ts index c0fc5a2..41bbbc8 100644 --- a/frontend/src/stores/favorites.ts +++ b/frontend/src/stores/favorites.ts @@ -1,6 +1,6 @@ -import { defineStore } from 'pinia' +import { defineStore } from 'pinia' import { ref, computed } from 'vue' -import { apiClient } from '@/services/apiClient' +import { supabase } from '@/supabase' export interface Favorite { id: string @@ -16,19 +16,24 @@ export const useFavoritesStore = defineStore('favorites', () => { const favorites = ref([]) const isLoading = ref(false) - // Computed const coupons = computed(() => favorites.value.filter(f => f.item_type === 'coupon')) const businesses = computed(() => favorites.value.filter(f => f.item_type === 'business')) const taxis = computed(() => favorites.value.filter(f => f.item_type === 'taxi')) const routes = computed(() => favorites.value.filter(f => f.item_type === 'route')) const stops = computed(() => favorites.value.filter(f => f.item_type === 'stop')) - // Actions async function loadFavorites() { isLoading.value = true try { - const response = await apiClient.get('/api/favorites') - favorites.value = response.data + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) { favorites.value = []; return } + + const { data, error } = await supabase + .from('favorites') + .select('*') + .eq('user_id', userData.user.id) + if (error) throw error + favorites.value = data as Favorite[] } catch (error) { console.error('Error loading favorites:', error) } finally { @@ -43,19 +48,20 @@ export const useFavoritesStore = defineStore('favorites', () => { itemImage?: string ) { try { - const response = await apiClient.post('/api/favorites', { + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) throw new Error('Not authenticated') + + const { data, error } = await supabase.from('favorites').insert([{ + user_id: userData.user.id, item_type: itemType, item_id: itemId, item_name: itemName, item_image: itemImage - }) - favorites.value.unshift(response.data) + }]).select().single() + if (error) throw error + favorites.value.unshift(data as Favorite) return true - } catch (error: any) { - if (error.response?.status === 400) { - // Already favorited - return false - } + } catch (error) { console.error('Error adding favorite:', error) throw error } @@ -63,7 +69,15 @@ export const useFavoritesStore = defineStore('favorites', () => { async function removeFavorite(itemType: string, itemId: string) { try { - await apiClient.delete(`/api/favorites/${itemType}/${itemId}`) + const { data: userData } = await supabase.auth.getUser() + if (!userData?.user) throw new Error('Not authenticated') + + const { error } = await supabase.from('favorites') + .delete() + .eq('user_id', userData.user.id) + .eq('item_type', itemType) + .eq('item_id', itemId) + if (error) throw error favorites.value = favorites.value.filter( f => !(f.item_type === itemType && f.item_id === itemId) ) @@ -83,7 +97,6 @@ export const useFavoritesStore = defineStore('favorites', () => { const existing = favorites.value.find( f => f.item_type === itemType && f.item_id === itemId ) - if (existing) { await removeFavorite(itemType, itemId) return false @@ -100,17 +113,7 @@ export const useFavoritesStore = defineStore('favorites', () => { } return { - favorites, - isLoading, - coupons, - businesses, - taxis, - routes, - stops, - loadFavorites, - addFavorite, - removeFavorite, - toggleFavorite, - isFavorite + favorites, isLoading, coupons, businesses, taxis, routes, stops, + loadFavorites, addFavorite, removeFavorite, toggleFavorite, isFavorite } }) diff --git a/frontend/src/utils/imageUrl.ts b/frontend/src/utils/imageUrl.ts index 6834466..2cd071b 100644 --- a/frontend/src/utils/imageUrl.ts +++ b/frontend/src/utils/imageUrl.ts @@ -1,8 +1,10 @@ -import { API_URL } from '@/services/apiClient' +import { SUPABASE_URL } from '@/supabase' + +const STORAGE_URL = `${SUPABASE_URL}/storage/v1/object/public/uploads/` /** * Returns a full URL for an image path. - * Handles null/undefined paths, absolute URLs, and relative backend paths. + * Handles Supabase Storage paths and absolute URLs (legacy or external). */ export function getImageUrl(path?: string | null, type: 'taxi' | 'shuttle' | 'business' | 'coupon' = 'business') { if (!path) { @@ -16,23 +18,12 @@ export function getImageUrl(path?: string | null, type: 'taxi' | 'shuttle' | 'bu return `https://ui-avatars.com/api/?name=${name}&background=fee715&color=101820&size=256&bold=true` } + // Already a full URL (Supabase Storage or external) if (path.startsWith('http')) { return path } - // Ensure path starts with / for joining with API_URL - const cleanPath = path.startsWith('/') ? path : `/${path}` - - // Ensure API_URL includes protocol if missing (safety check) - let cleanBaseUrl = API_URL.trim() - if (!cleanBaseUrl.startsWith('http')) { - cleanBaseUrl = `https://${cleanBaseUrl}` - } - - // Remove trailing slash from base URL - if (cleanBaseUrl.endsWith('/')) { - cleanBaseUrl = cleanBaseUrl.slice(0, -1) - } - - return `${cleanBaseUrl}${cleanPath}` + // Relative path → Supabase Storage + const cleanPath = path.startsWith('/') ? path.slice(1) : path + return `${STORAGE_URL}${cleanPath}` } diff --git a/frontend/src/views/AdminDrivers.vue b/frontend/src/views/AdminDrivers.vue index 62baa03..10fc525 100644 --- a/frontend/src/views/AdminDrivers.vue +++ b/frontend/src/views/AdminDrivers.vue @@ -1,4 +1,4 @@ -