From a2ede1f58249c047e280eaff42fe6c59ea2afda6 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sat, 4 May 2024 15:50:36 +0000
Subject: [PATCH 01/13] fix/ci-optimizations (#2)

Reviewed-on: https://git.kluster.moll.re/remoll/fast-network-navigation/pulls/2
---
 .drone.yml                          | 25 -----------------------
 .gitea/workflows/build-android.yaml | 19 +++++++++++++-----
 .gitea/workflows/build-web.yaml     | 17 ++++++++++++----
 .gitea/workflows/test.yaml          | 31 +++++++++++++++++++++++++++++
 4 files changed, 58 insertions(+), 34 deletions(-)
 delete mode 100644 .drone.yml
 create mode 100644 .gitea/workflows/test.yaml

diff --git a/.drone.yml b/.drone.yml
deleted file mode 100644
index 1ea50ce..0000000
--- a/.drone.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-kind: pipeline
-type: kubernetes
-name: build-apk
-
-clone:
-  depth: 1
-
-steps:
-  - name: build
-    image: cirrusci/flutter:stable
-    pull: true
-    commands:
-      - flutter packages get
-      - flutter build apk --release --split-per-abi
-      - mkdir apks
-      - mv build/app/outputs/apk/*/*/*.apk apks
-
-  - name: Publish APK
-    image: plugins/gitea-release
-    settings:
-      api_key:
-        from_secret: GITEA_TOKEN
-trigger:
-  event:
-    - push
\ No newline at end of file
diff --git a/.gitea/workflows/build-android.yaml b/.gitea/workflows/build-android.yaml
index 76305b1..b714b6c 100644
--- a/.gitea/workflows/build-android.yaml
+++ b/.gitea/workflows/build-android.yaml
@@ -1,5 +1,10 @@
-on: push
-name: Test, Build and Release apk
+on:
+  pull_request:
+    branches:
+      - main
+
+name: Build and release APK
+
 jobs:
   build:
     name: Build APK
@@ -10,6 +15,7 @@ jobs:
       run: |
         sudo apt-get update
         sudo apt-get install -y xz-utils unzip
+
     - uses: https://gitea.com/actions/checkout@v4
 
     - uses: https://github.com/actions/setup-java@v4
@@ -22,19 +28,22 @@ jobs:
         channel: stable
         flutter-version: 3.19.6
         cache: true
+
     - name: Setup Android SDK
       uses: https://github.com/android-actions/setup-android@v3
 
     - run: flutter pub get
-    # - run: flutter test
+
     - run: flutter build apk --debug --split-per-abi
-    
+
     - name: Release APK
       uses: https://gitea.com/akkuman/gitea-release-action@v1
       with:
         files: build/app/outputs/flutter-apk/*.apk
+        name: Testing release
+        release_name: testing
         tag: testing
-        release_name: Testing release
+        tag_name: testing
         release_body: "This is a testing release."
         prerelease: true
         token: ${{ secrets.GITEA_TOKEN }}
diff --git a/.gitea/workflows/build-web.yaml b/.gitea/workflows/build-web.yaml
index cc08a5e..cdb817c 100644
--- a/.gitea/workflows/build-web.yaml
+++ b/.gitea/workflows/build-web.yaml
@@ -1,21 +1,30 @@
-on: push
-name: Test, Build and Release web
+on:
+  pull_request:
+    branches:
+      - main
+
+name: Build web
+
 jobs:
   build:
     name: Build Web
     runs-on: k8s
     steps:
+
     - name: Install prerequisites
       run: |
         sudo apt-get update
         sudo apt-get install -y xz-utils
 
     - uses: actions/checkout@v4
+
     - uses: https://github.com/subosito/flutter-action@v2
       with:
         channel: stable
         flutter-version: 3.19.6
         cache: true
-    - run: flutter pub get
-    # - run: flutter test
+
+    - run: flutter pub get
+
+    - run: flutter build web
 
diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml
new file mode 100644
index 0000000..7f22525
--- /dev/null
+++ b/.gitea/workflows/test.yaml
@@ -0,0 +1,31 @@
+on:
+  push:
+  pull_request:
+    branches:
+      - main
+
+
+name: Test code
+
+jobs:
+  test:
+    name: Test code
+    runs-on: k8s
+    steps:
+
+    - name: Install prerequisites
+      run: |
+        sudo apt-get update
+        sudo apt-get install -y xz-utils
+
+    - uses: actions/checkout@v4
+
+    - uses: https://github.com/subosito/flutter-action@v2
+      with:
+        channel: stable
+        flutter-version: 3.19.6
+        cache: true
+
+    - run: flutter pub get
+
+    - run: flutter test
-- 
2.47.2


From 3256c6d46aada13dc32e72b0c13f2c94c5b32c0c Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sun, 5 May 2024 13:14:32 +0200
Subject: [PATCH 02/13] working state with dynamic location tracker

---
 .gitea/workflows/build-android.yaml |  2 +-
 lib/modules/navigation.dart         | 53 +++++++++++++++++++-
 lib/modules/overview.dart           | 78 +++++++++++++++++++++++++----
 pubspec.lock                        | 50 +++++++++++++++++-
 pubspec.yaml                        |  7 ++-
 5 files changed, 175 insertions(+), 15 deletions(-)

diff --git a/.gitea/workflows/build-android.yaml b/.gitea/workflows/build-android.yaml
index b714b6c..e2e530a 100644
--- a/.gitea/workflows/build-android.yaml
+++ b/.gitea/workflows/build-android.yaml
@@ -34,7 +34,7 @@ jobs:
 
     - run: flutter pub get
 
-    - run: flutter build apk --debug --split-per-abi
+    - run: flutter build apk --release --split-per-abi
 
     - name: Release APK
       uses: https://gitea.com/akkuman/gitea-release-action@v1
diff --git a/lib/modules/navigation.dart b/lib/modules/navigation.dart
index f7fcbcf..7952560 100644
--- a/lib/modules/navigation.dart
+++ b/lib/modules/navigation.dart
@@ -1,13 +1,62 @@
 import 'package:flutter/material.dart';
 
-Widget singleDestination(BuildContext context, String title, String description, String image) {
+
+
+List<Widget> loadDestinations() {
+  List<Widget> cities =  [
+    singleDestination(
+      "New York",
+      "The Big Apple",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/View_of_New_York_City.jpg/800px-View_of_New_York_City.jpg"
+    ),
+    singleDestination(
+      "Los Angeles",
+      "City of Angels",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Los_Angeles_City_Hall_2013.jpg/800px-Los_Angeles_City_Hall_2013.jpg"
+    ),
+    singleDestination(
+      "Chicago",
+      "The Windy City",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Chicago_skyline%2C_viewed_from_John_Hancock_Center.jpg/800px-Chicago_skyline%2C_viewed_from_John_Hancock_Center.jpg"
+    ),
+    singleDestination(
+      "San Francisco",
+      "The Golden City",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/San_Francisco_City_Hall_2013.jpg/800px-San_Francisco_City_Hall_2013.jpg"
+    ),
+    singleDestination(
+      "Miami",
+      "The Magic City",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Miami_collage.jpg/800px-Miami_collage.jpg"
+    ),
+    singleDestination(
+      "Las Vegas",
+      "Sin City",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Las_Vegas_Strip.jpg/800px-Las_Vegas_Strip.jpg"
+    ),
+    singleDestination(
+      "Seattle",
+      "Emerald City",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Seattle_Kerry_Park_Skyline.jpg/800px-Seattle_Kerry_Park_Skyline.jpg"
+    ),
+    singleDestination(
+      "Boston",
+      "Beantown",
+      "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Boston_skyline_from_Longfellow_Bridge_September_2017_panorama_2.jpg/800px-Boston"
+    )
+  ];
+  cities.shuffle();
+  return cities;
+}
+
+Widget singleDestination(String title, String description, String image) {
   return Card(
     child: ListTile(
       leading: Icon(Icons.location_on),
       title: Text(title),
       subtitle: Text(description),
       onTap: () {
-        Navigator.pushNamed(context, '/destination');
+        // Navigator.pushNamed(context, '/destination');
       },
     ),
   );
diff --git a/lib/modules/overview.dart b/lib/modules/overview.dart
index 7d6c0ed..ff03b9b 100644
--- a/lib/modules/overview.dart
+++ b/lib/modules/overview.dart
@@ -1,14 +1,74 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_map/flutter_map.dart';
 import 'package:sliding_up_panel/sliding_up_panel.dart';
+import 'package:latlong2/latlong.dart';
+import 'package:geocoding/geocoding.dart';
+import 'package:geocode/geocode.dart';
+import 'dart:async';
+
 import 'package:fast_network_navigation/modules/navigation.dart';
 
 class MapPage extends StatefulWidget {
   @override
   _MapPageState createState() => _MapPageState();
 }
+class Debounce {
+  Duration delay;
+  Timer? _timer;
+
+  Debounce(
+    this.delay,
+  );
+
+  call(void Function() callback) {
+    _timer?.cancel();
+    _timer = Timer(delay, callback);
+  }
+
+  dispose() {
+    _timer?.cancel();
+  }
+}
+
 
 class _MapPageState extends State<MapPage> {
+  GeoCode geoCode = GeoCode();
+  final mapController = MapController();
+  String _currentCityName = "...";
+  final Debounce _debounce = Debounce(Duration(seconds: 3));
+
+  void _setCurrentCityName() async {
+    if (mapController.camera.zoom < 9) {
+      return; // Don't bother if the view is too wide
+    }
+    var currentCoordinates = mapController.camera.center;
+    String? city;
+    
+    try{
+      List<Placemark> placemarks = await placemarkFromCoordinates(currentCoordinates.latitude, currentCoordinates.longitude);
+      city = placemarks[0].locality.toString();
+    } catch (e) {
+      debugPrint("Error: $e");
+      try {
+        Address address = await geoCode.reverseGeocoding(latitude: currentCoordinates.latitude, longitude: currentCoordinates.longitude);
+        
+        if (address.city == null || address.city.toString().contains("Throttled!")){
+          throw Exception("Probably rate limited");
+        }
+        city = address.city.toString();
+      } catch (e) {
+        debugPrint("Error: $e");
+
+      }
+    }
+    if (city != null) {
+      setState(() {
+        _currentCityName = city!;
+      });
+    } else {
+      _debounce(() async {_setCurrentCityName();});
+    }
+  }
 
   @override
   Widget build(BuildContext context) {
@@ -18,8 +78,15 @@ class _MapPageState extends State<MapPage> {
         panel: _floatingPanel(theme),
         collapsed: _floatingCollapsed(theme),
         body: FlutterMap(
+          mapController: mapController,
           options: MapOptions(
             initialZoom: 11,
+            initialCenter: LatLng(51.509364, -0.128928),
+            onMapReady: () {
+                mapController.mapEventStream.listen((evt) {_debounce(() async {_setCurrentCityName();});});
+                // And any other `MapController` dependent non-movement methods
+            },
+
           ),
           children: [
             openStreetMapTileLayer,
@@ -59,14 +126,7 @@ class _MapPageState extends State<MapPage> {
             children: <Widget>[
               Greeting(theme),
               Text("Got a lot to do today! Here is a rundown:"),
-              singleDestination(context, "Location 1", "some description", "Further information"),
-              singleDestination(context, "Location 2", "some description", "Further information"),
-              singleDestination(context, "Location 3", "some description", "Further information"),
-              singleDestination(context, "Location 4", "some description", "Further information"),
-              singleDestination(context, "Location 5", "some description", "Further information"),
-              singleDestination(context, "Location 6", "some description", "Further information"),
-              singleDestination(context, "Location 7", "some description", "Further information"),
-              singleDestination(context, "Location 8", "some description", "Further information"),
+              ...loadDestinations(),
             ],
           ),
         ),
@@ -78,7 +138,7 @@ class _MapPageState extends State<MapPage> {
   Widget Greeting (ThemeData theme) {
     return Center(
         child: Text(
-          "Explore Kview",
+            "Explore ${_currentCityName}",
           style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold),
         ),
       );
diff --git a/pubspec.lock b/pubspec.lock
index e8a2cb6..c5548c5 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -83,6 +83,46 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  geocode:
+    dependency: "direct main"
+    description:
+      name: geocode
+      sha256: cf9727c369bb3703b97d6e440225962dc27b7f3c686662fe3cdcc91cbfb7074d
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.3"
+  geocoding:
+    dependency: "direct main"
+    description:
+      name: geocoding
+      sha256: d580c801cba9386b4fac5047c4c785a4e19554f46be42f4f5e5b7deacd088a66
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.0"
+  geocoding_android:
+    dependency: transitive
+    description:
+      name: geocoding_android
+      sha256: "1b13eca79b11c497c434678fed109c2be020b158cec7512c848c102bc7232603"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.3.1"
+  geocoding_ios:
+    dependency: transitive
+    description:
+      name: geocoding_ios
+      sha256: "94ddba60387501bd1c11e18dca7c5a9e8c645d6e3da9c38b9762434941870c24"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.1"
+  geocoding_platform_interface:
+    dependency: transitive
+    description:
+      name: geocoding_platform_interface
+      sha256: "8c2c8226e5c276594c2e18bfe88b19110ed770aeb7c1ab50ede570be8b92229b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.0"
   http:
     dependency: transitive
     description:
@@ -108,7 +148,7 @@ packages:
     source: hosted
     version: "0.19.0"
   latlong2:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: latlong2
       sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
@@ -203,6 +243,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.9.0"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.8"
   polylabel:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 507aee5..53add6b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
-name: fast_network_navigation
-description: "A new Flutter project."
+name: "fast_network_navigation"
+description: "An interactive city navigator."
 # The following line prevents the package from being accidentally published to
 # pub.dev using `flutter pub publish`. This is preferred for private packages.
 publish_to: 'none' # Remove this line if you wish to publish to pub.dev
@@ -37,6 +37,9 @@ dependencies:
   cupertino_icons: ^1.0.6
   flutter_map: ^6.1.0
   sliding_up_panel: ^2.0.0+1
+  latlong2: ^0.9.1
+  geocoding: ^3.0.0
+  geocode: ^1.0.3
 
 dev_dependencies:
   flutter_test:
-- 
2.47.2


From 780bf0296484798a3924c904471b38ab6ac684fe Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Thu, 16 May 2024 17:00:10 +0200
Subject: [PATCH 03/13] more evolved mockup

---
 .gitea/workflows/build-android.yaml |  2 +-
 lib/modules/destination_card.dart   | 40 +++++++++++++++++++++++++++++
 lib/modules/navigation.dart         |  2 +-
 lib/structs/destination.dart        | 31 ++++++++++++++++++++++
 pubspec.lock                        | 26 +++++++++----------
 5 files changed, 86 insertions(+), 15 deletions(-)
 create mode 100644 lib/modules/destination_card.dart
 create mode 100644 lib/structs/destination.dart

diff --git a/.gitea/workflows/build-android.yaml b/.gitea/workflows/build-android.yaml
index e2e530a..b714b6c 100644
--- a/.gitea/workflows/build-android.yaml
+++ b/.gitea/workflows/build-android.yaml
@@ -34,7 +34,7 @@ jobs:
 
     - run: flutter pub get
 
-    - run: flutter build apk --release --split-per-abi
+    - run: flutter build apk --debug --split-per-abi
 
     - name: Release APK
       uses: https://gitea.com/akkuman/gitea-release-action@v1
diff --git a/lib/modules/destination_card.dart b/lib/modules/destination_card.dart
new file mode 100644
index 0000000..5829c5e
--- /dev/null
+++ b/lib/modules/destination_card.dart
@@ -0,0 +1,40 @@
+
+
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+
+
+class DestinationCard extends StatefulWidget {
+  final String title;
+  final String description;
+  final String image;
+  bool visited;
+
+  @override
+  _DestinationCardState createState() => _DestinationCardState();
+
+
+  DestinationCard(this.title, this.description, this.image, this.visited);
+
+  Widget build() {
+    return Card(
+      child: ListTile(
+        leading: Icon(Icons.location_on),
+        title: Text(title),
+        subtitle: Text(description),
+        onTap: () {
+          // Navigator.pushNamed(context, '/destination');
+        },
+      ),
+    );
+  }
+  
+}
+
+class _DestinationCardState extends State<DestinationCard> {
+  @override
+  Widget build(BuildContext context) {
+    return Card();
+  }
+
+}
\ No newline at end of file
diff --git a/lib/modules/navigation.dart b/lib/modules/navigation.dart
index 7952560..7bd62ac 100644
--- a/lib/modules/navigation.dart
+++ b/lib/modules/navigation.dart
@@ -1,7 +1,7 @@
+import 'package:fast_network_navigation/modules/destination_card.dart';
 import 'package:flutter/material.dart';
 
 
-
 List<Widget> loadDestinations() {
   List<Widget> cities =  [
     singleDestination(
diff --git a/lib/structs/destination.dart b/lib/structs/destination.dart
new file mode 100644
index 0000000..bb8d086
--- /dev/null
+++ b/lib/structs/destination.dart
@@ -0,0 +1,31 @@
+
+class Destination {
+  final double latitude;
+  final double longitude;
+  final String name;
+  final String description;
+  final DestinationType type;
+  final Duration duration;
+  final bool visited;
+
+  Destination({
+    required this.latitude,
+    required this.longitude,
+    required this.name,
+    required this.description,
+    required this.type,
+    required this.duration,
+    required this.visited,
+  });
+}
+
+
+class DestinationType {
+  final String name;
+  final String description;
+  
+  DestinationType({
+    required this.name,
+    required this.description,
+  });
+}
diff --git a/pubspec.lock b/pubspec.lock
index c5548c5..b88a8ef 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -159,26 +159,26 @@ packages:
     dependency: transitive
     description:
       name: leak_tracker
-      sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
+      sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
       url: "https://pub.dev"
     source: hosted
-    version: "10.0.0"
+    version: "10.0.4"
   leak_tracker_flutter_testing:
     dependency: transitive
     description:
       name: leak_tracker_flutter_testing
-      sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
+      sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "3.0.3"
   leak_tracker_testing:
     dependency: transitive
     description:
       name: leak_tracker_testing
-      sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
+      sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "3.0.1"
   lints:
     dependency: transitive
     description:
@@ -223,10 +223,10 @@ packages:
     dependency: transitive
     description:
       name: meta
-      sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
+      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
       url: "https://pub.dev"
     source: hosted
-    version: "1.11.0"
+    version: "1.12.0"
   mgrs_dart:
     dependency: transitive
     description:
@@ -324,10 +324,10 @@ packages:
     dependency: transitive
     description:
       name: test_api
-      sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
+      sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
       url: "https://pub.dev"
     source: hosted
-    version: "0.6.1"
+    version: "0.7.0"
   typed_data:
     dependency: transitive
     description:
@@ -356,10 +356,10 @@ packages:
     dependency: transitive
     description:
       name: vm_service
-      sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
+      sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
       url: "https://pub.dev"
     source: hosted
-    version: "13.0.0"
+    version: "14.2.1"
   web:
     dependency: transitive
     description:
@@ -378,4 +378,4 @@ packages:
     version: "2.0.0"
 sdks:
   dart: ">=3.3.4 <4.0.0"
-  flutter: ">=3.10.0"
+  flutter: ">=3.18.0-18.0.pre.54"
-- 
2.47.2


From 713e4a6671d72231b8f110828c252a578f6458f3 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Thu, 16 May 2024 17:08:18 +0200
Subject: [PATCH 04/13] split into frontend and backend

---
 ...ild-android.yaml => frontend_build-android.yaml} |   6 +++++-
 .../{build-web.yaml => frontend_build-web.yaml}     |   4 +++-
 .gitea/workflows/{test.yaml => frontend_test.yaml}  |   2 ++
 .gitignore => frontend/.gitignore                   |   0
 .metadata => frontend/.metadata                     |   0
 .../analysis_options.yaml                           |   0
 {android => frontend/android}/.gitignore            |   0
 {android => frontend/android}/app/build.gradle      |   0
 .../android}/app/src/debug/AndroidManifest.xml      |   0
 .../android}/app/src/main/AndroidManifest.xml       |   0
 .../example/fast_network_navigation/MainActivity.kt |   0
 .../src/main/res/drawable-v21/launch_background.xml |   0
 .../app/src/main/res/drawable/launch_background.xml |   0
 .../app/src/main/res/mipmap-hdpi/ic_launcher.png    | Bin
 .../app/src/main/res/mipmap-mdpi/ic_launcher.png    | Bin
 .../app/src/main/res/mipmap-xhdpi/ic_launcher.png   | Bin
 .../app/src/main/res/mipmap-xxhdpi/ic_launcher.png  | Bin
 .../app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin
 .../app/src/main/res/values-night/styles.xml        |   0
 .../android}/app/src/main/res/values/styles.xml     |   0
 .../android}/app/src/profile/AndroidManifest.xml    |   0
 {android => frontend/android}/build.gradle          |   0
 {android => frontend/android}/gradle.properties     |   0
 .../gradle/wrapper/gradle-wrapper.properties        |   0
 {android => frontend/android}/settings.gradle       |   0
 {ios => frontend/ios}/.gitignore                    |   0
 .../ios}/Flutter/AppFrameworkInfo.plist             |   0
 {ios => frontend/ios}/Flutter/Debug.xcconfig        |   0
 {ios => frontend/ios}/Flutter/Release.xcconfig      |   0
 .../ios}/Runner.xcodeproj/project.pbxproj           |   0
 .../project.xcworkspace/contents.xcworkspacedata    |   0
 .../xcshareddata/IDEWorkspaceChecks.plist           |   0
 .../xcshareddata/WorkspaceSettings.xcsettings       |   0
 .../xcshareddata/xcschemes/Runner.xcscheme          |   0
 .../Runner.xcworkspace/contents.xcworkspacedata     |   0
 .../xcshareddata/IDEWorkspaceChecks.plist           |   0
 .../xcshareddata/WorkspaceSettings.xcsettings       |   0
 {ios => frontend/ios}/Runner/AppDelegate.swift      |   0
 .../AppIcon.appiconset/Contents.json                |   0
 .../AppIcon.appiconset/Icon-App-1024x1024@1x.png    | Bin
 .../AppIcon.appiconset/Icon-App-20x20@1x.png        | Bin
 .../AppIcon.appiconset/Icon-App-20x20@2x.png        | Bin
 .../AppIcon.appiconset/Icon-App-20x20@3x.png        | Bin
 .../AppIcon.appiconset/Icon-App-29x29@1x.png        | Bin
 .../AppIcon.appiconset/Icon-App-29x29@2x.png        | Bin
 .../AppIcon.appiconset/Icon-App-29x29@3x.png        | Bin
 .../AppIcon.appiconset/Icon-App-40x40@1x.png        | Bin
 .../AppIcon.appiconset/Icon-App-40x40@2x.png        | Bin
 .../AppIcon.appiconset/Icon-App-40x40@3x.png        | Bin
 .../AppIcon.appiconset/Icon-App-60x60@2x.png        | Bin
 .../AppIcon.appiconset/Icon-App-60x60@3x.png        | Bin
 .../AppIcon.appiconset/Icon-App-76x76@1x.png        | Bin
 .../AppIcon.appiconset/Icon-App-76x76@2x.png        | Bin
 .../AppIcon.appiconset/Icon-App-83.5x83.5@2x.png    | Bin
 .../LaunchImage.imageset/Contents.json              |   0
 .../LaunchImage.imageset/LaunchImage.png            | Bin
 .../LaunchImage.imageset/LaunchImage@2x.png         | Bin
 .../LaunchImage.imageset/LaunchImage@3x.png         | Bin
 .../Assets.xcassets/LaunchImage.imageset/README.md  |   0
 .../ios}/Runner/Base.lproj/LaunchScreen.storyboard  |   0
 .../ios}/Runner/Base.lproj/Main.storyboard          |   0
 {ios => frontend/ios}/Runner/Info.plist             |   0
 .../ios}/Runner/Runner-Bridging-Header.h            |   0
 {ios => frontend/ios}/RunnerTests/RunnerTests.swift |   0
 {lib => frontend/lib}/main.dart                     |   0
 {lib => frontend/lib}/modules/destination_card.dart |   0
 {lib => frontend/lib}/modules/navigation.dart       |   0
 {lib => frontend/lib}/modules/overview.dart         |   0
 {lib => frontend/lib}/modules/profile.dart          |   0
 {lib => frontend/lib}/modules/scaffold.dart         |   0
 {lib => frontend/lib}/structs/destination.dart      |   0
 {linux => frontend/linux}/.gitignore                |   0
 {linux => frontend/linux}/CMakeLists.txt            |   0
 {linux => frontend/linux}/flutter/CMakeLists.txt    |   0
 .../linux}/flutter/generated_plugin_registrant.cc   |   0
 .../linux}/flutter/generated_plugin_registrant.h    |   0
 .../linux}/flutter/generated_plugins.cmake          |   0
 {linux => frontend/linux}/main.cc                   |   0
 {linux => frontend/linux}/my_application.cc         |   0
 {linux => frontend/linux}/my_application.h          |   0
 {macos => frontend/macos}/.gitignore                |   0
 .../macos}/Flutter/Flutter-Debug.xcconfig           |   0
 .../macos}/Flutter/Flutter-Release.xcconfig         |   0
 .../macos}/Flutter/GeneratedPluginRegistrant.swift  |   0
 .../macos}/Runner.xcodeproj/project.pbxproj         |   0
 .../xcshareddata/IDEWorkspaceChecks.plist           |   0
 .../xcshareddata/xcschemes/Runner.xcscheme          |   0
 .../Runner.xcworkspace/contents.xcworkspacedata     |   0
 .../xcshareddata/IDEWorkspaceChecks.plist           |   0
 {macos => frontend/macos}/Runner/AppDelegate.swift  |   0
 .../AppIcon.appiconset/Contents.json                |   0
 .../AppIcon.appiconset/app_icon_1024.png            | Bin
 .../AppIcon.appiconset/app_icon_128.png             | Bin
 .../AppIcon.appiconset/app_icon_16.png              | Bin
 .../AppIcon.appiconset/app_icon_256.png             | Bin
 .../AppIcon.appiconset/app_icon_32.png              | Bin
 .../AppIcon.appiconset/app_icon_512.png             | Bin
 .../AppIcon.appiconset/app_icon_64.png              | Bin
 .../macos}/Runner/Base.lproj/MainMenu.xib           |   0
 .../macos}/Runner/Configs/AppInfo.xcconfig          |   0
 .../macos}/Runner/Configs/Debug.xcconfig            |   0
 .../macos}/Runner/Configs/Release.xcconfig          |   0
 .../macos}/Runner/Configs/Warnings.xcconfig         |   0
 .../macos}/Runner/DebugProfile.entitlements         |   0
 {macos => frontend/macos}/Runner/Info.plist         |   0
 .../macos}/Runner/MainFlutterWindow.swift           |   0
 .../macos}/Runner/Release.entitlements              |   0
 .../macos}/RunnerTests/RunnerTests.swift            |   0
 pubspec.lock => frontend/pubspec.lock               |   0
 pubspec.yaml => frontend/pubspec.yaml               |   0
 {test => frontend/test}/widget_test.dart            |   0
 {web => frontend/web}/favicon.png                   | Bin
 {web => frontend/web}/icons/Icon-192.png            | Bin
 {web => frontend/web}/icons/Icon-512.png            | Bin
 {web => frontend/web}/icons/Icon-maskable-192.png   | Bin
 {web => frontend/web}/icons/Icon-maskable-512.png   | Bin
 {web => frontend/web}/index.html                    |   0
 {web => frontend/web}/manifest.json                 |   0
 {windows => frontend/windows}/.gitignore            |   0
 {windows => frontend/windows}/CMakeLists.txt        |   0
 .../windows}/flutter/CMakeLists.txt                 |   0
 .../windows}/flutter/generated_plugin_registrant.cc |   0
 .../windows}/flutter/generated_plugin_registrant.h  |   0
 .../windows}/flutter/generated_plugins.cmake        |   0
 {windows => frontend/windows}/runner/CMakeLists.txt |   0
 {windows => frontend/windows}/runner/Runner.rc      |   0
 .../windows}/runner/flutter_window.cpp              |   0
 .../windows}/runner/flutter_window.h                |   0
 {windows => frontend/windows}/runner/main.cpp       |   0
 {windows => frontend/windows}/runner/resource.h     |   0
 .../windows}/runner/resources/app_icon.ico          | Bin
 .../windows}/runner/runner.exe.manifest             |   0
 {windows => frontend/windows}/runner/utils.cpp      |   0
 {windows => frontend/windows}/runner/utils.h        |   0
 .../windows}/runner/win32_window.cpp                |   0
 {windows => frontend/windows}/runner/win32_window.h |   0
 136 files changed, 10 insertions(+), 2 deletions(-)
 rename .gitea/workflows/{build-android.yaml => frontend_build-android.yaml} (88%)
 rename .gitea/workflows/{build-web.yaml => frontend_build-web.yaml} (87%)
 rename .gitea/workflows/{test.yaml => frontend_test.yaml} (87%)
 rename .gitignore => frontend/.gitignore (100%)
 rename .metadata => frontend/.metadata (100%)
 rename analysis_options.yaml => frontend/analysis_options.yaml (100%)
 rename {android => frontend/android}/.gitignore (100%)
 rename {android => frontend/android}/app/build.gradle (100%)
 rename {android => frontend/android}/app/src/debug/AndroidManifest.xml (100%)
 rename {android => frontend/android}/app/src/main/AndroidManifest.xml (100%)
 rename {android => frontend/android}/app/src/main/kotlin/com/example/fast_network_navigation/MainActivity.kt (100%)
 rename {android => frontend/android}/app/src/main/res/drawable-v21/launch_background.xml (100%)
 rename {android => frontend/android}/app/src/main/res/drawable/launch_background.xml (100%)
 rename {android => frontend/android}/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%)
 rename {android => frontend/android}/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%)
 rename {android => frontend/android}/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%)
 rename {android => frontend/android}/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%)
 rename {android => frontend/android}/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%)
 rename {android => frontend/android}/app/src/main/res/values-night/styles.xml (100%)
 rename {android => frontend/android}/app/src/main/res/values/styles.xml (100%)
 rename {android => frontend/android}/app/src/profile/AndroidManifest.xml (100%)
 rename {android => frontend/android}/build.gradle (100%)
 rename {android => frontend/android}/gradle.properties (100%)
 rename {android => frontend/android}/gradle/wrapper/gradle-wrapper.properties (100%)
 rename {android => frontend/android}/settings.gradle (100%)
 rename {ios => frontend/ios}/.gitignore (100%)
 rename {ios => frontend/ios}/Flutter/AppFrameworkInfo.plist (100%)
 rename {ios => frontend/ios}/Flutter/Debug.xcconfig (100%)
 rename {ios => frontend/ios}/Flutter/Release.xcconfig (100%)
 rename {ios => frontend/ios}/Runner.xcodeproj/project.pbxproj (100%)
 rename {ios => frontend/ios}/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%)
 rename {ios => frontend/ios}/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%)
 rename {ios => frontend/ios}/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%)
 rename {ios => frontend/ios}/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%)
 rename {ios => frontend/ios}/Runner.xcworkspace/contents.xcworkspacedata (100%)
 rename {ios => frontend/ios}/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%)
 rename {ios => frontend/ios}/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%)
 rename {ios => frontend/ios}/Runner/AppDelegate.swift (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%)
 rename {ios => frontend/ios}/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%)
 rename {ios => frontend/ios}/Runner/Base.lproj/LaunchScreen.storyboard (100%)
 rename {ios => frontend/ios}/Runner/Base.lproj/Main.storyboard (100%)
 rename {ios => frontend/ios}/Runner/Info.plist (100%)
 rename {ios => frontend/ios}/Runner/Runner-Bridging-Header.h (100%)
 rename {ios => frontend/ios}/RunnerTests/RunnerTests.swift (100%)
 rename {lib => frontend/lib}/main.dart (100%)
 rename {lib => frontend/lib}/modules/destination_card.dart (100%)
 rename {lib => frontend/lib}/modules/navigation.dart (100%)
 rename {lib => frontend/lib}/modules/overview.dart (100%)
 rename {lib => frontend/lib}/modules/profile.dart (100%)
 rename {lib => frontend/lib}/modules/scaffold.dart (100%)
 rename {lib => frontend/lib}/structs/destination.dart (100%)
 rename {linux => frontend/linux}/.gitignore (100%)
 rename {linux => frontend/linux}/CMakeLists.txt (100%)
 rename {linux => frontend/linux}/flutter/CMakeLists.txt (100%)
 rename {linux => frontend/linux}/flutter/generated_plugin_registrant.cc (100%)
 rename {linux => frontend/linux}/flutter/generated_plugin_registrant.h (100%)
 rename {linux => frontend/linux}/flutter/generated_plugins.cmake (100%)
 rename {linux => frontend/linux}/main.cc (100%)
 rename {linux => frontend/linux}/my_application.cc (100%)
 rename {linux => frontend/linux}/my_application.h (100%)
 rename {macos => frontend/macos}/.gitignore (100%)
 rename {macos => frontend/macos}/Flutter/Flutter-Debug.xcconfig (100%)
 rename {macos => frontend/macos}/Flutter/Flutter-Release.xcconfig (100%)
 rename {macos => frontend/macos}/Flutter/GeneratedPluginRegistrant.swift (100%)
 rename {macos => frontend/macos}/Runner.xcodeproj/project.pbxproj (100%)
 rename {macos => frontend/macos}/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%)
 rename {macos => frontend/macos}/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%)
 rename {macos => frontend/macos}/Runner.xcworkspace/contents.xcworkspacedata (100%)
 rename {macos => frontend/macos}/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%)
 rename {macos => frontend/macos}/Runner/AppDelegate.swift (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png (100%)
 rename {macos => frontend/macos}/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png (100%)
 rename {macos => frontend/macos}/Runner/Base.lproj/MainMenu.xib (100%)
 rename {macos => frontend/macos}/Runner/Configs/AppInfo.xcconfig (100%)
 rename {macos => frontend/macos}/Runner/Configs/Debug.xcconfig (100%)
 rename {macos => frontend/macos}/Runner/Configs/Release.xcconfig (100%)
 rename {macos => frontend/macos}/Runner/Configs/Warnings.xcconfig (100%)
 rename {macos => frontend/macos}/Runner/DebugProfile.entitlements (100%)
 rename {macos => frontend/macos}/Runner/Info.plist (100%)
 rename {macos => frontend/macos}/Runner/MainFlutterWindow.swift (100%)
 rename {macos => frontend/macos}/Runner/Release.entitlements (100%)
 rename {macos => frontend/macos}/RunnerTests/RunnerTests.swift (100%)
 rename pubspec.lock => frontend/pubspec.lock (100%)
 rename pubspec.yaml => frontend/pubspec.yaml (100%)
 rename {test => frontend/test}/widget_test.dart (100%)
 rename {web => frontend/web}/favicon.png (100%)
 rename {web => frontend/web}/icons/Icon-192.png (100%)
 rename {web => frontend/web}/icons/Icon-512.png (100%)
 rename {web => frontend/web}/icons/Icon-maskable-192.png (100%)
 rename {web => frontend/web}/icons/Icon-maskable-512.png (100%)
 rename {web => frontend/web}/index.html (100%)
 rename {web => frontend/web}/manifest.json (100%)
 rename {windows => frontend/windows}/.gitignore (100%)
 rename {windows => frontend/windows}/CMakeLists.txt (100%)
 rename {windows => frontend/windows}/flutter/CMakeLists.txt (100%)
 rename {windows => frontend/windows}/flutter/generated_plugin_registrant.cc (100%)
 rename {windows => frontend/windows}/flutter/generated_plugin_registrant.h (100%)
 rename {windows => frontend/windows}/flutter/generated_plugins.cmake (100%)
 rename {windows => frontend/windows}/runner/CMakeLists.txt (100%)
 rename {windows => frontend/windows}/runner/Runner.rc (100%)
 rename {windows => frontend/windows}/runner/flutter_window.cpp (100%)
 rename {windows => frontend/windows}/runner/flutter_window.h (100%)
 rename {windows => frontend/windows}/runner/main.cpp (100%)
 rename {windows => frontend/windows}/runner/resource.h (100%)
 rename {windows => frontend/windows}/runner/resources/app_icon.ico (100%)
 rename {windows => frontend/windows}/runner/runner.exe.manifest (100%)
 rename {windows => frontend/windows}/runner/utils.cpp (100%)
 rename {windows => frontend/windows}/runner/utils.h (100%)
 rename {windows => frontend/windows}/runner/win32_window.cpp (100%)
 rename {windows => frontend/windows}/runner/win32_window.h (100%)

diff --git a/.gitea/workflows/build-android.yaml b/.gitea/workflows/frontend_build-android.yaml
similarity index 88%
rename from .gitea/workflows/build-android.yaml
rename to .gitea/workflows/frontend_build-android.yaml
index b714b6c..de430ce 100644
--- a/.gitea/workflows/build-android.yaml
+++ b/.gitea/workflows/frontend_build-android.yaml
@@ -33,13 +33,16 @@ jobs:
       uses: https://github.com/android-actions/setup-android@v3
 
     - run: flutter pub get
+      working-directory: ./frontend
 
     - run: flutter build apk --debug --split-per-abi
+      working-directory: ./frontend
+
 
     - name: Release APK
       uses: https://gitea.com/akkuman/gitea-release-action@v1
       with:
-        files: build/app/outputs/flutter-apk/*.apk
+        files: ./frontendbuild/app/outputs/flutter-apk/*.apk
         name: Testing release
         release_name: testing
         tag: testing
@@ -49,3 +52,4 @@ jobs:
         token: ${{ secrets.GITEA_TOKEN }}
       env:
         NODE_OPTIONS: '--experimental-fetch'
+      
diff --git a/.gitea/workflows/build-web.yaml b/.gitea/workflows/frontend_build-web.yaml
similarity index 87%
rename from .gitea/workflows/build-web.yaml
rename to .gitea/workflows/frontend_build-web.yaml
index cdb817c..416754a 100644
--- a/.gitea/workflows/build-web.yaml
+++ b/.gitea/workflows/frontend_build-web.yaml
@@ -25,6 +25,8 @@ jobs:
         cache: true
 
     - run: flutter pub get
+      working-directory: ./frontend
+
 
     - run: flutter build web
-
+      working-directory: ./frontend
diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/frontend_test.yaml
similarity index 87%
rename from .gitea/workflows/test.yaml
rename to .gitea/workflows/frontend_test.yaml
index 7f22525..aee253d 100644
--- a/.gitea/workflows/test.yaml
+++ b/.gitea/workflows/frontend_test.yaml
@@ -27,5 +27,7 @@ jobs:
         cache: true
 
     - run: flutter pub get
+      working-directory: ./frontend
 
     - run: flutter test
+      working-directory: ./frontend
diff --git a/.gitignore b/frontend/.gitignore
similarity index 100%
rename from .gitignore
rename to frontend/.gitignore
diff --git a/.metadata b/frontend/.metadata
similarity index 100%
rename from .metadata
rename to frontend/.metadata
diff --git a/analysis_options.yaml b/frontend/analysis_options.yaml
similarity index 100%
rename from analysis_options.yaml
rename to frontend/analysis_options.yaml
diff --git a/android/.gitignore b/frontend/android/.gitignore
similarity index 100%
rename from android/.gitignore
rename to frontend/android/.gitignore
diff --git a/android/app/build.gradle b/frontend/android/app/build.gradle
similarity index 100%
rename from android/app/build.gradle
rename to frontend/android/app/build.gradle
diff --git a/android/app/src/debug/AndroidManifest.xml b/frontend/android/app/src/debug/AndroidManifest.xml
similarity index 100%
rename from android/app/src/debug/AndroidManifest.xml
rename to frontend/android/app/src/debug/AndroidManifest.xml
diff --git a/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml
similarity index 100%
rename from android/app/src/main/AndroidManifest.xml
rename to frontend/android/app/src/main/AndroidManifest.xml
diff --git a/android/app/src/main/kotlin/com/example/fast_network_navigation/MainActivity.kt b/frontend/android/app/src/main/kotlin/com/example/fast_network_navigation/MainActivity.kt
similarity index 100%
rename from android/app/src/main/kotlin/com/example/fast_network_navigation/MainActivity.kt
rename to frontend/android/app/src/main/kotlin/com/example/fast_network_navigation/MainActivity.kt
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/android/app/src/main/res/drawable-v21/launch_background.xml
similarity index 100%
rename from android/app/src/main/res/drawable-v21/launch_background.xml
rename to frontend/android/app/src/main/res/drawable-v21/launch_background.xml
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/frontend/android/app/src/main/res/drawable/launch_background.xml
similarity index 100%
rename from android/app/src/main/res/drawable/launch_background.xml
rename to frontend/android/app/src/main/res/drawable/launch_background.xml
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
similarity index 100%
rename from android/app/src/main/res/mipmap-hdpi/ic_launcher.png
rename to frontend/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
similarity index 100%
rename from android/app/src/main/res/mipmap-mdpi/ic_launcher.png
rename to frontend/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
similarity index 100%
rename from android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
rename to frontend/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
similarity index 100%
rename from android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
rename to frontend/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
similarity index 100%
rename from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
rename to frontend/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
diff --git a/android/app/src/main/res/values-night/styles.xml b/frontend/android/app/src/main/res/values-night/styles.xml
similarity index 100%
rename from android/app/src/main/res/values-night/styles.xml
rename to frontend/android/app/src/main/res/values-night/styles.xml
diff --git a/android/app/src/main/res/values/styles.xml b/frontend/android/app/src/main/res/values/styles.xml
similarity index 100%
rename from android/app/src/main/res/values/styles.xml
rename to frontend/android/app/src/main/res/values/styles.xml
diff --git a/android/app/src/profile/AndroidManifest.xml b/frontend/android/app/src/profile/AndroidManifest.xml
similarity index 100%
rename from android/app/src/profile/AndroidManifest.xml
rename to frontend/android/app/src/profile/AndroidManifest.xml
diff --git a/android/build.gradle b/frontend/android/build.gradle
similarity index 100%
rename from android/build.gradle
rename to frontend/android/build.gradle
diff --git a/android/gradle.properties b/frontend/android/gradle.properties
similarity index 100%
rename from android/gradle.properties
rename to frontend/android/gradle.properties
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/frontend/android/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from android/gradle/wrapper/gradle-wrapper.properties
rename to frontend/android/gradle/wrapper/gradle-wrapper.properties
diff --git a/android/settings.gradle b/frontend/android/settings.gradle
similarity index 100%
rename from android/settings.gradle
rename to frontend/android/settings.gradle
diff --git a/ios/.gitignore b/frontend/ios/.gitignore
similarity index 100%
rename from ios/.gitignore
rename to frontend/ios/.gitignore
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/frontend/ios/Flutter/AppFrameworkInfo.plist
similarity index 100%
rename from ios/Flutter/AppFrameworkInfo.plist
rename to frontend/ios/Flutter/AppFrameworkInfo.plist
diff --git a/ios/Flutter/Debug.xcconfig b/frontend/ios/Flutter/Debug.xcconfig
similarity index 100%
rename from ios/Flutter/Debug.xcconfig
rename to frontend/ios/Flutter/Debug.xcconfig
diff --git a/ios/Flutter/Release.xcconfig b/frontend/ios/Flutter/Release.xcconfig
similarity index 100%
rename from ios/Flutter/Release.xcconfig
rename to frontend/ios/Flutter/Release.xcconfig
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/frontend/ios/Runner.xcodeproj/project.pbxproj
similarity index 100%
rename from ios/Runner.xcodeproj/project.pbxproj
rename to frontend/ios/Runner.xcodeproj/project.pbxproj
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to frontend/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
similarity index 100%
rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
rename to frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
similarity index 100%
rename from ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
rename to frontend/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/ios/Runner.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from ios/Runner.xcworkspace/contents.xcworkspacedata
rename to frontend/ios/Runner.xcworkspace/contents.xcworkspacedata
diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to frontend/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
similarity index 100%
rename from ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
rename to frontend/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
diff --git a/ios/Runner/AppDelegate.swift b/frontend/ios/Runner/AppDelegate.swift
similarity index 100%
rename from ios/Runner/AppDelegate.swift
rename to frontend/ios/Runner/AppDelegate.swift
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
rename to frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
similarity index 100%
rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
rename to frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
rename to frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
rename to frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
similarity index 100%
rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
rename to frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
similarity index 100%
rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
rename to frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/ios/Runner/Base.lproj/LaunchScreen.storyboard
similarity index 100%
rename from ios/Runner/Base.lproj/LaunchScreen.storyboard
rename to frontend/ios/Runner/Base.lproj/LaunchScreen.storyboard
diff --git a/ios/Runner/Base.lproj/Main.storyboard b/frontend/ios/Runner/Base.lproj/Main.storyboard
similarity index 100%
rename from ios/Runner/Base.lproj/Main.storyboard
rename to frontend/ios/Runner/Base.lproj/Main.storyboard
diff --git a/ios/Runner/Info.plist b/frontend/ios/Runner/Info.plist
similarity index 100%
rename from ios/Runner/Info.plist
rename to frontend/ios/Runner/Info.plist
diff --git a/ios/Runner/Runner-Bridging-Header.h b/frontend/ios/Runner/Runner-Bridging-Header.h
similarity index 100%
rename from ios/Runner/Runner-Bridging-Header.h
rename to frontend/ios/Runner/Runner-Bridging-Header.h
diff --git a/ios/RunnerTests/RunnerTests.swift b/frontend/ios/RunnerTests/RunnerTests.swift
similarity index 100%
rename from ios/RunnerTests/RunnerTests.swift
rename to frontend/ios/RunnerTests/RunnerTests.swift
diff --git a/lib/main.dart b/frontend/lib/main.dart
similarity index 100%
rename from lib/main.dart
rename to frontend/lib/main.dart
diff --git a/lib/modules/destination_card.dart b/frontend/lib/modules/destination_card.dart
similarity index 100%
rename from lib/modules/destination_card.dart
rename to frontend/lib/modules/destination_card.dart
diff --git a/lib/modules/navigation.dart b/frontend/lib/modules/navigation.dart
similarity index 100%
rename from lib/modules/navigation.dart
rename to frontend/lib/modules/navigation.dart
diff --git a/lib/modules/overview.dart b/frontend/lib/modules/overview.dart
similarity index 100%
rename from lib/modules/overview.dart
rename to frontend/lib/modules/overview.dart
diff --git a/lib/modules/profile.dart b/frontend/lib/modules/profile.dart
similarity index 100%
rename from lib/modules/profile.dart
rename to frontend/lib/modules/profile.dart
diff --git a/lib/modules/scaffold.dart b/frontend/lib/modules/scaffold.dart
similarity index 100%
rename from lib/modules/scaffold.dart
rename to frontend/lib/modules/scaffold.dart
diff --git a/lib/structs/destination.dart b/frontend/lib/structs/destination.dart
similarity index 100%
rename from lib/structs/destination.dart
rename to frontend/lib/structs/destination.dart
diff --git a/linux/.gitignore b/frontend/linux/.gitignore
similarity index 100%
rename from linux/.gitignore
rename to frontend/linux/.gitignore
diff --git a/linux/CMakeLists.txt b/frontend/linux/CMakeLists.txt
similarity index 100%
rename from linux/CMakeLists.txt
rename to frontend/linux/CMakeLists.txt
diff --git a/linux/flutter/CMakeLists.txt b/frontend/linux/flutter/CMakeLists.txt
similarity index 100%
rename from linux/flutter/CMakeLists.txt
rename to frontend/linux/flutter/CMakeLists.txt
diff --git a/linux/flutter/generated_plugin_registrant.cc b/frontend/linux/flutter/generated_plugin_registrant.cc
similarity index 100%
rename from linux/flutter/generated_plugin_registrant.cc
rename to frontend/linux/flutter/generated_plugin_registrant.cc
diff --git a/linux/flutter/generated_plugin_registrant.h b/frontend/linux/flutter/generated_plugin_registrant.h
similarity index 100%
rename from linux/flutter/generated_plugin_registrant.h
rename to frontend/linux/flutter/generated_plugin_registrant.h
diff --git a/linux/flutter/generated_plugins.cmake b/frontend/linux/flutter/generated_plugins.cmake
similarity index 100%
rename from linux/flutter/generated_plugins.cmake
rename to frontend/linux/flutter/generated_plugins.cmake
diff --git a/linux/main.cc b/frontend/linux/main.cc
similarity index 100%
rename from linux/main.cc
rename to frontend/linux/main.cc
diff --git a/linux/my_application.cc b/frontend/linux/my_application.cc
similarity index 100%
rename from linux/my_application.cc
rename to frontend/linux/my_application.cc
diff --git a/linux/my_application.h b/frontend/linux/my_application.h
similarity index 100%
rename from linux/my_application.h
rename to frontend/linux/my_application.h
diff --git a/macos/.gitignore b/frontend/macos/.gitignore
similarity index 100%
rename from macos/.gitignore
rename to frontend/macos/.gitignore
diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/frontend/macos/Flutter/Flutter-Debug.xcconfig
similarity index 100%
rename from macos/Flutter/Flutter-Debug.xcconfig
rename to frontend/macos/Flutter/Flutter-Debug.xcconfig
diff --git a/macos/Flutter/Flutter-Release.xcconfig b/frontend/macos/Flutter/Flutter-Release.xcconfig
similarity index 100%
rename from macos/Flutter/Flutter-Release.xcconfig
rename to frontend/macos/Flutter/Flutter-Release.xcconfig
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift
similarity index 100%
rename from macos/Flutter/GeneratedPluginRegistrant.swift
rename to frontend/macos/Flutter/GeneratedPluginRegistrant.swift
diff --git a/macos/Runner.xcodeproj/project.pbxproj b/frontend/macos/Runner.xcodeproj/project.pbxproj
similarity index 100%
rename from macos/Runner.xcodeproj/project.pbxproj
rename to frontend/macos/Runner.xcodeproj/project.pbxproj
diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to frontend/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
similarity index 100%
rename from macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
rename to frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/frontend/macos/Runner.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from macos/Runner.xcworkspace/contents.xcworkspacedata
rename to frontend/macos/Runner.xcworkspace/contents.xcworkspacedata
diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to frontend/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/macos/Runner/AppDelegate.swift b/frontend/macos/Runner/AppDelegate.swift
similarity index 100%
rename from macos/Runner/AppDelegate.swift
rename to frontend/macos/Runner/AppDelegate.swift
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
similarity index 100%
rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
rename to frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/frontend/macos/Runner/Base.lproj/MainMenu.xib
similarity index 100%
rename from macos/Runner/Base.lproj/MainMenu.xib
rename to frontend/macos/Runner/Base.lproj/MainMenu.xib
diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/frontend/macos/Runner/Configs/AppInfo.xcconfig
similarity index 100%
rename from macos/Runner/Configs/AppInfo.xcconfig
rename to frontend/macos/Runner/Configs/AppInfo.xcconfig
diff --git a/macos/Runner/Configs/Debug.xcconfig b/frontend/macos/Runner/Configs/Debug.xcconfig
similarity index 100%
rename from macos/Runner/Configs/Debug.xcconfig
rename to frontend/macos/Runner/Configs/Debug.xcconfig
diff --git a/macos/Runner/Configs/Release.xcconfig b/frontend/macos/Runner/Configs/Release.xcconfig
similarity index 100%
rename from macos/Runner/Configs/Release.xcconfig
rename to frontend/macos/Runner/Configs/Release.xcconfig
diff --git a/macos/Runner/Configs/Warnings.xcconfig b/frontend/macos/Runner/Configs/Warnings.xcconfig
similarity index 100%
rename from macos/Runner/Configs/Warnings.xcconfig
rename to frontend/macos/Runner/Configs/Warnings.xcconfig
diff --git a/macos/Runner/DebugProfile.entitlements b/frontend/macos/Runner/DebugProfile.entitlements
similarity index 100%
rename from macos/Runner/DebugProfile.entitlements
rename to frontend/macos/Runner/DebugProfile.entitlements
diff --git a/macos/Runner/Info.plist b/frontend/macos/Runner/Info.plist
similarity index 100%
rename from macos/Runner/Info.plist
rename to frontend/macos/Runner/Info.plist
diff --git a/macos/Runner/MainFlutterWindow.swift b/frontend/macos/Runner/MainFlutterWindow.swift
similarity index 100%
rename from macos/Runner/MainFlutterWindow.swift
rename to frontend/macos/Runner/MainFlutterWindow.swift
diff --git a/macos/Runner/Release.entitlements b/frontend/macos/Runner/Release.entitlements
similarity index 100%
rename from macos/Runner/Release.entitlements
rename to frontend/macos/Runner/Release.entitlements
diff --git a/macos/RunnerTests/RunnerTests.swift b/frontend/macos/RunnerTests/RunnerTests.swift
similarity index 100%
rename from macos/RunnerTests/RunnerTests.swift
rename to frontend/macos/RunnerTests/RunnerTests.swift
diff --git a/pubspec.lock b/frontend/pubspec.lock
similarity index 100%
rename from pubspec.lock
rename to frontend/pubspec.lock
diff --git a/pubspec.yaml b/frontend/pubspec.yaml
similarity index 100%
rename from pubspec.yaml
rename to frontend/pubspec.yaml
diff --git a/test/widget_test.dart b/frontend/test/widget_test.dart
similarity index 100%
rename from test/widget_test.dart
rename to frontend/test/widget_test.dart
diff --git a/web/favicon.png b/frontend/web/favicon.png
similarity index 100%
rename from web/favicon.png
rename to frontend/web/favicon.png
diff --git a/web/icons/Icon-192.png b/frontend/web/icons/Icon-192.png
similarity index 100%
rename from web/icons/Icon-192.png
rename to frontend/web/icons/Icon-192.png
diff --git a/web/icons/Icon-512.png b/frontend/web/icons/Icon-512.png
similarity index 100%
rename from web/icons/Icon-512.png
rename to frontend/web/icons/Icon-512.png
diff --git a/web/icons/Icon-maskable-192.png b/frontend/web/icons/Icon-maskable-192.png
similarity index 100%
rename from web/icons/Icon-maskable-192.png
rename to frontend/web/icons/Icon-maskable-192.png
diff --git a/web/icons/Icon-maskable-512.png b/frontend/web/icons/Icon-maskable-512.png
similarity index 100%
rename from web/icons/Icon-maskable-512.png
rename to frontend/web/icons/Icon-maskable-512.png
diff --git a/web/index.html b/frontend/web/index.html
similarity index 100%
rename from web/index.html
rename to frontend/web/index.html
diff --git a/web/manifest.json b/frontend/web/manifest.json
similarity index 100%
rename from web/manifest.json
rename to frontend/web/manifest.json
diff --git a/windows/.gitignore b/frontend/windows/.gitignore
similarity index 100%
rename from windows/.gitignore
rename to frontend/windows/.gitignore
diff --git a/windows/CMakeLists.txt b/frontend/windows/CMakeLists.txt
similarity index 100%
rename from windows/CMakeLists.txt
rename to frontend/windows/CMakeLists.txt
diff --git a/windows/flutter/CMakeLists.txt b/frontend/windows/flutter/CMakeLists.txt
similarity index 100%
rename from windows/flutter/CMakeLists.txt
rename to frontend/windows/flutter/CMakeLists.txt
diff --git a/windows/flutter/generated_plugin_registrant.cc b/frontend/windows/flutter/generated_plugin_registrant.cc
similarity index 100%
rename from windows/flutter/generated_plugin_registrant.cc
rename to frontend/windows/flutter/generated_plugin_registrant.cc
diff --git a/windows/flutter/generated_plugin_registrant.h b/frontend/windows/flutter/generated_plugin_registrant.h
similarity index 100%
rename from windows/flutter/generated_plugin_registrant.h
rename to frontend/windows/flutter/generated_plugin_registrant.h
diff --git a/windows/flutter/generated_plugins.cmake b/frontend/windows/flutter/generated_plugins.cmake
similarity index 100%
rename from windows/flutter/generated_plugins.cmake
rename to frontend/windows/flutter/generated_plugins.cmake
diff --git a/windows/runner/CMakeLists.txt b/frontend/windows/runner/CMakeLists.txt
similarity index 100%
rename from windows/runner/CMakeLists.txt
rename to frontend/windows/runner/CMakeLists.txt
diff --git a/windows/runner/Runner.rc b/frontend/windows/runner/Runner.rc
similarity index 100%
rename from windows/runner/Runner.rc
rename to frontend/windows/runner/Runner.rc
diff --git a/windows/runner/flutter_window.cpp b/frontend/windows/runner/flutter_window.cpp
similarity index 100%
rename from windows/runner/flutter_window.cpp
rename to frontend/windows/runner/flutter_window.cpp
diff --git a/windows/runner/flutter_window.h b/frontend/windows/runner/flutter_window.h
similarity index 100%
rename from windows/runner/flutter_window.h
rename to frontend/windows/runner/flutter_window.h
diff --git a/windows/runner/main.cpp b/frontend/windows/runner/main.cpp
similarity index 100%
rename from windows/runner/main.cpp
rename to frontend/windows/runner/main.cpp
diff --git a/windows/runner/resource.h b/frontend/windows/runner/resource.h
similarity index 100%
rename from windows/runner/resource.h
rename to frontend/windows/runner/resource.h
diff --git a/windows/runner/resources/app_icon.ico b/frontend/windows/runner/resources/app_icon.ico
similarity index 100%
rename from windows/runner/resources/app_icon.ico
rename to frontend/windows/runner/resources/app_icon.ico
diff --git a/windows/runner/runner.exe.manifest b/frontend/windows/runner/runner.exe.manifest
similarity index 100%
rename from windows/runner/runner.exe.manifest
rename to frontend/windows/runner/runner.exe.manifest
diff --git a/windows/runner/utils.cpp b/frontend/windows/runner/utils.cpp
similarity index 100%
rename from windows/runner/utils.cpp
rename to frontend/windows/runner/utils.cpp
diff --git a/windows/runner/utils.h b/frontend/windows/runner/utils.h
similarity index 100%
rename from windows/runner/utils.h
rename to frontend/windows/runner/utils.h
diff --git a/windows/runner/win32_window.cpp b/frontend/windows/runner/win32_window.cpp
similarity index 100%
rename from windows/runner/win32_window.cpp
rename to frontend/windows/runner/win32_window.cpp
diff --git a/windows/runner/win32_window.h b/frontend/windows/runner/win32_window.h
similarity index 100%
rename from windows/runner/win32_window.h
rename to frontend/windows/runner/win32_window.h
-- 
2.47.2


From 7f4f707ab522e1f735ff5d2a6a33daf15fdd31ff Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Thu, 16 May 2024 17:34:54 +0200
Subject: [PATCH 05/13] sample backend deployment

---
 backend/Dockerfile   |  11 +
 backend/Pipfile      |  14 +
 backend/Pipfile.lock | 884 +++++++++++++++++++++++++++++++++++++++++++
 backend/src/main.py  |  23 ++
 4 files changed, 932 insertions(+)
 create mode 100644 backend/Dockerfile
 create mode 100644 backend/Pipfile
 create mode 100644 backend/Pipfile.lock
 create mode 100644 backend/src/main.py

diff --git a/backend/Dockerfile b/backend/Dockerfile
new file mode 100644
index 0000000..1535818
--- /dev/null
+++ b/backend/Dockerfile
@@ -0,0 +1,11 @@
+FROM python:3
+
+WORKDIR /app
+COPY Pipfile Pipfile.lock /app/
+
+RUN pip install pipenv
+RUN pipenv install --deploy --ignore-pipfile
+
+COPY . /src
+
+CMD ["pipenv", "run", "python", "/app/src/main.py"]
diff --git a/backend/Pipfile b/backend/Pipfile
new file mode 100644
index 0000000..dfcd2a4
--- /dev/null
+++ b/backend/Pipfile
@@ -0,0 +1,14 @@
+[[source]]
+url = "https://pypi.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+numpy = "*"
+scipy = "*"
+fastapi = "*"
+
+[dev-packages]
+
+[requires]
+python_version = "3.12"
diff --git a/backend/Pipfile.lock b/backend/Pipfile.lock
new file mode 100644
index 0000000..a4c1f54
--- /dev/null
+++ b/backend/Pipfile.lock
@@ -0,0 +1,884 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "338629802198c23b4efab9dde90a89e178caf0840d99ff5c5936550b91d64d5e"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.12"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "annotated-types": {
+            "hashes": [
+                "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43",
+                "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.6.0"
+        },
+        "anyio": {
+            "hashes": [
+                "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8",
+                "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==4.3.0"
+        },
+        "certifi": {
+            "hashes": [
+                "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f",
+                "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==2024.2.2"
+        },
+        "click": {
+            "hashes": [
+                "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
+                "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==8.1.7"
+        },
+        "dnspython": {
+            "hashes": [
+                "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50",
+                "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.6.1"
+        },
+        "email-validator": {
+            "hashes": [
+                "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84",
+                "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.1.1"
+        },
+        "fastapi": {
+            "hashes": [
+                "sha256:97ecbf994be0bcbdadedf88c3150252bed7b2087075ac99735403b1b76cc8fc0",
+                "sha256:b9db9dd147c91cb8b769f7183535773d8741dd46f9dc6676cd82eab510228cd7"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.8'",
+            "version": "==0.111.0"
+        },
+        "fastapi-cli": {
+            "hashes": [
+                "sha256:3b6e4d2c4daee940fb8db59ebbfd60a72c4b962bcf593e263e4cc69da4ea3d7f",
+                "sha256:ae233115f729945479044917d949095e829d2d84f56f55ce1ca17627872825a5"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.0.3"
+        },
+        "h11": {
+            "hashes": [
+                "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d",
+                "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==0.14.0"
+        },
+        "httpcore": {
+            "hashes": [
+                "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61",
+                "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==1.0.5"
+        },
+        "httptools": {
+            "hashes": [
+                "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563",
+                "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142",
+                "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d",
+                "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b",
+                "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4",
+                "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb",
+                "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658",
+                "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084",
+                "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2",
+                "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97",
+                "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837",
+                "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3",
+                "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58",
+                "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da",
+                "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d",
+                "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90",
+                "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0",
+                "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1",
+                "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2",
+                "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e",
+                "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0",
+                "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf",
+                "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc",
+                "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3",
+                "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503",
+                "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a",
+                "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3",
+                "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949",
+                "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84",
+                "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb",
+                "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a",
+                "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f",
+                "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e",
+                "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81",
+                "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185",
+                "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"
+            ],
+            "version": "==0.6.1"
+        },
+        "httpx": {
+            "hashes": [
+                "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5",
+                "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.27.0"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
+                "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
+            ],
+            "markers": "python_version >= '3.5'",
+            "version": "==3.7"
+        },
+        "jinja2": {
+            "hashes": [
+                "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369",
+                "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==3.1.4"
+        },
+        "markdown-it-py": {
+            "hashes": [
+                "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
+                "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==3.0.0"
+        },
+        "markupsafe": {
+            "hashes": [
+                "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf",
+                "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff",
+                "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f",
+                "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3",
+                "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532",
+                "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f",
+                "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617",
+                "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df",
+                "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4",
+                "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906",
+                "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f",
+                "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4",
+                "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8",
+                "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371",
+                "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2",
+                "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465",
+                "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52",
+                "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6",
+                "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169",
+                "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad",
+                "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2",
+                "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0",
+                "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029",
+                "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f",
+                "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a",
+                "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced",
+                "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5",
+                "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c",
+                "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf",
+                "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9",
+                "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb",
+                "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad",
+                "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3",
+                "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1",
+                "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46",
+                "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc",
+                "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a",
+                "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee",
+                "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900",
+                "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5",
+                "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea",
+                "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f",
+                "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5",
+                "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e",
+                "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a",
+                "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f",
+                "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50",
+                "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a",
+                "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b",
+                "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4",
+                "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff",
+                "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2",
+                "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46",
+                "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b",
+                "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf",
+                "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5",
+                "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5",
+                "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab",
+                "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd",
+                "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==2.1.5"
+        },
+        "mdurl": {
+            "hashes": [
+                "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
+                "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==0.1.2"
+        },
+        "numpy": {
+            "hashes": [
+                "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b",
+                "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818",
+                "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20",
+                "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0",
+                "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010",
+                "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a",
+                "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea",
+                "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c",
+                "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71",
+                "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110",
+                "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be",
+                "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a",
+                "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a",
+                "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5",
+                "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed",
+                "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd",
+                "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c",
+                "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e",
+                "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0",
+                "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c",
+                "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a",
+                "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b",
+                "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0",
+                "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6",
+                "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2",
+                "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a",
+                "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30",
+                "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218",
+                "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5",
+                "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07",
+                "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2",
+                "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4",
+                "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764",
+                "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef",
+                "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3",
+                "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.9'",
+            "version": "==1.26.4"
+        },
+        "orjson": {
+            "hashes": [
+                "sha256:0943a96b3fa09bee1afdfccc2cb236c9c64715afa375b2af296c73d91c23eab2",
+                "sha256:0a62f9968bab8a676a164263e485f30a0b748255ee2f4ae49a0224be95f4532b",
+                "sha256:16bda83b5c61586f6f788333d3cf3ed19015e3b9019188c56983b5a299210eb5",
+                "sha256:1770e2a0eae728b050705206d84eda8b074b65ee835e7f85c919f5705b006c9b",
+                "sha256:17e0713fc159abc261eea0f4feda611d32eabc35708b74bef6ad44f6c78d5ea0",
+                "sha256:18566beb5acd76f3769c1d1a7ec06cdb81edc4d55d2765fb677e3eaa10fa99e0",
+                "sha256:1952c03439e4dce23482ac846e7961f9d4ec62086eb98ae76d97bd41d72644d7",
+                "sha256:1bd2218d5a3aa43060efe649ec564ebedec8ce6ae0a43654b81376216d5ebd42",
+                "sha256:1c23dfa91481de880890d17aa7b91d586a4746a4c2aa9a145bebdbaf233768d5",
+                "sha256:252124b198662eee80428f1af8c63f7ff077c88723fe206a25df8dc57a57b1fa",
+                "sha256:2b166507acae7ba2f7c315dcf185a9111ad5e992ac81f2d507aac39193c2c818",
+                "sha256:2e5e176c994ce4bd434d7aafb9ecc893c15f347d3d2bbd8e7ce0b63071c52e25",
+                "sha256:3582b34b70543a1ed6944aca75e219e1192661a63da4d039d088a09c67543b08",
+                "sha256:382e52aa4270a037d41f325e7d1dfa395b7de0c367800b6f337d8157367bf3a7",
+                "sha256:416b195f78ae461601893f482287cee1e3059ec49b4f99479aedf22a20b1098b",
+                "sha256:4ad1f26bea425041e0a1adad34630c4825a9e3adec49079b1fb6ac8d36f8b754",
+                "sha256:4c895383b1ec42b017dd2c75ae8a5b862fc489006afde06f14afbdd0309b2af0",
+                "sha256:5102f50c5fc46d94f2033fe00d392588564378260d64377aec702f21a7a22912",
+                "sha256:520de5e2ef0b4ae546bea25129d6c7c74edb43fc6cf5213f511a927f2b28148b",
+                "sha256:544a12eee96e3ab828dbfcb4d5a0023aa971b27143a1d35dc214c176fdfb29b3",
+                "sha256:73100d9abbbe730331f2242c1fc0bcb46a3ea3b4ae3348847e5a141265479700",
+                "sha256:831c6ef73f9aa53c5f40ae8f949ff7681b38eaddb6904aab89dca4d85099cb78",
+                "sha256:8bc7a4df90da5d535e18157220d7915780d07198b54f4de0110eca6b6c11e290",
+                "sha256:8d0b84403d287d4bfa9bf7d1dc298d5c1c5d9f444f3737929a66f2fe4fb8f134",
+                "sha256:8d40c7f7938c9c2b934b297412c067936d0b54e4b8ab916fd1a9eb8f54c02294",
+                "sha256:9059d15c30e675a58fdcd6f95465c1522b8426e092de9fff20edebfdc15e1cb0",
+                "sha256:93433b3c1f852660eb5abdc1f4dd0ced2be031ba30900433223b28ee0140cde5",
+                "sha256:978be58a68ade24f1af7758626806e13cff7748a677faf95fbb298359aa1e20d",
+                "sha256:99b880d7e34542db89f48d14ddecbd26f06838b12427d5a25d71baceb5ba119d",
+                "sha256:9a7bc9e8bc11bac40f905640acd41cbeaa87209e7e1f57ade386da658092dc16",
+                "sha256:9e253498bee561fe85d6325ba55ff2ff08fb5e7184cd6a4d7754133bd19c9195",
+                "sha256:9f3e87733823089a338ef9bbf363ef4de45e5c599a9bf50a7a9b82e86d0228da",
+                "sha256:9fb6c3f9f5490a3eb4ddd46fc1b6eadb0d6fc16fb3f07320149c3286a1409dd8",
+                "sha256:a39aa73e53bec8d410875683bfa3a8edf61e5a1c7bb4014f65f81d36467ea098",
+                "sha256:b69a58a37dab856491bf2d3bbf259775fdce262b727f96aafbda359cb1d114d8",
+                "sha256:b8d4d1a6868cde356f1402c8faeb50d62cee765a1f7ffcfd6de732ab0581e063",
+                "sha256:ba7f67aa7f983c4345eeda16054a4677289011a478ca947cd69c0a86ea45e534",
+                "sha256:be2719e5041e9fb76c8c2c06b9600fe8e8584e6980061ff88dcbc2691a16d20d",
+                "sha256:be2aab54313752c04f2cbaab4515291ef5af8c2256ce22abc007f89f42f49109",
+                "sha256:c0403ed9c706dcd2809f1600ed18f4aae50be263bd7112e54b50e2c2bc3ebd6d",
+                "sha256:c8334c0d87103bb9fbbe59b78129f1f40d1d1e8355bbed2ca71853af15fa4ed3",
+                "sha256:cb0175a5798bdc878956099f5c54b9837cb62cfbf5d0b86ba6d77e43861bcec2",
+                "sha256:ccaa0a401fc02e8828a5bedfd80f8cd389d24f65e5ca3954d72c6582495b4bcf",
+                "sha256:cf20465e74c6e17a104ecf01bf8cd3b7b252565b4ccee4548f18b012ff2f8069",
+                "sha256:d4a654ec1de8fdaae1d80d55cee65893cb06494e124681ab335218be6a0691e7",
+                "sha256:e852baafceff8da3c9defae29414cc8513a1586ad93e45f27b89a639c68e8176"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==3.10.3"
+        },
+        "pydantic": {
+            "hashes": [
+                "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5",
+                "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.7.1"
+        },
+        "pydantic-core": {
+            "hashes": [
+                "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b",
+                "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a",
+                "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90",
+                "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d",
+                "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e",
+                "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d",
+                "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027",
+                "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804",
+                "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347",
+                "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400",
+                "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3",
+                "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399",
+                "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349",
+                "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd",
+                "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c",
+                "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e",
+                "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413",
+                "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3",
+                "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e",
+                "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3",
+                "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91",
+                "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce",
+                "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c",
+                "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb",
+                "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664",
+                "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6",
+                "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd",
+                "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3",
+                "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af",
+                "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043",
+                "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350",
+                "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7",
+                "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0",
+                "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563",
+                "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761",
+                "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72",
+                "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3",
+                "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb",
+                "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788",
+                "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b",
+                "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c",
+                "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038",
+                "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250",
+                "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec",
+                "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c",
+                "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74",
+                "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81",
+                "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439",
+                "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75",
+                "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0",
+                "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8",
+                "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150",
+                "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438",
+                "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae",
+                "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857",
+                "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038",
+                "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374",
+                "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f",
+                "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241",
+                "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592",
+                "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4",
+                "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d",
+                "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b",
+                "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b",
+                "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182",
+                "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e",
+                "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641",
+                "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70",
+                "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9",
+                "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a",
+                "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543",
+                "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b",
+                "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f",
+                "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38",
+                "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845",
+                "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2",
+                "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0",
+                "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4",
+                "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.18.2"
+        },
+        "pygments": {
+            "hashes": [
+                "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
+                "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2.18.0"
+        },
+        "python-dotenv": {
+            "hashes": [
+                "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca",
+                "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"
+            ],
+            "version": "==1.0.1"
+        },
+        "python-multipart": {
+            "hashes": [
+                "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026",
+                "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.0.9"
+        },
+        "pyyaml": {
+            "hashes": [
+                "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5",
+                "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc",
+                "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df",
+                "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741",
+                "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206",
+                "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27",
+                "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595",
+                "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62",
+                "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98",
+                "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696",
+                "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290",
+                "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9",
+                "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d",
+                "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6",
+                "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867",
+                "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47",
+                "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486",
+                "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6",
+                "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3",
+                "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007",
+                "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938",
+                "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0",
+                "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c",
+                "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735",
+                "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d",
+                "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28",
+                "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4",
+                "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba",
+                "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8",
+                "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef",
+                "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5",
+                "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd",
+                "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3",
+                "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0",
+                "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515",
+                "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c",
+                "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c",
+                "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924",
+                "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34",
+                "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43",
+                "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859",
+                "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673",
+                "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54",
+                "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a",
+                "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b",
+                "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab",
+                "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa",
+                "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c",
+                "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585",
+                "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d",
+                "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"
+            ],
+            "version": "==6.0.1"
+        },
+        "rich": {
+            "hashes": [
+                "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222",
+                "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"
+            ],
+            "markers": "python_full_version >= '3.7.0'",
+            "version": "==13.7.1"
+        },
+        "scipy": {
+            "hashes": [
+                "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922",
+                "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5",
+                "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa",
+                "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820",
+                "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd",
+                "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42",
+                "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e",
+                "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d",
+                "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86",
+                "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e",
+                "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c",
+                "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602",
+                "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e",
+                "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5",
+                "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a",
+                "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21",
+                "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d",
+                "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6",
+                "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78",
+                "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551",
+                "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7",
+                "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4",
+                "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d",
+                "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b",
+                "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.9'",
+            "version": "==1.13.0"
+        },
+        "shellingham": {
+            "hashes": [
+                "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686",
+                "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==1.5.4"
+        },
+        "sniffio": {
+            "hashes": [
+                "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",
+                "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==1.3.1"
+        },
+        "starlette": {
+            "hashes": [
+                "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee",
+                "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.37.2"
+        },
+        "typer": {
+            "hashes": [
+                "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914",
+                "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==0.12.3"
+        },
+        "typing-extensions": {
+            "hashes": [
+                "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0",
+                "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==4.11.0"
+        },
+        "ujson": {
+            "hashes": [
+                "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e",
+                "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b",
+                "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6",
+                "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7",
+                "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9",
+                "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd",
+                "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569",
+                "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f",
+                "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51",
+                "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20",
+                "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1",
+                "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf",
+                "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc",
+                "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e",
+                "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a",
+                "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539",
+                "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27",
+                "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165",
+                "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126",
+                "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1",
+                "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816",
+                "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64",
+                "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8",
+                "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e",
+                "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287",
+                "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3",
+                "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb",
+                "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0",
+                "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043",
+                "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557",
+                "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e",
+                "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21",
+                "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d",
+                "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd",
+                "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0",
+                "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337",
+                "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753",
+                "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804",
+                "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f",
+                "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f",
+                "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5",
+                "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5",
+                "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1",
+                "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00",
+                "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2",
+                "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050",
+                "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e",
+                "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4",
+                "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8",
+                "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996",
+                "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6",
+                "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1",
+                "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f",
+                "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1",
+                "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4",
+                "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b",
+                "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88",
+                "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518",
+                "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5",
+                "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770",
+                "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4",
+                "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a",
+                "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76",
+                "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe",
+                "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988",
+                "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1",
+                "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5",
+                "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b",
+                "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7",
+                "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8",
+                "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc",
+                "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a",
+                "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720",
+                "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3",
+                "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b",
+                "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9",
+                "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1",
+                "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==5.10.0"
+        },
+        "uvicorn": {
+            "extras": [
+                "standard"
+            ],
+            "hashes": [
+                "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de",
+                "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==0.29.0"
+        },
+        "uvloop": {
+            "hashes": [
+                "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd",
+                "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec",
+                "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b",
+                "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc",
+                "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797",
+                "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5",
+                "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2",
+                "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d",
+                "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be",
+                "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd",
+                "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12",
+                "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17",
+                "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef",
+                "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24",
+                "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428",
+                "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1",
+                "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849",
+                "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593",
+                "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd",
+                "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67",
+                "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6",
+                "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3",
+                "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd",
+                "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8",
+                "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7",
+                "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533",
+                "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957",
+                "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650",
+                "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e",
+                "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7",
+                "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"
+            ],
+            "version": "==0.19.0"
+        },
+        "watchfiles": {
+            "hashes": [
+                "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc",
+                "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365",
+                "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0",
+                "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e",
+                "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124",
+                "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c",
+                "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317",
+                "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094",
+                "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7",
+                "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235",
+                "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c",
+                "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c",
+                "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c",
+                "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235",
+                "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293",
+                "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa",
+                "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef",
+                "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19",
+                "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8",
+                "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d",
+                "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915",
+                "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429",
+                "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097",
+                "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe",
+                "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0",
+                "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d",
+                "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99",
+                "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1",
+                "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a",
+                "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895",
+                "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94",
+                "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562",
+                "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab",
+                "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360",
+                "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1",
+                "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7",
+                "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f",
+                "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03",
+                "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01",
+                "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58",
+                "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052",
+                "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e",
+                "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765",
+                "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6",
+                "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137",
+                "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85",
+                "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca",
+                "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f",
+                "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214",
+                "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7",
+                "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7",
+                "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3",
+                "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b",
+                "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7",
+                "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6",
+                "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994",
+                "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9",
+                "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec",
+                "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128",
+                "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c",
+                "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2",
+                "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078",
+                "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3",
+                "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e",
+                "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a",
+                "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6",
+                "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49",
+                "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b",
+                "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28",
+                "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9",
+                "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586",
+                "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400",
+                "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165",
+                "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303",
+                "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d"
+            ],
+            "version": "==0.21.0"
+        },
+        "websockets": {
+            "hashes": [
+                "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b",
+                "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6",
+                "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df",
+                "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b",
+                "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205",
+                "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892",
+                "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53",
+                "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2",
+                "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed",
+                "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c",
+                "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd",
+                "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b",
+                "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931",
+                "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30",
+                "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370",
+                "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be",
+                "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec",
+                "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf",
+                "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62",
+                "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b",
+                "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402",
+                "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f",
+                "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123",
+                "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9",
+                "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603",
+                "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45",
+                "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558",
+                "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4",
+                "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438",
+                "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137",
+                "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480",
+                "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447",
+                "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8",
+                "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04",
+                "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c",
+                "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb",
+                "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967",
+                "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b",
+                "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d",
+                "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def",
+                "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c",
+                "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92",
+                "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2",
+                "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113",
+                "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b",
+                "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28",
+                "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7",
+                "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d",
+                "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f",
+                "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468",
+                "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8",
+                "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae",
+                "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611",
+                "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d",
+                "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9",
+                "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca",
+                "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f",
+                "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2",
+                "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077",
+                "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2",
+                "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6",
+                "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374",
+                "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc",
+                "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e",
+                "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53",
+                "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399",
+                "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547",
+                "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3",
+                "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870",
+                "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5",
+                "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8",
+                "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"
+            ],
+            "version": "==12.0"
+        }
+    },
+    "develop": {}
+}
diff --git a/backend/src/main.py b/backend/src/main.py
new file mode 100644
index 0000000..e0072b0
--- /dev/null
+++ b/backend/src/main.py
@@ -0,0 +1,23 @@
+import fastapi
+from dataclasses import dataclass
+
+
+@dataclass
+class Destination:
+    name: str
+    location: tuple
+    attractiveness: int
+
+
+
+d = Destination()
+
+
+
+def get_route() -> list[Destination]:
+    return {"route": "Hello World"}
+
+endpoint = ("/get_route", get_route)
+end
+if __name__ == "__main__":
+    fastapi.run()
-- 
2.47.2


From 3f1c16b575d187d468562920b2744a3b23421a0f Mon Sep 17 00:00:00 2001
From: Kilian Scheidecker <kilian.scheidecker@orange.fr>
Date: Thu, 16 May 2024 17:36:12 +0200
Subject: [PATCH 06/13] added the optimizer

---
 backend/src/optimizer.py | 206 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 206 insertions(+)
 create mode 100644 backend/src/optimizer.py

diff --git a/backend/src/optimizer.py b/backend/src/optimizer.py
new file mode 100644
index 0000000..dac0df5
--- /dev/null
+++ b/backend/src/optimizer.py
@@ -0,0 +1,206 @@
+from scipy.optimize import linprog
+import numpy as np
+from scipy.linalg import block_diag
+
+
+# Defines the landmark class (aka some place there is to visit)
+class landmark :
+    def __init__(self, name: str, attractiveness: int, loc: tuple):
+        self.name = name
+        self.attractiveness = attractiveness
+        self.loc = loc
+
+# Convert the result (edges from j to k like d_25 = edge between vertex 2 and vertex 5) into the list of indices corresponding to the landmarks
+def untangle(res: list) :
+    N = len(res)                # length of res
+    L = int(np.sqrt(N))         # number of landmarks. CAST INTO INT but should not be a problem because N = L**2 by def.
+    n_landmarks = res.sum()     # number of visited landmarks
+    visit_order = []
+    cnt = 0
+
+    if n_landmarks % 2 == 1 :                                     # if odd number of visited checkpoints
+        for i in range(L) :
+            for j in range(L) :
+                if res[i*L + j] == 1 :              # if index is 1
+                    cnt += 1                        # increment counter
+                    if cnt % 2 == 1 :               # if counter odd
+                        visit_order.append(i)
+                        visit_order.append(j)
+    else :                                   # if even number of ones
+        for i in range(L) :
+            for j in range(L) :
+                if res[i*L + j] == 1 :              # if index is one
+                    cnt += 1                        # increment counter
+                    if j % (L-1) == 0 :             # if last node
+                        visit_order.append(j)       # append only the last index
+                        return visit_order          # return
+                    if cnt % 2 == 1 : 
+                        visit_order.append(i)
+                        visit_order.append(j)
+    return visit_order
+
+# Just to print the result
+def print_res(res: list, P) :
+    X = abs(res.x)
+    order = untangle(X)
+
+    # print("Optimal value:", -res.fun)  # Minimization, so we negate to get the maximum
+    # print("Optimal point:", res.x)
+    # N = int(np.sqrt(len(X)))
+    # for i in range(N):
+    #     print(X[i*N:i*N+N])
+    # print(order)
+
+    if (X.sum()+1)**2 == len(X) : 
+        print('\nAll landmarks can be visited within max_steps, the following order is most likely not the fastest')
+    else :
+        print('Could not visit all the landmarks, the following order could be the fastest but not sure')
+    print("Order of visit :")
+    for i, elem in enumerate(landmarks) : 
+        if i in order : print('- ' + elem.name)
+
+    steps = path_length(P, abs(res.x))
+    print("\nSteps walked : " + str(steps))
+
+# Constraint to use only the upper triangular indices for travel
+def break_sym(landmarks, A_eq, b_eq):
+    L = len(landmarks)
+    l = [0]*L*L
+    for i in range(L) :
+        for j in range(L) :
+            if i >= j :
+                l[j+i*L] = 1
+
+    A_eq = np.vstack((A_eq,l))
+    b_eq.append(0)
+
+    return A_eq, b_eq
+
+# Constraint to respect max number of travels
+def respect_number(landmarks, A_ub, b_ub):
+    h = []
+    for i in range(len(landmarks)) : h.append([1]*len(landmarks))
+    T = block_diag(*h)
+    return np.vstack((A_ub, T)), b_ub + [1]*len(landmarks)
+
+# Constraint to tie the problem together and have a connected path
+def respect_order(landmarks: list, A_eq, b_eq): 
+    N = len(landmarks)
+    for i in range(N-1) :     # Prevent stacked ones
+        if i == 0 :
+            continue
+        else : 
+            l = [0]*N
+            l[i] = -1
+            l = l*N
+            for j in range(N) :
+                l[i*N + j] = 1
+
+            A_eq = np.vstack((A_eq,l))
+            b_eq.append(0)
+
+    return A_eq, b_eq
+
+# Compute manhattan distance between 2 locations
+def manhattan_distance(loc1: tuple, loc2: tuple):
+    x1, y1 = loc1
+    x2, y2 = loc2
+    return abs(x1 - x2) + abs(y1 - y2)
+
+# Constraint to not stay in position
+def init_eq_not_stay(landmarks): 
+    L = len(landmarks)
+    l = [0]*L*L
+    for i in range(L) :
+        for j in range(L) :
+            if j == i :
+                l[j + i*L] = 1
+    #A_eq = np.array([np.array(xi) for xi in A_eq])                  # Must convert A_eq into an np array
+    l = np.array(np.array(l))
+    return [l], [0]
+
+# Initialize A and c. Compute the distances from all landmarks to each other and store attractiveness
+# We want to maximize the sightseeing :  max(c) st. A*x < b   and   A_eq*x = b_eq
+def init_ub_dist(landmarks: list, max_steps: int):
+    # Objective function coefficients. a*x1 + b*x2 + c*x3 + ...
+    c = []
+    # Coefficients of inequality constraints (left-hand side)
+    A = []
+    for i, spot1 in enumerate(landmarks) :
+        dist_table = [0]*len(landmarks)
+        c.append(-spot1.attractiveness)
+        for j, spot2 in enumerate(landmarks) :
+            dist_table[j] = manhattan_distance(spot1.loc, spot2.loc)
+        A.append(dist_table)
+    c = c*len(landmarks)
+    A_ub = []
+    for line in A :
+        A_ub += line
+    return c, A_ub, [max_steps]
+
+# Go through the landmarks and force the optimizer to use landmarks where attractiveness is set to -1
+def respect_user_mustsee(landmarks: list, A_eq: list, b_eq: list) :
+    L = len(landmarks)
+    for i, elem in enumerate(landmarks) :
+        if elem.attractiveness == -1 :
+            l = [0]*L*L
+            if elem.name != "arrivée" :
+                for j in range(L) :
+                    l[j +i*L] = 1
+            else :                          # This ensures we go to goal
+                for k in range(L-1) :
+                        l[k*L+L-1] = 1
+            A_eq = np.vstack((A_eq,l))
+            b_eq.append(1)
+    return A_eq, b_eq
+
+# Computes the path length given path matrix (dist_table) and a result
+def path_length(P: list, resx: list) :
+    return np.dot(P, resx)
+
+# Initialize all landmarks (+ start and goal). Order matters here
+landmarks = []
+landmarks.append(landmark("départ", -1, (0, 0)))
+landmarks.append(landmark("concorde", -1, (5,5)))
+landmarks.append(landmark("tour eiffel", 99, (1,1)))                           # PUT IN JSON
+landmarks.append(landmark("arc de triomphe", 99, (2,3)))
+landmarks.append(landmark("louvre", 70, (4,2)))
+landmarks.append(landmark("montmartre", 20, (0,2)))
+landmarks.append(landmark("arrivée", -1, (0, 0)))
+
+
+
+# CONSTRAINT TO RESPECT MAX NUMBER OF STEPS
+max_steps = 25
+
+# SET CONSTRAINTS FOR INEQUALITY
+c, A_ub, b_ub = init_ub_dist(landmarks, max_steps)              # Add the distances from each landmark to the other
+P = A_ub                                                        # store the paths for later. Needed to compute path length
+A_ub, b_ub = respect_number(landmarks, A_ub, b_ub)              # Respect max number of visits. 
+
+# SET CONSTRAINTS FOR EQUALITY
+A_eq, b_eq = init_eq_not_stay(landmarks)                       # Force solution not to stay in same place
+A_eq, b_eq = respect_user_mustsee(landmarks, A_eq, b_eq)       # Check if there are user_defined must_see. Also takes care of start/goal
+A_eq, b_eq = break_sym(landmarks, A_eq, b_eq)                  # break the symmetry. Only use the upper diagonal values
+A_eq, b_eq = respect_order(landmarks, A_eq, b_eq)              # Respect order of visit (only works when max_steps is limiting factor)
+
+# Bounds for variables (x can only be 0 or 1)
+x_bounds = [(0, 1)] * len(c)
+
+# Solve linear programming problem
+res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq = b_eq, bounds=x_bounds, method='highs', integrality=3)
+
+# Raise error if no solution is found
+if not res.success :
+    raise ValueError("No solution has been found, please adapt your max steps")
+
+# Print result
+print_res(res, P)
+
+
+
+
+
+
+
+
-- 
2.47.2


From 3854cef54a062ca68308a1b74d4d4ea04e3bc590 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Fri, 17 May 2024 20:12:59 +0200
Subject: [PATCH 07/13] adding google maps baby!

---
 .gitea/workflows/frontend_build-android.yaml  |   2 +-
 frontend/android/app/build.gradle             |   3 +
 .../android/app/src/main/AndroidManifest.xml  |   4 +-
 frontend/lib/modules/map.dart                 |  81 +++++++++++++
 frontend/lib/modules/overview.dart            |  78 ++----------
 frontend/pubspec.lock                         | 111 +++++++++++++++++-
 frontend/pubspec.yaml                         |   1 +
 frontend/web/index.html                       |   1 +
 8 files changed, 212 insertions(+), 69 deletions(-)
 create mode 100644 frontend/lib/modules/map.dart

diff --git a/.gitea/workflows/frontend_build-android.yaml b/.gitea/workflows/frontend_build-android.yaml
index de430ce..02bf3bf 100644
--- a/.gitea/workflows/frontend_build-android.yaml
+++ b/.gitea/workflows/frontend_build-android.yaml
@@ -35,7 +35,7 @@ jobs:
     - run: flutter pub get
       working-directory: ./frontend
 
-    - run: flutter build apk --debug --split-per-abi
+    - run: flutter build apk --release --split-per-abi
       working-directory: ./frontend
 
 
diff --git a/frontend/android/app/build.gradle b/frontend/android/app/build.gradle
index 21a5169..f6b499e 100644
--- a/frontend/android/app/build.gradle
+++ b/frontend/android/app/build.gradle
@@ -45,6 +45,9 @@ android {
         applicationId "com.example.fast_network_navigation"
         // You can update the following values to match your application needs.
         // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+        // Minimum Android version for Google Maps SDK
+        // https://developers.google.com/maps/flutter-package/config#android
+        minSdk = 21
         minSdkVersion flutter.minSdkVersion
         targetSdkVersion flutter.targetSdkVersion
         versionCode flutterVersionCode.toInteger()
diff --git a/frontend/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml
index fc057fe..54f939a 100644
--- a/frontend/android/app/src/main/AndroidManifest.xml
+++ b/frontend/android/app/src/main/AndroidManifest.xml
@@ -28,7 +28,9 @@
              This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
         <meta-data
             android:name="flutterEmbedding"
-            android:value="2" />
+            android:value="2"
+            android:name="com.google.android.geo.API_KEY"
+            android:value="AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw"/> />
     </application>
     <!-- Required to query activities that can process text, see:
          https://developer.android.com/training/package-visibility?hl=en and
diff --git a/frontend/lib/modules/map.dart b/frontend/lib/modules/map.dart
new file mode 100644
index 0000000..9f7a22d
--- /dev/null
+++ b/frontend/lib/modules/map.dart
@@ -0,0 +1,81 @@
+import 'package:flutter/material.dart';
+
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+
+class MapWidget extends StatefulWidget {
+  @override
+  State<MapWidget> createState() => _MapWidgetState();
+}
+
+class _MapWidgetState extends State<MapWidget> {
+  late GoogleMapController mapController;
+
+  final LatLng _center = const LatLng(45.521563, -122.677433);
+
+  void _onMapCreated(GoogleMapController controller) {
+    mapController = controller;
+  }
+  void _onCameraIdle() {
+    // print(mapController.getLatLng());
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return GoogleMap(
+      onMapCreated: _onMapCreated,
+      initialCameraPosition: CameraPosition(
+        target: _center,
+        zoom: 11.0,
+      ),
+      onCameraIdle: _onCameraIdle,
+    );
+  }
+}
+
+
+
+  // GeoCode geoCode = GeoCode();
+  // String _currentCityName = "...";
+  // final Debounce _debounce = Debounce(Duration(seconds: 3));
+
+  // final LatLng _center = const LatLng(45.521563, -122.677433);
+  // late GoogleMapController mapController;
+
+  // void _onMapCreated(GoogleMapController controller) {
+  //   mapController = controller;
+  // }
+
+  // // void _setCurrentCityName() async {
+  //   if (mapController.camera.zoom < 9) {
+  //     return; // Don't bother if the view is too wide
+  //   }
+  //   var currentCoordinates = mapController.camera.center;
+  //   String? city;
+    
+  //   try{
+  //     List<Placemark> placemarks = await placemarkFromCoordinates(currentCoordinates.latitude, currentCoordinates.longitude);
+  //     city = placemarks[0].locality.toString();
+  //   } catch (e) {
+  //     debugPrint("Error: $e");
+  //     try {
+  //       Address address = await geoCode.reverseGeocoding(latitude: currentCoordinates.latitude, longitude: currentCoordinates.longitude);
+        
+  //       if (address.city == null || address.city.toString().contains("Throttled!")){
+  //         throw Exception("Probably rate limited");
+  //       }
+  //       city = address.city.toString();
+  //     } catch (e) {
+  //       debugPrint("Error: $e");
+
+  //     }
+  //   }
+  //   if (city != null) {
+  //     setState(() {
+  //       _currentCityName = city!;
+  //     });
+  //   } else {
+  //     _debounce(() async {_setCurrentCityName();});
+  //   }
+  // }
+
+  
\ No newline at end of file
diff --git a/frontend/lib/modules/overview.dart b/frontend/lib/modules/overview.dart
index ff03b9b..d9bc126 100644
--- a/frontend/lib/modules/overview.dart
+++ b/frontend/lib/modules/overview.dart
@@ -1,17 +1,21 @@
 import 'package:flutter/material.dart';
-import 'package:flutter_map/flutter_map.dart';
 import 'package:sliding_up_panel/sliding_up_panel.dart';
-import 'package:latlong2/latlong.dart';
-import 'package:geocoding/geocoding.dart';
 import 'package:geocode/geocode.dart';
 import 'dart:async';
+import 'package:google_maps_flutter/google_maps_flutter.dart';
 
 import 'package:fast_network_navigation/modules/navigation.dart';
+import 'package:fast_network_navigation/modules/map.dart';
 
-class MapPage extends StatefulWidget {
+
+
+class MainPage extends StatefulWidget {
   @override
-  _MapPageState createState() => _MapPageState();
+  State<MainPage> createState() => _MainPageState();
 }
+
+
+
 class Debounce {
   Duration delay;
   Timer? _timer;
@@ -31,44 +35,7 @@ class Debounce {
 }
 
 
-class _MapPageState extends State<MapPage> {
-  GeoCode geoCode = GeoCode();
-  final mapController = MapController();
-  String _currentCityName = "...";
-  final Debounce _debounce = Debounce(Duration(seconds: 3));
-
-  void _setCurrentCityName() async {
-    if (mapController.camera.zoom < 9) {
-      return; // Don't bother if the view is too wide
-    }
-    var currentCoordinates = mapController.camera.center;
-    String? city;
-    
-    try{
-      List<Placemark> placemarks = await placemarkFromCoordinates(currentCoordinates.latitude, currentCoordinates.longitude);
-      city = placemarks[0].locality.toString();
-    } catch (e) {
-      debugPrint("Error: $e");
-      try {
-        Address address = await geoCode.reverseGeocoding(latitude: currentCoordinates.latitude, longitude: currentCoordinates.longitude);
-        
-        if (address.city == null || address.city.toString().contains("Throttled!")){
-          throw Exception("Probably rate limited");
-        }
-        city = address.city.toString();
-      } catch (e) {
-        debugPrint("Error: $e");
-
-      }
-    }
-    if (city != null) {
-      setState(() {
-        _currentCityName = city!;
-      });
-    } else {
-      _debounce(() async {_setCurrentCityName();});
-    }
-  }
+class _MainPageState extends State<MainPage> {
 
   @override
   Widget build(BuildContext context) {
@@ -77,21 +44,7 @@ class _MapPageState extends State<MapPage> {
         renderPanelSheet: false,
         panel: _floatingPanel(theme),
         collapsed: _floatingCollapsed(theme),
-        body: FlutterMap(
-          mapController: mapController,
-          options: MapOptions(
-            initialZoom: 11,
-            initialCenter: LatLng(51.509364, -0.128928),
-            onMapReady: () {
-                mapController.mapEventStream.listen((evt) {_debounce(() async {_setCurrentCityName();});});
-                // And any other `MapController` dependent non-movement methods
-            },
-
-          ),
-          children: [
-            openStreetMapTileLayer,
-          ],
-        ),
+        body: MapWidget()
     );
   }
 
@@ -138,16 +91,9 @@ class _MapPageState extends State<MapPage> {
   Widget Greeting (ThemeData theme) {
     return Center(
         child: Text(
-            "Explore ${_currentCityName}",
+            "Explore #todo",
           style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold),
         ),
       );
   }
 }
-
-TileLayer get openStreetMapTileLayer => TileLayer(
-  urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
-  userAgentPackageName: 'flutter_map',
-);
-
-// Add a pin to the map
diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock
index b88a8ef..f72974c 100644
--- a/frontend/pubspec.lock
+++ b/frontend/pubspec.lock
@@ -41,6 +41,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.18.0"
+  csslib:
+    dependency: transitive
+    description:
+      name: csslib
+      sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
   cupertino_icons:
     dependency: "direct main"
     description:
@@ -78,11 +86,24 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "6.1.0"
+  flutter_plugin_android_lifecycle:
+    dependency: transitive
+    description:
+      name: flutter_plugin_android_lifecycle
+      sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.19"
   flutter_test:
     dependency: "direct dev"
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_web_plugins:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
   geocode:
     dependency: "direct main"
     description:
@@ -123,6 +144,62 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.2.0"
+  google_maps:
+    dependency: transitive
+    description:
+      name: google_maps
+      sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.1.0"
+  google_maps_flutter:
+    dependency: "direct main"
+    description:
+      name: google_maps_flutter
+      sha256: c1972cbad779bc5346c49045f26ae45550a0958b1cbca5b524dd3c8954995d28
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.6.1"
+  google_maps_flutter_android:
+    dependency: transitive
+    description:
+      name: google_maps_flutter_android
+      sha256: "0bcadb80eba39afda77dede89a6caafd3b68f2786b90491eceea4a01c3db181c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.8.0"
+  google_maps_flutter_ios:
+    dependency: transitive
+    description:
+      name: google_maps_flutter_ios
+      sha256: e5132d17f051600d90d79d9f574b177c24231da702453a036db2490f9ced4646
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.6.0"
+  google_maps_flutter_platform_interface:
+    dependency: transitive
+    description:
+      name: google_maps_flutter_platform_interface
+      sha256: "167af879da4d004cd58771f1469b91dcc3b9b0a2c5334cc6bf71fd41d4b35403"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.6.0"
+  google_maps_flutter_web:
+    dependency: transitive
+    description:
+      name: google_maps_flutter_web
+      sha256: "0c0d5c723d94b295cf86dd1c45ff91d2ac1fff7c05ddca4f01bef9fa0a014690"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.5.7"
+  html:
+    dependency: transitive
+    description:
+      name: html
+      sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.15.4"
   http:
     dependency: transitive
     description:
@@ -147,6 +224,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.19.0"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.6.7"
+  js_wrapping:
+    dependency: transitive
+    description:
+      name: js_wrapping
+      sha256: e385980f7c76a8c1c9a560dfb623b890975841542471eade630b2871d243851c
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.7.4"
   latlong2:
     dependency: "direct main"
     description:
@@ -267,6 +360,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.0"
+  sanitize_html:
+    dependency: transitive
+    description:
+      name: sanitize_html
+      sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.0"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -304,6 +405,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.2"
+  stream_transform:
+    dependency: transitive
+    description:
+      name: stream_transform
+      sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.0"
   string_scanner:
     dependency: transitive
     description:
@@ -378,4 +487,4 @@ packages:
     version: "2.0.0"
 sdks:
   dart: ">=3.3.4 <4.0.0"
-  flutter: ">=3.18.0-18.0.pre.54"
+  flutter: ">=3.19.0"
diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml
index 53add6b..4c794d1 100644
--- a/frontend/pubspec.yaml
+++ b/frontend/pubspec.yaml
@@ -40,6 +40,7 @@ dependencies:
   latlong2: ^0.9.1
   geocoding: ^3.0.0
   geocode: ^1.0.3
+  google_maps_flutter: ^2.6.1
 
 dev_dependencies:
   flutter_test:
diff --git a/frontend/web/index.html b/frontend/web/index.html
index 30e08e2..5cbcc91 100644
--- a/frontend/web/index.html
+++ b/frontend/web/index.html
@@ -14,6 +14,7 @@
     This is a placeholder for base href that will be replaced by the value of
     the `--base-href` argument provided to `flutter build`.
   -->
+  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw"></script>
   <base href="$FLUTTER_BASE_HREF">
 
   <meta charset="UTF-8">
-- 
2.47.2


From 66fc4e7d33712e6b202ea933e381f3efb501792c Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sat, 18 May 2024 10:56:04 +0200
Subject: [PATCH 08/13] update deps

---
 frontend/pubspec.lock | 88 ++-----------------------------------------
 frontend/pubspec.yaml |  4 +-
 2 files changed, 5 insertions(+), 87 deletions(-)

diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock
index f72974c..21fb46f 100644
--- a/frontend/pubspec.lock
+++ b/frontend/pubspec.lock
@@ -74,18 +74,10 @@ packages:
     dependency: "direct dev"
     description:
       name: flutter_lints
-      sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
+      sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.2"
-  flutter_map:
-    dependency: "direct main"
-    description:
-      name: flutter_map
-      sha256: cda8d72135b697f519287258b5294a57ce2f2a5ebf234f0e406aad4dc14c9399
-      url: "https://pub.dev"
-    source: hosted
-    version: "6.1.0"
+    version: "4.0.0"
   flutter_plugin_android_lifecycle:
     dependency: transitive
     description:
@@ -216,14 +208,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.0.2"
-  intl:
-    dependency: transitive
-    description:
-      name: intl
-      sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.19.0"
   js:
     dependency: transitive
     description:
@@ -240,14 +224,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.7.4"
-  latlong2:
-    dependency: "direct main"
-    description:
-      name: latlong2
-      sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.9.1"
   leak_tracker:
     dependency: transitive
     description:
@@ -276,26 +252,10 @@ packages:
     dependency: transitive
     description:
       name: lints
-      sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+      sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.0"
-  lists:
-    dependency: transitive
-    description:
-      name: lists
-      sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.0.1"
-  logger:
-    dependency: transitive
-    description:
-      name: logger
-      sha256: "8c94b8c219e7e50194efc8771cd0e9f10807d8d3e219af473d89b06cc2ee4e04"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.2.0"
+    version: "4.0.0"
   matcher:
     dependency: transitive
     description:
@@ -320,14 +280,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.12.0"
-  mgrs_dart:
-    dependency: transitive
-    description:
-      name: mgrs_dart
-      sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.0.0"
   path:
     dependency: transitive
     description:
@@ -344,22 +296,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.8"
-  polylabel:
-    dependency: transitive
-    description:
-      name: polylabel
-      sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b"
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.0.1"
-  proj4dart:
-    dependency: transitive
-    description:
-      name: proj4dart
-      sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.1.0"
   sanitize_html:
     dependency: transitive
     description:
@@ -445,14 +381,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.3.2"
-  unicode:
-    dependency: transitive
-    description:
-      name: unicode
-      sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1"
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.3.1"
   vector_math:
     dependency: transitive
     description:
@@ -477,14 +405,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.5.1"
-  wkt_parser:
-    dependency: transitive
-    description:
-      name: wkt_parser
-      sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13"
-      url: "https://pub.dev"
-    source: hosted
-    version: "2.0.0"
 sdks:
   dart: ">=3.3.4 <4.0.0"
   flutter: ">=3.19.0"
diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml
index 4c794d1..b0409b2 100644
--- a/frontend/pubspec.yaml
+++ b/frontend/pubspec.yaml
@@ -35,9 +35,7 @@ dependencies:
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^1.0.6
-  flutter_map: ^6.1.0
   sliding_up_panel: ^2.0.0+1
-  latlong2: ^0.9.1
   geocoding: ^3.0.0
   geocode: ^1.0.3
   google_maps_flutter: ^2.6.1
@@ -51,7 +49,7 @@ dev_dependencies:
   # activated in the `analysis_options.yaml` file located at the root of your
   # package. See that file for information about deactivating specific lint
   # rules and activating additional ones.
-  flutter_lints: ^3.0.0
+  flutter_lints: ^4.0.0
 
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec
-- 
2.47.2


From f6e3cfc8a0482f3ad95a0f5d86b4f253f1c639fb Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Mon, 20 May 2024 12:09:33 +0200
Subject: [PATCH 09/13] build like this

---
 .gitea/workflows/frontend_build-android.yaml | 6 +++---
 deployment/kustomization.yaml                | 0
 frontend/lib/modules/scaffold.dart           | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)
 create mode 100644 deployment/kustomization.yaml

diff --git a/.gitea/workflows/frontend_build-android.yaml b/.gitea/workflows/frontend_build-android.yaml
index 02bf3bf..b255196 100644
--- a/.gitea/workflows/frontend_build-android.yaml
+++ b/.gitea/workflows/frontend_build-android.yaml
@@ -8,13 +8,13 @@ name: Build and release APK
 jobs:
   build:
     name: Build APK
-    runs-on: k8s
+    runs-on: ubuntu-latest
     steps:
 
     - name: Install prerequisites
       run: |
-        sudo apt-get update
-        sudo apt-get install -y xz-utils unzip
+        apt-get update
+        apt-get install -y jq
 
     - uses: https://gitea.com/actions/checkout@v4
 
diff --git a/deployment/kustomization.yaml b/deployment/kustomization.yaml
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/lib/modules/scaffold.dart b/frontend/lib/modules/scaffold.dart
index 34c603c..822f208 100644
--- a/frontend/lib/modules/scaffold.dart
+++ b/frontend/lib/modules/scaffold.dart
@@ -22,7 +22,7 @@ class _BasePageState extends State<BasePage> {
     });
   }
 
-  Widget currentView = MapPage();
+  Widget currentView = MainPage();
   @override
   Widget build(BuildContext context) {
     final ThemeData theme = Theme.of(context);
@@ -51,7 +51,7 @@ class _BasePageState extends State<BasePage> {
                 // Update the state of the app
                 _onItemTapped(0);
                 // Then close the drawer
-                currentView = MapPage();
+                currentView = MainPage();
                 Navigator.pop(context);
               },
             ),
-- 
2.47.2


From 6405f33a34ff28e9404dde72d0095d2b4477ef8f Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Mon, 20 May 2024 21:07:10 +0200
Subject: [PATCH 10/13] update flutter builder

---
 .gitea/workflows/frontend_build-android.yaml | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/.gitea/workflows/frontend_build-android.yaml b/.gitea/workflows/frontend_build-android.yaml
index b255196..e510298 100644
--- a/.gitea/workflows/frontend_build-android.yaml
+++ b/.gitea/workflows/frontend_build-android.yaml
@@ -18,15 +18,19 @@ jobs:
 
     - uses: https://gitea.com/actions/checkout@v4
 
+
     - uses: https://github.com/actions/setup-java@v4
       with:
         java-version: '17'
         distribution: 'zulu'
 
+    - name: Fix flutter SDK folder permission
+      run: git config --global --add safe.directory "*"
+
     - uses: https://github.com/subosito/flutter-action@v2
       with:
         channel: stable
-        flutter-version: 3.19.6
+        flutter-version: 3.22.0
         cache: true
 
     - name: Setup Android SDK
-- 
2.47.2


From 3688229d7b159f07ee182c20af127a4a7c7ebf2c Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Mon, 20 May 2024 22:18:08 +0000
Subject: [PATCH 11/13] Update
 frontend/android/app/src/main/AndroidManifest.xml

---
 frontend/android/app/src/main/AndroidManifest.xml | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/frontend/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml
index 54f939a..58e6f22 100644
--- a/frontend/android/app/src/main/AndroidManifest.xml
+++ b/frontend/android/app/src/main/AndroidManifest.xml
@@ -29,8 +29,13 @@
         <meta-data
             android:name="flutterEmbedding"
             android:value="2"
+        />
+        <meta-data
             android:name="com.google.android.geo.API_KEY"
-            android:value="AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw"/> />
+            android:value="AIzaSyCeWk_D2xvfOHLidvV56EZeQCUybypEntw"
+        />
+
+
     </application>
     <!-- Required to query activities that can process text, see:
          https://developer.android.com/training/package-visibility?hl=en and
-- 
2.47.2


From 07830de1b2429a23967a1bd86db263799076079d Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Tue, 21 May 2024 06:29:10 +0000
Subject: [PATCH 12/13] Update .gitea/workflows/frontend_build-android.yaml

---
 .gitea/workflows/frontend_build-android.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitea/workflows/frontend_build-android.yaml b/.gitea/workflows/frontend_build-android.yaml
index e510298..456a138 100644
--- a/.gitea/workflows/frontend_build-android.yaml
+++ b/.gitea/workflows/frontend_build-android.yaml
@@ -46,7 +46,7 @@ jobs:
     - name: Release APK
       uses: https://gitea.com/akkuman/gitea-release-action@v1
       with:
-        files: ./frontendbuild/app/outputs/flutter-apk/*.apk
+        files: ./frontend/build/app/outputs/flutter-apk/*.apk
         name: Testing release
         release_name: testing
         tag: testing
-- 
2.47.2


From 3029fb85374ded3b3f713b9f6d4ad4c5c96ecfa7 Mon Sep 17 00:00:00 2001
From: Remy Moll <me@moll.re>
Date: Sat, 25 May 2024 18:55:58 +0200
Subject: [PATCH 13/13] some preference improvements

---
 .../android/app/src/main/AndroidManifest.xml  |   3 +
 .../{modules/scaffold.dart => layout.dart}    |   8 +-
 frontend/lib/main.dart                        |   2 +-
 frontend/lib/modules/overview.dart            |   6 +-
 frontend/lib/modules/profile.dart             | 114 ++++++++++------
 frontend/lib/structs/destination.dart         |  39 +++++-
 frontend/lib/structs/preferences.dart         |  82 ++++++++++++
 frontend/lib/structs/route.dart               |  14 ++
 frontend/lib/utils/get_route.dart             |  18 +++
 .../Flutter/GeneratedPluginRegistrant.swift   |   2 +
 frontend/pubspec.lock                         | 124 +++++++++++++++++-
 frontend/pubspec.yaml                         |   2 +
 frontend/test/widget_test.dart                |   7 +-
 13 files changed, 365 insertions(+), 56 deletions(-)
 rename frontend/lib/{modules/scaffold.dart => layout.dart} (92%)
 create mode 100644 frontend/lib/structs/preferences.dart
 create mode 100644 frontend/lib/structs/route.dart
 create mode 100644 frontend/lib/utils/get_route.dart

diff --git a/frontend/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml
index 58e6f22..f144d58 100644
--- a/frontend/android/app/src/main/AndroidManifest.xml
+++ b/frontend/android/app/src/main/AndroidManifest.xml
@@ -48,4 +48,7 @@
             <data android:mimeType="text/plain"/>
         </intent>
     </queries>
+
+    <!-- Required to fetch data from the internet. -->
+    <uses-permission android:name="android.permission.INTERNET" />
 </manifest>
diff --git a/frontend/lib/modules/scaffold.dart b/frontend/lib/layout.dart
similarity index 92%
rename from frontend/lib/modules/scaffold.dart
rename to frontend/lib/layout.dart
index 822f208..875ccbc 100644
--- a/frontend/lib/modules/scaffold.dart
+++ b/frontend/lib/layout.dart
@@ -4,9 +4,10 @@ import 'package:fast_network_navigation/modules/overview.dart';
 import 'package:fast_network_navigation/modules/profile.dart';
 
 
+// BasePage is the scaffold that holds all other pages
+// A side drawer is used to switch between pages
 class BasePage extends StatefulWidget {
   const BasePage({super.key, required this.title});
-
   final String title;
 
   @override
@@ -22,7 +23,7 @@ class _BasePageState extends State<BasePage> {
     });
   }
 
-  Widget currentView = MainPage();
+  Widget currentView = NavigationOverview();
   @override
   Widget build(BuildContext context) {
     final ThemeData theme = Theme.of(context);
@@ -51,7 +52,7 @@ class _BasePageState extends State<BasePage> {
                 // Update the state of the app
                 _onItemTapped(0);
                 // Then close the drawer
-                currentView = MainPage();
+                currentView = NavigationOverview();
                 Navigator.pop(context);
               },
             ),
@@ -87,3 +88,4 @@ class _BasePageState extends State<BasePage> {
     );
   }
 }
+
diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart
index 424c0d5..d818628 100644
--- a/frontend/lib/main.dart
+++ b/frontend/lib/main.dart
@@ -1,5 +1,5 @@
 import 'package:flutter/material.dart';
-import 'package:fast_network_navigation/modules/scaffold.dart';
+import 'package:fast_network_navigation/layout.dart';
 
 void main() => runApp(const App());
 
diff --git a/frontend/lib/modules/overview.dart b/frontend/lib/modules/overview.dart
index d9bc126..bfcf18f 100644
--- a/frontend/lib/modules/overview.dart
+++ b/frontend/lib/modules/overview.dart
@@ -9,9 +9,9 @@ import 'package:fast_network_navigation/modules/map.dart';
 
 
 
-class MainPage extends StatefulWidget {
+class NavigationOverview extends StatefulWidget {
   @override
-  State<MainPage> createState() => _MainPageState();
+  State<NavigationOverview> createState() => _NavigationOverviewState();
 }
 
 
@@ -35,7 +35,7 @@ class Debounce {
 }
 
 
-class _MainPageState extends State<MainPage> {
+class _NavigationOverviewState extends State<NavigationOverview> {
 
   @override
   Widget build(BuildContext context) {
diff --git a/frontend/lib/modules/profile.dart b/frontend/lib/modules/profile.dart
index 69bfba4..e8beb08 100644
--- a/frontend/lib/modules/profile.dart
+++ b/frontend/lib/modules/profile.dart
@@ -1,3 +1,4 @@
+import 'package:fast_network_navigation/structs/preferences.dart';
 import 'package:flutter/material.dart';
 
 
@@ -8,48 +9,83 @@ class ProfilePage extends StatefulWidget {
 }
 
 class _ProfilePageState extends State<ProfilePage> {
-  
-  double value = 0.0;
-  void onChanged(double newValue) {
-    setState(() {
-      value = newValue;
-    });
-  }
   @override
   Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: Text('Profile'),
-      ),
-      body: Padding(
-        padding: EdgeInsets.all(8.0),
-        child: Column(
-          children: <Widget>[
-            Card(
-              child: ListTile(
-                leading: Icon(Icons.notifications_sharp),
-                title: Text('Notification 1'),
-                subtitle: Text('This is a first notification'),
-              ),
-            ),
-            Card(
-              child: ListTile(
-                leading: Icon(Icons.notifications_sharp),
-                title: Text('Notification 2'),
-                subtitle: Text('This is a notification'),
-              ),
-            ),
-            Card(
-              child: ListTile(
-                leading: Icon(Icons.outdoor_grill),
-                title: Text("Eating preference"),
-                subtitle: Slider.adaptive(value: value, onChanged: onChanged, min: 0, max: 5, divisions: 5, label: value.toInt().toString(),)
-                
-              )
-            )
-          ],
+    return ListView(
+      children: [
+        // First a round, centered image
+        Center(
+          child: CircleAvatar(
+            radius: 100,
+            child: Icon(Icons.person, size: 100),
+          )
         ),
-      )
+        Center(
+          child: Text('Curious traveler', style: TextStyle(fontSize: 24))
+        ),
+
+        Padding(
+          padding: EdgeInsets.all(10),
+        ),
+
+        Text('Please rate your preferences for the following activities:'),
+
+        // Now the sliders
+        ImportanceSliders()
+      ]
     );
   }
 }
+
+
+
+class ImportanceSliders extends StatefulWidget {
+
+  @override
+  State<ImportanceSliders> createState() => _ImportanceSlidersState();
+}
+
+
+class _ImportanceSlidersState extends State<ImportanceSliders> {
+
+  UserPreferences _prefs = UserPreferences();
+
+  @override
+  void initState() {
+    super.initState();
+    _prefs.load();
+  }
+
+  List<Card> _createSliders() {
+    List<Card> sliders = [];
+    for (SinglePreference pref in _prefs.preferences) {
+      sliders.add(Card(
+        child: ListTile(
+          leading: pref.icon,
+          title: Text(pref.name),
+          subtitle: Slider(
+            value: pref.value.toDouble(),
+            min: 0,
+            max: 10,
+            divisions: 10,
+            label: pref.value.toString(),
+            onChanged: (double newValue) {
+              setState(() {
+                pref.value = newValue.toInt();
+                _prefs.save();
+              });
+            },
+          )
+        ),
+        margin: EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0),
+        shadowColor: Colors.grey,
+      ));
+    }
+    return sliders;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(children: _createSliders());
+  }
+}
diff --git a/frontend/lib/structs/destination.dart b/frontend/lib/structs/destination.dart
index bb8d086..c44fbf9 100644
--- a/frontend/lib/structs/destination.dart
+++ b/frontend/lib/structs/destination.dart
@@ -1,31 +1,62 @@
+import "package:flutter/material.dart";
 
 class Destination {
   final double latitude;
   final double longitude;
   final String name;
   final String description;
-  final DestinationType type;
+  // final DestinationType type;
   final Duration duration;
   final bool visited;
 
-  Destination({
+  const Destination({
     required this.latitude,
     required this.longitude,
     required this.name,
     required this.description,
-    required this.type,
+    // required this.type,
     required this.duration,
     required this.visited,
   });
+
+  factory Destination.fromJson(Map<String, dynamic> json) {
+  return switch (json) {
+    {
+      'lat': double latitude,
+      'lon': double longitude,
+      'name': String name,
+      'description': String description,
+      // 'type': String type,
+      'duration': int duration,
+      'visited': bool visited
+
+    } =>
+      Destination(
+        latitude: latitude,
+        longitude: longitude,
+        name: name,
+        description: description,
+        // type: "DestinationType.values.firstWhere((element) => element.name == type)",
+        duration: Duration(minutes: duration),
+        visited: visited
+      ),
+    _ => throw const FormatException('Failed to load destination.'),
+  };
+}
+
 }
 
 
 class DestinationType {
   final String name;
   final String description;
+  final Icon icon;
   
-  DestinationType({
+  const DestinationType({
     required this.name,
     required this.description,
+    required this.icon,
   });
 }
+
+
diff --git a/frontend/lib/structs/preferences.dart b/frontend/lib/structs/preferences.dart
new file mode 100644
index 0000000..7746393
--- /dev/null
+++ b/frontend/lib/structs/preferences.dart
@@ -0,0 +1,82 @@
+import 'package:flutter/material.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+
+class SinglePreference {
+  String name;
+  String description;
+  int value;
+  Icon icon;
+  String key;
+
+  SinglePreference({
+    required this.name,
+    required this.description,
+    required this.value,
+    required this.icon,
+    required this.key,
+  });
+}
+
+
+class UserPreferences {
+  List<SinglePreference> preferences = [
+    SinglePreference(
+      name: "Sightseeing",
+      description: "How much do you like sightseeing?",
+      value: 0,
+      icon: Icon(Icons.church),
+      key: "sightseeing",
+    ),
+    SinglePreference(
+      name: "Shopping",
+      description: "How much do you like shopping?",
+      value: 0,
+      icon: Icon(Icons.shopping_bag),
+      key: "shopping",
+    ),
+    SinglePreference(
+      name: "Foods & Drinks",
+      description: "How much do you like eating?",
+      value: 0,
+      icon: Icon(Icons.restaurant),
+      key: "eating",
+    ),
+    SinglePreference(
+      name: "Nightlife",
+      description: "How much do you like nightlife?",
+      value: 0,
+      icon: Icon(Icons.wine_bar),
+      key: "nightlife",
+    ),
+    SinglePreference(
+      name: "Nature",
+      description: "How much do you like nature?",
+      value: 0,
+      icon: Icon(Icons.landscape),
+      key: "nature",
+    ),
+    SinglePreference(
+      name: "Culture",
+      description: "How much do you like culture?",
+      value: 0,
+      icon: Icon(Icons.palette),
+      key: "culture",
+    ),
+  ];
+
+
+  void save() async {
+    SharedPreferences prefs = await SharedPreferences.getInstance();
+    for (SinglePreference pref in preferences) {
+      prefs.setInt(pref.key, pref.value);
+    }
+  }
+
+  void load() async {
+    SharedPreferences prefs = await SharedPreferences.getInstance();
+    for (SinglePreference pref in preferences) {
+      pref.value = prefs.getInt(pref.key) ?? 0;
+    }
+  }
+}
\ No newline at end of file
diff --git a/frontend/lib/structs/route.dart b/frontend/lib/structs/route.dart
new file mode 100644
index 0000000..8b46787
--- /dev/null
+++ b/frontend/lib/structs/route.dart
@@ -0,0 +1,14 @@
+import "package:fast_network_navigation/structs/destination.dart";
+
+
+class Route {
+  final String name;
+  final Duration duration;
+  final List<Destination> destinations;
+  
+  Route({
+    required this.name,
+    required this.duration,
+    required this.destinations
+  });
+}
\ No newline at end of file
diff --git a/frontend/lib/utils/get_route.dart b/frontend/lib/utils/get_route.dart
new file mode 100644
index 0000000..fccf6ac
--- /dev/null
+++ b/frontend/lib/utils/get_route.dart
@@ -0,0 +1,18 @@
+import "package:fast_network_navigation/structs/destination.dart";
+import 'package:http/http.dart' as http;
+import 'dart:convert';
+
+Future<Destination> fetchDestination() async {
+  final response = await http
+      .get(Uri.parse('https://nav.kluster.moll.re/v1/destination/1'));
+
+  if (response.statusCode == 200) {
+    // If the server did return a 200 OK response,
+    // then parse the JSON.
+    return Destination.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
+  } else {
+    // If the server did not return a 200 OK response,
+    // then throw an exception.
+    throw Exception('Failed to load destination');
+  }
+}
\ No newline at end of file
diff --git a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift
index cccf817..724bb2a 100644
--- a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -5,6 +5,8 @@
 import FlutterMacOS
 import Foundation
 
+import shared_preferences_foundation
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
 }
diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock
index 21fb46f..7c2f396 100644
--- a/frontend/pubspec.lock
+++ b/frontend/pubspec.lock
@@ -65,6 +65,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.3.1"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.0.0"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -193,7 +209,7 @@ packages:
     source: hosted
     version: "0.15.4"
   http:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: http
       sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
@@ -288,6 +304,38 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.9.0"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.4"
   plugin_platform_interface:
     dependency: transitive
     description:
@@ -304,6 +352,62 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.0"
+  shared_preferences:
+    dependency: "direct main"
+    description:
+      name: shared_preferences
+      sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.3"
+  shared_preferences_android:
+    dependency: transitive
+    description:
+      name: shared_preferences_android
+      sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.2"
+  shared_preferences_foundation:
+    dependency: transitive
+    description:
+      name: shared_preferences_foundation
+      sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.4.0"
+  shared_preferences_linux:
+    dependency: transitive
+    description:
+      name: shared_preferences_linux
+      sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
+  shared_preferences_platform_interface:
+    dependency: transitive
+    description:
+      name: shared_preferences_platform_interface
+      sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
+  shared_preferences_web:
+    dependency: transitive
+    description:
+      name: shared_preferences_web
+      sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.0"
+  shared_preferences_windows:
+    dependency: transitive
+    description:
+      name: shared_preferences_windows
+      sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -405,6 +509,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.5.1"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.5.1"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.4"
 sdks:
-  dart: ">=3.3.4 <4.0.0"
+  dart: ">=3.4.0 <4.0.0"
   flutter: ">=3.19.0"
diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml
index b0409b2..9f1732c 100644
--- a/frontend/pubspec.yaml
+++ b/frontend/pubspec.yaml
@@ -39,6 +39,8 @@ dependencies:
   geocoding: ^3.0.0
   geocode: ^1.0.3
   google_maps_flutter: ^2.6.1
+  http: ^1.2.1
+  shared_preferences: ^2.2.3
 
 dev_dependencies:
   flutter_test:
diff --git a/frontend/test/widget_test.dart b/frontend/test/widget_test.dart
index 1eacbc4..143b24f 100644
--- a/frontend/test/widget_test.dart
+++ b/frontend/test/widget_test.dart
@@ -9,16 +9,15 @@ import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 
 // import 'package:fast_network_navigation/main.dart';
-import 'package:fast_network_navigation/modules/scaffold.dart';
+import 'package:fast_network_navigation/layout.dart';
 
 void main() {
   testWidgets('Counter increments smoke test', (WidgetTester tester) async {
     // Build our app and trigger a frame.
     await tester.pumpWidget(BasePage(title: "City Nav"));
 
-    // Verify that our counter starts at 0.
-    expect(find.text('0'), findsOneWidget);
-    expect(find.text('1'), findsNothing);
+    // Verfiy that the title is displayed
+    expect(find.text('City Nav'), findsOneWidget);
 
     // Tap the '+' icon and trigger a frame.
     await tester.tap(find.byIcon(Icons.add));
-- 
2.47.2