Compare commits
57 Commits
renovate/c
...
v0.0.17
Author | SHA1 | Date | |
---|---|---|---|
59f3f0d454 | |||
06dc0c7c3b | |||
d37fb09d62 | |||
88b825ea31 | |||
d323194ea7 | |||
ed60fcba06 | |||
eaa2334942 | |||
f71aab22dc | |||
1f7b006a64 | |||
e5ea6e64e7 | |||
9deb461925 | |||
7414f7109d | |||
94d12f2983 | |||
0e3f56a131 | |||
2f901e008e | |||
f45dccff97 | |||
da85b91975 | |||
156661bfba | |||
205ec37764 | |||
db821b4856 | |||
b63c50ebd0 | |||
d4066a1726 | |||
7617c5788c | |||
1ade92aed3 | |||
d1c53e08bb | |||
797db5c1da | |||
055089bf76 | |||
3475990e5f | |||
7cbf5a037c | |||
20f20da9c5 | |||
b11f082803 | |||
0ae20e4995 | |||
728b954643 | |||
83d83b03a9 | |||
87ef37f0a9 | |||
5912f562c3 | |||
eaecc27305 | |||
003b8d0f9c | |||
a1fcc8d23b | |||
da921171e9 | |||
d24bc2470b | |||
6d3399640e | |||
e951032f11 | |||
22ca038017 | |||
311b1c2218 | |||
bea3a65fec | |||
f71b9b19a6 | |||
89511f39cb | |||
71d9554d97 | |||
c87a01b2e8 | |||
5748630b99 | |||
016622c7af | |||
bf129b201d | |||
86bcec6b29 | |||
07dde5ab58 | |||
db82495f11 | |||
889b6c2096 |
24
.gitea/workflows/backend_build-deploy-prod.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
name: Build and deploy the backend to production
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build and push image
|
||||
uses: ./.gitea/workflows/workflow_build-image.yaml
|
||||
with:
|
||||
tag: stable
|
||||
secrets:
|
||||
PACKAGE_REGISTRY_ACCESS: ${{ secrets.PACKAGE_REGISTRY_ACCESS }}
|
||||
|
||||
deploy-prod:
|
||||
name: Deploy to production
|
||||
uses: ./.gitea/workflows/workflow_deploy-container.yaml
|
||||
with:
|
||||
overlay: prod
|
||||
secrets:
|
||||
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
||||
needs: build-and-push
|
26
.gitea/workflows/backend_build-deploy-stg.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- backend/**
|
||||
|
||||
name: Build and deploy the backend to staging
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build and push image
|
||||
uses: ./.gitea/workflows/workflow_build-image.yaml
|
||||
with:
|
||||
tag: unstable
|
||||
secrets:
|
||||
PACKAGE_REGISTRY_ACCESS: ${{ secrets.PACKAGE_REGISTRY_ACCESS }}
|
||||
|
||||
deploy-prod:
|
||||
name: Deploy to staging
|
||||
uses: ./.gitea/workflows/workflow_deploy-container.yaml
|
||||
with:
|
||||
overlay: stg
|
||||
secrets:
|
||||
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
||||
needs: build-and-push
|
@@ -43,8 +43,10 @@ jobs:
|
||||
working-directory: ./frontend
|
||||
|
||||
- name: Add required secrets
|
||||
env:
|
||||
ANDROID_SECRETS_PROPERTIES: ${{ secrets.ANDROID_SECRETS_PROPERTIES }}
|
||||
run: |
|
||||
echo ${{ secrets.ANDROID_SECRETS_PROPERTIES }} > ./android/secrets.properties
|
||||
echo "$ANDROID_SECRETS_PROPERTIES" >> ./android/secrets.properties
|
||||
working-directory: ./frontend
|
||||
|
||||
- name: Sanity check
|
||||
|
39
.gitea/workflows/frontend_trigger_deployment.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
push-to-remote:
|
||||
# We want to use the macos runner provided by github actions. This requires to push to a remote first.
|
||||
# After the push we can use the action under frontend/.github/actions/ to deploy properly using fastlane on macos.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'src'
|
||||
|
||||
- name: Checkout remote repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: 'dest'
|
||||
ref: 'main'
|
||||
github-server-url: 'https://github.com'
|
||||
repository: 'moll-re/anyway-frontend-builder'
|
||||
token: ${{ secrets.PUSH_GITHUB_API_TOKEN }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
|
||||
- name: Copy files to remote repository
|
||||
run: cp -r src/frontend/. dest/
|
||||
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
cd dest
|
||||
git config --global user.email "me@moll.re"
|
||||
git config --global user.name "[bot]"
|
||||
git add .
|
||||
git commit -m "Automatic code update for tag"
|
||||
git tag -a ${{ github.ref_name }} -m "mirrored tag"
|
||||
git push origin main --tags
|
@@ -1,12 +1,17 @@
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- backend/**
|
||||
workflow_call:
|
||||
inputs:
|
||||
tag:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
PACKAGE_REGISTRY_ACCESS:
|
||||
required: true
|
||||
|
||||
|
||||
name: Build and push docker image
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
@@ -29,5 +34,5 @@ jobs:
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: backend
|
||||
tags: git.kluster.moll.re/anydev/anyway-backend:latest
|
||||
tags: git.kluster.moll.re/anydev/anyway-backend:${{ inputs.tag }}
|
||||
push: true
|
35
.gitea/workflows/workflow_deploy-container.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
overlay:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
KUBE_CONFIG:
|
||||
required: true
|
||||
|
||||
|
||||
name: Deploy the newly built container
|
||||
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: https://gitea.com/actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: setup kubectl
|
||||
uses: https://github.com/azure/setup-kubectl@v4
|
||||
|
||||
- name: Set kubeconfig
|
||||
run: |
|
||||
echo "${{ secrets.KUBE_CONFIG }}" > kubeconfig
|
||||
|
||||
- name: Deploy to k8s
|
||||
run: |
|
||||
kubectl apply -k backend/deployment/overlays/${{ inputs.overlay }} --kubeconfig=kubeconfig
|
||||
kubectl -n anyway-backend rollout restart deployment/anyway-backend-${{ inputs.overlay }}
|
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "backend/deployment"]
|
||||
path = backend/deployment
|
||||
url = https://git.kluster.moll.re/anydev/anyway-backend-deployment
|
6
backend/.gitignore
vendored
@@ -1,6 +1,10 @@
|
||||
# osm-cache
|
||||
# osm-cache and wikidata cache
|
||||
cache/
|
||||
apicache/
|
||||
|
||||
# wikidata throttle
|
||||
*.ctrl
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
@@ -13,5 +13,6 @@ EXPOSE 8000
|
||||
# Set environment variables used by the deployment. These can be overridden by the user using this image.
|
||||
ENV NUM_WORKERS=1
|
||||
ENV OSM_CACHE_DIR=/cache
|
||||
ENV MEMCACHED_HOST_PATH=none
|
||||
|
||||
CMD fastapi run src/main.py --port 8000 --workers $NUM_WORKERS
|
||||
|
@@ -14,3 +14,4 @@ shapely = "*"
|
||||
scipy = "*"
|
||||
osmpythontools = "*"
|
||||
pywikibot = "*"
|
||||
pymemcache = "*"
|
||||
|
25
backend/Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "f0de801038593d42d8b780d14c2c72bb4f5f5e66df02f72244917ede5d5ebce6"
|
||||
"sha256": "4f8b3f0395b4e5352330616870da13acf41e16d1b69ba31b15fd688e90b8b628"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -1102,6 +1102,15 @@
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.18.0"
|
||||
},
|
||||
"pymemcache": {
|
||||
"hashes": [
|
||||
"sha256:27bf9bd1bbc1e20f83633208620d56de50f14185055e49504f4f5e94e94aff94",
|
||||
"sha256:f507bc20e0dc8d562f8df9d872107a278df049fa496805c1431b926f3ddd0eab"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad",
|
||||
@@ -1142,12 +1151,12 @@
|
||||
},
|
||||
"pywikibot": {
|
||||
"hashes": [
|
||||
"sha256:3f4fbc57f1765aa0fa1ccf84125bcfa475cae95b9cc0291867b751f3d4ac8fa2",
|
||||
"sha256:a26d918cf88ef56fdb1421b65b09def200cc28031cdc922d72a4198fbfddd225"
|
||||
"sha256:0dd8291f1a26abb9fce2c2108a90dc338274988e60d21723aec1d3b0de321b5e",
|
||||
"sha256:7953fc4a6c498057e6eb7d9b762bbccb61348af0a599b89d7e246d5175b20a9b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==9.2.1"
|
||||
"version": "==9.3.0"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
@@ -1349,7 +1358,7 @@
|
||||
"sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d",
|
||||
"sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"markers": "python_version < '3.13'",
|
||||
"version": "==4.12.2"
|
||||
},
|
||||
"tzdata": {
|
||||
@@ -1658,11 +1667,11 @@
|
||||
},
|
||||
"xarray": {
|
||||
"hashes": [
|
||||
"sha256:0b91e0bc4dc0296947947640fe31ec6e867ce258d2f7cbc10bedf4a6d68340c7",
|
||||
"sha256:721a7394e8ec3d592b2d8ebe21eed074ac077dc1bb1bd777ce00e41700b4866c"
|
||||
"sha256:1b0fd51ec408474aa1f4a355d75c00cc1c02bd425d97b2c2e551fd21810e7f64",
|
||||
"sha256:4cae512d121a8522d41e66d942fb06c526bc1fd32c2c181d5fe62fe65b671638"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==2024.6.0"
|
||||
"version": "==2024.7.0"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
|
@@ -9,8 +9,11 @@ This repository contains the backend code for the application. It utilizes FastA
|
||||
- Since the application is aimed to be deployed in a container, the `Dockerfile` is provided to build the image.
|
||||
|
||||
### Deployment
|
||||
To deploy the backend docker container, we use kubernetes. The deployment configuration is located under [https://git.kluster.moll.re/anydev/deployment-backend/](https://git.kluster.moll.re/anydev/deployment-backend/).
|
||||
To deploy the backend docker container, we use kubernetes. Modifications to the backend are automatically pushed to a two-stage environment through the CI pipeline. See [deployment/README](deployment/README.md] for further information.
|
||||
|
||||
The deployment configuration is included as a submodule in the `deployment` directory. The standalone repository is under [https://git.kluster.moll.re/anydev/anyway-backend-deployment/](https://git.kluster.moll.re/anydev/anyway-backend-deployment/).
|
||||
|
||||
|
||||
## Development
|
||||
TBD
|
||||
TBD
|
||||
|
||||
|
1
backend/deployment
Submodule
@@ -15,13 +15,21 @@ OSM_CACHE_DIR = Path(cache_dir_string)
|
||||
|
||||
|
||||
import logging
|
||||
import yaml
|
||||
|
||||
LOGGING_CONFIG = LOCATION_PREFIX / 'log_config.yaml'
|
||||
config = yaml.safe_load(LOGGING_CONFIG.read_text())
|
||||
|
||||
logging.config.dictConfig(config)
|
||||
|
||||
# if we are in a debug session, set the log level to debug
|
||||
# if we are in a debug session, set verbose and rich logging
|
||||
if os.getenv('DEBUG', False):
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
from rich.logging import RichHandler
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
handlers=[RichHandler()]
|
||||
)
|
||||
else:
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
)
|
||||
|
||||
|
||||
MEMCACHED_HOST_PATH = os.getenv('MEMCACHED_HOST_PATH', None)
|
||||
if MEMCACHED_HOST_PATH == "none":
|
||||
MEMCACHED_HOST_PATH = None
|
||||
|
@@ -1,34 +0,0 @@
|
||||
version: 1
|
||||
disable_existing_loggers: False
|
||||
formatters:
|
||||
simple:
|
||||
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
handlers:
|
||||
console:
|
||||
class: rich.logging.RichHandler
|
||||
formatter: simple
|
||||
# access:
|
||||
# class: logging.FileHandler
|
||||
# filename: logs/access.log
|
||||
# level: INFO
|
||||
# formatter: simple
|
||||
|
||||
|
||||
|
||||
|
||||
loggers:
|
||||
uvicorn.error:
|
||||
level: INFO
|
||||
handlers:
|
||||
- console
|
||||
propagate: no
|
||||
# uvicorn.access:
|
||||
# level: INFO
|
||||
# handlers:
|
||||
# - access
|
||||
# propagate: no
|
||||
root:
|
||||
level: INFO
|
||||
handlers:
|
||||
- console
|
||||
propagate: yes
|
@@ -1,12 +1,14 @@
|
||||
import logging
|
||||
from fastapi import FastAPI, Query, Body
|
||||
from fastapi import FastAPI, Query, Body, HTTPException
|
||||
|
||||
from structs.landmark import Landmark
|
||||
from structs.preferences import Preferences
|
||||
from structs.linked_landmarks import LinkedLandmarks
|
||||
from structs.trip import Trip
|
||||
from utils.landmarks_manager import LandmarkManager
|
||||
from utils.optimizer import Optimizer
|
||||
from utils.refiner import Refiner
|
||||
from persistence import client as cache_client
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -17,8 +19,8 @@ optimizer = Optimizer()
|
||||
refiner = Refiner(optimizer=optimizer)
|
||||
|
||||
|
||||
@app.post("/route/new")
|
||||
def get_route(preferences: Preferences, start: tuple[float, float], end: tuple[float, float] | None = None) -> str:
|
||||
@app.post("/trip/new")
|
||||
def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[float, float] | None = None) -> Trip:
|
||||
'''
|
||||
Main function to call the optimizer.
|
||||
:param preferences: the preferences specified by the user as the post body
|
||||
@@ -27,15 +29,17 @@ def get_route(preferences: Preferences, start: tuple[float, float], end: tuple[f
|
||||
:return: the uuid of the first landmark in the optimized route
|
||||
'''
|
||||
if preferences is None:
|
||||
raise ValueError("Please provide preferences in the form of a 'Preference' BaseModel class.")
|
||||
raise HTTPException(status_code=406, detail="Preferences not provided")
|
||||
if preferences.shopping.score == 0 and preferences.sightseeing.score == 0 and preferences.nature.score == 0:
|
||||
raise HTTPException(status_code=406, detail="All preferences are 0.")
|
||||
if start is None:
|
||||
raise ValueError("Please provide the starting coordinates as a tuple of floats.")
|
||||
raise HTTPException(status_code=406, detail="Start coordinates not provided")
|
||||
if end is None:
|
||||
end = start
|
||||
logger.info("No end coordinates provided. Using start=end.")
|
||||
|
||||
start_landmark = Landmark(name='start', type='start', location=(start[0], start[1]), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||
end_landmark = Landmark(name='end', type='finish', location=(end[0], end[1]), osm_type='end', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||
end_landmark = Landmark(name='finish', type='finish', location=(end[0], end[1]), osm_type='end', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||
|
||||
# Generate the landmarks from the start location
|
||||
landmarks, landmarks_short = manager.generate_landmarks_list(
|
||||
@@ -47,22 +51,37 @@ def get_route(preferences: Preferences, start: tuple[float, float], end: tuple[f
|
||||
landmarks_short.insert(0, start_landmark)
|
||||
landmarks_short.append(end_landmark)
|
||||
|
||||
# TODO infer these parameters from the preferences
|
||||
max_walking_time = 4 # hours
|
||||
detour = 30 # minutes
|
||||
|
||||
# First stage optimization
|
||||
base_tour = optimizer.solve_optimization(max_walking_time*60, landmarks_short)
|
||||
try:
|
||||
base_tour = optimizer.solve_optimization(preferences.max_time_minute, landmarks_short)
|
||||
except ArithmeticError:
|
||||
raise HTTPException(status_code=500, detail="No solution found")
|
||||
except TimeoutError:
|
||||
raise HTTPException(status_code=500, detail="Optimzation took too long")
|
||||
|
||||
# Second stage optimization
|
||||
refined_tour = refiner.refine_optimization(landmarks, base_tour, max_walking_time*60, detour)
|
||||
refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute)
|
||||
|
||||
linked_tour = LinkedLandmarks(refined_tour)
|
||||
return linked_tour[0].uuid
|
||||
# upon creation of the trip, persistence of both the trip and its landmarks is ensured. Ca
|
||||
trip = Trip.from_linked_landmarks(linked_tour, cache_client)
|
||||
return trip
|
||||
|
||||
|
||||
#### For already existing trips/landmarks
|
||||
@app.get("/trip/{trip_uuid}")
|
||||
def get_trip(trip_uuid: str) -> Trip:
|
||||
try:
|
||||
trip = cache_client.get(f"trip_{trip_uuid}")
|
||||
return trip
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="Trip not found")
|
||||
|
||||
|
||||
@app.get("/landmark/{landmark_uuid}")
|
||||
def get_landmark(landmark_uuid: str) -> Landmark:
|
||||
#cherche dans linked_tour et retourne le landmark correspondant
|
||||
pass
|
||||
try:
|
||||
landmark = cache_client.get(f"landmark_{landmark_uuid}")
|
||||
return landmark
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="Landmark not found")
|
@@ -1,6 +1,11 @@
|
||||
city_bbox_side: 5000 #m
|
||||
city_bbox_side: 7500 #m
|
||||
radius_close_to: 50
|
||||
church_coeff: 0.8
|
||||
park_coeff: 1.2
|
||||
tag_coeff: 10
|
||||
church_coeff: 0.75
|
||||
nature_coeff: 1.25
|
||||
overall_coeff: 10
|
||||
tag_exponent: 1.15
|
||||
image_bonus: 10
|
||||
viewpoint_bonus: 15
|
||||
wikipedia_bonus: 6
|
||||
N_important: 40
|
||||
pay_bonus: -1
|
||||
|
@@ -1,4 +1,6 @@
|
||||
detour_factor: 1.4
|
||||
detour_corridor_width: 200
|
||||
detour_corridor_width: 300
|
||||
average_walking_speed: 4.8
|
||||
max_landmarks: 7
|
||||
max_landmarks: 10
|
||||
max_landmarks_refiner: 30
|
||||
overshoot: 1.8
|
||||
|
28
backend/src/persistence.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from pymemcache.client.base import Client
|
||||
from pymemcache import serde
|
||||
|
||||
import constants
|
||||
|
||||
|
||||
class DummyClient:
|
||||
_data = {}
|
||||
def set(self, key, value, **kwargs):
|
||||
self._data[key] = value
|
||||
|
||||
def set_many(self, data, **kwargs):
|
||||
self._data.update(data)
|
||||
|
||||
def get(self, key, **kwargs):
|
||||
return self._data[key]
|
||||
|
||||
|
||||
if constants.MEMCACHED_HOST_PATH is None:
|
||||
client = DummyClient()
|
||||
else:
|
||||
client = Client(
|
||||
constants.MEMCACHED_HOST_PATH,
|
||||
timeout=1,
|
||||
allow_unicode_keys=True,
|
||||
encoding='utf-8',
|
||||
serde=serde.pickle_serde
|
||||
)
|
@@ -15,8 +15,11 @@ class Landmark(BaseModel) :
|
||||
attractiveness : int
|
||||
n_tags : int
|
||||
image_url : Optional[str] = None # TODO future
|
||||
website_url : Optional[str] = None
|
||||
wikipedia_url : Optional[str] = None
|
||||
description : Optional[str] = None # TODO future
|
||||
duration : Optional[int] = 0 # TODO future
|
||||
name_en : Optional[str] = None
|
||||
|
||||
# Unique ID of a given landmark
|
||||
uuid: str = Field(default_factory=uuid4) # TODO implement this ASAP
|
||||
@@ -34,5 +37,8 @@ class Landmark(BaseModel) :
|
||||
|
||||
def __str__(self) -> str:
|
||||
time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else ""
|
||||
return f'Landmark({self.type}): [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}]'
|
||||
is_secondary_str = f", secondary" if self.is_secondary else ""
|
||||
type_str = '(' + self.type + ')'
|
||||
if self.type in ["start", "finish", "nature", "shopping"] : type_str += '\t '
|
||||
return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]'
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import uuid
|
||||
from .landmark import Landmark
|
||||
from utils.get_time_separation import get_time
|
||||
|
||||
@@ -9,8 +8,7 @@ class LinkedLandmarks:
|
||||
"""
|
||||
|
||||
_landmarks = list[Landmark]
|
||||
total_time = int
|
||||
uuid = str
|
||||
total_time: int = 0
|
||||
|
||||
def __init__(self, data: list[Landmark] = None) -> None:
|
||||
"""
|
||||
@@ -19,7 +17,6 @@ class LinkedLandmarks:
|
||||
Args:
|
||||
data (list[Landmark], optional): The list of landmarks that are linked together. Defaults to None.
|
||||
"""
|
||||
self.uuid = uuid.uuid4()
|
||||
self._landmarks = data if data else []
|
||||
self._link_landmarks()
|
||||
|
||||
@@ -28,7 +25,11 @@ class LinkedLandmarks:
|
||||
"""
|
||||
Create the links between the landmarks in the list by setting their .next_uuid and the .time_to_next attributes.
|
||||
"""
|
||||
self.total_time = 0
|
||||
|
||||
# Mark secondary landmarks as such
|
||||
self.update_secondary_landmarks()
|
||||
|
||||
|
||||
for i, landmark in enumerate(self._landmarks[:-1]):
|
||||
landmark.next_uuid = self._landmarks[i + 1].uuid
|
||||
time_to_next = get_time(landmark.location, self._landmarks[i + 1].location)
|
||||
@@ -38,24 +39,26 @@ class LinkedLandmarks:
|
||||
self._landmarks[-1].next_uuid = None
|
||||
self._landmarks[-1].time_to_reach_next = 0
|
||||
|
||||
def update_secondary_landmarks(self) -> None:
|
||||
# Extract the attractiveness scores and sort them in descending order
|
||||
scores = sorted([landmark.attractiveness for landmark in self._landmarks], reverse=True)
|
||||
|
||||
# Determine the 10th highest score
|
||||
if len(scores) >= 10:
|
||||
threshold_score = scores[9]
|
||||
else:
|
||||
# If there are fewer than 10 landmarks, use the lowest score in the list as the threshold
|
||||
threshold_score = min(scores) if scores else 0
|
||||
|
||||
# Update 'is_secondary' for landmarks with attractiveness below the threshold score
|
||||
for landmark in self._landmarks:
|
||||
if landmark.attractiveness < threshold_score and landmark.type not in ["start", "finish"]:
|
||||
landmark.is_secondary = True
|
||||
|
||||
|
||||
def __getitem__(self, index: int) -> Landmark:
|
||||
return self._landmarks[index]
|
||||
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"LinkedLandmarks, total time: {self.total_time} minutes, {len(self._landmarks)} stops: [{','.join([str(landmark) for landmark in self._landmarks])}]"
|
||||
|
||||
|
||||
def asdict(self) -> dict:
|
||||
"""
|
||||
Convert the linked landmarks to a json serializable dictionary.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary representation of the linked landmarks.
|
||||
"""
|
||||
return {
|
||||
'uuid': self.uuid,
|
||||
'total_time': self.total_time,
|
||||
'landmarks': [landmark.dict() for landmark in self._landmarks]
|
||||
}
|
||||
return f"LinkedLandmarks [{' ->'.join([str(landmark) for landmark in self._landmarks])}]"
|
||||
|
@@ -2,7 +2,6 @@ from pydantic import BaseModel
|
||||
from typing import Optional, Literal
|
||||
|
||||
class Preference(BaseModel) :
|
||||
name: str
|
||||
type: Literal['sightseeing', 'nature', 'shopping', 'start', 'finish']
|
||||
score: int # score could be from 1 to 5
|
||||
|
||||
@@ -17,5 +16,5 @@ class Preferences(BaseModel) :
|
||||
# Shopping (diriger plutôt vers des zones / rues commerçantes)
|
||||
shopping : Preference
|
||||
|
||||
max_time_minute: Optional[int] = 6*60
|
||||
max_time_minute: Optional[int] = 6*60
|
||||
detour_tolerance_minute: Optional[int] = 0
|
||||
|
30
backend/src/structs/trip.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pymemcache.client.base import Client
|
||||
|
||||
from .linked_landmarks import LinkedLandmarks
|
||||
import uuid
|
||||
|
||||
class Trip(BaseModel):
|
||||
uuid: str = Field(default_factory=uuid.uuid4)
|
||||
total_time: int
|
||||
first_landmark_uuid: str
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_linked_landmarks(self, landmarks: LinkedLandmarks, cache_client: Client) -> "Trip":
|
||||
"""
|
||||
Initialize a new Trip object and ensure it is stored in the cache.
|
||||
"""
|
||||
trip = Trip(
|
||||
total_time = landmarks.total_time,
|
||||
first_landmark_uuid = str(landmarks[0].uuid)
|
||||
)
|
||||
|
||||
# Store the trip in the cache
|
||||
cache_client.set(f"trip_{trip.uuid}", trip)
|
||||
cache_client.set_many({f"landmark_{landmark.uuid}": landmark for landmark in landmarks}, expire=3600)
|
||||
# is equivalent to:
|
||||
# for landmark in landmarks:
|
||||
# cache_client.set(f"landmark_{landmark.uuid}", landmark, expire=3600)
|
||||
|
||||
return trip
|
@@ -20,22 +20,12 @@ def test(start_coords: tuple[float, float], finish_coords: tuple[float, float] =
|
||||
|
||||
|
||||
preferences = Preferences(
|
||||
sightseeing=Preference(
|
||||
name='sightseeing',
|
||||
type='sightseeing',
|
||||
score = 5),
|
||||
nature=Preference(
|
||||
name='nature',
|
||||
type='nature',
|
||||
score = 5),
|
||||
shopping=Preference(
|
||||
name='shopping',
|
||||
type='shopping',
|
||||
score = 5),
|
||||
|
||||
max_time_minute=180,
|
||||
detour_tolerance_minute=30
|
||||
)
|
||||
sightseeing=Preference(type='sightseeing', score = 5),
|
||||
nature=Preference(type='nature', score = 5),
|
||||
shopping=Preference(type='shopping', score = 5),
|
||||
max_time_minute=100,
|
||||
detour_tolerance_minute=0
|
||||
)
|
||||
|
||||
# Create start and finish
|
||||
if finish_coords is None :
|
||||
@@ -69,7 +59,11 @@ def test(start_coords: tuple[float, float], finish_coords: tuple[float, float] =
|
||||
refined_tour = refiner.refine_optimization(all_landmarks=landmarks, base_tour=base_tour, max_time = preferences.max_time_minute, detour = preferences.detour_tolerance_minute)
|
||||
|
||||
linked_tour = LinkedLandmarks(refined_tour)
|
||||
logger.info(f"Optimized route: {linked_tour}")
|
||||
total_time = 0
|
||||
logger.info("Optimized route : ")
|
||||
for l in linked_tour :
|
||||
logger.info(f"{l}")
|
||||
logger.info(f"Estimated length of tour : {linked_tour.total_time} mintutes and visiting {len(linked_tour._landmarks)} landmarks.")
|
||||
|
||||
# with open('linked_tour.yaml', 'w') as f:
|
||||
# yaml.dump(linked_tour.asdict(), f)
|
||||
@@ -77,9 +71,9 @@ def test(start_coords: tuple[float, float], finish_coords: tuple[float, float] =
|
||||
return linked_tour
|
||||
|
||||
|
||||
#test(tuple((48.8344400, 2.3220540))) # Café Chez César
|
||||
#test(tuple((48.8375946, 2.2949904))) # Point random
|
||||
#test(tuple((47.377859, 8.540585))) # Zurich HB
|
||||
#test(tuple((45.7576485, 4.8330241))) # Lyon Bellecour
|
||||
# test(tuple((48.8344400, 2.3220540))) # Café Chez César
|
||||
# test(tuple((48.8375946, 2.2949904))) # Point random
|
||||
# test(tuple((47.377859, 8.540585))) # Zurich HB
|
||||
# test(tuple((45.758217, 4.831814))) # Lyon Bellecour
|
||||
test(tuple((48.5848435, 7.7332974))) # Strasbourg Gare
|
||||
#test(tuple((48.2067858, 16.3692340))) # Vienne
|
||||
# test(tuple((48.2067858, 16.3692340))) # Vienne
|
||||
|
@@ -15,21 +15,16 @@ from .take_most_important import take_most_important
|
||||
import constants
|
||||
|
||||
|
||||
SIGHTSEEING = 'sightseeing'
|
||||
NATURE = 'nature'
|
||||
SHOPPING = 'shopping'
|
||||
|
||||
|
||||
|
||||
class LandmarkManager:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
city_bbox_side: int # bbox side in meters
|
||||
radius_close_to: int # radius in meters
|
||||
church_coeff: float # coeff to adjsut score of churches
|
||||
park_coeff: float # coeff to adjust score of parks
|
||||
tag_coeff: float # coeff to adjust weight of tags
|
||||
nature_coeff: float # coeff to adjust score of parks
|
||||
overall_coeff: float # coeff to adjust weight of tags
|
||||
N_important: int # number of important landmarks to consider
|
||||
|
||||
|
||||
@@ -40,12 +35,22 @@ class LandmarkManager:
|
||||
|
||||
with constants.LANDMARK_PARAMETERS_PATH.open('r') as f:
|
||||
parameters = yaml.safe_load(f)
|
||||
self.city_bbox_side = parameters['city_bbox_side']
|
||||
self.max_bbox_side = parameters['city_bbox_side']
|
||||
self.radius_close_to = parameters['radius_close_to']
|
||||
self.church_coeff = parameters['church_coeff']
|
||||
self.park_coeff = parameters['park_coeff']
|
||||
self.tag_coeff = parameters['tag_coeff']
|
||||
self.nature_coeff = parameters['nature_coeff']
|
||||
self.overall_coeff = parameters['overall_coeff']
|
||||
self.tag_exponent = parameters['tag_exponent']
|
||||
self.image_bonus = parameters['image_bonus']
|
||||
self.wikipedia_bonus = parameters['wikipedia_bonus']
|
||||
self.viewpoint_bonus = parameters['viewpoint_bonus']
|
||||
self.pay_bonus = parameters['pay_bonus']
|
||||
self.N_important = parameters['N_important']
|
||||
|
||||
with constants.OPTIMIZER_PARAMETERS_PATH.open('r') as f:
|
||||
parameters = yaml.safe_load(f)
|
||||
self.walking_speed = parameters['average_walking_speed']
|
||||
self.detour_factor = parameters['detour_factor']
|
||||
|
||||
self.overpass = Overpass()
|
||||
CachingStrategy.use(JSON, cacheDir=constants.OSM_CACHE_DIR)
|
||||
@@ -69,30 +74,33 @@ class LandmarkManager:
|
||||
- A list of the most important landmarks based on the user's preferences.
|
||||
"""
|
||||
|
||||
max_walk_dist = (preferences.max_time_minute/2)/60*self.walking_speed*1000/self.detour_factor
|
||||
reachable_bbox_side = min(max_walk_dist, self.max_bbox_side)
|
||||
|
||||
L = []
|
||||
bbox = self.create_bbox(center_coordinates)
|
||||
bbox = self.create_bbox(center_coordinates, reachable_bbox_side)
|
||||
# list for sightseeing
|
||||
if preferences.sightseeing.score != 0:
|
||||
score_function = lambda loc, n_tags: int((self.count_elements_close_to(loc) + ((n_tags**1.2)*self.tag_coeff) )*self.church_coeff)
|
||||
L1 = self.fetch_landmarks(bbox, self.amenity_selectors['sightseeing'], SIGHTSEEING, score_function)
|
||||
self.correct_score(L1, preferences.sightseeing)
|
||||
score_function = lambda score: int(score*10*preferences.sightseeing.score/5) # self.count_elements_close_to(loc) +
|
||||
L1 = self.fetch_landmarks(bbox, self.amenity_selectors['sightseeing'], preferences.sightseeing.type, score_function)
|
||||
L += L1
|
||||
|
||||
# list for nature
|
||||
if preferences.nature.score != 0:
|
||||
score_function = lambda loc, n_tags: int((self.count_elements_close_to(loc) + ((n_tags**1.2)*self.tag_coeff) )*self.park_coeff)
|
||||
L2 = self.fetch_landmarks(bbox, self.amenity_selectors['nature'], NATURE, score_function)
|
||||
self.correct_score(L2, preferences.nature)
|
||||
score_function = lambda score: int(score*10*self.nature_coeff*preferences.nature.score/5) # self.count_elements_close_to(loc) +
|
||||
L2 = self.fetch_landmarks(bbox, self.amenity_selectors['nature'], preferences.nature.type, score_function)
|
||||
L += L2
|
||||
|
||||
# list for shopping
|
||||
if preferences.shopping.score != 0:
|
||||
score_function = lambda loc, n_tags: int(self.count_elements_close_to(loc) + ((n_tags**1.2)*self.tag_coeff))
|
||||
L3 = self.fetch_landmarks(bbox, self.amenity_selectors['shopping'], SHOPPING, score_function)
|
||||
self.correct_score(L3, preferences.shopping)
|
||||
score_function = lambda score: int(score*10*preferences.shopping.score/5) # self.count_elements_close_to(loc) +
|
||||
L3 = self.fetch_landmarks(bbox, self.amenity_selectors['shopping'], preferences.shopping.type, score_function)
|
||||
L += L3
|
||||
|
||||
|
||||
L = self.remove_duplicates(L)
|
||||
# self.correct_score(L, preferences)
|
||||
|
||||
L_constrained = take_most_important(L, self.N_important)
|
||||
self.logger.info(f'Generated {len(L)} landmarks around {center_coordinates}, and constrained to {len(L_constrained)} most important ones.')
|
||||
|
||||
@@ -123,7 +131,7 @@ class LandmarkManager:
|
||||
return L_clean
|
||||
|
||||
|
||||
def correct_score(self, landmarks: list[Landmark], preference: Preference):
|
||||
def correct_score(self, landmarks: list[Landmark], preferences: Preferences) -> None:
|
||||
"""
|
||||
Adjust the attractiveness score of each landmark in the list based on user preferences.
|
||||
|
||||
@@ -132,20 +140,16 @@ class LandmarkManager:
|
||||
|
||||
Args:
|
||||
landmarks (list[Landmark]): A list of landmarks whose scores need to be corrected.
|
||||
preference (Preference): The user's preference settings that influence the attractiveness score adjustment.
|
||||
|
||||
Raises:
|
||||
TypeError: If the type of any landmark in the list does not match the expected type in the preference.
|
||||
preferences (Preferences): The user's preference settings that influence the attractiveness score adjustment.
|
||||
"""
|
||||
|
||||
if len(landmarks) == 0:
|
||||
return
|
||||
|
||||
if landmarks[0].type != preference.type:
|
||||
raise TypeError(f"LandmarkType {preference.type} does not match the type of Landmark {landmarks[0].name}")
|
||||
|
||||
for elem in landmarks:
|
||||
elem.attractiveness = int(elem.attractiveness*preference.score/5) # arbitrary computation
|
||||
score_dict = {
|
||||
preferences.sightseeing.type: preferences.sightseeing.score,
|
||||
preferences.nature.type: preferences.nature.score,
|
||||
preferences.shopping.type: preferences.shopping.score
|
||||
}
|
||||
for landmark in landmarks:
|
||||
landmark.attractiveness = int(landmark.attractiveness * score_dict[landmark.type] / 5)
|
||||
|
||||
|
||||
def count_elements_close_to(self, coordinates: tuple[float, float]) -> int:
|
||||
@@ -191,12 +195,13 @@ class LandmarkManager:
|
||||
return 0
|
||||
|
||||
|
||||
def create_bbox(self, coordinates: tuple[float, float]) -> tuple[float, float, float, float]:
|
||||
def create_bbox(self, coordinates: tuple[float, float], reachable_bbox_side: int) -> tuple[float, float, float, float]:
|
||||
"""
|
||||
Create a bounding box around the given coordinates.
|
||||
|
||||
Args:
|
||||
coordinates (tuple[float, float]): The latitude and longitude of the center of the bounding box.
|
||||
reachable_bbox_side (int): The side length of the bounding box in meters.
|
||||
|
||||
Returns:
|
||||
tuple[float, float, float, float]: The minimum latitude, minimum longitude, maximum latitude, and maximum longitude
|
||||
@@ -207,7 +212,7 @@ class LandmarkManager:
|
||||
lon = coordinates[1]
|
||||
|
||||
# Half the side length in km (since it's a square bbox)
|
||||
half_side_length_km = self.city_bbox_side / 2 / 1000
|
||||
half_side_length_km = reachable_bbox_side / 2 / 1000
|
||||
|
||||
# Convert distance to degrees
|
||||
lat_diff = half_side_length_km / 111 # 1 degree latitude is approximately 111 km
|
||||
@@ -273,8 +278,8 @@ class LandmarkManager:
|
||||
continue
|
||||
|
||||
# skip if unused
|
||||
if 'disused:leisure' in elem.tags().keys():
|
||||
continue
|
||||
# if 'disused:leisure' in elem.tags().keys():
|
||||
# continue
|
||||
|
||||
# skip if part of another building
|
||||
if 'building:part' in elem.tags().keys() and elem.tag('building:part') == 'yes':
|
||||
@@ -284,33 +289,45 @@ class LandmarkManager:
|
||||
osm_id = elem.id() # Add OSM id
|
||||
elem_type = landmarktype # Add the landmark type as 'sightseeing,
|
||||
n_tags = len(elem.tags().keys()) # Add number of tags
|
||||
score = n_tags**self.tag_exponent # Add score
|
||||
website_url = None
|
||||
wikpedia_url = None
|
||||
image_url = None
|
||||
name_en = None
|
||||
|
||||
# remove specific tags
|
||||
skip = False
|
||||
for tag in elem.tags().keys():
|
||||
if "pay" in tag:
|
||||
n_tags -= 1 # discard payment options for tags
|
||||
score += self.pay_bonus # discard payment options for tags
|
||||
|
||||
if "disused" in tag:
|
||||
skip = True # skip disused amenities
|
||||
break
|
||||
|
||||
if "wikipedia" in tag:
|
||||
n_tags += 3 # wikipedia entries count more
|
||||
if "wiki" in tag:
|
||||
score += self.wikipedia_bonus # wikipedia entries count more
|
||||
|
||||
# if tag == "wikidata":
|
||||
# Q = elem.tag('wikidata')
|
||||
# site = Site("wikidata", "wikidata")
|
||||
# item = ItemPage(site, Q)
|
||||
# item.get()
|
||||
# n_languages = len(item.labels)
|
||||
# n_tags += n_languages/10
|
||||
|
||||
if tag == "wikidata":
|
||||
Q = elem.tag('wikidata')
|
||||
site = Site("wikidata", "wikidata")
|
||||
item = ItemPage(site, Q)
|
||||
item.get()
|
||||
n_languages = len(item.labels)
|
||||
n_tags += n_languages/10
|
||||
if "viewpoint" in tag:
|
||||
score += self.viewpoint_bonus
|
||||
duration = 10
|
||||
|
||||
if "image" in tag:
|
||||
score += self.image_bonus
|
||||
|
||||
if elem_type != "nature":
|
||||
if "leisure" in tag and elem.tag('leisure') == "park":
|
||||
elem_type = "nature"
|
||||
|
||||
if landmarktype != SHOPPING:
|
||||
if landmarktype != "shopping":
|
||||
if "shop" in tag:
|
||||
skip = True
|
||||
break
|
||||
@@ -318,24 +335,49 @@ class LandmarkManager:
|
||||
if tag == "building" and elem.tag('building') in ['retail', 'supermarket', 'parking']:
|
||||
skip = True
|
||||
break
|
||||
|
||||
# Get additional information
|
||||
# if tag == 'wikipedia' :
|
||||
# wikpedia_url = elem.tag('wikipedia')
|
||||
if tag in ['website', 'contact:website'] :
|
||||
website_url = elem.tag(tag)
|
||||
if tag == 'image' :
|
||||
image_url = elem.tag('image')
|
||||
if tag =='name:en' :
|
||||
name_en = elem.tag('name:en')
|
||||
|
||||
if skip:
|
||||
continue
|
||||
|
||||
score = score_function(location, n_tags)
|
||||
if score != 0:
|
||||
# Generate the landmark and append it to the list
|
||||
landmark = Landmark(
|
||||
name=name,
|
||||
type=elem_type,
|
||||
location=location,
|
||||
osm_type=osm_type,
|
||||
osm_id=osm_id,
|
||||
attractiveness=score,
|
||||
must_do=False,
|
||||
n_tags=int(n_tags)
|
||||
)
|
||||
return_list.append(landmark)
|
||||
score = score_function(score)
|
||||
if "place_of_worship" in elem.tags().values() :
|
||||
score = int(score*self.church_coeff)
|
||||
duration = 15
|
||||
|
||||
elif "museum" in elem.tags().values() :
|
||||
score = int(score*self.church_coeff)
|
||||
duration = 60
|
||||
|
||||
else :
|
||||
duration = 5
|
||||
|
||||
# Generate the landmark and append it to the list
|
||||
landmark = Landmark(
|
||||
name=name,
|
||||
type=elem_type,
|
||||
location=location,
|
||||
osm_type=osm_type,
|
||||
osm_id=osm_id,
|
||||
attractiveness=score,
|
||||
must_do=False,
|
||||
n_tags=int(n_tags),
|
||||
duration = duration,
|
||||
name_en=name_en,
|
||||
image_url=image_url,
|
||||
# wikipedia_url=wikpedia_url,
|
||||
website_url=website_url
|
||||
)
|
||||
return_list.append(landmark)
|
||||
|
||||
self.logger.debug(f"Fetched {len(return_list)} landmarks of type {landmarktype} in {bbox}")
|
||||
|
||||
|
@@ -17,10 +17,11 @@ class Optimizer:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
detour: int = None # accepted max detour time (in minutes)
|
||||
detour_factor: float # detour factor of straight line vs real distance in cities
|
||||
average_walking_speed: float # average walking speed of adult
|
||||
max_landmarks: int # max number of landmarks to visit
|
||||
detour: int = None # accepted max detour time (in minutes)
|
||||
detour_factor: float # detour factor of straight line vs real distance in cities
|
||||
average_walking_speed: float # average walking speed of adult
|
||||
max_landmarks: int # max number of landmarks to visit
|
||||
overshoot: float # overshoot to allow maxtime to overflow. Optimizer is a bit restrictive
|
||||
|
||||
|
||||
def __init__(self) :
|
||||
@@ -31,6 +32,7 @@ class Optimizer:
|
||||
self.detour_factor = parameters['detour_factor']
|
||||
self.average_walking_speed = parameters['average_walking_speed']
|
||||
self.max_landmarks = parameters['max_landmarks']
|
||||
self.overshoot = parameters['overshoot']
|
||||
|
||||
|
||||
|
||||
@@ -167,7 +169,7 @@ class Optimizer:
|
||||
|
||||
|
||||
|
||||
def init_ub_dist(self, landmarks: list[Landmark], max_steps: int):
|
||||
def init_ub_dist(self, landmarks: list[Landmark], max_time: int):
|
||||
"""
|
||||
Initialize the objective function coefficients and inequality constraints for the optimization problem.
|
||||
|
||||
@@ -176,7 +178,7 @@ class Optimizer:
|
||||
|
||||
Args:
|
||||
landmarks (list[Landmark]): List of landmarks.
|
||||
max_steps (int): Maximum number of steps allowed.
|
||||
max_time (int): Maximum time of visit allowed.
|
||||
|
||||
Returns:
|
||||
Tuple[list[float], list[float], list[int]]: Objective function coefficients, inequality constraint coefficients, and the right-hand side of the inequality constraint.
|
||||
@@ -191,19 +193,19 @@ class Optimizer:
|
||||
dist_table = [0]*len(landmarks)
|
||||
c.append(-spot1.attractiveness)
|
||||
for j, spot2 in enumerate(landmarks) :
|
||||
t = get_time(spot1.location, spot2.location)
|
||||
t = get_time(spot1.location, spot2.location) + spot1.duration
|
||||
dist_table[j] = t
|
||||
closest = sorted(dist_table)[:22]
|
||||
closest = sorted(dist_table)[:25]
|
||||
for i, dist in enumerate(dist_table) :
|
||||
if dist not in closest :
|
||||
dist_table[i] = 32700
|
||||
A_ub += dist_table
|
||||
c = c*len(landmarks)
|
||||
|
||||
return c, A_ub, [max_steps]
|
||||
return c, A_ub, [max_time*self.overshoot]
|
||||
|
||||
|
||||
def respect_number(self, L: int):
|
||||
def respect_number(self, L, max_landmarks: int):
|
||||
"""
|
||||
Generate constraints to ensure each landmark is visited only once and cap the total number of visited landmarks.
|
||||
|
||||
@@ -224,7 +226,7 @@ class Optimizer:
|
||||
b.append(1)
|
||||
|
||||
A = np.vstack((A, ones*L))
|
||||
b.append(self.max_landmarks+1)
|
||||
b.append(max_landmarks+1)
|
||||
|
||||
return A, b
|
||||
|
||||
@@ -433,6 +435,7 @@ class Optimizer:
|
||||
self,
|
||||
max_time: int,
|
||||
landmarks: list[Landmark],
|
||||
max_landmarks: int = None
|
||||
) -> list[Landmark]:
|
||||
"""
|
||||
Main optimization pipeline to solve the landmark visiting problem.
|
||||
@@ -443,15 +446,18 @@ class Optimizer:
|
||||
Args:
|
||||
max_time (int): Maximum time allowed for the tour in minutes.
|
||||
landmarks (list[Landmark]): List of landmarks to visit.
|
||||
max_landmarks (int): Maximum number of landmarks visited
|
||||
Returns:
|
||||
list[Landmark]: The optimized tour of landmarks with updated travel times, or None if no valid solution is found.
|
||||
"""
|
||||
if max_landmarks is None :
|
||||
max_landmarks = self.max_landmarks
|
||||
|
||||
L = len(landmarks)
|
||||
|
||||
# SET CONSTRAINTS FOR INEQUALITY
|
||||
c, A_ub, b_ub = self.init_ub_dist(landmarks, max_time) # Add the distances from each landmark to the other
|
||||
A, b = self.respect_number(L) # Respect max number of visits (no more possible stops than landmarks).
|
||||
A, b = self.respect_number(L, max_landmarks) # Respect max number of visits (no more possible stops than landmarks).
|
||||
A_ub = np.vstack((A_ub, A), dtype=np.int16)
|
||||
b_ub += b
|
||||
A, b = self.break_sym(L) # break the 'zig-zag' symmetry
|
||||
@@ -470,7 +476,7 @@ class Optimizer:
|
||||
A, b = self.respect_start_finish(L) # Force start and finish positions
|
||||
A_eq = np.vstack((A_eq, A), dtype=np.int8)
|
||||
b_eq += b
|
||||
A, b = self.respect_order(L) # Respect order of visit (only works when max_steps is limiting factor)
|
||||
A, b = self.respect_order(L) # Respect order of visit (only works when max_time is limiting factor)
|
||||
A_eq = np.vstack((A_eq, A), dtype=np.int8)
|
||||
b_eq += b
|
||||
|
||||
|
@@ -17,7 +17,7 @@ class Refiner :
|
||||
detour_factor: float # detour factor of straight line vs real distance in cities
|
||||
detour_corridor_width: float # width of the corridor around the path
|
||||
average_walking_speed: float # average walking speed of adult
|
||||
max_landmarks: int # max number of landmarks to visit
|
||||
max_landmarks_refiner: int # max number of landmarks to visit
|
||||
optimizer: Optimizer # optimizer object
|
||||
|
||||
def __init__(self, optimizer: Optimizer) :
|
||||
@@ -29,7 +29,7 @@ class Refiner :
|
||||
self.detour_factor = parameters['detour_factor']
|
||||
self.detour_corridor_width = parameters['detour_corridor_width']
|
||||
self.average_walking_speed = parameters['average_walking_speed']
|
||||
self.max_landmarks = parameters['max_landmarks'] + 4
|
||||
self.max_landmarks_refiner = parameters['max_landmarks_refiner']
|
||||
|
||||
|
||||
def create_corridor(self, landmarks: list[Landmark], width: float) :
|
||||
@@ -214,7 +214,7 @@ class Refiner :
|
||||
if self.is_in_area(area, landmark.location) and landmark.name not in visited_names:
|
||||
second_order_landmarks.append(landmark)
|
||||
|
||||
return take_most_important.take_most_important(second_order_landmarks, len(visited_landmarks))
|
||||
return take_most_important.take_most_important(second_order_landmarks, int(self.max_landmarks_refiner*0.75))
|
||||
|
||||
|
||||
# Try fix the shortest path using shapely
|
||||
@@ -308,8 +308,8 @@ class Refiner :
|
||||
"""
|
||||
|
||||
# No need to refine if no detour is taken
|
||||
if detour == 0:
|
||||
return base_tour
|
||||
# if detour == 0:
|
||||
# return base_tour
|
||||
|
||||
minor_landmarks = self.get_minor_landmarks(all_landmarks, base_tour, self.detour_corridor_width)
|
||||
|
||||
@@ -322,7 +322,8 @@ class Refiner :
|
||||
# get a new tour
|
||||
new_tour = self.optimizer.solve_optimization(
|
||||
max_time = max_time + detour,
|
||||
landmarks = full_set
|
||||
landmarks = full_set,
|
||||
max_landmarks = self.max_landmarks_refiner
|
||||
)
|
||||
|
||||
if new_tour is None:
|
||||
|
50
frontend/.github/workflows/build_app_android.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up ruby env
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.2.1
|
||||
bundler-cache: true
|
||||
|
||||
- name: Setup java for android build
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Setup android SDK
|
||||
uses: android-actions/setup-android@v3
|
||||
|
||||
- name: Infer version number from git tag
|
||||
id: version
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run:
|
||||
# remove the 'v' prefix from the tag name
|
||||
echo "VERSION=${REF_NAME//v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Load secrets from github
|
||||
run: |
|
||||
echo "${{ secrets.ANDROID_SECRET_PROPERTIES }}" > secrets.properties
|
||||
echo "${{ secrets.ANDROID_KEYSTORE }}" > release.keystore
|
||||
echo "${{ secrets.ANDROID_GOOGLE_PLAY_JSON }}" > google-key.json
|
||||
working-directory: android
|
||||
|
||||
- name: Install fastlane
|
||||
run: bundle install
|
||||
working-directory: android
|
||||
|
||||
- name: Run fastlane lane
|
||||
run: bundle exec fastlane deploy_release
|
||||
working-directory: android
|
||||
env:
|
||||
VERSION_NAME: ${{ steps.version.VERSION }}
|
@@ -1,6 +1,6 @@
|
||||
# Frontend
|
||||
|
||||
This is the frontend of the project. It is a Flutter application that is designed to run on both Android and iOS devices. The frontend is responsible for displaying the user interface and handling user input. It communicates with the backend to retrieve and send data.
|
||||
The frontend of this project is a Flutter application designed to run on both Android and iOS devices (and possibly as a PWA). The frontend is responsible for displaying the user interface and handling user input. It communicates with the backend via a REST-api to retrieve and send data.
|
||||
|
||||
|
||||
## Getting Started
|
||||
@@ -15,3 +15,43 @@ Once you have the Flutter SDK installed, you can locally install the dependencie
|
||||
```bash
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
## Development
|
||||
### ...
|
||||
### Icons and logos
|
||||
The application uses a custom launcher icon and splash screen. These are managed platform-independently using the `flutter_launcher_icons` package.
|
||||
|
||||
To update the icons, change the `flutter_launcher_icons.yaml` configuration file. Especially the `image_path` is relevant. Then run
|
||||
```bash
|
||||
dart run flutter_launcher_icons
|
||||
```
|
||||
|
||||
### Deploying a new version
|
||||
To truly deploy a new version of the application, i.e. to the official app stores, a special CI step is required. This listens for new tags. To create a new tag position yourself on the main branch and run
|
||||
```bash
|
||||
git tag -a v<name> -m "Release <name>"
|
||||
git push origin v<name>
|
||||
```
|
||||
We adhere to the [Semantic Versioning](https://semver.org/) standard, so the tag should be of the form `v0.1.8` for example.
|
||||
|
||||
|
||||
## Fastlane - in depth
|
||||
The application is deployed to the Google Play Store and the Apple App Store using fastlane: [https://docs.fastlane.tools/](https://docs.fastlane.tools/)
|
||||
|
||||
Fastlane is installed as a Ruby gem. Since the bundler-gemfile is scoped to a single directory, a `Gemfile` is included in both the `android` and `ios` directories. Once installed, the usage is
|
||||
```bash
|
||||
cd frontend/android # or ios
|
||||
bundle install
|
||||
bundle exec fastlane <lane>
|
||||
```
|
||||
This is reused in the CI/CD pipeline to automate the deployment process.
|
||||
|
||||
Fastlane assumes mutliple secrets to be present as files in the platform directories. These are:
|
||||
- for android:
|
||||
- `secrets.properties` used by gradle to load secrets needed at execution time
|
||||
- `release.keystore` used by gradle to sign the apk
|
||||
- `google-key.json` used by fastlane to authenticate with the Google Play Store
|
||||
- for ios:
|
||||
- TODO
|
||||
|
||||
These files are stored as secrets in the GitHub repository so that the CI pipeline can access them.
|
6
frontend/android/.gitignore
vendored
@@ -1,8 +1,5 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
/secrets.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
@@ -12,3 +9,6 @@ GeneratedPluginRegistrant.java
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
|
||||
# Fastlane google cloud access
|
||||
google-key.json
|
||||
|
3
frontend/android/Gemfile
Normal file
@@ -0,0 +1,3 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
220
frontend/android/Gemfile.lock
Normal file
@@ -0,0 +1,220 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.7)
|
||||
base64
|
||||
nkf
|
||||
rexml
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.970.0)
|
||||
aws-sdk-core (3.202.2)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.88.0)
|
||||
aws-sdk-core (~> 3, >= 3.201.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.159.0)
|
||||
aws-sdk-core (~> 3, >= 3.201.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.9.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
base64 (0.2.0)
|
||||
claide (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.6.5)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.6.20240107)
|
||||
dotenv (2.8.1)
|
||||
emoji_regex (3.2.3)
|
||||
excon (0.111.0)
|
||||
faraday (1.10.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0)
|
||||
faraday-multipart (~> 1.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.0)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
faraday-retry (~> 1.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-multipart (1.0.4)
|
||||
multipart-post (~> 2)
|
||||
faraday-net_http (1.0.2)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.3.1)
|
||||
fastlane (2.222.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored (~> 1.2)
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-env (>= 1.6.0, < 2.0.0)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
http-cookie (~> 1.0.5)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (>= 0.1.1, < 1.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.5)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (~> 3)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.3)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
google-apis-iamcredentials_v1 (0.17.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.13.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.31.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-cloud-core (1.7.1)
|
||||
google-cloud-env (>= 1.0, < 3.a)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.4.0)
|
||||
google-cloud-storage (1.47.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.31.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.8.1)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.7)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.2)
|
||||
json (2.7.2)
|
||||
jwt (2.8.2)
|
||||
base64
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
nkf (0.2.0)
|
||||
optparse (0.5.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.1)
|
||||
public_suffix (6.0.1)
|
||||
rake (13.2.1)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.3.6)
|
||||
strscan
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.5)
|
||||
signet (0.19.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
strscan (3.1.0)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.2)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unicode-display_width (2.5.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.25.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (>= 3.3.2, < 4.0)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.18
|
@@ -2,13 +2,12 @@
|
||||
|
||||
### Keystore setup
|
||||
```bash
|
||||
keytool -genkey -v -keystore release.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias release
|
||||
keytool -genkey -v -keystore release.keystore -keyalg RSA -keysize 2048 -validity 10000 -alias upload
|
||||
```
|
||||
- This is required to store local credentials securely (not used for now).
|
||||
- But necesseary in order to restrict the particular api key to a particular app (through the sha1 of the associated keystore).
|
||||
- This is required to store local credentials securely and more importantly to sign the app for google play store distribution.
|
||||
|
||||
|
||||
### Building and secret credentials
|
||||
### Using secret credentials during build
|
||||
Following the guide under [https://developers.google.com/maps/flutter-package/config#android_1](https://developers.google.com/maps/flutter-package/config#android_1).
|
||||
- Add the following to `android/build.gradle`:
|
||||
```gradle
|
||||
@@ -36,13 +35,39 @@ Following the guide under [https://developers.google.com/maps/flutter-package/co
|
||||
android:value="${MAPS_API_KEY}" />
|
||||
```
|
||||
|
||||
### Signing the app
|
||||
Compared to the flutter template application, a few changes have to be made:
|
||||
- Added to `android/app/build.gradle`:
|
||||
```gradle
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias = secretProperties['keyAlias']
|
||||
keyPassword = secretProperties['keyPassword']
|
||||
storeFile = secretProperties['storeFile'] ? file(secretProperties['storeFile']) : null
|
||||
storePassword = secretProperties['storePassword']
|
||||
}
|
||||
}
|
||||
```
|
||||
- Changed the `buildTypes` to use the `release` signing config:
|
||||
```gradle
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
```
|
||||
This makes use of the `secretProperties` defined previously:
|
||||
```gradle
|
||||
secretPropertiesFile.withReader('UTF-8') { reader ->
|
||||
secretProperties.load(reader)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Using the credentials in CI
|
||||
- Add the base64 encoded credentials to the repository secrets (e.g. `ANDROID_SECRETS`).
|
||||
- Add the secret files to the repository secrets (e.g. `ANDROID_SECRETS_PROPERTIES`).
|
||||
|
||||
- temporarily write them back to files during the CI execution:
|
||||
```bash
|
||||
base64 -i android/secrets.properties
|
||||
echo {{ secrets.ANDROID_SECRETS }} >> android/secrets.properties
|
||||
```
|
||||
- Use the following in the CI script:
|
||||
```bash
|
||||
echo {{ secrets.ANDROID_SECRETS }} | base64 -d > android/secrets.properties
|
||||
```
|
@@ -42,7 +42,7 @@ if (secretPropertiesFile.exists()) {
|
||||
|
||||
|
||||
android {
|
||||
namespace "com.example.fast_network_navigation"
|
||||
namespace "com.anydev.anyway"
|
||||
compileSdk flutter.compileSdkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
@@ -61,7 +61,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.example.fast_network_navigation"
|
||||
applicationId "com.anydev.anyway"
|
||||
// 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
|
||||
@@ -76,11 +76,18 @@ android {
|
||||
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias = secretProperties['keyAlias']
|
||||
keyPassword = secretProperties['keyPassword']
|
||||
storeFile = secretProperties['storeFile'] ? file(secretProperties['storeFile']) : null
|
||||
storePassword = secretProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
signingConfig = signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,12 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Required to fetch data from the internet. -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<!-- Required to show user location -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:label="fast_network_navigation"
|
||||
android:label="anyway"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.example.fast_network_navigation
|
||||
package com.anydev.anyway
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 13 KiB |
2
frontend/android/fastlane/Appfile
Normal file
@@ -0,0 +1,2 @@
|
||||
json_key_file("google-key.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
|
||||
package_name("com.anydev.anyway") # e.g. com.krausefx.app
|
41
frontend/android/fastlane/Fastfile
Normal file
@@ -0,0 +1,41 @@
|
||||
# Uncomment the line if you want fastlane to automatically update itself
|
||||
# update_fastlane
|
||||
|
||||
default_platform(:android)
|
||||
|
||||
platform :android do
|
||||
# desc "Runs all the tests"
|
||||
# lane :test do
|
||||
# gradle(task: "test")
|
||||
# end
|
||||
|
||||
desc "Deploy a new version as a preview version"
|
||||
lane :deploy_testing do
|
||||
gradle(
|
||||
task: "bundle",
|
||||
# flavor: "staging",
|
||||
)
|
||||
|
||||
upload_to_play_store(
|
||||
track: 'alpha',
|
||||
skip_upload_apk: true,
|
||||
skip_upload_changelogs: true,
|
||||
)
|
||||
end
|
||||
|
||||
desc "Deploy a new version as a full release"
|
||||
lane :deploy_release do
|
||||
gradle(
|
||||
task: "clean assembleRelease",
|
||||
properties: {
|
||||
# loaded from environment
|
||||
"android.injected.version.name" => ENV["VERSION_NAME"],
|
||||
}
|
||||
)
|
||||
upload_to_play_store(
|
||||
track: "production",
|
||||
skip_upload_apk: true,
|
||||
skip_upload_changelogs: true,
|
||||
)
|
||||
end
|
||||
end
|
40
frontend/android/fastlane/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
fastlane documentation
|
||||
----
|
||||
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```sh
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
|
||||
|
||||
# Available Actions
|
||||
|
||||
## Android
|
||||
|
||||
### android deploy_testing
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android deploy_testing
|
||||
```
|
||||
|
||||
Deploy a new version as a preview version
|
||||
|
||||
### android deploy_release
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android deploy_release
|
||||
```
|
||||
|
||||
Deploy a new version as a full release
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||
|
||||
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
|
||||
|
||||
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
@@ -0,0 +1,7 @@
|
||||
AnyWay - plan city trips your way
|
||||
|
||||
AnyWay is a mobile application that helps users plan city trips. The app allows users to specify their preferences and constraints, and then generates a personalized itinerary for them. The planning follows some guiding principles:
|
||||
- **Personalization**:The user's preferences should be reflected in the choice of destinations.
|
||||
- **Efficiency**:The itinerary should be optimized for the user's constraints.
|
||||
- **Flexibility**: We aknowledge that tourism is a dynamic activity, and that users may want to change their plans on the go.
|
||||
- **Discoverability**: Tourism is an inherently exploratory activity. Once a rough itinerary is generated, detours and spontaneous decisions should be encouraged.
|
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 637 KiB |
After Width: | Height: | Size: 573 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 360 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 637 KiB |
After Width: | Height: | Size: 573 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 360 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 637 KiB |
After Width: | Height: | Size: 573 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 360 KiB |
@@ -0,0 +1 @@
|
||||
AnyWay - plan city trips your way!
|
@@ -0,0 +1 @@
|
||||
AnyWay
|
BIN
frontend/android/gradle/wrapper/gradle-wrapper.jar
vendored
Executable file
160
frontend/android/gradlew
vendored
Executable file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
frontend/android/gradlew.bat
vendored
Executable file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@@ -20,7 +20,7 @@ pluginManagement {
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "7.3.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
107
frontend/assets/cat.svg
Normal file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
|
||||
<g id="OBJECTS">
|
||||
<g>
|
||||
<path style="fill:#F2DBDE;" d="M381.005,363.01c-53.963,8.445-84.441,11.1-138.832,6.101
|
||||
c-54.388-4.998-109.48-25.844-144.743-67.555c-23.468-27.759-36.728-62.943-43.732-98.613c-3.745-19.07-5.754-39.21,0.433-57.635
|
||||
c7.513-22.378,26.565-39.569,48.136-49.156c21.572-9.589,45.552-12.365,69.151-12.944c47.753-1.172,95.706,6.26,140.863,21.831
|
||||
c35.603,12.277,69.954,29.937,96.972,56.171c27.019,26.233,46.213,61.723,47.963,99.341
|
||||
C458.967,298.17,438.434,354.022,381.005,363.01z"/>
|
||||
<g>
|
||||
<path style="fill:#F2BFC6;" d="M314.479,248.209c-22.398,36.41-29.246,81.831-19.597,123.401
|
||||
c27.302-0.242,52.026-3.263,86.124-8.6c57.429-8.989,77.961-64.84,76.211-102.458c-1.503-32.308-15.881-63.041-37.024-87.694
|
||||
C375.546,184.337,337.241,211.21,314.479,248.209z"/>
|
||||
<path style="fill:#F2BFC6;" d="M60.074,229.111c2.232,7.566,4.802,15.029,7.749,22.32c40.138-5.931,78.066-26.379,104.834-56.907
|
||||
c26.459-30.176,41.716-69.876,42.677-109.969c-14.6-1.246-29.267-1.705-43.916-1.345c-11.908,0.292-23.911,1.147-35.655,3.151
|
||||
C136.569,142.478,107.155,198.423,60.074,229.111z"/>
|
||||
<path style="fill:#F2BFC6;" d="M365.131,128.557c-16.748-9.529-34.631-17.233-52.85-23.516
|
||||
c-6.45-2.224-12.962-4.262-19.517-6.153c-1.712,23.304-4.543,46.555-11.914,68.659c-9.236,27.692-26.464,53.808-52.01,67.931
|
||||
c-22.973,12.7-50.376,14.689-74.443,25.169c-21.624,9.417-39.587,25.305-54.36,43.893c8.346,9.381,17.714,17.663,27.862,24.902
|
||||
c16.736-21.461,41.874-37.166,67.161-48.559c35.578-16.03,74.129-26.682,105.739-49.566
|
||||
C334.357,207.023,357.577,169.22,365.131,128.557z"/>
|
||||
</g>
|
||||
</g>
|
||||
<ellipse style="opacity:0.15;fill:#2D3038;" cx="250.223" cy="394.224" rx="109.236" ry="18.917"/>
|
||||
<g>
|
||||
<path style="fill:#2D3038;" d="M305.132,388.442c-0.168,1.158-0.626,2.243-1.458,3.061c-1.863,1.832-4.823,1.724-7.427,1.538
|
||||
c-17.939-1.285-36.017-0.625-53.815,1.965c-7.053,3.155-16.423,3.233-25.275,2.004c-8.853-1.231-17.514-3.684-26.397-4.661
|
||||
c-8.885-0.976-21.867-0.33-26.499,2.758c0,0-7.266,3.996-12.907,12.021c-3.367,4.789-4.105,11.306-2.377,16.899
|
||||
c2.452,7.945,10.312,13.334,18.475,14.912c8.163,1.579,16.603-0.053,24.6-2.327c22.82-6.49,43.805-18.134,66.018-26.468
|
||||
c22.213-8.334,47.017-13.282,69.546-5.844c3.96,1.306,7.879,3.033,10.941,5.866c3.062,2.832,5.173,6.927,4.813,11.081
|
||||
c-0.464,5.356-4.97,9.719-10.061,11.444c-5.092,1.726-10.658,1.275-15.953,0.346c-5.296-0.93-10.554-2.17-15.926-2.414
|
||||
c-20.08-0.909-38.455,4.247-56.124,10.857c-17.669,6.608-35.096,14.21-53.56,18.085c-18.463,3.874-35.807,8.106-51.682-4.186
|
||||
c-20.345-15.753-19.603-41.137-8.091-63.296c5.521-10.629,12.589-18.637,19.416-27.732c-1.72-12.542-6.898-24.945-9.467-37.525
|
||||
c-4.135-20.25-1.309-41.854,7.666-61.314c5.614-15.439,11.257-30.942,19.093-45.38c7.835-14.438,18.007-27.88,31.297-37.536
|
||||
c13.289-9.656,29.927-15.279,46.993-13.222c7.787-8.403,16.038-16.377,24.703-23.871c-1.319-7.29-1.183-14.637,0.584-20.961
|
||||
c-4.077-8.872-8.2-17.907-9.54-27.579c-0.835-6.027-0.441-12.408,1.577-17.991c1.878-5.198,8.452-6.799,12.542-3.08
|
||||
c6.673,6.07,12.683,12.869,17.891,20.235c18.398-4.802,38.164-4.231,56.264,1.583c6.473-8.017,14.398-14.861,23.286-20.075
|
||||
c2.366-1.388,5.533-2.613,7.657-0.875c1.683,1.377,1.736,3.89,1.592,6.059c-0.815,12.217-3.418,24.313-8.016,36.577
|
||||
c4.862,15.779,0.82,33.862-9.812,46.412c-2.168,11.956,1.193,24.438,2.504,36.665c2.294,21.385-1.98,43.411-12.271,62.744
|
||||
c-2.4,4.508-5.754,8.444-9.863,11.477c-1.71,1.263-3.38,2.581-5.006,3.951c-5.172,20.881-10.139,41.311-15.351,62.281
|
||||
c2.061,7.78,4.487,15.496,7.272,23.126c3.209-0.899,6.478-1.696,9.816-1.809c3.896-0.132,7.942,0.744,11.024,3.131
|
||||
c2.308,1.785,3.979,4.375,4.658,7.212c0.484,2.028,0.445,4.26-0.563,6.086c-0.663,1.203-1.81,2.171-3.102,2.583
|
||||
c0.454,1.78,0.565,3.616,0.106,5.385c-0.778,3.004-3.622,5.6-6.675,5.375c-0.047,0.112-0.097,0.223-0.151,0.333
|
||||
c-0.979,1.985-3.08,3.228-5.239,3.714c-2.063,0.464-4.207,0.333-6.319,0.174c-0.138,0.225-0.3,0.437-0.489,0.633
|
||||
c-1.556,1.603-4.16,1.338-6.346,0.87c-3.015-0.645-6.04-1.471-8.688-3.051c-2.647-1.583-4.906-4.013-5.707-6.991
|
||||
c-1.237-4.607,2.111-10.097,0.151-14.313c-3.538-7.609-7.733-14.893-12.004-22.126c-8.712,7.077-18.162,13.242-28.147,18.367
|
||||
c6.95-0.974,14.248-1.345,21.476-0.293c3.273,0.475,6.596,1.283,9.285,3.208c2.689,1.924,4.631,5.173,4.214,8.453
|
||||
c-0.34,2.664-2.596,5.054-5.156,5.449"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M151.465,379.089
|
||||
c0.578-3.877,0.614-7.729,0.28-11.566"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M296.431,98.602
|
||||
c1.739,2.591,3.381,5.247,4.918,7.962"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M273.736,153.553
|
||||
c-0.645-1.929-1.188-3.891-1.625-5.865"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M295.23,106.811
|
||||
c-4.87-7.904-10.55-15.309-16.923-22.061c-1.834-1.943-4.156-3.987-6.799-3.598c-2.928,0.431-4.574,3.626-5.147,6.53
|
||||
c-1.629,8.254,1.474,16.627,4.521,24.47"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M352.846,98.327
|
||||
c1.084,0.372,2.162,0.763,3.232,1.174"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M363.545,168.179
|
||||
c-1.077,1.107-2.211,2.161-3.399,3.155"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M295.583,130.136
|
||||
c3.86-4.907,10.772-7.181,16.791-5.521c6.019,1.659,10.791,7.151,11.446,13.054c-4.594,3.601-11.6,3.717-16.311,0.268
|
||||
c-3.162-2.315-5.105-6.101-5.423-9.993"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M363.109,126.785
|
||||
c-1.79-2.631-5.159-4.002-8.321-3.646c-3.162,0.356-6.042,2.317-7.787,4.979c-1.743,2.662-2.395,5.96-1.828,9.854
|
||||
c4.738,1.952,10.727,0.164,13.621-4.066c1.462-2.137,2.057-4.785,1.832-7.36"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M350.957,171.048
|
||||
c-4.278,4.378-10.749,6.497-16.787,5.499"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M338.68,282.717
|
||||
c-5.42,4.867-10.31,10.327-14.541,16.258"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M333.834,368.351
|
||||
c0.757,2.017,1.54,4.028,2.348,6.032c2.26-0.589,4.541-1.183,6.876-1.268c2.333-0.084,4.757,0.381,6.656,1.74
|
||||
c1.559,1.116,2.664,2.753,3.552,4.452c0.261,0.499,0.505,1.013,0.727,1.536"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M317.138,283.315
|
||||
c0.476,18.805,3.038,37.553,7.633,55.961"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M337.823,376.837
|
||||
c2.877-0.595,5.878,0.99,7.67,3.316c1.791,2.327,2.567,5.273,3.025,8.174c0.191,1.214,0.327,2.48,0.209,3.695"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M327.236,380.633
|
||||
c3.086-0.38,6.102,1.606,7.733,4.252c1.632,2.645,2.112,5.835,2.285,8.939c0.04,0.721,0.054,1.476-0.027,2.204"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M305.059,385.808
|
||||
c-0.036-0.193-0.079-0.385-0.128-0.573c-1.058-4.111-4.728-7.422-8.927-8.052"/>
|
||||
<g>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M250.442,264.812
|
||||
c-1.67-3.125-3.183-6.325-4.488-9.622c-5.098-12.883-6.92-27.047-5.248-40.801"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M302.266,351.248
|
||||
c-7.667-12.944-15.022-25.405-19.496-39.762"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M272.435,372.065
|
||||
c-3.368,0.554-6.637,1.226-9.757,1.918c10.852-22.715,21.971-46.794,19.913-71.883c-0.826-10.055-4.036-20.316-11.156-27.463
|
||||
c-8.522-8.553-21.576-11.406-33.547-9.827c-22.022,2.903-41.327,20.57-46.167,42.248"/>
|
||||
</g>
|
||||
<g>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M328.579,152.076
|
||||
c1.379-0.341,2.796,0.501,3.736,1.565c0.942,1.065,1.588,2.366,2.551,3.41c0.963,1.044,2.43,1.826,3.784,1.398
|
||||
c1.002-0.317,1.702-1.217,2.207-2.139c0.504-0.921,0.888-1.923,1.572-2.721c1.237-1.447,3.432-1.978,5.192-1.258"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M360.735,158.173
|
||||
c-2.16,5.007-7.325,8.57-12.773,8.812c-1.946,0.086-3.967-0.245-5.593-1.317c-1.872-1.234-2.979-3.253-3.85-5.361
|
||||
c-0.089,1.146-0.496,2.29-1.133,3.25c-1.229,1.854-3.175,3.116-5.189,4.059c-3.3,1.546-7.007,2.373-10.616,1.879
|
||||
c-3.611-0.495-7.099-2.413-9.07-5.477"/>
|
||||
<path style="fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" d="M338.276,158.534
|
||||
c0,0,0.176,1.073,0.244,1.773"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.5 KiB |
273
frontend/assets/city.svg
Normal file
@@ -0,0 +1,273 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1000 700" style="enable-background:new 0 0 1000 700;" xml:space="preserve">
|
||||
<g id="Shadow">
|
||||
<g style="opacity:0.1;">
|
||||
<path style="fill:#38415C;" d="M186.919,556.734c0,0.331,0.541,0.599,1.208,0.599c0.667,0,1.208-0.268,1.208-0.599
|
||||
c0-0.331-0.541-0.599-1.208-0.599C187.46,556.135,186.919,556.403,186.919,556.734z"/>
|
||||
<path style="fill:#38415C;" d="M957.699,446.328h-12.196h-37.267h-8.131h-4.525h-22.106h-29.729h-8.01h-8.921h-7.462H777.69h-5.38
|
||||
h-8.517h-13.921h-24.898h-0.367h-35.201h-33.29h-13.405h-8.642h-18.387h-20.084H584.19h-2.542h-5.421h-37.944h-7.453h-2.757
|
||||
h-2.757h-1.428h-8.748h-5.514h-10.175h-0.905h-4.609h-10.175h-5.514h-10.175h-2.757h-2.757h-27.938h-8.05h-29.96h-6.713h-18.964
|
||||
h-11.234h-48.644h-12.099h-10.229h-20.764h-12.382h-3.512h-23.242h-5.943h-13.266h-10.795h-35.413h-16.467h-4.656h-8.696h-25.877
|
||||
H89.054h-4.763H72.026h-7.508H53.821H42.302v9.376h11.519v6.41h10.696v6.835h19.774v2.177h20.658v9.405h17.084v-5.919h11.557
|
||||
v10.475h3.789v11.69h11.18v9.823h-4.017v1.763h7.066v4.785h23.433v28.254h-1.845v1.897h4.028v2.429h4.636v0.913v2.777v2.41h5.594
|
||||
v4.306h0.673l0,0h0.673v-4.306h3.015l1.823-2.41h12.206v-3.69h31.948V543.3h4.028v-1.897h-1.845V484.37h15.302v40.617h1.509v3.023
|
||||
h2.811v10.012h1.016v-10.012h2.287v7.997h1.017v-7.997h4.828v-3.023h6.098v-10.569h11.445v-0.743h-1.492v-2.116h7.56v32.974
|
||||
h-1.078v0.849h7.678v5.101h-0.992v0.817h7.047v2.933h-1.099v0.627h3.502v2.77h3.348v5.513h0.402h0.398h0.314v-5.513h1.354v9.889
|
||||
h0.402h0.399h0.314v-9.889h0.451h2.897v-2.77h3.034v-0.627h-0.632v-2.933h7.047v-0.817h-0.992v-5.101h7.678v-0.849h-1.078v-43.096
|
||||
h23.505v-5.982h8.399v31.88h-4.954v0.806h4.954v1.443h6.279v2.37h30.344v27.318h7.165v21.803h13.871V593h1.952v-11.927h4.298
|
||||
v9.528h1.952v-9.528h21.941v-12.964h3.982v-8.839h11.148v-32.999h4.318v-7.629l6.342,0.769v1.742h5.514v-1.073l10.175,1.234v1.969
|
||||
h5.514v-1.3l9.332,1.131v9.523h2.491v16.539h11.982v6.297h6.46v5.29h2.267v9.068h0.586v-9.068h2.267v-5.29h6.46v-6.297h12.075
|
||||
v-16.539h2.399v-45.67l5.467,13.925h5.729v12.219h-2.645v0.527h31.278v6.75h-3.52v0.763h-1.791v2.08h8.284v2.313h-1.087v0.668
|
||||
h18.198v-0.668h-1.087v-2.313h23.966c0.802,1.935,2.023,3.811,3.668,5.596l-3.992,0.913c-0.688-0.732-2.184-1.239-3.92-1.239
|
||||
c-2.388,0-4.324,0.96-4.324,2.143c0,1.183,1.936,2.143,4.324,2.143c2.388,0,4.324-0.96,4.324-2.143
|
||||
c0-0.239-0.08-0.468-0.225-0.683l4.015-0.919c2.595,2.749,6.165,5.281,10.623,7.491c0.352,0.174,0.709,0.346,1.069,0.515
|
||||
l-3.154,1.668c-0.76-0.329-1.753-0.528-2.841-0.528c-2.388,0-4.324,0.959-4.324,2.143s1.936,2.143,4.324,2.143
|
||||
c2.388,0,4.324-0.959,4.324-2.143c0-0.559-0.432-1.068-1.139-1.449l3.16-1.671c5.36,2.471,11.576,4.337,18.308,5.527l-1.744,2.453
|
||||
c-0.378-0.054-0.777-0.083-1.19-0.083c-2.388,0-4.324,0.96-4.324,2.143c0,1.183,1.936,2.143,4.324,2.143
|
||||
c2.388,0,4.324-0.96,4.324-2.143c0-0.895-1.107-1.662-2.68-1.982l1.743-2.451c5.551,0.953,11.445,1.449,17.493,1.449
|
||||
c0.498,0,0.995-0.003,1.491-0.01l0.198,3.017c-2.096,0.148-3.707,1.041-3.707,2.121c0,1.183,1.936,2.143,4.324,2.143
|
||||
c2.388,0,4.324-0.96,4.324-2.143c0-1.184-1.936-2.143-4.324-2.143c-0.046,0-0.091,0.001-0.137,0.002l-0.197-3.004
|
||||
c2.456-0.044,4.881-0.173,7.265-0.378l-2.223,24.735l79.948-8.225v-43.336h13.883v22.309h24.985v8.902h1.355v-8.902h2.795v16.446
|
||||
h1.355v-16.446h3.219v11.855h1.355v-11.855h4.235v-54.059h12.874V506.6h2.033v3.715h2.033v2.582h14.483v-2.582h2.033V506.6h7.369
|
||||
v1.594h3.557V506.6h1.259v4.262h5.082V506.6h1.452l3.161-11.593h11.528v5.526h0.762v-5.526h4.32v6.746h0.762v-6.746h6.25v-1.567
|
||||
h-1.592v-17.317h12.874l1.507-4.997h10.931v-9.012h11.954v-6.86h12.196V446.328z M653.829,518.335l-11.117,0.179v-7.937h2.055
|
||||
v-0.76h-2.055v-0.593l13.295,2.426c-1.417,1.94-2.19,4.031-2.19,6.21C653.816,518.019,653.821,518.177,653.829,518.335z
|
||||
M689.289,499.58c-4.354,0.083-8.516,0.542-12.36,1.312l-5.314-6.414v-0.42h5.082v4.786h5.082v-4.786h7.148L689.289,499.58z
|
||||
M702.329,517.554l-8.713,0.14c-0.026-0.114-0.079-0.224-0.155-0.328l9.073-2.076L702.329,517.554z M666.025,494.058v0.401
|
||||
c-0.325,0.085-0.657,0.163-0.979,0.251l-0.713-0.651H666.025z M666.025,495.263v0.341l-0.291-0.266
|
||||
C665.83,495.311,665.929,495.289,666.025,495.263z M666.025,496.603v2.241h2.454l3.554,3.247c-2.98,0.871-5.693,1.943-8.062,3.179
|
||||
l-10.904-5.064c0.33-0.173,0.666-0.344,1.007-0.513c3.276-1.624,6.914-3.003,10.823-4.12L666.025,496.603z M672.377,502.405
|
||||
l15.07,13.768l-22.95-10.659C666.813,504.306,669.465,503.258,672.377,502.405z M669.572,498.844h2.043v-3.739l4.87,5.877
|
||||
c-1.242,0.259-2.449,0.55-3.618,0.872L669.572,498.844z M691.664,494.058v4.786h12.332l-1.224,1.721
|
||||
c-3.776-0.648-7.828-1.001-12.044-1.001c-0.32,0-0.64,0.002-0.959,0.006l-0.361-5.512H691.664z M703.939,499.641l-0.101,1.127
|
||||
c-0.206-0.039-0.404-0.087-0.612-0.124L703.939,499.641z M702.896,511.25l-8.307,4.394l8.619-7.874L702.896,511.25z
|
||||
M702.863,511.616l-0.306,3.407l-9.299,2.127c-0.053-0.046-0.11-0.09-0.172-0.133l0.598-0.547L702.863,511.616z M693.364,518.468
|
||||
l8.74,1.595l-0.252,2.801l-8.846-4.108C693.147,518.667,693.268,518.571,693.364,518.468z M693.53,518.245
|
||||
c0.056-0.1,0.091-0.205,0.102-0.312l8.676-0.14l-0.182,2.021L693.53,518.245z M656.116,486.551l-11.415-10.428h11.415V486.551z
|
||||
M656.116,487.55v4.746h-1.779v1.763h8.903l0.969,0.885c-4.029,1.15-7.778,2.571-11.154,4.243
|
||||
c-0.352,0.175-0.698,0.352-1.039,0.53l-3.311-1.538c0.63-0.372,1.01-0.852,1.01-1.376c0-1.184-1.936-2.143-4.324-2.143
|
||||
c-1.018,0-1.941,0.182-2.68,0.473v-5.035h2.055v-0.76h-2.055v-9.479h2.055v-0.76h-2.055v-2.977h0.897L656.116,487.55z
|
||||
M642.711,500.338h2.055v-0.76h-2.055v-1.104c0.739,0.292,1.662,0.473,2.68,0.473c1.158,0,2.209-0.226,2.985-0.593l3.31,1.537
|
||||
c-3.677,1.959-6.684,4.15-8.975,6.503V500.338z M642.711,508.163c2.337-2.844,5.703-5.479,10.027-7.784l10.906,5.065
|
||||
c-3.215,1.722-5.771,3.749-7.47,5.983l-13.463-2.457V508.163z M664.17,505.688l24.004,11.148l0.198,0.181
|
||||
c-0.107,0.074-0.2,0.152-0.279,0.235l-31.242-5.701C658.515,509.362,661.02,507.375,664.17,505.688z M673.21,502.168
|
||||
c1.146-0.316,2.33-0.602,3.548-0.855l12.647,15.264c-0.111,0.028-0.218,0.06-0.32,0.094L673.21,502.168z M677.203,501.222
|
||||
c3.766-0.755,7.844-1.204,12.11-1.286l1.082,16.492c-0.187,0.011-0.369,0.03-0.544,0.057L677.203,501.222z M689.793,499.928
|
||||
c0.311-0.004,0.623-0.006,0.935-0.006c4.131,0,8.103,0.346,11.804,0.981l-11.067,15.563c-0.19-0.025-0.388-0.04-0.591-0.045
|
||||
L689.793,499.928z M702.985,500.982c0.278,0.05,0.543,0.112,0.818,0.165l-0.497,5.535l-10.935,9.99
|
||||
c-0.142-0.048-0.294-0.09-0.453-0.126L702.985,500.982z M692.678,518.929l9.146,4.247l-0.629,7.002l-9.143-11.035
|
||||
C692.279,519.085,692.49,519.013,692.678,518.929z M656.683,511.774l31.244,5.702c-0.056,0.1-0.091,0.204-0.102,0.312
|
||||
l-33.276,0.536c-0.008-0.154-0.012-0.309-0.012-0.464C654.537,515.724,655.295,513.675,656.683,511.774z M687.841,518.026
|
||||
c0.026,0.114,0.079,0.224,0.155,0.328l-30.225,6.916c-1.892-2.059-3.018-4.325-3.204-6.708L687.841,518.026z M688.199,518.57
|
||||
c0.106,0.092,0.231,0.178,0.373,0.257l-22.753,12.035c-3.243-1.527-5.915-3.348-7.845-5.376L688.199,518.57z M688.923,518.989
|
||||
c0.188,0.074,0.394,0.137,0.616,0.186l-11.067,15.563c-4.604-0.824-8.776-2.098-12.301-3.714L688.923,518.989z M689.992,519.254
|
||||
c0.19,0.024,0.388,0.04,0.591,0.045l1.082,16.493c-0.311,0.004-0.623,0.006-0.936,0.006c-4.131,0-8.102-0.346-11.804-0.98
|
||||
L689.992,519.254z M691.063,519.291c0.187-0.011,0.369-0.03,0.544-0.057l9.537,11.51l-0.39,4.342
|
||||
c-2.753,0.394-5.632,0.641-8.61,0.697L691.063,519.291z M640.035,523.229h7.987v-2.08h-1.791v-0.763h-3.52v-1.635l11.136-0.179
|
||||
c0.189,2.432,1.339,4.745,3.27,6.846l-13.578,3.106C641.982,526.835,640.816,525.059,640.035,523.229z M654.074,536.027
|
||||
c-4.336-2.149-7.809-4.612-10.333-7.285l13.579-3.107c1.969,2.07,4.697,3.929,8.007,5.487l-10.218,5.404
|
||||
C654.761,536.362,654.415,536.196,654.074,536.027z M655.459,536.689l10.219-5.405c3.597,1.65,7.855,2.95,12.553,3.791
|
||||
l-4.97,6.989C666.716,540.907,660.672,539.092,655.459,536.689z M690.728,543.552c-5.882,0-11.614-0.483-17.013-1.409l4.97-6.989
|
||||
c3.776,0.648,7.828,1.001,12.043,1.001c0.321,0,0.64-0.002,0.959-0.006l0.485,7.393
|
||||
C691.692,543.549,691.211,543.552,690.728,543.552z M692.653,543.535l-0.485-7.395c2.956-0.057,5.813-0.299,8.553-0.681
|
||||
l-0.69,7.679C697.611,543.354,695.148,543.49,692.653,543.535z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Object">
|
||||
<g style="opacity:0.3;">
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="207.5072" y1="393.376" x2="207.5072" y2="229.7061">
|
||||
<stop offset="0" style="stop-color:#403E40"/>
|
||||
<stop offset="0.1275" style="stop-color:#4E4D4E"/>
|
||||
<stop offset="0.3124" style="stop-color:#5A5A5A"/>
|
||||
<stop offset="0.5479" style="stop-color:#626262"/>
|
||||
<stop offset="1" style="stop-color:#646464"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="175.04,393.376 239.974,393.376 239.974,259.43 241.819,259.43 241.819,255.601
|
||||
237.792,255.601 237.792,250.701 205.844,250.701 205.844,243.255 193.638,243.255 191.815,238.393 188.799,238.393
|
||||
188.799,229.706 188.126,229.706 187.454,229.706 187.454,238.393 181.859,238.393 181.859,243.255 181.859,248.859
|
||||
181.859,250.701 177.223,250.701 177.223,255.601 173.195,255.601 173.195,259.43 175.04,259.43 "/>
|
||||
|
||||
<linearGradient id="SVGID_00000000931258187104496080000017865145222397382034_" gradientUnits="userSpaceOnUse" x1="188.1266" y1="229.7061" x2="188.1266" y2="227.2891">
|
||||
<stop offset="0" style="stop-color:#403E40"/>
|
||||
<stop offset="0.1275" style="stop-color:#4E4D4E"/>
|
||||
<stop offset="0.3124" style="stop-color:#5A5A5A"/>
|
||||
<stop offset="0.5479" style="stop-color:#626262"/>
|
||||
<stop offset="1" style="stop-color:#646464"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000000931258187104496080000017865145222397382034_);" d="M189.335,228.498
|
||||
c0-0.668-0.541-1.209-1.209-1.209c-0.667,0-1.208,0.541-1.208,1.209c0,0.667,0.541,1.208,1.208,1.208
|
||||
C188.794,229.706,189.335,229.165,189.335,228.498z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000036247364810958532620000001993945857249512106_" gradientUnits="userSpaceOnUse" x1="508.9194" y1="421.4165" x2="508.9194" y2="155.3276">
|
||||
<stop offset="0" style="stop-color:#403E40"/>
|
||||
<stop offset="0.1275" style="stop-color:#4E4D4E"/>
|
||||
<stop offset="0.3124" style="stop-color:#5A5A5A"/>
|
||||
<stop offset="0.5479" style="stop-color:#626262"/>
|
||||
<stop offset="1" style="stop-color:#646464"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_00000036247364810958532620000001993945857249512106_);" points="777.689,401.218 777.689,221.14
|
||||
697.741,204.545 706.501,401.218 471.904,401.218 471.904,289.958 467.586,289.958 467.586,223.38 456.438,223.38
|
||||
456.438,205.547 452.456,205.547 452.456,179.391 430.514,179.391 430.514,160.168 428.562,160.168 428.562,179.391
|
||||
424.264,179.391 424.264,155.328 422.311,155.328 422.311,179.391 408.44,179.391 408.44,223.38 401.275,223.38 401.275,289.958
|
||||
395.133,289.958 395.133,401.218 332.748,401.218 332.748,253.114 333.825,253.114 333.825,251.402 326.147,251.402
|
||||
326.147,241.111 327.14,241.111 327.14,239.463 320.092,239.463 320.092,233.547 320.725,233.547 320.725,232.282 317.69,232.282
|
||||
317.69,226.693 314.794,226.693 314.343,226.693 314.343,206.742 314.029,206.742 313.63,206.742 313.228,206.742
|
||||
313.228,226.693 311.874,226.693 311.874,215.571 311.56,215.571 311.161,215.571 310.759,215.571 310.759,226.693
|
||||
307.411,226.693 307.411,232.282 303.909,232.282 303.909,233.547 305.009,233.547 305.009,239.463 297.962,239.463
|
||||
297.962,241.111 298.954,241.111 298.954,251.402 291.276,251.402 291.276,253.114 292.354,253.114 292.354,401.218
|
||||
84.29,401.218 84.29,421.417 933.548,421.417 933.548,401.218 "/>
|
||||
</g>
|
||||
|
||||
<linearGradient id="SVGID_00000121963338060960119620000016097684000583641491_" gradientUnits="userSpaceOnUse" x1="499.6613" y1="451.2495" x2="499.6613" y2="202.0752">
|
||||
<stop offset="0.0815" style="stop-color:#403E40"/>
|
||||
<stop offset="0.4715" style="stop-color:#444244"/>
|
||||
<stop offset="0.8768" style="stop-color:#504F50"/>
|
||||
<stop offset="1" style="stop-color:#555455"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000121963338060960119620000016097684000583641491_);" d="M918.278,419.4v-18.183h-25.56
|
||||
l-9.674-71.571h-1.452v-8.598h-5.082v8.598h-1.259v-3.216h-3.557v3.216h-7.369v-7.496h-2.033v-5.209h-14.483v5.209h-2.033v7.496
|
||||
h-2.033v42.986h-12.874V263.564h-4.235v-23.92h-1.355v23.92h-3.219v-33.181h-1.355v33.181h-2.795v-17.961h-1.355v17.961h-24.985
|
||||
v77.418h-27.78v50.154h-25.944l-20.601-37.972c3.473-2,6.738-4.405,9.735-7.193l4.225,4.508c-0.907,0.793-1.481,1.957-1.481,3.256
|
||||
c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
|
||||
c-0.916,0-1.764,0.285-2.463,0.771l-4.255-4.54c0.36-0.341,0.717-0.687,1.069-1.039c4.458-4.459,8.028-9.568,10.623-15.114
|
||||
l4.705,2.172c-0.086,0.339-0.131,0.693-0.131,1.059c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324
|
||||
c0-2.388-1.936-4.324-4.324-4.324c-1.852,0-3.432,1.165-4.048,2.803l-4.648-2.146c2.866-6.273,4.489-13.092,4.744-20.153
|
||||
l5.065,0.165c0.062,2.334,1.972,4.207,4.321,4.207c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
|
||||
c-2.266,0-4.123,1.743-4.308,3.961l-5.064-0.165c0.013-0.496,0.021-0.993,0.021-1.491c0-6.303-1.088-12.438-3.173-18.192
|
||||
l4.231-1.558c0.664,1.533,2.191,2.606,3.968,2.606c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
|
||||
c-2.388,0-4.324,1.936-4.324,4.324c0,0.44,0.066,0.866,0.189,1.267l-4.229,1.557c-2.41-6.464-6.085-12.437-10.898-17.611
|
||||
l3.31-3.102c0.776,0.741,1.827,1.197,2.985,1.197c2.388,0,4.324-1.935,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324
|
||||
c-2.388,0-4.324,1.936-4.324,4.324c0,1.057,0.38,2.025,1.01,2.776l-3.31,3.102c-0.341-0.36-0.687-0.717-1.039-1.069
|
||||
c-5.012-5.013-10.848-8.903-17.201-11.546l1.821-4.434c0.413,0.131,0.853,0.203,1.309,0.203c2.388,0,4.324-1.936,4.324-4.324
|
||||
c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.936-4.324,4.324c0,1.762,1.054,3.276,2.566,3.95l-1.816,4.423
|
||||
c-5.685-2.304-11.775-3.615-18.057-3.842l0.197-6.06c0.046,0.001,0.091,0.003,0.137,0.003c2.388,0,4.324-1.936,4.324-4.324
|
||||
c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.936-4.324,4.324c0,2.179,1.611,3.98,3.707,4.279l-0.198,6.086
|
||||
c-0.496-0.014-0.993-0.021-1.491-0.021c-6.048,0-11.942,1.001-17.493,2.925l-1.743-4.946c1.573-0.647,2.68-2.193,2.68-4
|
||||
c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.936-4.324,4.324c0,2.388,1.936,4.324,4.324,4.324
|
||||
c0.413,0,0.812-0.059,1.19-0.167l1.744,4.948c-6.732,2.401-12.948,6.166-18.308,11.152l-3.16-3.372
|
||||
c0.707-0.77,1.139-1.796,1.139-2.923c0-2.388-1.936-4.324-4.324-4.324c-2.388,0-4.324,1.935-4.324,4.324
|
||||
c0,2.388,1.936,4.324,4.324,4.324c1.088,0,2.081-0.402,2.841-1.065l3.154,3.366c-0.36,0.341-0.717,0.688-1.069,1.04
|
||||
c-4.458,4.458-8.028,9.568-10.623,15.114l-4.015-1.854c0.146-0.433,0.225-0.896,0.225-1.377c0-2.388-1.936-4.324-4.324-4.324
|
||||
c-2.388,0-4.324,1.936-4.324,4.324c0,2.388,1.936,4.324,4.324,4.324c1.736,0,3.232-1.023,3.92-2.5l3.992,1.843
|
||||
c-2.865,6.273-4.489,13.093-4.744,20.153l-5.154-0.167c-0.064-2.333-1.973-4.204-4.321-4.204c-2.388,0-4.324,1.936-4.324,4.324
|
||||
c0,2.388,1.936,4.324,4.324,4.324c2.267,0,4.125-1.744,4.308-3.963l5.153,0.167c-0.013,0.496-0.021,0.993-0.021,1.491
|
||||
c0,6.302,1.088,12.438,3.173,18.191l-4.231,1.558c-0.664-1.533-2.191-2.606-3.969-2.606c-2.388,0-4.324,1.936-4.324,4.324
|
||||
c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-0.44-0.066-0.866-0.189-1.266l4.229-1.557
|
||||
c2.409,6.464,6.084,12.436,10.898,17.611l-3.31,3.102c-0.776-0.741-1.827-1.197-2.985-1.197c-2.388,0-4.324,1.935-4.324,4.324
|
||||
c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-1.057-0.38-2.025-1.01-2.776l3.311-3.102
|
||||
c0.341,0.36,0.687,0.717,1.039,1.069c3.376,3.375,7.125,6.242,11.154,8.561l-20.601,37.972h-16.685v-25.743h-6.801v-48.882h2.645
|
||||
v-1.063H564.32v1.063h2.645v24.652h-5.729l-5.467,28.096v-92.143h-2.399v-33.37h-12.075v-12.705h-6.46V220.37h-2.267v-18.294
|
||||
h-0.586v18.294h-2.267v10.672h-6.46v12.705h-11.982v33.37h-2.491V337.7h-18.579v53.436h-61.639V287.814h4.954v-1.626h-4.954v-2.911
|
||||
h-6.279v-4.781h-51.354v4.781h-6.279v2.911h-4.954v1.626h4.954v64.319h-8.4v-12.069h-51.819v14.737h-11.298v27.442h-18.294V292.55
|
||||
h-6.098v-6.099h-4.828v-16.134h-1.017v16.134h-2.287v-20.2h-1.016v20.2h-2.811v6.099h-1.509v89.693h-37.859v-52.597h1.779v-3.557
|
||||
h-11.688v-9.655h-5.59v9.655h-5.082v-9.655h-5.082v9.655h-9.885v-9.655h-30.261v9.655h-7.066v3.557h4.017v19.819h-11.18v44.72
|
||||
h-15.346v-11.942h-17.084v26.044H84.29V419.4H53.82v31.849h891.682V419.4H918.278z M716.559,351.896l-7.135-13.152
|
||||
c2.287-1.349,4.417-2.938,6.354-4.731l10.219,10.906C723.091,347.622,719.925,349.955,716.559,351.896z M689.85,309.7
|
||||
c0.175,0.055,0.357,0.094,0.544,0.116l-1.082,33.274c-4.266-0.165-8.344-1.071-12.11-2.594L689.85,309.7z M676.758,340.314
|
||||
c-1.218-0.512-2.402-1.089-3.548-1.726l15.875-29.261c0.102,0.07,0.209,0.133,0.32,0.19L676.758,340.314z M690.874,309.832
|
||||
c0.203-0.01,0.401-0.041,0.591-0.091l11.067,31.4c-3.701,1.281-7.673,1.978-11.804,1.978c-0.313,0-0.625-0.004-0.936-0.012
|
||||
L690.874,309.832z M691.917,309.581c0.159-0.072,0.311-0.157,0.453-0.254l15.875,29.261c-1.677,0.932-3.435,1.734-5.261,2.394
|
||||
L691.917,309.581z M694.589,311.399l20.697,22.088c-1.893,1.751-3.973,3.303-6.206,4.623L694.589,311.399z M693.683,309.731
|
||||
l-0.598-1.103c0.062-0.086,0.119-0.176,0.172-0.268l30.224,13.952c-1.93,4.091-4.602,7.766-7.844,10.847L693.683,309.731z
|
||||
M693.46,307.925c0.077-0.21,0.129-0.432,0.156-0.662l33.274,1.082c-0.186,4.809-1.313,9.38-3.204,13.534L693.46,307.925z
|
||||
M693.631,306.783c-0.011-0.217-0.046-0.428-0.102-0.63l31.244-11.503c1.388,3.836,2.146,7.971,2.146,12.279
|
||||
c0,0.313-0.004,0.624-0.012,0.936L693.631,306.783z M693.364,305.702c-0.097-0.207-0.217-0.401-0.358-0.579l24.281-22.752
|
||||
c3.15,3.404,5.654,7.411,7.319,11.828L693.364,305.702z M692.678,304.772c-0.188-0.17-0.399-0.315-0.627-0.433l12.647-30.797
|
||||
c4.661,1.958,8.83,4.864,12.261,8.477L692.678,304.772z M691.606,304.157c-0.175-0.055-0.357-0.094-0.544-0.116l1.082-33.273
|
||||
c4.265,0.164,8.344,1.071,12.11,2.594L691.606,304.157z M690.582,304.025c-0.203,0.01-0.401,0.041-0.591,0.09l-11.067-31.4
|
||||
c3.701-1.281,7.672-1.978,11.804-1.978c0.313,0,0.625,0.004,0.936,0.012L690.582,304.025z M689.539,304.276
|
||||
c-0.221,0.099-0.428,0.226-0.616,0.375L666.17,280.37c3.525-3.261,7.697-5.832,12.301-7.494L689.539,304.276z M688.572,304.978
|
||||
c-0.143,0.158-0.268,0.332-0.373,0.518l-30.224-13.953c1.929-4.091,4.602-7.766,7.845-10.847L688.572,304.978z M687.996,305.932
|
||||
c-0.077,0.211-0.129,0.432-0.156,0.662l-33.274-1.082c0.186-4.809,1.313-9.38,3.204-13.534L687.996,305.932z M687.825,307.075
|
||||
c0.011,0.217,0.046,0.427,0.102,0.629l-31.244,11.503c-1.388-3.836-2.146-7.97-2.146-12.279c0-0.313,0.004-0.625,0.012-0.936
|
||||
L687.825,307.075z M688.092,308.155c0.078,0.168,0.171,0.326,0.279,0.474l-0.198,0.365l-24.004,22.492
|
||||
c-3.15-3.404-5.654-7.411-7.319-11.828L688.092,308.155z M687.446,310.332l-15.07,27.777c-2.912-1.72-5.564-3.835-7.88-6.272
|
||||
L687.446,310.332z M672.866,339.221c1.169,0.649,2.376,1.238,3.618,1.759l-5.681,13.833c-1.732-0.721-3.424-1.537-5.07-2.445
|
||||
L672.866,339.221z M676.929,341.163c3.843,1.555,8.006,2.479,12.36,2.647l-0.485,14.92c-6.107-0.221-12.028-1.496-17.555-3.735
|
||||
L676.929,341.163z M689.769,343.828c0.319,0.008,0.638,0.013,0.959,0.013c4.215,0,8.267-0.712,12.043-2.02l4.97,14.101
|
||||
c-5.399,1.87-11.131,2.844-17.013,2.844c-0.482,0-0.964-0.007-1.444-0.021L689.769,343.828z M703.225,341.661
|
||||
c1.862-0.672,3.655-1.49,5.365-2.44l7.133,13.148c-2.417,1.333-4.933,2.468-7.528,3.394L703.225,341.661z M727.382,343.582
|
||||
c-0.341,0.341-0.686,0.676-1.035,1.007l-10.217-10.904c3.31-3.144,6.038-6.895,8.007-11.07l13.579,6.269
|
||||
C735.191,334.277,731.718,339.247,727.382,343.582z M737.917,328.448l-13.578-6.268c1.931-4.239,3.081-8.904,3.27-13.813
|
||||
l14.921,0.485C742.281,315.718,740.702,322.349,737.917,328.448z M742.565,306.929c0,0.482-0.007,0.963-0.02,1.444l-14.917-0.485
|
||||
c0.008-0.319,0.012-0.639,0.012-0.959c0-4.397-0.774-8.615-2.19-12.528l14.03-5.165
|
||||
C741.507,294.832,742.565,300.799,742.565,306.929z M728.718,271.66c4.68,5.032,8.253,10.839,10.596,17.124l-14.032,5.167
|
||||
c-1.699-4.508-4.255-8.598-7.47-12.072L728.718,271.66z M727.382,270.274c0.341,0.341,0.676,0.686,1.007,1.035l-10.904,10.217
|
||||
c-3.502-3.687-7.756-6.653-12.513-8.65l5.681-13.833C716.831,261.615,722.507,265.399,727.382,270.274z M692.652,255.126
|
||||
c6.107,0.221,12.028,1.496,17.555,3.735l-5.681,13.833c-3.843-1.555-8.006-2.479-12.36-2.647L692.652,255.126z M690.728,255.092
|
||||
c0.482,0,0.964,0.007,1.444,0.02l-0.485,14.917c-0.319-0.008-0.638-0.012-0.959-0.012c-4.215,0-8.267,0.712-12.043,2.019
|
||||
l-4.97-14.101C679.114,256.065,684.846,255.092,690.728,255.092z M673.261,258.094l4.97,14.102
|
||||
c-4.698,1.696-8.956,4.319-12.553,7.648l-10.219-10.906C660.671,264.091,666.716,260.43,673.261,258.094z M654.074,270.274
|
||||
c0.341-0.341,0.687-0.676,1.035-1.007l10.218,10.904c-3.31,3.144-6.038,6.895-8.007,11.071l-13.579-6.269
|
||||
C646.265,279.58,649.738,274.61,654.074,270.274z M643.539,285.409l13.578,6.268c-1.931,4.239-3.081,8.905-3.27,13.813
|
||||
l-14.921-0.485C639.175,298.14,640.754,291.509,643.539,285.409z M638.891,306.929c0-0.482,0.007-0.964,0.02-1.444l14.917,0.485
|
||||
c-0.008,0.318-0.012,0.638-0.012,0.959c0,4.396,0.774,8.614,2.19,12.528l-14.03,5.166
|
||||
C639.949,319.025,638.891,313.058,638.891,306.929z M652.738,342.197c-4.68-5.032-8.253-10.839-10.597-17.124l14.032-5.167
|
||||
c1.699,4.508,4.255,8.598,7.47,12.072L652.738,342.197z M654.074,343.582c-0.341-0.341-0.676-0.686-1.007-1.035l10.904-10.217
|
||||
c2.368,2.494,5.082,4.656,8.062,6.414l-7.135,13.152C660.988,349.642,657.35,346.859,654.074,343.582z M665.046,353.636
|
||||
c1.692,0.934,3.431,1.771,5.21,2.512l-1.821,4.434c-0.413-0.131-0.853-0.202-1.309-0.202c-2.388,0-4.324,1.936-4.324,4.324
|
||||
c0,2.388,1.936,4.324,4.324,4.324c2.388,0,4.324-1.936,4.324-4.324c0-1.762-1.054-3.276-2.566-3.95l1.816-4.423
|
||||
c5.685,2.304,11.775,3.615,18.057,3.842l-0.148,4.534c-2.341,0.053-4.224,1.967-4.224,4.321c0,2.388,1.936,4.324,4.324,4.324
|
||||
c2.388,0,4.324-1.936,4.324-4.324c0-2.26-1.734-4.113-3.944-4.306l0.148-4.535c0.496,0.014,0.993,0.021,1.491,0.021
|
||||
c6.048,0,11.942-1.001,17.493-2.925l1.554,4.408c-1.471,0.69-2.491,2.184-2.491,3.916c0,2.388,1.936,4.324,4.324,4.324
|
||||
c2.388,0,4.324-1.936,4.324-4.324c0-2.388-1.936-4.324-4.324-4.324c-0.485,0-0.951,0.081-1.387,0.229l-1.547-4.388
|
||||
c2.667-0.952,5.252-2.117,7.736-3.487l20.345,37.5h-92.055L665.046,353.636z"/>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_00000121273610027325662480000007068999652675512506_" gradientUnits="userSpaceOnUse" x1="815.83" y1="285.1626" x2="815.83" y2="287.5796">
|
||||
<stop offset="0" style="stop-color:#403E40"/>
|
||||
<stop offset="1" style="stop-color:#161F21"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000121273610027325662480000007068999652675512506_);" d="M816.844,286.371
|
||||
c0-0.667-0.454-1.208-1.014-1.208c-0.56,0-1.014,0.541-1.014,1.208c0,0.668,0.454,1.208,1.014,1.208
|
||||
C816.39,287.58,816.844,287.039,816.844,286.371z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000011738580747612097720000010840228285618223286_" gradientUnits="userSpaceOnUse" x1="500" y1="287.5796" x2="500" y2="451.2495">
|
||||
<stop offset="0" style="stop-color:#403E40"/>
|
||||
<stop offset="1" style="stop-color:#161F21"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_00000011738580747612097720000010840228285618223286_);" points="927.404,433.241 921.11,391.136
|
||||
908.236,391.136 908.236,356.197 909.828,356.197 909.828,353.036 903.578,353.036 903.578,339.427 902.815,339.427
|
||||
902.815,353.036 898.496,353.036 898.496,341.887 897.734,341.887 897.734,353.036 871.695,353.036 871.695,356.197
|
||||
873.474,356.197 873.474,427.088 843.745,427.088 843.745,395.334 826.815,395.334 826.815,317.303 828.363,317.303
|
||||
828.363,313.475 824.982,313.475 824.982,308.574 821.091,308.574 821.091,306.732 821.091,301.129 821.091,296.267
|
||||
816.395,296.267 816.395,287.58 815.83,287.58 815.265,287.58 815.265,296.267 812.734,296.267 811.204,301.129 800.958,301.129
|
||||
800.958,308.574 774.141,308.574 774.141,313.475 770.76,313.475 770.76,317.303 772.309,317.303 772.309,368.073
|
||||
749.871,368.073 749.871,417.957 724.973,406.925 724.973,358.507 728.991,358.507 728.991,354.95 721.924,354.95
|
||||
721.924,345.294 691.664,345.294 691.664,354.95 681.778,354.95 681.778,345.294 676.696,345.294 676.696,354.95 671.615,354.95
|
||||
671.615,345.294 666.025,345.294 666.025,354.95 654.337,354.95 654.337,358.507 656.115,358.507 656.115,425.617
|
||||
644.765,425.617 644.765,424.913 642.711,424.913 642.711,405.789 644.765,405.789 644.765,404.255 642.711,404.255
|
||||
642.711,385.13 644.765,385.13 644.765,383.597 642.711,383.597 642.711,364.472 644.765,364.472 644.765,362.939
|
||||
642.711,362.939 642.711,343.814 644.765,343.814 644.765,342.28 642.711,342.28 642.711,323.156 644.765,323.156
|
||||
644.765,321.622 642.711,321.622 642.711,301.83 646.231,301.83 646.231,300.291 648.021,300.291 648.021,296.095
|
||||
614.595,296.095 614.595,291.429 615.682,291.429 615.682,290.081 597.484,290.081 597.484,291.429 598.571,291.429
|
||||
598.571,296.095 590.287,296.095 590.287,300.291 592.078,300.291 592.078,301.83 595.598,301.83 595.598,321.622
|
||||
593.543,321.622 593.543,323.156 595.598,323.156 595.598,342.28 593.543,342.28 593.543,343.814 595.598,343.814
|
||||
595.598,362.939 593.543,362.939 593.543,364.472 595.598,364.472 595.598,383.597 593.543,383.597 593.543,385.13
|
||||
595.598,385.13 595.598,404.255 593.543,404.255 593.543,405.789 595.598,405.789 595.598,424.913 593.543,424.913
|
||||
593.543,426.447 595.598,426.447 595.598,442.075 584.189,442.075 584.189,381.685 538.283,381.685 538.283,425.617
|
||||
530.83,425.617 530.83,288.763 525.315,288.763 525.315,292.286 515.14,294.775 515.14,292.487 509.625,292.487 509.625,296.124
|
||||
499.45,298.612 499.45,295.989 493.936,295.989 493.936,299.961 483.76,302.45 483.76,300.286 478.246,300.286 478.246,303.799
|
||||
468.071,306.288 468.071,304.423 462.557,304.423 462.557,438.816 454.799,438.816 454.799,367.168 426.065,367.168
|
||||
426.065,411.227 396.608,411.227 396.608,373.655 392.979,373.655 392.979,361.316 395.133,361.316 395.133,360.077
|
||||
385.601,360.077 385.601,356.197 384.584,356.197 384.584,360.077 381.535,360.077 381.535,340.162 380.773,340.162
|
||||
380.773,360.077 376.802,360.077 376.802,361.316 379.138,361.316 379.138,373.655 359.697,373.655 359.697,402.316
|
||||
340.771,402.316 330.886,438.816 311.053,438.816 311.053,319.642 284.794,319.642 284.794,315.373 286.286,315.373
|
||||
286.286,313.875 266.397,313.875 266.397,315.373 267.961,315.373 267.961,319.642 267.961,326.508 267.961,408.127
|
||||
255.579,408.127 255.579,377.289 259.98,377.289 259.98,374.497 228.825,374.497 228.825,355.867 222.882,355.867
|
||||
222.882,352.039 209.616,352.039 209.616,355.867 198.821,355.867 198.821,422.389 163.408,422.389 163.408,373.052
|
||||
133.589,373.052 133.589,412.021 107.712,412.021 107.712,436.954 89.054,436.954 89.054,405.609 64.517,405.609 64.517,432.333
|
||||
42.301,432.333 42.301,451.25 64.517,451.25 72.025,451.25 84.29,451.25 89.054,451.25 107.712,451.25 133.589,451.25
|
||||
142.285,451.25 146.941,451.25 163.408,451.25 198.821,451.25 209.616,451.25 222.882,451.25 228.825,451.25 252.067,451.25
|
||||
255.579,451.25 267.961,451.25 288.725,451.25 298.954,451.25 311.053,451.25 359.697,451.25 370.931,451.25 389.895,451.25
|
||||
396.608,451.25 426.568,451.25 434.618,451.25 462.557,451.25 465.314,451.25 468.071,451.25 478.246,451.25 483.76,451.25
|
||||
493.936,451.25 498.545,451.25 499.45,451.25 509.625,451.25 515.14,451.25 523.887,451.25 525.315,451.25 528.072,451.25
|
||||
530.83,451.25 538.283,451.25 576.227,451.25 581.647,451.25 584.189,451.25 595.598,451.25 615.682,451.25 634.069,451.25
|
||||
642.711,451.25 656.115,451.25 689.405,451.25 724.606,451.25 724.973,451.25 749.871,451.25 763.792,451.25 772.309,451.25
|
||||
777.689,451.25 819.353,451.25 826.815,451.25 835.736,451.25 843.745,451.25 873.474,451.25 895.58,451.25 900.105,451.25
|
||||
908.236,451.25 957.698,451.25 957.698,433.241 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 28 KiB |
BIN
frontend/assets/launcher/icon.png
Normal file
After Width: | Height: | Size: 24 KiB |
161
frontend/assets/plan.svg
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 2200 2200" style="enable-background:new 0 0 2200 2200;" xml:space="preserve">
|
||||
|
||||
<g id="Objects">
|
||||
<g>
|
||||
<path style="fill:#788D8E;" d="M1202.178,2002.073c-5.328,0-9.648-4.319-9.649-9.647c-0.001-5.328,4.319-9.649,9.647-9.649
|
||||
c9.63-0.001,19.271-0.006,28.918-0.014c0.003,0,0.006,0,0.009,0c5.325,0,9.643,4.314,9.647,9.639
|
||||
c0.005,5.328-4.311,9.651-9.639,9.656C1221.458,2002.068,1211.813,2002.072,1202.178,2002.073z M1144.298,2002.03
|
||||
c-0.006,0-0.01,0-0.016,0c-9.658-0.015-19.305-0.036-28.94-0.061c-5.328-0.014-9.636-4.345-9.622-9.673
|
||||
c0.014-5.319,4.331-9.622,9.648-9.622c0.008,0,0.017,0,0.025,0c9.628,0.025,19.269,0.046,28.919,0.061
|
||||
c5.328,0.009,9.641,4.335,9.632,9.663C1153.937,1997.721,1149.619,2002.03,1144.298,2002.03z M1288.979,2001.966
|
||||
c-5.317,0-9.634-4.306-9.647-9.626c-0.012-5.328,4.298-9.657,9.626-9.669c9.634-0.022,19.274-0.047,28.923-0.075
|
||||
c5.297,0.018,9.66,4.292,9.676,9.619c0.015,5.328-4.291,9.66-9.619,9.676c-9.652,0.028-19.299,0.054-28.936,0.075
|
||||
C1288.994,2001.966,1288.986,2001.966,1288.979,2001.966z M1057.498,2001.759c-0.015,0-0.03,0-0.045,0
|
||||
c-9.659-0.044-19.306-0.095-28.939-0.152c-5.328-0.031-9.622-4.376-9.591-9.704c0.031-5.309,4.344-9.591,9.646-9.591
|
||||
c0.02,0,0.04,0,0.058,0c9.625,0.057,19.263,0.107,28.914,0.152c5.328,0.025,9.628,4.364,9.603,9.692
|
||||
C1067.12,1997.468,1062.805,2001.759,1057.498,2001.759z M1375.787,2001.691c-5.31,0-9.625-4.293-9.647-9.609
|
||||
c-0.022-5.328,4.281-9.665,9.609-9.686c9.636-0.039,19.28-0.079,28.928-0.123c0.015,0,0.029,0,0.044,0
|
||||
c5.308,0,9.623,4.291,9.647,9.604c0.024,5.328-4.276,9.666-9.604,9.691c-9.651,0.043-19.297,0.084-28.937,0.122
|
||||
C1375.813,2001.691,1375.8,2001.691,1375.787,2001.691z M1462.601,2001.29c-5.305,0-9.619-4.287-9.647-9.598
|
||||
c-0.027-5.328,4.27-9.67,9.598-9.698c9.641-0.05,19.285-0.102,28.932-0.156c0.018,0,0.037,0,0.056,0
|
||||
c5.302,0,9.616,4.284,9.646,9.594c0.029,5.328-4.266,9.671-9.594,9.701c-9.649,0.054-19.297,0.105-28.94,0.156
|
||||
C1462.635,2001.29,1462.618,2001.29,1462.601,2001.29z M970.707,2001.198c-0.027,0-0.054,0-0.081,0
|
||||
c-9.662-0.079-19.308-0.166-28.939-0.259c-5.328-0.052-9.605-4.413-9.554-9.741c0.052-5.296,4.361-9.554,9.646-9.554
|
||||
c0.032,0,0.063,0,0.095,0.001c9.621,0.093,19.258,0.179,28.911,0.258c5.328,0.044,9.612,4.399,9.568,9.727
|
||||
C980.31,1996.93,975.998,2001.198,970.707,2001.198z M1549.42,2000.802c-5.301,0-9.614-4.281-9.646-9.59
|
||||
c-0.032-5.328,4.262-9.673,9.59-9.705l28.936-0.176c0.021,0,0.042,0,0.061,0c5.301,0,9.614,4.279,9.647,9.587
|
||||
c0.033,5.328-4.259,9.674-9.587,9.708l-28.942,0.176C1549.459,2000.802,1549.439,2000.802,1549.42,2000.802z M883.923,2000.297
|
||||
c-0.041,0-0.083,0-0.124-0.001c-9.663-0.122-19.308-0.25-28.935-0.385c-5.328-0.075-9.586-4.454-9.511-9.782
|
||||
c0.075-5.328,4.464-9.604,9.782-9.511c9.617,0.136,19.254,0.264,28.907,0.385c5.328,0.067,9.592,4.44,9.525,9.768
|
||||
C893.501,1996.057,889.195,2000.297,883.923,2000.297z M1636.244,2000.264c-5.3,0-9.612-4.279-9.646-9.586
|
||||
c-0.034-5.328,4.258-9.675,9.586-9.709l28.943-0.184c0.021,0,0.042,0,0.062,0c5.3,0,9.613,4.279,9.647,9.586
|
||||
c0.034,5.328-4.259,9.675-9.586,9.709l-28.943,0.184C1636.286,2000.264,1636.265,2000.264,1636.244,2000.264z M1723.075,1999.719
|
||||
c-5.3,0-9.614-4.28-9.647-9.588c-0.033-5.328,4.26-9.674,9.588-9.707l28.946-0.177c0.02,0,0.04,0,0.059,0
|
||||
c5.301,0,9.615,4.28,9.647,9.589c0.032,5.328-4.261,9.674-9.589,9.706l-28.945,0.177
|
||||
C1723.115,1999.719,1723.095,1999.719,1723.075,1999.719z M1809.912,1999.201c-5.303,0-9.616-4.283-9.647-9.593
|
||||
c-0.03-5.328,4.265-9.672,9.593-9.702l28.952-0.16c0.018,0,0.036,0,0.053,0c5.304,0,9.618,4.285,9.647,9.596
|
||||
c0.028,5.328-4.268,9.67-9.596,9.699l-28.947,0.16C1809.949,1999.201,1809.931,1999.201,1809.912,1999.201z M797.15,1998.997
|
||||
c-0.057,0-0.115-0.001-0.172-0.002c-9.665-0.169-19.31-0.346-28.935-0.531c-5.327-0.103-9.562-4.504-9.459-9.832
|
||||
c0.104-5.327,4.48-9.533,9.832-9.459c9.612,0.186,19.245,0.363,28.899,0.531c5.327,0.092,9.57,4.487,9.477,9.814
|
||||
C806.701,1994.788,802.399,1998.997,797.15,1998.997z M1896.756,1998.75c-5.307,0-9.621-4.29-9.647-9.602
|
||||
c-0.025-5.328,4.274-9.667,9.602-9.693c9.658-0.045,19.31-0.089,28.958-0.129c0.014,0,0.027,0,0.041,0
|
||||
c5.309,0,9.624,4.292,9.647,9.607c0.023,5.328-4.279,9.666-9.607,9.688c-9.644,0.041-19.294,0.084-28.948,0.129
|
||||
C1896.787,1998.75,1896.771,1998.75,1896.756,1998.75z M710.388,1997.237c-0.076,0-0.152-0.001-0.228-0.003
|
||||
c-9.667-0.223-19.311-0.457-28.932-0.7c-5.326-0.135-9.535-4.562-9.401-9.889c0.133-5.243,4.425-9.404,9.64-9.404
|
||||
c0.083,0,0.166,0.001,0.249,0.003c9.607,0.243,19.237,0.477,28.891,0.7c5.327,0.122,9.545,4.541,9.421,9.868
|
||||
C719.907,1993.064,715.612,1997.237,710.388,1997.237z M623.642,1994.948c-0.096,0-0.193-0.001-0.29-0.004
|
||||
c-9.67-0.287-19.314-0.585-28.929-0.894c-5.326-0.172-9.503-4.628-9.333-9.953c0.171-5.325,4.65-9.465,9.953-9.333
|
||||
c9.6,0.309,19.227,0.607,28.88,0.892c5.326,0.158,9.516,4.604,9.357,9.93C633.126,1990.815,628.838,1994.948,623.642,1994.948z
|
||||
M536.937,1991.683c-0.226,0-0.453-0.007-0.682-0.024c-10.955-0.765-20.624-1.8-29.559-3.167
|
||||
c-5.267-0.806-8.883-5.728-8.078-10.995c0.805-5.268,5.725-8.888,10.995-8.078c8.408,1.286,17.563,2.264,27.985,2.992
|
||||
c5.316,0.371,9.323,4.981,8.952,10.296C546.196,1987.794,541.959,1991.683,536.937,1991.683z M452.936,1972.044
|
||||
c-1.444,0-2.91-0.325-4.291-1.012c-5.129-2.553-10.134-5.398-14.875-8.458c-3.821-2.466-7.597-5.17-11.224-8.036
|
||||
c-4.179-3.305-4.889-9.372-1.585-13.552c3.305-4.18,9.371-4.889,13.552-1.585c3.144,2.486,6.415,4.828,9.719,6.961
|
||||
c4.142,2.673,8.519,5.162,13.01,7.397c4.77,2.373,6.713,8.165,4.34,12.935C459.893,1970.083,456.481,1972.044,452.936,1972.044z
|
||||
M390.843,1913.094c-3.257,0-6.436-1.65-8.252-4.636c-5.088-8.366-9.753-17.406-13.866-26.869
|
||||
c-2.125-4.886,0.115-10.57,5.002-12.693c4.884-2.125,10.569,0.114,12.694,5.002c3.765,8.661,8.023,16.915,12.657,24.534
|
||||
c2.768,4.552,1.323,10.487-3.23,13.256C394.28,1912.639,392.55,1913.094,390.843,1913.094z M360.798,1832.103
|
||||
c-4.545,0-8.593-3.227-9.469-7.857c-1.832-9.681-3.208-19.642-4.092-29.605c-0.471-5.307,3.45-9.991,8.757-10.463
|
||||
c5.305-0.466,9.991,3.449,10.462,8.757c0.828,9.335,2.117,18.663,3.831,27.724c0.99,5.236-2.451,10.282-7.686,11.272
|
||||
C361.996,1832.047,361.393,1832.103,360.798,1832.103z M357.3,1745.636c-0.337,0-0.677-0.018-1.02-0.054
|
||||
c-5.299-0.557-9.143-5.304-8.586-10.603c1.051-10.004,2.612-19.95,4.636-29.561c1.098-5.214,6.217-8.55,11.429-7.451
|
||||
c5.214,1.099,8.55,6.215,7.451,11.429c-1.889,8.965-3.345,18.252-4.327,27.6C366.362,1741.952,362.175,1745.636,357.3,1745.636z
|
||||
M379.592,1662.099c-1.292,0-2.604-0.261-3.863-0.812c-4.881-2.136-7.107-7.824-4.97-12.706
|
||||
c3.967-9.067,8.429-18.064,13.26-26.742c2.591-4.655,8.466-6.329,13.122-3.737c4.656,2.592,6.329,8.466,3.737,13.122
|
||||
c-4.533,8.143-8.72,16.585-12.442,25.091C386.85,1659.939,383.308,1662.099,379.592,1662.099z M425.149,1588.527
|
||||
c-2.174,0-4.36-0.73-6.162-2.228c-4.097-3.407-4.658-9.489-1.252-13.587c6.291-7.567,13.033-14.977,20.039-22.024
|
||||
c3.756-3.78,9.865-3.796,13.644-0.039c3.778,3.756,3.796,9.865,0.039,13.643c-6.604,6.642-12.958,13.624-18.884,20.754
|
||||
C430.666,1587.342,427.917,1588.527,425.149,1588.527z M488.757,1529.81c-3.021,0-5.994-1.414-7.875-4.063
|
||||
c-3.085-4.345-2.062-10.367,2.282-13.452c8.036-5.705,16.424-11.148,24.935-16.182c4.587-2.711,10.502-1.194,13.215,3.393
|
||||
c2.712,4.586,1.194,10.503-3.393,13.215c-8.051,4.762-15.987,9.912-23.588,15.308
|
||||
C492.639,1529.232,490.688,1529.81,488.757,1529.81z M565.026,1488.849c-3.858,0-7.5-2.33-8.989-6.14
|
||||
c-1.939-4.962,0.513-10.558,5.476-12.497c8.996-3.515,18.386-6.814,27.91-9.805c5.085-1.593,10.499,1.23,12.094,6.314
|
||||
c1.597,5.083-1.229,10.498-6.313,12.095c-9.107,2.86-18.081,6.012-26.67,9.368
|
||||
C567.381,1488.636,566.194,1488.849,565.026,1488.849z M648.419,1465.236c-4.529,0-8.569-3.204-9.462-7.816
|
||||
c-1.012-5.232,2.408-10.293,7.639-11.306c9.243-1.788,18.981-3.446,28.945-4.926c5.268-0.786,10.177,2.855,10.961,8.125
|
||||
c0.783,5.27-2.855,10.178-8.125,10.961c-9.686,1.439-19.145,3.049-28.114,4.784
|
||||
C649.644,1465.178,649.027,1465.236,648.419,1465.236z M734.448,1453.776c-4.949,0-9.161-3.786-9.599-8.809
|
||||
c-0.464-5.308,3.463-9.987,8.771-10.45c8.927-0.779,18.419-1.521,29.019-2.265c5.285-0.369,9.926,3.633,10.3,8.948
|
||||
c0.373,5.315-3.633,9.926-8.948,10.299c-10.489,0.737-19.875,1.469-28.691,2.239
|
||||
C735.013,1453.764,734.729,1453.776,734.448,1453.776z M821.074,1447.866c-5.059,0-9.308-3.941-9.621-9.059
|
||||
c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.767c5.341-0.318,9.893,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
|
||||
l-28.889,1.766C821.471,1447.86,821.272,1447.866,821.074,1447.866z M907.74,1442.568c-5.059,0-9.308-3.941-9.621-9.059
|
||||
c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.766c5.344-0.326,9.893,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.218
|
||||
l-28.889,1.767C908.137,1442.562,907.938,1442.568,907.74,1442.568z M994.406,1437.269c-5.059,0-9.307-3.941-9.62-9.059
|
||||
c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.766c5.345-0.309,9.893,3.722,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
|
||||
l-28.889,1.767C994.805,1437.263,994.604,1437.269,994.406,1437.269z M1081.072,1431.969c-5.059,0-9.307-3.941-9.62-9.059
|
||||
c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.766c5.322-0.318,9.894,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
|
||||
l-28.889,1.767C1081.47,1431.964,1081.27,1431.969,1081.072,1431.969z M1167.738,1426.671c-5.059,0-9.307-3.941-9.62-9.059
|
||||
c-0.325-5.318,3.722-9.893,9.041-10.219l28.889-1.767c5.349-0.326,9.894,3.723,10.219,9.041c0.325,5.318-3.722,9.893-9.041,10.219
|
||||
l-28.889,1.766C1168.135,1426.665,1167.936,1426.671,1167.738,1426.671z M1254.358,1420.693c-4.914,0-9.115-3.738-9.592-8.73
|
||||
c-0.508-5.304,3.38-10.015,8.685-10.523c10.205-0.975,19.481-2.043,28.357-3.264c5.276-0.72,10.146,2.966,10.872,8.244
|
||||
c0.725,5.279-2.966,10.146-8.244,10.872c-9.142,1.257-18.676,2.354-29.148,3.356
|
||||
C1254.976,1420.678,1254.665,1420.693,1254.358,1420.693z M1339.835,1406.05c-4.233,0-8.115-2.807-9.295-7.086
|
||||
c-1.416-5.136,1.6-10.448,6.735-11.864c9.242-2.549,18.223-5.456,26.694-8.639c4.994-1.875,10.551,0.65,12.425,5.636
|
||||
c1.875,4.988-0.649,10.55-5.636,12.425c-9.014,3.388-18.553,6.476-28.353,9.178
|
||||
C1341.548,1405.937,1340.684,1406.05,1339.835,1406.05z M1418.99,1371.212c-3.131,0-6.201-1.522-8.057-4.329
|
||||
c-2.938-4.445-1.716-10.43,2.729-13.368c7.542-4.985,14.948-10.622,22.014-16.754c4.022-3.493,10.115-3.063,13.609,0.962
|
||||
c3.493,4.024,3.062,10.117-0.962,13.609c-7.698,6.683-15.781,12.832-24.022,18.28
|
||||
C1422.663,1370.694,1420.817,1371.212,1418.99,1371.212z M1480.743,1310.868c-1.931,0-3.882-0.578-5.577-1.782
|
||||
c-4.344-3.086-5.366-9.108-2.281-13.452c5.366-7.558,10.318-15.487,14.721-23.567c2.549-4.679,8.41-6.406,13.087-3.856
|
||||
c4.679,2.549,6.406,8.409,3.856,13.087c-4.765,8.747-10.126,17.328-15.932,25.506
|
||||
C1486.737,1309.454,1483.762,1310.868,1480.743,1310.868z M1517.216,1232.602c-0.778,0-1.568-0.094-2.356-0.292
|
||||
c-5.169-1.297-8.306-6.538-7.009-11.707c2.256-8.984,3.898-18.121,4.878-27.155c0.575-5.299,5.342-9.13,10.632-8.55
|
||||
c5.298,0.575,9.126,5.335,8.55,10.633c-1.076,9.911-2.875,19.928-5.346,29.771
|
||||
C1525.467,1229.681,1521.535,1232.602,1517.216,1232.602z M1520.169,1146.498c-4.554,0-8.606-3.239-9.472-7.879
|
||||
c-1.672-8.957-4.032-17.905-7.015-26.593c-1.731-5.04,0.953-10.527,5.992-12.257c5.036-1.729,10.528,0.953,12.257,5.992
|
||||
c3.287,9.575,5.889,19.438,7.733,29.318c0.978,5.237-2.475,10.276-7.713,11.254
|
||||
C1521.352,1146.444,1520.757,1146.498,1520.169,1146.498z M1486.631,1067.128c-3.053,0-6.055-1.445-7.93-4.142
|
||||
c-5.223-7.514-11.025-14.791-17.243-21.63c-3.585-3.942-3.295-10.044,0.647-13.629c3.942-3.584,10.044-3.295,13.628,0.648
|
||||
c6.781,7.457,13.11,15.396,18.811,23.597c3.041,4.375,1.961,10.387-2.415,13.428
|
||||
C1490.452,1066.568,1488.532,1067.128,1486.631,1067.128z M1424.593,1007.152c-1.794,0-3.608-0.499-5.227-1.546
|
||||
c-7.728-4.995-15.75-9.441-23.845-13.217l-0.314-0.146c-4.827-2.257-6.911-7.999-4.653-12.826c2.257-4.826,8-6.91,12.825-4.653
|
||||
l0.276,0.129c8.915,4.158,17.716,9.036,26.183,14.508c4.475,2.892,5.758,8.864,2.866,13.339
|
||||
C1430.859,1005.596,1427.759,1007.152,1424.593,1007.152z M1344.533,974.803c-0.7,0-1.41-0.076-2.123-0.236
|
||||
c-8.759-1.966-18.077-3.643-27.693-4.985c-5.277-0.736-8.958-5.611-8.222-10.888c0.737-5.277,5.615-8.957,10.888-8.222
|
||||
c10.137,1.415,19.98,3.187,29.254,5.268c5.199,1.167,8.467,6.327,7.3,11.527C1352.93,971.754,1348.947,974.803,1344.533,974.803z
|
||||
M274.324,966.773c-5.318,0-9.634-4.305-9.647-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.016,0,0.023,0
|
||||
c5.317,0,9.634,4.305,9.647,9.625c0.012,5.328-4.297,9.657-9.625,9.67l-28.943,0.066
|
||||
C274.339,966.773,274.331,966.773,274.324,966.773z M361.152,966.573c-5.318,0-9.635-4.305-9.647-9.625
|
||||
c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c5.338-0.002,9.657,4.297,9.67,9.625s-4.297,9.657-9.625,9.67l-28.943,0.066
|
||||
C361.167,966.573,361.16,966.573,361.152,966.573z M447.979,966.373c-5.318,0-9.634-4.305-9.647-9.625
|
||||
c-0.012-5.328,4.297-9.657,9.625-9.67l28.942-0.066c0.008,0,0.015,0,0.023,0c5.318,0,9.635,4.305,9.648,9.625
|
||||
c0.012,5.328-4.297,9.657-9.626,9.67l-28.942,0.066C447.995,966.373,447.987,966.373,447.979,966.373z M534.808,966.174
|
||||
c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0
|
||||
c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
|
||||
C534.823,966.174,534.815,966.174,534.808,966.174z M621.636,965.973c-5.318,0-9.635-4.305-9.648-9.625
|
||||
c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0c5.318,0,9.635,4.305,9.648,9.625
|
||||
c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066C621.651,965.973,621.643,965.973,621.636,965.973z M708.463,965.774
|
||||
c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0
|
||||
c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
|
||||
C708.478,965.774,708.471,965.774,708.463,965.774z M795.291,965.574c-5.318,0-9.635-4.305-9.648-9.625
|
||||
c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c5.292,0.018,9.658,4.297,9.67,9.625c0.012,5.328-4.297,9.657-9.626,9.67
|
||||
l-28.943,0.066C795.306,965.574,795.299,965.574,795.291,965.574z M882.12,965.374c-5.318,0-9.635-4.305-9.648-9.625
|
||||
c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.016,0,0.024,0c5.317,0,9.634,4.305,9.647,9.625
|
||||
c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066C882.135,965.374,882.127,965.374,882.12,965.374z M968.947,965.174
|
||||
c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.015,0,0.023,0
|
||||
c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
|
||||
C968.962,965.174,968.955,965.174,968.947,965.174z M1258.376,965.13c-0.103,0-0.204-0.001-0.307-0.005
|
||||
c-8.629-0.27-17.745-0.424-28.69-0.483c-5.328-0.029-9.623-4.372-9.595-9.7c0.029-5.31,4.342-9.595,9.647-9.595
|
||||
c0.018,0,0.036,0,0.054,0c11.114,0.06,20.389,0.216,29.188,0.492c5.326,0.167,9.508,4.619,9.341,9.945
|
||||
C1267.849,961.007,1263.564,965.13,1258.376,965.13z M1055.775,964.974c-5.318,0-9.635-4.305-9.648-9.625
|
||||
c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.008,0,0.016,0,0.024,0c5.318,0,9.634,4.305,9.647,9.625
|
||||
c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066C1055.79,964.974,1055.783,964.974,1055.775,964.974z M1142.603,964.775
|
||||
c-5.318,0-9.635-4.305-9.648-9.625c-0.012-5.328,4.297-9.657,9.625-9.67l28.943-0.066c0.007,0,0.015,0,0.023,0
|
||||
c5.318,0,9.635,4.305,9.648,9.625c0.012,5.328-4.297,9.657-9.626,9.67l-28.943,0.066
|
||||
C1142.619,964.775,1142.611,964.775,1142.603,964.775z"/>
|
||||
<path style="fill:#D13737;" d="M462.452,197.927c-156.647,0-283.638,126.991-283.638,283.638
|
||||
c0,251.801,283.638,464.048,283.638,464.048S746.09,733.366,746.09,481.565C746.09,324.918,619.099,197.927,462.452,197.927z
|
||||
M462.316,679.485c-109.374,0-198.045-88.671-198.045-198.055c0-109.374,88.671-198.045,198.045-198.045
|
||||
c109.384,0,198.055,88.671,198.055,198.045C660.371,590.814,571.701,679.485,462.316,679.485z"/>
|
||||
<path style="fill:#18ACB7;" d="M1737.548,1228.212c-156.647,0-283.638,126.991-283.638,283.638
|
||||
c0,251.801,283.638,464.048,283.638,464.048s283.638-212.246,283.638-464.048
|
||||
C2021.187,1355.203,1894.196,1228.212,1737.548,1228.212z M1737.413,1709.77c-109.374,0-198.045-88.671-198.045-198.055
|
||||
c0-109.374,88.671-198.045,198.045-198.045c109.384,0,198.055,88.671,198.055,198.045
|
||||
C1935.468,1621.1,1846.797,1709.77,1737.413,1709.77z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 16 KiB |
3
frontend/devtools_options.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
17
frontend/flutter_launcher_icons.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
flutter_launcher_icons:
|
||||
image_path: "assets/launcher/icon.png"
|
||||
|
||||
# Android section
|
||||
android: true
|
||||
min_sdk_android: 21 # android min sdk min:16, default 21
|
||||
|
||||
# iOS section
|
||||
ios: true
|
||||
remove_alpha_ios: true # app store rejecs icons with alpha
|
||||
|
||||
# Web section
|
||||
web:
|
||||
generate: true
|
||||
image_path: "assets/launcher/icon.png"
|
||||
# background_color: "#hexcode"
|
||||
# theme_color: "#hexcode"
|
@@ -427,7 +427,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -484,7 +484,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 738 B |
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -13,7 +13,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>fast_network_navigation</string>
|
||||
<string>anyway</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
85
frontend/lib/constants.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const String APP_NAME = 'AnyWay';
|
||||
|
||||
String API_URL_BASE = 'https://anyway.anydev.info';
|
||||
String PRIVACY_URL = 'https://anydev.info/privacy';
|
||||
|
||||
const String MAP_ID = '41c21ac9b81dbfd8';
|
||||
|
||||
|
||||
const Color GRADIENT_START = Color(0xFFF9B208);
|
||||
const Color GRADIENT_END = Color(0xFFE72E77);
|
||||
|
||||
const Color PRIMARY_COLOR = Color(0xFFF38F1A);
|
||||
|
||||
|
||||
|
||||
const double TRIP_PANEL_MAX_HEIGHT = 0.8;
|
||||
const double TRIP_PANEL_MIN_HEIGHT = 0.12;
|
||||
|
||||
ThemeData APP_THEME = ThemeData(
|
||||
primaryColor: PRIMARY_COLOR,
|
||||
|
||||
scaffoldBackgroundColor: Colors.white,
|
||||
cardColor: Colors.white,
|
||||
useMaterial3: true,
|
||||
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: PRIMARY_COLOR,
|
||||
secondary: GRADIENT_END,
|
||||
surface: Colors.white,
|
||||
error: Colors.red,
|
||||
onPrimary: Colors.white,
|
||||
onSecondary: const Color.fromARGB(255, 30, 22, 22),
|
||||
onSurface: Colors.black,
|
||||
onError: Colors.white,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
|
||||
|
||||
textButtonTheme: const TextButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||
side: WidgetStatePropertyAll(
|
||||
BorderSide(
|
||||
color: PRIMARY_COLOR,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
|
||||
elevatedButtonTheme: const ElevatedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||
)
|
||||
),
|
||||
|
||||
outlinedButtonTheme: const OutlinedButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
cardTheme: const CardTheme(
|
||||
shadowColor: Colors.grey,
|
||||
elevation: 2,
|
||||
margin: EdgeInsets.all(10),
|
||||
),
|
||||
|
||||
sliderTheme: const SliderThemeData(
|
||||
trackHeight: 15,
|
||||
inactiveTrackColor: Colors.grey,
|
||||
thumbColor: PRIMARY_COLOR,
|
||||
activeTrackColor: GRADIENT_END
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
const Gradient APP_GRADIENT = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [GRADIENT_START, GRADIENT_END],
|
||||
);
|