Upload 120 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .dockerignore +9 -0
- .env +43 -0
- .github/dependabot.yml +20 -0
- .github/workflows/auto-merge.yml +18 -0
- .github/workflows/codeql.yml +42 -0
- .github/workflows/docker-image.yml +19 -0
- .github/workflows/greetings.yml +16 -0
- .github/workflows/hadolint.yml +39 -0
- .github/workflows/linters.yml +38 -0
- .gitignore +132 -0
- .pre-commit-config.yaml +19 -0
- Dockerfile +25 -0
- LICENSE.md +157 -0
- Makefile +104 -0
- README.md +215 -10
- admin/Dockerfile +24 -0
- admin/__init__.py +0 -0
- admin/app.py +247 -0
- admin/config.py +58 -0
- admin/gunicorn_conf.py +16 -0
- admin/static/fonts/glyphicons-halflings-regular.eot +0 -0
- admin/static/fonts/glyphicons-halflings-regular.svg +0 -0
- admin/static/fonts/glyphicons-halflings-regular.ttf +0 -0
- admin/static/fonts/glyphicons-halflings-regular.woff +0 -0
- admin/static/fonts/glyphicons-halflings-regular.woff2 +0 -0
- admin/static/js/pages/dashboard.js +210 -0
- admin/static/plugins/jvectormap/jquery-jvectormap-1.2.2.css +40 -0
- admin/static/plugins/jvectormap/jquery-jvectormap-1.2.2.min.js +8 -0
- admin/static/plugins/jvectormap/jquery-jvectormap-usa-en.js +1 -0
- admin/static/plugins/jvectormap/jquery-jvectormap-world-mill-en.js +0 -0
- admin/templates/admin/base.html +201 -0
- admin/templates/admin/custom_index.html +76 -0
- admin/templates/admin/index.html +223 -0
- admin/templates/my_master.html +46 -0
- admin/templates/security/_macros.html +27 -0
- admin/templates/security/_menu.html +15 -0
- admin/templates/security/_messages.html +9 -0
- admin/templates/security/login_user.html +22 -0
- admin/templates/security/register_user.html +23 -0
- admin/views/__init__.py +0 -0
- admin/views/users.py +29 -0
- alembic.ini +121 -0
- bot/__init__.py +0 -0
- bot/__main__.py +122 -0
- bot/analytics/__init__.py +0 -0
- bot/analytics/amplitude/__init__.py +3 -0
- bot/analytics/amplitude/client.py +57 -0
- bot/analytics/google/__init__.py +3 -0
- bot/analytics/google/client.py +50 -0
- bot/analytics/posthog/__init__.py +3 -0
.dockerignore
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ignore all files
|
2 |
+
**
|
3 |
+
|
4 |
+
# exclusion
|
5 |
+
!/bot/
|
6 |
+
|
7 |
+
!/alembic.ini
|
8 |
+
!/poetry.lock
|
9 |
+
!/pyproject.toml
|
.env
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Telegram Bot Settings
|
2 |
+
BOT_TOKEN="7028675955:AAGKUzOCGjEqv0nmGWgh1UibDPSKxPFJzq4"
|
3 |
+
SUPPORT_URL="http://localhost:5000/support"
|
4 |
+
RATE_LIMIT=0.5
|
5 |
+
DEBUG=False
|
6 |
+
# Webhook Server Settings (Optional)
|
7 |
+
USE_WEBHOOK=False
|
8 |
+
WEBHOOK_HOST="0.0.0.0"
|
9 |
+
WEBHOOK_PORT=8080
|
10 |
+
WEBHOOK_BASE_URL="http://azils-tgbs.hf.space/"
|
11 |
+
WEBHOOK_PATH="/webhook"
|
12 |
+
WEBHOOK_SECRET="Pl7U9AJUFb2"
|
13 |
+
|
14 |
+
# Admin Panel Settings
|
15 |
+
ADMIN_HOST="0.0.0.0"
|
16 |
+
ADMIN_PORT=5000
|
17 |
+
DEFAULT_ADMIN_EMAIL="[email protected]"
|
18 |
+
DEFAULT_ADMIN_PASSWORD="admin"
|
19 |
+
SECURITY_PASSWORD_HASH="pbkdf2_sha512"
|
20 |
+
SECURITY_PASSWORD_SALT="ATGUOHAELKiubahiughaerGOJAEGj"
|
21 |
+
|
22 |
+
# Database Settings
|
23 |
+
DB_HOST="pgbouncer"
|
24 |
+
DB_PORT=5432
|
25 |
+
DB_USER="tgbot"
|
26 |
+
DB_PASS="OGU6P2TNUEwxekD0OHe7"
|
27 |
+
DB_NAME="bot_db"
|
28 |
+
|
29 |
+
# Redis (for FSM and Cache) Settings
|
30 |
+
REDIS_HOST="redis"
|
31 |
+
REDIS_PORT=6379
|
32 |
+
REDIS_PASS=
|
33 |
+
|
34 |
+
# External Services Settings (API Keys for example)
|
35 |
+
SENTRY_DSN=""
|
36 |
+
AMPLITUDE_API_KEY=""
|
37 |
+
POSTHOG_API_KEY=""
|
38 |
+
|
39 |
+
# Performance Monitoring System Settings
|
40 |
+
PROMETHEUS_PORT=9090
|
41 |
+
GRAFANA_PORT=3000
|
42 |
+
GRAFANA_ADMIN_USER="admin"
|
43 |
+
GRAFANA_ADMIN_PASSWORD="admin"
|
.github/dependabot.yml
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
version: 2
|
2 |
+
|
3 |
+
updates:
|
4 |
+
- package-ecosystem: pip
|
5 |
+
directory: "/"
|
6 |
+
labels:
|
7 |
+
- dependencies
|
8 |
+
schedule:
|
9 |
+
interval: daily
|
10 |
+
time: "02:00"
|
11 |
+
open-pull-requests-limit: 10
|
12 |
+
|
13 |
+
- package-ecosystem: github-actions
|
14 |
+
directory: "/"
|
15 |
+
labels:
|
16 |
+
- dependencies
|
17 |
+
schedule:
|
18 |
+
interval: daily
|
19 |
+
time: "02:00"
|
20 |
+
open-pull-requests-limit: 10
|
.github/workflows/auto-merge.yml
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Automerge Dependabot PRs
|
2 |
+
|
3 |
+
on:
|
4 |
+
workflow_run:
|
5 |
+
workflows: [Linting]
|
6 |
+
types: [completed]
|
7 |
+
|
8 |
+
jobs:
|
9 |
+
merge-me:
|
10 |
+
name: Merge me!
|
11 |
+
runs-on: ubuntu-latest
|
12 |
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
13 |
+
steps:
|
14 |
+
- name: Merge me!
|
15 |
+
uses: ridedott/merge-me-action@v2
|
16 |
+
with:
|
17 |
+
GITHUB_TOKEN: ${{ secrets.AUTOMERGE_GITHUB_ACCESS_TOKEN }}
|
18 |
+
timeout-minutes: 5
|
.github/workflows/codeql.yml
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: CodeQL
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches: ["main"]
|
6 |
+
pull_request:
|
7 |
+
# The branches below must be a subset of the branches above
|
8 |
+
branches: ["main"]
|
9 |
+
schedule:
|
10 |
+
- cron: "20 13 * * 0"
|
11 |
+
|
12 |
+
jobs:
|
13 |
+
analyze:
|
14 |
+
name: Analyze
|
15 |
+
runs-on: ubuntu-latest
|
16 |
+
permissions:
|
17 |
+
actions: read
|
18 |
+
contents: read
|
19 |
+
security-events: write
|
20 |
+
|
21 |
+
strategy:
|
22 |
+
fail-fast: false
|
23 |
+
matrix:
|
24 |
+
language: ["python"]
|
25 |
+
|
26 |
+
steps:
|
27 |
+
- name: Checkout repository
|
28 |
+
uses: actions/checkout@v4
|
29 |
+
|
30 |
+
# Initializes the CodeQL tools for scanning.
|
31 |
+
- name: Initialize CodeQL
|
32 |
+
uses: github/codeql-action/init@v2
|
33 |
+
with:
|
34 |
+
languages: ${{ matrix.language }}
|
35 |
+
|
36 |
+
- name: Autobuild
|
37 |
+
uses: github/codeql-action/autobuild@v2
|
38 |
+
|
39 |
+
- name: Perform CodeQL Analysis
|
40 |
+
uses: github/codeql-action/analyze@v2
|
41 |
+
with:
|
42 |
+
category: "/language:${{matrix.language}}"
|
.github/workflows/docker-image.yml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Docker Image CI
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches: [ "main" ]
|
6 |
+
pull_request:
|
7 |
+
branches: [ "main" ]
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
docker:
|
11 |
+
name: Build Checks
|
12 |
+
runs-on: ubuntu-latest
|
13 |
+
steps:
|
14 |
+
- uses: actions/checkout@v4
|
15 |
+
|
16 |
+
- name: Build the Docker image
|
17 |
+
run: |
|
18 |
+
docker build . --file Dockerfile --tag image-bot:$(date +%s)
|
19 |
+
docker build . --file admin/Dockerfile --tag image-admin:$(date +%s)
|
.github/workflows/greetings.yml
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Greetings
|
2 |
+
|
3 |
+
on: [pull_request_target, issues]
|
4 |
+
|
5 |
+
jobs:
|
6 |
+
greeting:
|
7 |
+
runs-on: ubuntu-latest
|
8 |
+
permissions:
|
9 |
+
issues: write
|
10 |
+
pull-requests: write
|
11 |
+
steps:
|
12 |
+
- uses: actions/first-interaction@v1
|
13 |
+
with:
|
14 |
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
15 |
+
issue-message: "Hello! 👋 Thank you for opening your first issue. We appreciate your contribution! 🎉"
|
16 |
+
pr-message: "Hi there! 👋 Congratulations on your first pull request! Your efforts make a difference! 🚀"
|
.github/workflows/hadolint.yml
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Hadolint
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches: ["main"]
|
6 |
+
pull_request:
|
7 |
+
# The branches below must be a subset of the branches above
|
8 |
+
branches: ["main"]
|
9 |
+
schedule:
|
10 |
+
- cron: "20 13 * * 0"
|
11 |
+
|
12 |
+
permissions:
|
13 |
+
contents: read
|
14 |
+
|
15 |
+
jobs:
|
16 |
+
hadolint:
|
17 |
+
name: Run hadolint scanning
|
18 |
+
runs-on: ubuntu-latest
|
19 |
+
permissions:
|
20 |
+
contents: read # for actions/checkout to fetch code
|
21 |
+
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
22 |
+
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
23 |
+
steps:
|
24 |
+
- name: Checkout code
|
25 |
+
uses: actions/checkout@v4
|
26 |
+
|
27 |
+
- name: Run hadolint
|
28 |
+
uses: hadolint/hadolint-action@f988afea3da57ee48710a9795b6bb677cc901183
|
29 |
+
with:
|
30 |
+
dockerfile: ./Dockerfile
|
31 |
+
format: sarif
|
32 |
+
output-file: hadolint-results.sarif
|
33 |
+
no-fail: true
|
34 |
+
|
35 |
+
- name: Upload analysis results to GitHub
|
36 |
+
uses: github/codeql-action/upload-sarif@v2
|
37 |
+
with:
|
38 |
+
sarif_file: hadolint-results.sarif
|
39 |
+
wait-for-processing: true
|
.github/workflows/linters.yml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Linting
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches: [ main ]
|
6 |
+
pull_request:
|
7 |
+
branches: [ main ]
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
lint:
|
11 |
+
name: Run Linters
|
12 |
+
runs-on: ubuntu-latest
|
13 |
+
strategy:
|
14 |
+
matrix:
|
15 |
+
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
16 |
+
|
17 |
+
steps:
|
18 |
+
- uses: actions/checkout@v4
|
19 |
+
|
20 |
+
- name: Install Python ${{ matrix.python-version }}
|
21 |
+
uses: actions/setup-python@v4
|
22 |
+
with:
|
23 |
+
python-version: ${{ matrix.python-version }}
|
24 |
+
|
25 |
+
- name: Install dependencies
|
26 |
+
run: |
|
27 |
+
python -m pip install --upgrade pip
|
28 |
+
python -m pip install poetry
|
29 |
+
poetry install
|
30 |
+
|
31 |
+
- name: Check using Ruff
|
32 |
+
run: poetry run ruff check .
|
33 |
+
|
34 |
+
- name: Check using Ruff formatter
|
35 |
+
run: poetry run ruff format --check .
|
36 |
+
|
37 |
+
- name: Check Type Hints
|
38 |
+
run: poetry run mypy
|
.gitignore
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
pip-wheel-metadata/
|
24 |
+
share/python-wheels/
|
25 |
+
*.egg-info/
|
26 |
+
.installed.cfg
|
27 |
+
*.egg
|
28 |
+
MANIFEST
|
29 |
+
|
30 |
+
# PyInstaller
|
31 |
+
# Usually these files are written by a python script from a template
|
32 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
33 |
+
*.manifest
|
34 |
+
*.spec
|
35 |
+
|
36 |
+
# Installer logs
|
37 |
+
pip-log.txt
|
38 |
+
pip-delete-this-directory.txt
|
39 |
+
|
40 |
+
# Unit test / coverage reports
|
41 |
+
htmlcov/
|
42 |
+
.tox/
|
43 |
+
.nox/
|
44 |
+
.coverage
|
45 |
+
.coverage.*
|
46 |
+
.cache
|
47 |
+
nosetests.xml
|
48 |
+
coverage.xml
|
49 |
+
*.cover
|
50 |
+
*.py,cover
|
51 |
+
.hypothesis/
|
52 |
+
.pytest_cache/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
target/
|
76 |
+
|
77 |
+
# Jupyter Notebook
|
78 |
+
.ipynb_checkpoints
|
79 |
+
|
80 |
+
# IPython
|
81 |
+
profile_default/
|
82 |
+
ipython_config.py
|
83 |
+
|
84 |
+
# pyenv
|
85 |
+
.python-version
|
86 |
+
|
87 |
+
# pipenv
|
88 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
89 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
90 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
91 |
+
# install all needed dependencies.
|
92 |
+
#Pipfile.lock
|
93 |
+
|
94 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
95 |
+
__pypackages__/
|
96 |
+
|
97 |
+
# Celery stuff
|
98 |
+
celerybeat-schedule
|
99 |
+
celerybeat.pid
|
100 |
+
|
101 |
+
# SageMath parsed files
|
102 |
+
*.sage.py
|
103 |
+
|
104 |
+
# Environments
|
105 |
+
.env
|
106 |
+
.venv
|
107 |
+
env/
|
108 |
+
venv/
|
109 |
+
ENV/
|
110 |
+
env.bak/
|
111 |
+
venv.bak/
|
112 |
+
|
113 |
+
# Spyder project settings
|
114 |
+
.spyderproject
|
115 |
+
.spyproject
|
116 |
+
|
117 |
+
# Rope project settings
|
118 |
+
.ropeproject
|
119 |
+
|
120 |
+
# mkdocs documentation
|
121 |
+
/site
|
122 |
+
|
123 |
+
# mypy
|
124 |
+
.mypy_cache/
|
125 |
+
.dmypy.json
|
126 |
+
dmypy.json
|
127 |
+
|
128 |
+
# Pyre type checker
|
129 |
+
.pyre/
|
130 |
+
|
131 |
+
# Pycharm
|
132 |
+
.idea/
|
.pre-commit-config.yaml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
repos:
|
2 |
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
3 |
+
rev: v5.0.0
|
4 |
+
hooks:
|
5 |
+
- id: trailing-whitespace
|
6 |
+
- id: end-of-file-fixer
|
7 |
+
- id: check-yaml
|
8 |
+
- id: check-added-large-files
|
9 |
+
- id: check-merge-conflict
|
10 |
+
- id: check-byte-order-marker
|
11 |
+
- id: debug-statements
|
12 |
+
- id: detect-private-key
|
13 |
+
- id: check-ast
|
14 |
+
|
15 |
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
16 |
+
rev: v0.8.4
|
17 |
+
hooks:
|
18 |
+
- id: ruff
|
19 |
+
- id: ruff-format
|
Dockerfile
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10.13-alpine3.18
|
2 |
+
|
3 |
+
ENV POETRY_NO_INTERACTION=1 \
|
4 |
+
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
5 |
+
POETRY_VIRTUALENVS_CREATE=0 \
|
6 |
+
POETRY_HOME="/etc/poetry" \
|
7 |
+
POETRY_CACHE_DIR="/tmp/poetry_cache" \
|
8 |
+
POETRY_VERSION=1.8.3
|
9 |
+
|
10 |
+
WORKDIR /usr/src/app
|
11 |
+
|
12 |
+
COPY . .
|
13 |
+
|
14 |
+
RUN pip install --no-cache-dir "poetry==$POETRY_VERSION" \
|
15 |
+
&& poetry install --without admin --without dev --no-root \
|
16 |
+
&& pip uninstall -y poetry \
|
17 |
+
&& pybabel compile -d bot/locales \
|
18 |
+
&& rm -rf /home/appuser/.cache \
|
19 |
+
&& rm -rf $POETRY_CACHE_DIR \
|
20 |
+
&& adduser -D appuser \
|
21 |
+
&& chown -R appuser:appuser .
|
22 |
+
|
23 |
+
USER appuser
|
24 |
+
|
25 |
+
CMD ["python", "-m", "bot"]
|
LICENSE.md
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# GNU LESSER GENERAL PUBLIC LICENSE
|
2 |
+
|
3 |
+
Version 3, 29 June 2007
|
4 |
+
|
5 |
+
Copyright (C) 2007 Free Software Foundation, Inc.
|
6 |
+
<https://fsf.org/>
|
7 |
+
|
8 |
+
Everyone is permitted to copy and distribute verbatim copies of this
|
9 |
+
license document, but changing it is not allowed.
|
10 |
+
|
11 |
+
This version of the GNU Lesser General Public License incorporates the
|
12 |
+
terms and conditions of version 3 of the GNU General Public License,
|
13 |
+
supplemented by the additional permissions listed below.
|
14 |
+
|
15 |
+
## 0. Additional Definitions.
|
16 |
+
|
17 |
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
18 |
+
General Public License, and the "GNU GPL" refers to version 3 of the
|
19 |
+
GNU General Public License.
|
20 |
+
|
21 |
+
"The Library" refers to a covered work governed by this License, other
|
22 |
+
than an Application or a Combined Work as defined below.
|
23 |
+
|
24 |
+
An "Application" is any work that makes use of an interface provided
|
25 |
+
by the Library, but which is not otherwise based on the Library.
|
26 |
+
Defining a subclass of a class defined by the Library is deemed a mode
|
27 |
+
of using an interface provided by the Library.
|
28 |
+
|
29 |
+
A "Combined Work" is a work produced by combining or linking an
|
30 |
+
Application with the Library. The particular version of the Library
|
31 |
+
with which the Combined Work was made is also called the "Linked
|
32 |
+
Version".
|
33 |
+
|
34 |
+
The "Minimal Corresponding Source" for a Combined Work means the
|
35 |
+
Corresponding Source for the Combined Work, excluding any source code
|
36 |
+
for portions of the Combined Work that, considered in isolation, are
|
37 |
+
based on the Application, and not on the Linked Version.
|
38 |
+
|
39 |
+
The "Corresponding Application Code" for a Combined Work means the
|
40 |
+
object code and/or source code for the Application, including any data
|
41 |
+
and utility programs needed for reproducing the Combined Work from the
|
42 |
+
Application, but excluding the System Libraries of the Combined Work.
|
43 |
+
|
44 |
+
## 1. Exception to Section 3 of the GNU GPL.
|
45 |
+
|
46 |
+
You may convey a covered work under sections 3 and 4 of this License
|
47 |
+
without being bound by section 3 of the GNU GPL.
|
48 |
+
|
49 |
+
## 2. Conveying Modified Versions.
|
50 |
+
|
51 |
+
If you modify a copy of the Library, and, in your modifications, a
|
52 |
+
facility refers to a function or data to be supplied by an Application
|
53 |
+
that uses the facility (other than as an argument passed when the
|
54 |
+
facility is invoked), then you may convey a copy of the modified
|
55 |
+
version:
|
56 |
+
|
57 |
+
- a) under this License, provided that you make a good faith effort
|
58 |
+
to ensure that, in the event an Application does not supply the
|
59 |
+
function or data, the facility still operates, and performs
|
60 |
+
whatever part of its purpose remains meaningful, or
|
61 |
+
- b) under the GNU GPL, with none of the additional permissions of
|
62 |
+
this License applicable to that copy.
|
63 |
+
|
64 |
+
## 3. Object Code Incorporating Material from Library Header Files.
|
65 |
+
|
66 |
+
The object code form of an Application may incorporate material from a
|
67 |
+
header file that is part of the Library. You may convey such object
|
68 |
+
code under terms of your choice, provided that, if the incorporated
|
69 |
+
material is not limited to numerical parameters, data structure
|
70 |
+
layouts and accessors, or small macros, inline functions and templates
|
71 |
+
(ten or fewer lines in length), you do both of the following:
|
72 |
+
|
73 |
+
- a) Give prominent notice with each copy of the object code that
|
74 |
+
the Library is used in it and that the Library and its use are
|
75 |
+
covered by this License.
|
76 |
+
- b) Accompany the object code with a copy of the GNU GPL and this
|
77 |
+
license document.
|
78 |
+
|
79 |
+
## 4. Combined Works.
|
80 |
+
|
81 |
+
You may convey a Combined Work under terms of your choice that, taken
|
82 |
+
together, effectively do not restrict modification of the portions of
|
83 |
+
the Library contained in the Combined Work and reverse engineering for
|
84 |
+
debugging such modifications, if you also do each of the following:
|
85 |
+
|
86 |
+
- a) Give prominent notice with each copy of the Combined Work that
|
87 |
+
the Library is used in it and that the Library and its use are
|
88 |
+
covered by this License.
|
89 |
+
- b) Accompany the Combined Work with a copy of the GNU GPL and this
|
90 |
+
license document.
|
91 |
+
- c) For a Combined Work that displays copyright notices during
|
92 |
+
execution, include the copyright notice for the Library among
|
93 |
+
these notices, as well as a reference directing the user to the
|
94 |
+
copies of the GNU GPL and this license document.
|
95 |
+
- d) Do one of the following:
|
96 |
+
- 0) Convey the Minimal Corresponding Source under the terms of
|
97 |
+
this License, and the Corresponding Application Code in a form
|
98 |
+
suitable for, and under terms that permit, the user to
|
99 |
+
recombine or relink the Application with a modified version of
|
100 |
+
the Linked Version to produce a modified Combined Work, in the
|
101 |
+
manner specified by section 6 of the GNU GPL for conveying
|
102 |
+
Corresponding Source.
|
103 |
+
- 1) Use a suitable shared library mechanism for linking with
|
104 |
+
the Library. A suitable mechanism is one that (a) uses at run
|
105 |
+
time a copy of the Library already present on the user's
|
106 |
+
computer system, and (b) will operate properly with a modified
|
107 |
+
version of the Library that is interface-compatible with the
|
108 |
+
Linked Version.
|
109 |
+
- e) Provide Installation Information, but only if you would
|
110 |
+
otherwise be required to provide such information under section 6
|
111 |
+
of the GNU GPL, and only to the extent that such information is
|
112 |
+
necessary to install and execute a modified version of the
|
113 |
+
Combined Work produced by recombining or relinking the Application
|
114 |
+
with a modified version of the Linked Version. (If you use option
|
115 |
+
4d0, the Installation Information must accompany the Minimal
|
116 |
+
Corresponding Source and Corresponding Application Code. If you
|
117 |
+
use option 4d1, you must provide the Installation Information in
|
118 |
+
the manner specified by section 6 of the GNU GPL for conveying
|
119 |
+
Corresponding Source.)
|
120 |
+
|
121 |
+
## 5. Combined Libraries.
|
122 |
+
|
123 |
+
You may place library facilities that are a work based on the Library
|
124 |
+
side by side in a single library together with other library
|
125 |
+
facilities that are not Applications and are not covered by this
|
126 |
+
License, and convey such a combined library under terms of your
|
127 |
+
choice, if you do both of the following:
|
128 |
+
|
129 |
+
- a) Accompany the combined library with a copy of the same work
|
130 |
+
based on the Library, uncombined with any other library
|
131 |
+
facilities, conveyed under the terms of this License.
|
132 |
+
- b) Give prominent notice with the combined library that part of it
|
133 |
+
is a work based on the Library, and explaining where to find the
|
134 |
+
accompanying uncombined form of the same work.
|
135 |
+
|
136 |
+
## 6. Revised Versions of the GNU Lesser General Public License.
|
137 |
+
|
138 |
+
The Free Software Foundation may publish revised and/or new versions
|
139 |
+
of the GNU Lesser General Public License from time to time. Such new
|
140 |
+
versions will be similar in spirit to the present version, but may
|
141 |
+
differ in detail to address new problems or concerns.
|
142 |
+
|
143 |
+
Each version is given a distinguishing version number. If the Library
|
144 |
+
as you received it specifies that a certain numbered version of the
|
145 |
+
GNU Lesser General Public License "or any later version" applies to
|
146 |
+
it, you have the option of following the terms and conditions either
|
147 |
+
of that published version or of any later version published by the
|
148 |
+
Free Software Foundation. If the Library as you received it does not
|
149 |
+
specify a version number of the GNU Lesser General Public License, you
|
150 |
+
may choose any version of the GNU Lesser General Public License ever
|
151 |
+
published by the Free Software Foundation.
|
152 |
+
|
153 |
+
If the Library as you received it specifies that a proxy can decide
|
154 |
+
whether future versions of the GNU Lesser General Public License shall
|
155 |
+
apply, that proxy's public statement of acceptance of any version is
|
156 |
+
permanent authorization for you to choose that version for the
|
157 |
+
Library.
|
Makefile
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
include .env
|
2 |
+
export
|
3 |
+
|
4 |
+
LOCALES = bot/locales
|
5 |
+
|
6 |
+
.PHONY: help
|
7 |
+
|
8 |
+
help: ## Display this help screen
|
9 |
+
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
10 |
+
|
11 |
+
deps: ## Install dependencies
|
12 |
+
@poetry install --no-root
|
13 |
+
.PHONY: deps
|
14 |
+
|
15 |
+
compose-up: ## Run docker compose
|
16 |
+
docker compose up --build -d
|
17 |
+
.PHONY: compose-up
|
18 |
+
|
19 |
+
compose-down: ## Down docker compose
|
20 |
+
docker compose down
|
21 |
+
.PHONY: compose-down
|
22 |
+
|
23 |
+
compose-stop: ## docker compose stop
|
24 |
+
docker compose stop
|
25 |
+
|
26 |
+
compose-kill: ## docker compose kill
|
27 |
+
docker compose kill
|
28 |
+
|
29 |
+
compose-build: ## docker compose build
|
30 |
+
docker compose build
|
31 |
+
|
32 |
+
compose-ps: ## docker compose ps
|
33 |
+
docker compose ps
|
34 |
+
|
35 |
+
compose-exec: ## Exec command in app container
|
36 |
+
docker compose exec app $(args)
|
37 |
+
|
38 |
+
logs:
|
39 |
+
docker compose logs $(args) -f
|
40 |
+
|
41 |
+
# MIGRATIONS
|
42 |
+
mm: ## Create new migrations with args name in docker compose
|
43 |
+
docker compose exec bot alembic revision --autogenerate -m "$(args)"
|
44 |
+
.PHONY: mm
|
45 |
+
|
46 |
+
migrate: ## Upgrade migrations in docker compose
|
47 |
+
docker compose exec bot alembic upgrade head
|
48 |
+
.PHONY: migrate
|
49 |
+
|
50 |
+
downgrade: ## Downgrade to args name migration in docker compose
|
51 |
+
docker compose exec bot alembic downgrade $(args)
|
52 |
+
.PHONY: downgrade
|
53 |
+
|
54 |
+
# STYLE
|
55 |
+
check: ## Run linters to check code
|
56 |
+
@poetry run ruff check .
|
57 |
+
@poetry run ruff format --check .
|
58 |
+
.PHONY: check
|
59 |
+
|
60 |
+
format: ## Run linters to fix code
|
61 |
+
@poetry run ruff check --fix .
|
62 |
+
@poetry run ruff format .
|
63 |
+
.PHONY: format
|
64 |
+
|
65 |
+
clean: ## Delete all temporary and generated files
|
66 |
+
@rm -rf .pytest_cache .ruff_cache .hypothesis build/ -rf dist/ .eggs/ .coverage coverage.xml coverage.json htmlcov/ .mypy_cache
|
67 |
+
@find . -name '*.egg-info' -exec rm -rf {} +
|
68 |
+
@find . -name '*.egg' -exec rm -f {} +
|
69 |
+
@find . -name '*.pyc' -exec rm -f {} +
|
70 |
+
@find . -name '*.pyo' -exec rm -f {} +
|
71 |
+
@find . -name '*~' -exec rm -f {} +
|
72 |
+
@find . -name '__pycache__' -exec rm -rf {} +
|
73 |
+
@find . -name '.pytest_cache' -exec rm -rf {} +
|
74 |
+
@find . -name '.ipynb_checkpoints' -exec rm -rf {} +
|
75 |
+
.PHONY: clean
|
76 |
+
|
77 |
+
# BACKUPS
|
78 |
+
backup:
|
79 |
+
docker compose exec bot scripts/postgres/backup
|
80 |
+
.PHONY: backup
|
81 |
+
|
82 |
+
mount-docker-backup:
|
83 |
+
docker cp app_db:/backups/$(args) ./$(args)
|
84 |
+
.PHONY: mount-docker-backup
|
85 |
+
|
86 |
+
restore:
|
87 |
+
docker compose exec app_db scripts/postgres/restore $(args)
|
88 |
+
.PHONY: restore
|
89 |
+
|
90 |
+
# I18N
|
91 |
+
babel-extract: ## Extracts translatable strings from the source code into a .pot file
|
92 |
+
@poetry run pybabel extract --input-dirs=. -o $(LOCALES)/messages.pot
|
93 |
+
.PHONY: locales-extract
|
94 |
+
|
95 |
+
babel-update: ## Updates .pot files by merging changed strings into the existing .pot files
|
96 |
+
@poetry run pybabel update -d $(LOCALES) -i $(LOCALES)/messages.pot
|
97 |
+
.PHONY: locales-update
|
98 |
+
|
99 |
+
babel-compile: ## Compiles translation .po files into binary .mo files
|
100 |
+
@poetry run pybabel compile -d $(LOCALES)
|
101 |
+
.PHONY: locales-compile
|
102 |
+
|
103 |
+
babel: extract update
|
104 |
+
.PHONY: babel
|
README.md
CHANGED
@@ -1,10 +1,215 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h1 align="center"><em>Telegram bot template</em></h1>
|
2 |
+
|
3 |
+
<h3 align="center">
|
4 |
+
Best way to create a scalable telegram bot with analytics
|
5 |
+
</h3>
|
6 |
+
|
7 |
+
<p align="center">
|
8 |
+
<a href="https://github.com/donBarbos/telegram-bot-template/tags"><img alt="GitHub tag (latest SemVer)" src="https://img.shields.io/github/v/tag/donBarbos/telegram-bot-template"></a>
|
9 |
+
<a href="https://github.com/donBarbos/telegram-bot-template/actions/workflows/linters.yml"><img src="https://img.shields.io/github/actions/workflow/status/donBarbos/telegram-bot-template/linters.yml?label=linters" alt="Linters Status"></a>
|
10 |
+
<a href="https://github.com/donBarbos/telegram-bot-template/actions/workflows/docker-image.yml"><img src="https://img.shields.io/github/actions/workflow/status/donBarbos/telegram-bot-template/docker-image.yml?label=docker%20image" alt="Docker Build Status"></a>
|
11 |
+
<a href="https://www.python.org/downloads"><img src="https://img.shields.io/badge/python-3.10%2B-blue" alt="Python"></a>
|
12 |
+
<a href="https://github.com/donBarbos/telegram-bot-template/blob/main/LICENSE"><img src="https://img.shields.io/github/license/donbarbos/telegram-bot-template?color=blue" alt="License"></a>
|
13 |
+
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Code style"></a>
|
14 |
+
<p>
|
15 |
+
|
16 |
+
## ✨ Features
|
17 |
+
|
18 |
+
- [x] Admin Panel based on [`Flask-Admin-Dashboard`](https://github.com/jonalxh/Flask-Admin-Dashboard/) ([`Flask-Admin`](https://flask-admin.readthedocs.io/) + [`AdminLTE`](https://adminlte.io/) = ❤️ )
|
19 |
+
- [x] Product Analytics System: using [`Amplitude`](https://amplitude.com/) or [`Posthog`](https://posthog.com/) or [`Google Analytics`](https://analytics.google.com)
|
20 |
+
- [x] Performance Monitoring System: using [`Prometheus`](https://prometheus.io/) and [`Grafana`](https://grafana.com/)
|
21 |
+
- [x] Tracking System: using [`Sentry`](https://sentry.io/)
|
22 |
+
- [x] Seamless use of `Docker` and `Docker Compose`
|
23 |
+
- [x] Export all users in `.csv` (or `.xlsx`, `.json`, `yaml` from admin panel)
|
24 |
+
- [x] Configured CI pipeline from git hooks to github actions
|
25 |
+
- [x] [`SQLAlchemy V2`](https://pypi.org/project/SQLAlchemy/) is used to communicate with the database
|
26 |
+
- [x] Database Migrations with [`Alembic`](https://pypi.org/project/alembic/)
|
27 |
+
- [x] Ability to cache using decorator
|
28 |
+
- [x] Convenient validation using [`Pydantic V2`](https://pypi.org/project/pydantic/)
|
29 |
+
- [x] Internationalization (i18n) using GNU gettex and [`Babel`](https://pypi.org/project/Babel/)
|
30 |
+
|
31 |
+
## 🚀 How to Use
|
32 |
+
|
33 |
+
### 🐳 Running in Docker _(recommended method)_
|
34 |
+
|
35 |
+
- configure environment variables in `.env` file
|
36 |
+
|
37 |
+
- start services
|
38 |
+
|
39 |
+
```bash
|
40 |
+
docker compose up -d --build
|
41 |
+
```
|
42 |
+
|
43 |
+
### 💻 Running on Local Machine
|
44 |
+
|
45 |
+
- install dependencies using [Poetry](https://python-poetry.org "python package manager")
|
46 |
+
|
47 |
+
```bash
|
48 |
+
poetry install
|
49 |
+
```
|
50 |
+
|
51 |
+
- start the necessary services (at least the database and redis)
|
52 |
+
|
53 |
+
- configure environment variables in `.env` file
|
54 |
+
|
55 |
+
- start telegram bot
|
56 |
+
|
57 |
+
```bash
|
58 |
+
poetry run python -m bot
|
59 |
+
```
|
60 |
+
|
61 |
+
- start admin panel
|
62 |
+
|
63 |
+
```bash
|
64 |
+
poetry run gunicorn -c admin/gunicorn_conf.py
|
65 |
+
```
|
66 |
+
|
67 |
+
- make migrations
|
68 |
+
|
69 |
+
```bash
|
70 |
+
poetry run alembic upgrade head
|
71 |
+
```
|
72 |
+
|
73 |
+
## 🌍 Environment variables
|
74 |
+
|
75 |
+
to launch the bot you only need a token bot, database and redis settings, everything else can be left out
|
76 |
+
|
77 |
+
| name | description |
|
78 |
+
| ------------------------ | ------------------------------------------------------------------------------------------- |
|
79 |
+
| `BOT_TOKEN` | Telegram bot API token |
|
80 |
+
| `RATE_LIMIT` | Maximum number of requests allowed per minute for rate limiting |
|
81 |
+
| `DEBUG` | Enable or disable debugging mode (e.g., `True` or `False`) |
|
82 |
+
| `USE_WEBHOOK` | Flag to indicate whether the bot should use a webhook for updates (e.g., `True` or `False`) |
|
83 |
+
| `WEBHOOK_BASE_URL` | Base URL for the webhook |
|
84 |
+
| `WEBHOOK_PATH` | Path to receive updates from Telegram |
|
85 |
+
| `WEBHOOK_SECRET` | Secret key for securing the webhook communication |
|
86 |
+
| `WEBHOOK_HOST` | Hostname or IP address for the main application |
|
87 |
+
| `WEBHOOK_PORT` | Port number for the main application |
|
88 |
+
| `ADMIN_HOST` | Hostname or IP address for the admin panel |
|
89 |
+
| `ADMIN_PORT` | Port number for the admin panel |
|
90 |
+
| `DEFAULT_ADMIN_EMAIL` | Default email for the admin user |
|
91 |
+
| `DEFAULT_ADMIN_PASSWORD` | Default password for the admin user |
|
92 |
+
| `SECURITY_PASSWORD_HASH` | Hashing algorithm for user passwords (e.g., `bcrypt`) |
|
93 |
+
| `SECURITY_PASSWORD_SALT` | Salt value for user password hashing |
|
94 |
+
| `DB_HOST` | Hostname or IP address of the PostgreSQL database |
|
95 |
+
| `DB_PORT` | Port number for the PostgreSQL database |
|
96 |
+
| `DB_USER` | Username for authenticating with the PostgreSQL database |
|
97 |
+
| `DB_PASS` | Password for authenticating with the PostgreSQL database |
|
98 |
+
| `DB_NAME` | Name of the PostgreSQL database |
|
99 |
+
| `REDIS_HOST` | Hostname or IP address of the Redis database |
|
100 |
+
| `REDIS_PORT` | Port number for the Redis database |
|
101 |
+
| `REDIS_PASS` | Password for authenticating with the Redis database |
|
102 |
+
| `SENTRY_DSN` | Sentry DSN (Data Source Name) for error tracking |
|
103 |
+
| `AMPLITUDE_API_KEY` | API key for Amplitude analytics |
|
104 |
+
| `POSTHOG_API_KEY` | API key for PostHog analytics |
|
105 |
+
| `PROMETHEUS_PORT` | Port number for the Prometheus monitoring system |
|
106 |
+
| `GRAFANA_PORT` | Port number for the Grafana monitoring and visualization platform |
|
107 |
+
| `GRAFANA_ADMIN_USER` | Admin username for accessing Grafana |
|
108 |
+
| `GRAFANA_ADMIN_PASSWORD` | Admin password for accessing Grafana |
|
109 |
+
|
110 |
+
## 📂 Project Folder Structure
|
111 |
+
|
112 |
+
```bash
|
113 |
+
.
|
114 |
+
├── admin # Source code for admin panel
|
115 |
+
│ ├── __init__.py
|
116 |
+
│ ├── app.py # Main application module for the admin panel
|
117 |
+
│ ├── config.py # Configuration module for the admin panel
|
118 |
+
│ ├── Dockerfile # Dockerfile for admin panel
|
119 |
+
│ ├── gunicorn_conf.py # Gunicorn configuration file for serving admin panel
|
120 |
+
│ ├── static # Folder for static assets
|
121 |
+
│ │ ├── css/
|
122 |
+
│ │ ├── fonts/
|
123 |
+
│ │ ├── img/
|
124 |
+
│ │ ├── js/
|
125 |
+
│ │ └── plugins/
|
126 |
+
│ ├── templates # HTML templates for the admin panel
|
127 |
+
│ │ ├── admin/
|
128 |
+
│ │ ├── index.html
|
129 |
+
│ │ ├── my_master.html
|
130 |
+
│ │ └── security/
|
131 |
+
│ └── views # Custom View modules for handling web requests
|
132 |
+
│ ├── __init__.py
|
133 |
+
│ └── users.py
|
134 |
+
│
|
135 |
+
├── bot # Source code for Telegram Bot
|
136 |
+
│ ├── __init__.py
|
137 |
+
│ ├── __main__.py # Main entry point to launch the bot
|
138 |
+
│ ├── analytics/ # Interaction with analytics services (e.g., Amplitude or Google Analytics)
|
139 |
+
│ ├── cache/ # Logic for using Redis cache
|
140 |
+
│ ├── core/ # Settings for application and other core components
|
141 |
+
│ ├── database/ # Database functions and SQLAlchemy Models
|
142 |
+
│ ├── filters/ # Filters for processing incoming messages or updates
|
143 |
+
│ ├── handlers/ # Handlers for processing user commands and interactions
|
144 |
+
│ ├── keyboards # Modules for creating custom keyboards
|
145 |
+
│ │ ├── default_commands.py # Default command keyboards
|
146 |
+
│ │ ├── __init__.py
|
147 |
+
│ │ ├── inline/ # Inline keyboards
|
148 |
+
│ │ └── reply/ # Reply keyboards
|
149 |
+
│ ├── locales/ # Localization files for supporting multiple languages
|
150 |
+
│ ├── middlewares/ # Middleware modules for processing incoming updates
|
151 |
+
│ ├── services/ # Business logic for application
|
152 |
+
│ └── utils/ # Utility functions and helper modules
|
153 |
+
│
|
154 |
+
├── migrations # Database Migrations managed by Alembic
|
155 |
+
│ ├── env.py # Environment setup for Alembic
|
156 |
+
│ ├── __init__.py
|
157 |
+
│ ├── README
|
158 |
+
│ ├── script.py.mako # Script template for generating migrations
|
159 |
+
│ └── versions/ # Folder containing individual migration scripts
|
160 |
+
│
|
161 |
+
├── configs # Config folder for Monitoring (Prometheus, Node-exporter and Grafana)
|
162 |
+
│ ├── grafana # Configuration files for Grafana
|
163 |
+
│ │ └── datasource.yml
|
164 |
+
│ └── prometheus # Configuration files for Prometheus
|
165 |
+
│ └── prometheus.yml
|
166 |
+
│
|
167 |
+
├── scripts/ # Sripts folder
|
168 |
+
├── Makefile # List of commands for standard
|
169 |
+
├── alembic.ini # Configuration file for migrations
|
170 |
+
├── docker-compose.yml # Docker Compose configuration file for orchestrating containers
|
171 |
+
├── Dockerfile # Dockerfile for Telegram Bot
|
172 |
+
├── LICENSE.md # License file for the project
|
173 |
+
├── poetry.lock # Lock file for Poetry dependency management
|
174 |
+
├── pyproject.toml # Configuration file for Python projects, including build tools, dependencies, and metadata
|
175 |
+
└── README.md # Documentation
|
176 |
+
```
|
177 |
+
|
178 |
+
## 🔧 Tech Stack
|
179 |
+
|
180 |
+
- `sqlalchemy` — object-relational mapping (ORM) library that provides a set of high-level API for interacting with relational databases
|
181 |
+
- `asyncpg` — asynchronous PostgreSQL database client library
|
182 |
+
- `aiogram` — asynchronous framework for Telegram Bot API
|
183 |
+
- `flask-admin` — simple and extensible administrative interface framework
|
184 |
+
- `loguru` — third party library for logging in Python
|
185 |
+
- `poetry` — development workflow
|
186 |
+
- `docker` — to automate deployment
|
187 |
+
- `postgres` — powerful, open source object-relational database system
|
188 |
+
- `pgbouncer` — connection pooler for PostgreSQL database
|
189 |
+
- `redis` — in-memory data structure store used as a cache and FSM
|
190 |
+
- `prometheus` — time series database for collecting metrics from various systems
|
191 |
+
- `grafana` — visualization and analysis from various sources, including Prometheus
|
192 |
+
|
193 |
+
## ⭐ Star History
|
194 |
+
|
195 |
+
[](https://star-history.com/#donBarbos/telegram-bot-template&Date)
|
196 |
+
|
197 |
+
## 👷 Contributing
|
198 |
+
|
199 |
+
First off, thanks for taking the time to contribute! Contributions are what makes the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are greatly appreciated.
|
200 |
+
|
201 |
+
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
|
202 |
+
|
203 |
+
1. `Fork` this repository
|
204 |
+
2. Create a `branch`
|
205 |
+
3. `Commit` your changes
|
206 |
+
4. `Push` your `commits` to the `branch`
|
207 |
+
5. Submit a `pull request`
|
208 |
+
|
209 |
+
## 📝 License
|
210 |
+
|
211 |
+
Distributed under the LGPL-3.0 license. See [`LICENSE`](./LICENSE.md) for more information.
|
212 |
+
|
213 |
+
## 📢 Contact
|
214 |
+
|
215 |
+
[donbarbos](https://github.com/donBarbos): [email protected]
|
admin/Dockerfile
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10.13-alpine3.18
|
2 |
+
|
3 |
+
ENV POETRY_NO_INTERACTION=1 \
|
4 |
+
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
5 |
+
POETRY_VIRTUALENVS_CREATE=0 \
|
6 |
+
POETRY_HOME="/etc/poetry" \
|
7 |
+
POETRY_CACHE_DIR="/tmp/poetry_cache" \
|
8 |
+
POETRY_VERSION=1.8.3
|
9 |
+
|
10 |
+
WORKDIR /usr/src/app
|
11 |
+
|
12 |
+
COPY . .
|
13 |
+
|
14 |
+
RUN pip install --no-cache-dir "poetry==$POETRY_VERSION" \
|
15 |
+
&& poetry install --without bot --without dev --no-root \
|
16 |
+
&& pip uninstall -y poetry \
|
17 |
+
&& rm -rf /root/.cache \
|
18 |
+
&& rm -rf $POETRY_CACHE_DIR \
|
19 |
+
&& adduser -D appuser \
|
20 |
+
&& chown -R appuser:appuser .
|
21 |
+
|
22 |
+
USER appuser
|
23 |
+
|
24 |
+
CMD ["gunicorn", "-c", "admin/gunicorn_conf.py"]
|
admin/__init__.py
ADDED
File without changes
|
admin/app.py
ADDED
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ruff: noqa: RUF012
|
2 |
+
from __future__ import annotations
|
3 |
+
from datetime import datetime, timedelta, timezone
|
4 |
+
from typing import TYPE_CHECKING, Any
|
5 |
+
|
6 |
+
from flask import Flask, abort, redirect, request, url_for
|
7 |
+
from flask_admin import Admin, AdminIndexView, expose, helpers
|
8 |
+
from flask_admin.consts import ICON_TYPE_FONT_AWESOME
|
9 |
+
from flask_admin.contrib.sqla import ModelView
|
10 |
+
from flask_babel import Babel
|
11 |
+
from flask_caching import Cache
|
12 |
+
from flask_login import current_user
|
13 |
+
from flask_security.core import RoleMixin, Security, UserMixin
|
14 |
+
from flask_security.datastore import SQLAlchemyUserDatastore
|
15 |
+
from flask_security.utils import hash_password
|
16 |
+
from flask_sqlalchemy import SQLAlchemy
|
17 |
+
from sqlalchemy import inspect
|
18 |
+
from wtforms import PasswordField
|
19 |
+
|
20 |
+
from admin.views.users import UserView as AppUserView
|
21 |
+
from bot.database.models import UserModel as AppUserModel
|
22 |
+
|
23 |
+
if TYPE_CHECKING:
|
24 |
+
from werkzeug.wrappers.response import Response
|
25 |
+
|
26 |
+
# Create Flask application
|
27 |
+
app = Flask(__name__)
|
28 |
+
app.config.from_pyfile("config.py")
|
29 |
+
db = SQLAlchemy(app)
|
30 |
+
cache = Cache(app)
|
31 |
+
babel = Babel(app)
|
32 |
+
|
33 |
+
# Define models
|
34 |
+
roles_admins = db.Table(
|
35 |
+
"roles_admins",
|
36 |
+
db.Column("admin_id", db.Integer(), db.ForeignKey("admin.id")),
|
37 |
+
db.Column("role_id", db.Integer(), db.ForeignKey("role.id")),
|
38 |
+
)
|
39 |
+
|
40 |
+
|
41 |
+
class RoleModel(db.Model, RoleMixin):
|
42 |
+
__tablename__ = "role"
|
43 |
+
|
44 |
+
id = db.Column(db.Integer(), primary_key=True)
|
45 |
+
name = db.Column(db.String(80), unique=True)
|
46 |
+
description = db.Column(db.String(255))
|
47 |
+
|
48 |
+
def __str__(self) -> str:
|
49 |
+
return self.name
|
50 |
+
|
51 |
+
|
52 |
+
class AdminModel(db.Model, UserMixin):
|
53 |
+
__tablename__ = "admin"
|
54 |
+
|
55 |
+
id = db.Column(db.Integer, primary_key=True)
|
56 |
+
first_name = db.Column(db.String(255))
|
57 |
+
last_name = db.Column(db.String(255))
|
58 |
+
email = db.Column(db.String(255), unique=True, nullable=False)
|
59 |
+
password = db.Column(db.String(255), nullable=False)
|
60 |
+
active = db.Column(db.Boolean())
|
61 |
+
confirmed_at = db.Column(db.DateTime(), default=datetime.utcnow)
|
62 |
+
fs_uniquifier = db.Column(db.String(255), unique=True)
|
63 |
+
roles = db.relationship("RoleModel", secondary=roles_admins, backref=db.backref("admins", lazy="dynamic"))
|
64 |
+
|
65 |
+
def __str__(self) -> str:
|
66 |
+
return self.email
|
67 |
+
|
68 |
+
|
69 |
+
# Setup Flask-Security
|
70 |
+
admin_datastore = SQLAlchemyUserDatastore(db, AdminModel, RoleModel)
|
71 |
+
security = Security(app, admin_datastore)
|
72 |
+
|
73 |
+
|
74 |
+
# Create customized model view class
|
75 |
+
class RoleView(ModelView):
|
76 |
+
can_delete = False
|
77 |
+
can_edit = False
|
78 |
+
can_create = False
|
79 |
+
can_view_details = False
|
80 |
+
edit_modal = True
|
81 |
+
create_modal = True
|
82 |
+
can_export = False
|
83 |
+
details_modal = True
|
84 |
+
|
85 |
+
def is_accessible(self) -> bool:
|
86 |
+
if not current_user.is_active or not current_user.is_authenticated:
|
87 |
+
return False
|
88 |
+
|
89 |
+
return bool(current_user.has_role("superuser"))
|
90 |
+
|
91 |
+
def _handle_view(self, _name: str, **_kwargs: dict) -> Response | None:
|
92 |
+
"""Override builtin _handle_view in order to redirect users when a view is not accessible."""
|
93 |
+
if not self.is_accessible():
|
94 |
+
if current_user.is_authenticated:
|
95 |
+
# permission denied
|
96 |
+
abort(403)
|
97 |
+
else:
|
98 |
+
# login
|
99 |
+
return redirect(url_for("security.login", next=request.url))
|
100 |
+
return None
|
101 |
+
|
102 |
+
|
103 |
+
class AdminView(RoleView):
|
104 |
+
can_view_details = True
|
105 |
+
can_delete = True
|
106 |
+
can_edit = True
|
107 |
+
can_export = True
|
108 |
+
can_create = True
|
109 |
+
export_types = ["csv", "xlsx", "json", "yaml"]
|
110 |
+
|
111 |
+
column_editable_list = ["email", "first_name", "last_name"]
|
112 |
+
column_searchable_list = column_editable_list
|
113 |
+
column_exclude_list = ["password"]
|
114 |
+
form_excluded_columns = ["confirmed_at"]
|
115 |
+
column_details_exclude_list = column_exclude_list
|
116 |
+
column_filters = column_editable_list
|
117 |
+
form_overrides = {"password": PasswordField}
|
118 |
+
|
119 |
+
|
120 |
+
# Flask views
|
121 |
+
def get_orders_count() -> int:
|
122 |
+
return 0
|
123 |
+
|
124 |
+
|
125 |
+
def get_user_count() -> int:
|
126 |
+
return db.session.query(AppUserModel).count()
|
127 |
+
|
128 |
+
|
129 |
+
def get_new_user_count(days_before: int = 1) -> int:
|
130 |
+
period_start = datetime.now(timezone.utc) - timedelta(days=days_before)
|
131 |
+
return db.session.query(AppUserModel).filter(AppUserModel.created_at >= period_start).count()
|
132 |
+
|
133 |
+
|
134 |
+
class CustomAdminIndexView(AdminIndexView):
|
135 |
+
@expose("/")
|
136 |
+
def index(self) -> str:
|
137 |
+
days_before: int = 1
|
138 |
+
period_start = datetime.now(timezone.utc) - timedelta(days=days_before)
|
139 |
+
order_count = get_orders_count()
|
140 |
+
user_count = get_user_count()
|
141 |
+
new_user_count = get_new_user_count(days_before)
|
142 |
+
new_user_count = get_new_user_count(days_before)
|
143 |
+
|
144 |
+
return self.render(
|
145 |
+
"admin/index.html",
|
146 |
+
order_count=order_count,
|
147 |
+
user_count=user_count,
|
148 |
+
new_user_count=new_user_count,
|
149 |
+
period_start=period_start,
|
150 |
+
default_email=app.config.get("DEFAULT_ADMIN_EMAIL"),
|
151 |
+
default_password=app.config.get("DEFAULT_ADMIN_PASSWORD"),
|
152 |
+
)
|
153 |
+
|
154 |
+
|
155 |
+
@app.route("/")
|
156 |
+
def index() -> Response:
|
157 |
+
return redirect(url_for("admin.index"))
|
158 |
+
|
159 |
+
|
160 |
+
# Initializing the admin panel
|
161 |
+
admin = Admin(
|
162 |
+
app,
|
163 |
+
name="Telegram Bot",
|
164 |
+
base_template="my_master.html",
|
165 |
+
index_view=CustomAdminIndexView(
|
166 |
+
name="Home",
|
167 |
+
url="/admin",
|
168 |
+
menu_icon_type=ICON_TYPE_FONT_AWESOME,
|
169 |
+
menu_icon_value="fa-home",
|
170 |
+
),
|
171 |
+
template_mode="bootstrap4",
|
172 |
+
)
|
173 |
+
|
174 |
+
admin.add_view(
|
175 |
+
AppUserView(
|
176 |
+
AppUserModel,
|
177 |
+
db.session,
|
178 |
+
menu_icon_type=ICON_TYPE_FONT_AWESOME,
|
179 |
+
menu_icon_value="fa-users",
|
180 |
+
name="Users",
|
181 |
+
endpoint="users",
|
182 |
+
),
|
183 |
+
)
|
184 |
+
|
185 |
+
admin.add_view(
|
186 |
+
AdminView(
|
187 |
+
AdminModel,
|
188 |
+
db.session,
|
189 |
+
menu_icon_type=ICON_TYPE_FONT_AWESOME,
|
190 |
+
menu_icon_value="fa-black-tie",
|
191 |
+
name="Admins",
|
192 |
+
endpoint="admins",
|
193 |
+
),
|
194 |
+
)
|
195 |
+
admin.add_view(
|
196 |
+
RoleView(
|
197 |
+
RoleModel,
|
198 |
+
db.session,
|
199 |
+
menu_icon_type=ICON_TYPE_FONT_AWESOME,
|
200 |
+
menu_icon_value="fa-tags",
|
201 |
+
name="Roles",
|
202 |
+
endpoint="roles",
|
203 |
+
),
|
204 |
+
)
|
205 |
+
|
206 |
+
|
207 |
+
# define a context processor for merging flask-admin's template context into the flask-security views.
|
208 |
+
@security.context_processor
|
209 |
+
def security_context_processor() -> dict[str, Any]:
|
210 |
+
return {
|
211 |
+
"admin_base_template": admin.base_template,
|
212 |
+
"admin_view": admin.index_view,
|
213 |
+
"h": helpers,
|
214 |
+
"get_url": url_for,
|
215 |
+
}
|
216 |
+
|
217 |
+
|
218 |
+
def init_db() -> None:
|
219 |
+
inspector = inspect(db.engine)
|
220 |
+
if inspector.has_table("admin") and inspector.has_table("role"):
|
221 |
+
return
|
222 |
+
|
223 |
+
db.create_all()
|
224 |
+
|
225 |
+
admin_role = RoleModel(name="user", description="does not have access to other administrators")
|
226 |
+
super_admin_role = RoleModel(name="superuser", description="has access to manage all administrators")
|
227 |
+
db.session.add(admin_role)
|
228 |
+
db.session.add(super_admin_role)
|
229 |
+
db.session.commit()
|
230 |
+
|
231 |
+
admin_datastore.create_user(
|
232 |
+
first_name="Admin",
|
233 |
+
email=app.config.get("DEFAULT_ADMIN_EMAIL"),
|
234 |
+
password=hash_password(str(app.config.get("DEFAULT_ADMIN_PASSWORD"))),
|
235 |
+
roles=[admin_role, super_admin_role],
|
236 |
+
)
|
237 |
+
|
238 |
+
db.session.commit()
|
239 |
+
|
240 |
+
return
|
241 |
+
|
242 |
+
|
243 |
+
with app.app_context():
|
244 |
+
init_db()
|
245 |
+
|
246 |
+
if __name__ == "__main__":
|
247 |
+
app.run(host=app.config.get("ADMIN_HOST"), port=app.config.get("ADMIN_PORT"), debug=app.config.get("DEBUG"))
|
admin/config.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
import os
|
3 |
+
|
4 |
+
from dotenv import load_dotenv
|
5 |
+
|
6 |
+
load_dotenv()
|
7 |
+
|
8 |
+
ADMIN_HOST: str = os.getenv("ADMIN_HOST") or "localhost"
|
9 |
+
ADMIN_PORT: int = int(os.getenv("ADMIN_PORT") or 5000)
|
10 |
+
DEFAULT_ADMIN_EMAIL: str = os.getenv("DEFAULT_ADMIN_EMAIL") or "[email protected]"
|
11 |
+
DEFAULT_ADMIN_PASSWORD: str = os.getenv("DEFAULT_ADMIN_PASSWORD") or "admin"
|
12 |
+
|
13 |
+
DEBUG: bool = str(os.getenv("DEBUG")).lower() == "true"
|
14 |
+
|
15 |
+
BABEL_DEFAULT_LOCALE = os.getenv("BABEL_DEFAULT_LOCALE") or "en"
|
16 |
+
|
17 |
+
# Create dummy secrey key so we can use sessions
|
18 |
+
SECRET_KEY: str = os.getenv("SECRET_KEY") or "x%#3&%giwv8f0+%r946en7z&d@9*rc$sl0qoql56xr%bh^w2mj"
|
19 |
+
|
20 |
+
|
21 |
+
# SQLAlchemy config
|
22 |
+
def database_url() -> str:
|
23 |
+
db_host: str = os.getenv("DB_HOST") or "localhost"
|
24 |
+
db_port: int = int(os.getenv("DB_PORT") or 5432)
|
25 |
+
db_user: str = os.getenv("DB_USER") or "postgres"
|
26 |
+
db_pass: str | None = os.getenv("DB_PASS")
|
27 |
+
db_name: str = os.getenv("DB_NAME") or "postgres"
|
28 |
+
|
29 |
+
if db_pass:
|
30 |
+
return f"postgresql://{db_user}:{db_pass}@{db_host}:{db_port}/{db_name}"
|
31 |
+
return f"postgresql://{db_user}@{db_host}:{db_port}/{db_name}"
|
32 |
+
|
33 |
+
|
34 |
+
SQLALCHEMY_DATABASE_URI: str = database_url()
|
35 |
+
SQLALCHEMY_ECHO = False
|
36 |
+
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
37 |
+
|
38 |
+
# Flask-Security config
|
39 |
+
SECURITY_URL_PREFIX = "/admin"
|
40 |
+
SECURITY_PASSWORD_HASH: str = os.getenv("SECURITY_PASSWORD_HASH") or "pbkdf2_sha512"
|
41 |
+
SECURITY_PASSWORD_SALT: str = os.getenv("SECURITY_PASSWORD_SALT") or "ATGUOHAELKiubahiughaerGOJAEGj"
|
42 |
+
|
43 |
+
# Flask-Security URLs, overridden because they don't put a / at the end
|
44 |
+
SECURITY_LOGIN_URL = "/login/"
|
45 |
+
SECURITY_LOGOUT_URL = "/logout/"
|
46 |
+
SECURITY_REGISTER_URL = "/register/"
|
47 |
+
|
48 |
+
SECURITY_POST_LOGIN_VIEW = "/admin/"
|
49 |
+
SECURITY_POST_LOGOUT_VIEW = "/admin/"
|
50 |
+
SECURITY_POST_REGISTER_VIEW = "/admin/"
|
51 |
+
|
52 |
+
# Flask-Security features
|
53 |
+
SECURITY_REGISTERABLE = True
|
54 |
+
SECURITY_SEND_REGISTER_EMAIL = False
|
55 |
+
|
56 |
+
# Cache config
|
57 |
+
CACHE_TYPE = "SimpleCache"
|
58 |
+
CACHE_DEFAULT_TIMEOUT = 300
|
admin/gunicorn_conf.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from admin.config import ADMIN_HOST, ADMIN_PORT, DEBUG
|
2 |
+
|
3 |
+
reload = DEBUG
|
4 |
+
|
5 |
+
# The address and port your Flask app will listen on
|
6 |
+
bind = f"{ADMIN_HOST}:{ADMIN_PORT}"
|
7 |
+
|
8 |
+
# Number of workers. Gunicorn recommends 2-4 workers per core
|
9 |
+
workers = 1
|
10 |
+
|
11 |
+
# The location of your Flask app
|
12 |
+
wsgi_app = "admin.app:app"
|
13 |
+
|
14 |
+
# Set logging - this example logs to a file
|
15 |
+
accesslog = "-"
|
16 |
+
errorlog = "-"
|
admin/static/fonts/glyphicons-halflings-regular.eot
ADDED
Binary file (20.1 kB). View file
|
|
admin/static/fonts/glyphicons-halflings-regular.svg
ADDED
|
admin/static/fonts/glyphicons-halflings-regular.ttf
ADDED
Binary file (45.4 kB). View file
|
|
admin/static/fonts/glyphicons-halflings-regular.woff
ADDED
Binary file (23.4 kB). View file
|
|
admin/static/fonts/glyphicons-halflings-regular.woff2
ADDED
Binary file (18 kB). View file
|
|
admin/static/js/pages/dashboard.js
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
* Author: Abdullah A Almsaeed
|
3 |
+
* Date: 4 Jan 2014
|
4 |
+
* Description:
|
5 |
+
* This is a demo file used only for the main dashboard (index.html)
|
6 |
+
**/
|
7 |
+
|
8 |
+
$(function () {
|
9 |
+
|
10 |
+
"use strict";
|
11 |
+
|
12 |
+
//Make the dashboard widgets sortable Using jquery UI
|
13 |
+
$(".connectedSortable").sortable({
|
14 |
+
placeholder: "sort-highlight",
|
15 |
+
connectWith: ".connectedSortable",
|
16 |
+
handle: ".box-header, .nav-tabs",
|
17 |
+
forcePlaceholderSize: true,
|
18 |
+
zIndex: 999999
|
19 |
+
});
|
20 |
+
$(".connectedSortable .box-header, .connectedSortable .nav-tabs-custom").css("cursor", "move");
|
21 |
+
|
22 |
+
//jQuery UI sortable for the todo list
|
23 |
+
$(".todo-list").sortable({
|
24 |
+
placeholder: "sort-highlight",
|
25 |
+
handle: ".handle",
|
26 |
+
forcePlaceholderSize: true,
|
27 |
+
zIndex: 999999
|
28 |
+
});
|
29 |
+
|
30 |
+
//bootstrap WYSIHTML5 - text editor
|
31 |
+
$(".textarea").wysihtml5();
|
32 |
+
|
33 |
+
$('.daterange').daterangepicker({
|
34 |
+
ranges: {
|
35 |
+
'Today': [moment(), moment()],
|
36 |
+
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
|
37 |
+
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
|
38 |
+
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
|
39 |
+
'This Month': [moment().startOf('month'), moment().endOf('month')],
|
40 |
+
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
|
41 |
+
},
|
42 |
+
startDate: moment().subtract(29, 'days'),
|
43 |
+
endDate: moment()
|
44 |
+
}, function (start, end) {
|
45 |
+
window.alert("You chose: " + start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
|
46 |
+
});
|
47 |
+
|
48 |
+
/* jQueryKnob */
|
49 |
+
$(".knob").knob();
|
50 |
+
|
51 |
+
//jvectormap data
|
52 |
+
var visitorsData = {
|
53 |
+
"US": 398, //USA
|
54 |
+
"SA": 400, //Saudi Arabia
|
55 |
+
"CA": 1000, //Canada
|
56 |
+
"DE": 500, //Germany
|
57 |
+
"FR": 760, //France
|
58 |
+
"CN": 300, //China
|
59 |
+
"AU": 700, //Australia
|
60 |
+
"BR": 600, //Brazil
|
61 |
+
"IN": 800, //India
|
62 |
+
"GB": 320, //Great Britain
|
63 |
+
"RU": 3000 //Russia
|
64 |
+
};
|
65 |
+
//World map by jvectormap
|
66 |
+
$('#world-map').vectorMap({
|
67 |
+
map: 'world_mill_en',
|
68 |
+
backgroundColor: "transparent",
|
69 |
+
regionStyle: {
|
70 |
+
initial: {
|
71 |
+
fill: '#e4e4e4',
|
72 |
+
"fill-opacity": 1,
|
73 |
+
stroke: 'none',
|
74 |
+
"stroke-width": 0,
|
75 |
+
"stroke-opacity": 1
|
76 |
+
}
|
77 |
+
},
|
78 |
+
series: {
|
79 |
+
regions: [{
|
80 |
+
values: visitorsData,
|
81 |
+
scale: ["#92c1dc", "#ebf4f9"],
|
82 |
+
normalizeFunction: 'polynomial'
|
83 |
+
}]
|
84 |
+
},
|
85 |
+
onRegionLabelShow: function (e, el, code) {
|
86 |
+
if (typeof visitorsData[code] != "undefined")
|
87 |
+
el.html(el.html() + ': ' + visitorsData[code] + ' new visitors');
|
88 |
+
}
|
89 |
+
});
|
90 |
+
|
91 |
+
//Sparkline charts
|
92 |
+
var myvalues = [1000, 1200, 920, 927, 931, 1027, 819, 930, 1021];
|
93 |
+
$('#sparkline-1').sparkline(myvalues, {
|
94 |
+
type: 'line',
|
95 |
+
lineColor: '#92c1dc',
|
96 |
+
fillColor: "#ebf4f9",
|
97 |
+
height: '50',
|
98 |
+
width: '80'
|
99 |
+
});
|
100 |
+
myvalues = [515, 519, 520, 522, 652, 810, 370, 627, 319, 630, 921];
|
101 |
+
$('#sparkline-2').sparkline(myvalues, {
|
102 |
+
type: 'line',
|
103 |
+
lineColor: '#92c1dc',
|
104 |
+
fillColor: "#ebf4f9",
|
105 |
+
height: '50',
|
106 |
+
width: '80'
|
107 |
+
});
|
108 |
+
myvalues = [15, 19, 20, 22, 33, 27, 31, 27, 19, 30, 21];
|
109 |
+
$('#sparkline-3').sparkline(myvalues, {
|
110 |
+
type: 'line',
|
111 |
+
lineColor: '#92c1dc',
|
112 |
+
fillColor: "#ebf4f9",
|
113 |
+
height: '50',
|
114 |
+
width: '80'
|
115 |
+
});
|
116 |
+
|
117 |
+
//The Calender
|
118 |
+
$("#calendar").datepicker();
|
119 |
+
|
120 |
+
//SLIMSCROLL FOR CHAT WIDGET
|
121 |
+
$('#chat-box').slimScroll({
|
122 |
+
height: '250px'
|
123 |
+
});
|
124 |
+
|
125 |
+
/* Morris.js Charts */
|
126 |
+
// Sales chart
|
127 |
+
var area = new Morris.Area({
|
128 |
+
element: 'revenue-chart',
|
129 |
+
resize: true,
|
130 |
+
data: [
|
131 |
+
{y: '2011 Q1', item1: 2666, item2: 2666},
|
132 |
+
{y: '2011 Q2', item1: 2778, item2: 2294},
|
133 |
+
{y: '2011 Q3', item1: 4912, item2: 1969},
|
134 |
+
{y: '2011 Q4', item1: 3767, item2: 3597},
|
135 |
+
{y: '2012 Q1', item1: 6810, item2: 1914},
|
136 |
+
{y: '2012 Q2', item1: 5670, item2: 4293},
|
137 |
+
{y: '2012 Q3', item1: 4820, item2: 3795},
|
138 |
+
{y: '2012 Q4', item1: 15073, item2: 5967},
|
139 |
+
{y: '2013 Q1', item1: 10687, item2: 4460},
|
140 |
+
{y: '2013 Q2', item1: 8432, item2: 5713}
|
141 |
+
],
|
142 |
+
xkey: 'y',
|
143 |
+
ykeys: ['item1', 'item2'],
|
144 |
+
labels: ['Item 1', 'Item 2'],
|
145 |
+
lineColors: ['#a0d0e0', '#3c8dbc'],
|
146 |
+
hideHover: 'auto'
|
147 |
+
});
|
148 |
+
var line = new Morris.Line({
|
149 |
+
element: 'line-chart',
|
150 |
+
resize: true,
|
151 |
+
data: [
|
152 |
+
{y: '2011 Q1', item1: 2666},
|
153 |
+
{y: '2011 Q2', item1: 2778},
|
154 |
+
{y: '2011 Q3', item1: 4912},
|
155 |
+
{y: '2011 Q4', item1: 3767},
|
156 |
+
{y: '2012 Q1', item1: 6810},
|
157 |
+
{y: '2012 Q2', item1: 5670},
|
158 |
+
{y: '2012 Q3', item1: 4820},
|
159 |
+
{y: '2012 Q4', item1: 15073},
|
160 |
+
{y: '2013 Q1', item1: 10687},
|
161 |
+
{y: '2013 Q2', item1: 8432}
|
162 |
+
],
|
163 |
+
xkey: 'y',
|
164 |
+
ykeys: ['item1'],
|
165 |
+
labels: ['Item 1'],
|
166 |
+
lineColors: ['#efefef'],
|
167 |
+
lineWidth: 2,
|
168 |
+
hideHover: 'auto',
|
169 |
+
gridTextColor: "#fff",
|
170 |
+
gridStrokeWidth: 0.4,
|
171 |
+
pointSize: 4,
|
172 |
+
pointStrokeColors: ["#efefef"],
|
173 |
+
gridLineColor: "#efefef",
|
174 |
+
gridTextFamily: "Open Sans",
|
175 |
+
gridTextSize: 10
|
176 |
+
});
|
177 |
+
|
178 |
+
//Donut Chart
|
179 |
+
var donut = new Morris.Donut({
|
180 |
+
element: 'sales-chart',
|
181 |
+
resize: true,
|
182 |
+
colors: ["#3c8dbc", "#f56954", "#00a65a"],
|
183 |
+
data: [
|
184 |
+
{label: "Download Sales", value: 12},
|
185 |
+
{label: "In-Store Sales", value: 30},
|
186 |
+
{label: "Mail-Order Sales", value: 20}
|
187 |
+
],
|
188 |
+
hideHover: 'auto'
|
189 |
+
});
|
190 |
+
|
191 |
+
//Fix for charts under tabs
|
192 |
+
$('.box ul.nav a').on('shown.bs.tab', function () {
|
193 |
+
area.redraw();
|
194 |
+
donut.redraw();
|
195 |
+
line.redraw();
|
196 |
+
});
|
197 |
+
|
198 |
+
/* The todo list plugin */
|
199 |
+
$(".todo-list").todolist({
|
200 |
+
onCheck: function (ele) {
|
201 |
+
window.console.log("The element has been checked");
|
202 |
+
return ele;
|
203 |
+
},
|
204 |
+
onUncheck: function (ele) {
|
205 |
+
window.console.log("The element has been unchecked");
|
206 |
+
return ele;
|
207 |
+
}
|
208 |
+
});
|
209 |
+
|
210 |
+
});
|
admin/static/plugins/jvectormap/jquery-jvectormap-1.2.2.css
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.jvectormap-label {
|
2 |
+
position: absolute;
|
3 |
+
display: none;
|
4 |
+
border: solid 1px #CDCDCD;
|
5 |
+
-webkit-border-radius: 3px;
|
6 |
+
-moz-border-radius: 3px;
|
7 |
+
border-radius: 3px;
|
8 |
+
background: #292929;
|
9 |
+
color: white;
|
10 |
+
font-size: 10px!important;
|
11 |
+
padding: 3px;
|
12 |
+
z-index: 9999;
|
13 |
+
}
|
14 |
+
|
15 |
+
.jvectormap-zoomin, .jvectormap-zoomout {
|
16 |
+
position: absolute;
|
17 |
+
top: 100%;
|
18 |
+
margin-top: -25px;
|
19 |
+
-webkit-border-radius: 2px;
|
20 |
+
-moz-border-radius: 2px;
|
21 |
+
border-radius: 2px;
|
22 |
+
background: #d2d6de;//rgba(0,0,0,0.4);
|
23 |
+
padding: 5px;
|
24 |
+
color: #444;
|
25 |
+
cursor: pointer;
|
26 |
+
line-height: 10px;
|
27 |
+
text-align: center;
|
28 |
+
font-weight: bold;
|
29 |
+
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
30 |
+
}
|
31 |
+
|
32 |
+
.jvectormap-zoomin {
|
33 |
+
left: 100%;
|
34 |
+
margin-left: -50px;
|
35 |
+
}
|
36 |
+
|
37 |
+
.jvectormap-zoomout {
|
38 |
+
left: 100%;
|
39 |
+
margin-left: -30px;
|
40 |
+
}
|
admin/static/plugins/jvectormap/jquery-jvectormap-1.2.2.min.js
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* jVectorMap version 1.2.2
|
3 |
+
*
|
4 |
+
* Copyright 2011-2013, Kirill Lebedev
|
5 |
+
* Licensed under the MIT license.
|
6 |
+
*
|
7 |
+
*/(function(e){var t={set:{colors:1,values:1,backgroundColor:1,scaleColors:1,normalizeFunction:1,focus:1},get:{selectedRegions:1,selectedMarkers:1,mapObject:1,regionName:1}};e.fn.vectorMap=function(e){var n,r,i,n=this.children(".jvectormap-container").data("mapObject");if(e==="addMap")jvm.WorldMap.maps[arguments[1]]=arguments[2];else{if(!(e!=="set"&&e!=="get"||!t[e][arguments[1]]))return r=arguments[1].charAt(0).toUpperCase()+arguments[1].substr(1),n[e+r].apply(n,Array.prototype.slice.call(arguments,2));e=e||{},e.container=this,n=new jvm.WorldMap(e)}return this}})(jQuery),function(e){function r(t){var n=t||window.event,r=[].slice.call(arguments,1),i=0,s=!0,o=0,u=0;return t=e.event.fix(n),t.type="mousewheel",n.wheelDelta&&(i=n.wheelDelta/120),n.detail&&(i=-n.detail/3),u=i,n.axis!==undefined&&n.axis===n.HORIZONTAL_AXIS&&(u=0,o=-1*i),n.wheelDeltaY!==undefined&&(u=n.wheelDeltaY/120),n.wheelDeltaX!==undefined&&(o=-1*n.wheelDeltaX/120),r.unshift(t,i,o,u),(e.event.dispatch||e.event.handle).apply(this,r)}var t=["DOMMouseScroll","mousewheel"];if(e.event.fixHooks)for(var n=t.length;n;)e.event.fixHooks[t[--n]]=e.event.mouseHooks;e.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var e=t.length;e;)this.addEventListener(t[--e],r,!1);else this.onmousewheel=r},teardown:function(){if(this.removeEventListener)for(var e=t.length;e;)this.removeEventListener(t[--e],r,!1);else this.onmousewheel=null}},e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})}(jQuery);var jvm={inherits:function(e,t){function n(){}n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e,e.parentClass=t},mixin:function(e,t){var n;for(n in t.prototype)t.prototype.hasOwnProperty(n)&&(e.prototype[n]=t.prototype[n])},min:function(e){var t=Number.MAX_VALUE,n;if(e instanceof Array)for(n=0;n<e.length;n++)e[n]<t&&(t=e[n]);else for(n in e)e[n]<t&&(t=e[n]);return t},max:function(e){var t=Number.MIN_VALUE,n;if(e instanceof Array)for(n=0;n<e.length;n++)e[n]>t&&(t=e[n]);else for(n in e)e[n]>t&&(t=e[n]);return t},keys:function(e){var t=[],n;for(n in e)t.push(n);return t},values:function(e){var t=[],n,r;for(r=0;r<arguments.length;r++){e=arguments[r];for(n in e)t.push(e[n])}return t}};jvm.$=jQuery,jvm.AbstractElement=function(e,t){this.node=this.createElement(e),this.name=e,this.properties={},t&&this.set(t)},jvm.AbstractElement.prototype.set=function(e,t){var n;if(typeof e=="object")for(n in e)this.properties[n]=e[n],this.applyAttr(n,e[n]);else this.properties[e]=t,this.applyAttr(e,t)},jvm.AbstractElement.prototype.get=function(e){return this.properties[e]},jvm.AbstractElement.prototype.applyAttr=function(e,t){this.node.setAttribute(e,t)},jvm.AbstractElement.prototype.remove=function(){jvm.$(this.node).remove()},jvm.AbstractCanvasElement=function(e,t,n){this.container=e,this.setSize(t,n),this.rootElement=new jvm[this.classPrefix+"GroupElement"],this.node.appendChild(this.rootElement.node),this.container.appendChild(this.node)},jvm.AbstractCanvasElement.prototype.add=function(e,t){t=t||this.rootElement,t.add(e),e.canvas=this},jvm.AbstractCanvasElement.prototype.addPath=function(e,t,n){var r=new jvm[this.classPrefix+"PathElement"](e,t);return this.add(r,n),r},jvm.AbstractCanvasElement.prototype.addCircle=function(e,t,n){var r=new jvm[this.classPrefix+"CircleElement"](e,t);return this.add(r,n),r},jvm.AbstractCanvasElement.prototype.addGroup=function(e){var t=new jvm[this.classPrefix+"GroupElement"];return e?e.node.appendChild(t.node):this.node.appendChild(t.node),t.canvas=this,t},jvm.AbstractShapeElement=function(e,t,n){this.style=n||{},this.style.current={},this.isHovered=!1,this.isSelected=!1,this.updateStyle()},jvm.AbstractShapeElement.prototype.setHovered=function(e){this.isHovered!==e&&(this.isHovered=e,this.updateStyle())},jvm.AbstractShapeElement.prototype.setSelected=function(e){this.isSelected!==e&&(this.isSelected=e,this.updateStyle(),jvm.$(this.node).trigger("selected",[e]))},jvm.AbstractShapeElement.prototype.setStyle=function(e,t){var n={};typeof e=="object"?n=e:n[e]=t,jvm.$.extend(this.style.current,n),this.updateStyle()},jvm.AbstractShapeElement.prototype.updateStyle=function(){var e={};jvm.AbstractShapeElement.mergeStyles(e,this.style.initial),jvm.AbstractShapeElement.mergeStyles(e,this.style.current),this.isHovered&&jvm.AbstractShapeElement.mergeStyles(e,this.style.hover),this.isSelected&&(jvm.AbstractShapeElement.mergeStyles(e,this.style.selected),this.isHovered&&jvm.AbstractShapeElement.mergeStyles(e,this.style.selectedHover)),this.set(e)},jvm.AbstractShapeElement.mergeStyles=function(e,t){var n;t=t||{};for(n in t)t[n]===null?delete e[n]:e[n]=t[n]},jvm.SVGElement=function(e,t){jvm.SVGElement.parentClass.apply(this,arguments)},jvm.inherits(jvm.SVGElement,jvm.AbstractElement),jvm.SVGElement.svgns="http://www.w3.org/2000/svg",jvm.SVGElement.prototype.createElement=function(e){return document.createElementNS(jvm.SVGElement.svgns,e)},jvm.SVGElement.prototype.addClass=function(e){this.node.setAttribute("class",e)},jvm.SVGElement.prototype.getElementCtr=function(e){return jvm["SVG"+e]},jvm.SVGElement.prototype.getBBox=function(){return this.node.getBBox()},jvm.SVGGroupElement=function(){jvm.SVGGroupElement.parentClass.call(this,"g")},jvm.inherits(jvm.SVGGroupElement,jvm.SVGElement),jvm.SVGGroupElement.prototype.add=function(e){this.node.appendChild(e.node)},jvm.SVGCanvasElement=function(e,t,n){this.classPrefix="SVG",jvm.SVGCanvasElement.parentClass.call(this,"svg"),jvm.AbstractCanvasElement.apply(this,arguments)},jvm.inherits(jvm.SVGCanvasElement,jvm.SVGElement),jvm.mixin(jvm.SVGCanvasElement,jvm.AbstractCanvasElement),jvm.SVGCanvasElement.prototype.setSize=function(e,t){this.width=e,this.height=t,this.node.setAttribute("width",e),this.node.setAttribute("height",t)},jvm.SVGCanvasElement.prototype.applyTransformParams=function(e,t,n){this.scale=e,this.transX=t,this.transY=n,this.rootElement.node.setAttribute("transform","scale("+e+") translate("+t+", "+n+")")},jvm.SVGShapeElement=function(e,t,n){jvm.SVGShapeElement.parentClass.call(this,e,t),jvm.AbstractShapeElement.apply(this,arguments)},jvm.inherits(jvm.SVGShapeElement,jvm.SVGElement),jvm.mixin(jvm.SVGShapeElement,jvm.AbstractShapeElement),jvm.SVGPathElement=function(e,t){jvm.SVGPathElement.parentClass.call(this,"path",e,t),this.node.setAttribute("fill-rule","evenodd")},jvm.inherits(jvm.SVGPathElement,jvm.SVGShapeElement),jvm.SVGCircleElement=function(e,t){jvm.SVGCircleElement.parentClass.call(this,"circle",e,t)},jvm.inherits(jvm.SVGCircleElement,jvm.SVGShapeElement),jvm.VMLElement=function(e,t){jvm.VMLElement.VMLInitialized||jvm.VMLElement.initializeVML(),jvm.VMLElement.parentClass.apply(this,arguments)},jvm.inherits(jvm.VMLElement,jvm.AbstractElement),jvm.VMLElement.VMLInitialized=!1,jvm.VMLElement.initializeVML=function(){try{document.namespaces.rvml||document.namespaces.add("rvml","urn:schemas-microsoft-com:vml"),jvm.VMLElement.prototype.createElement=function(e){return document.createElement("<rvml:"+e+' class="rvml">')}}catch(e){jvm.VMLElement.prototype.createElement=function(e){return document.createElement("<"+e+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}document.createStyleSheet().addRule(".rvml","behavior:url(#default#VML)"),jvm.VMLElement.VMLInitialized=!0},jvm.VMLElement.prototype.getElementCtr=function(e){return jvm["VML"+e]},jvm.VMLElement.prototype.addClass=function(e){jvm.$(this.node).addClass(e)},jvm.VMLElement.prototype.applyAttr=function(e,t){this.node[e]=t},jvm.VMLElement.prototype.getBBox=function(){var e=jvm.$(this.node);return{x:e.position().left/this.canvas.scale,y:e.position().top/this.canvas.scale,width:e.width()/this.canvas.scale,height:e.height()/this.canvas.scale}},jvm.VMLGroupElement=function(){jvm.VMLGroupElement.parentClass.call(this,"group"),this.node.style.left="0px",this.node.style.top="0px",this.node.coordorigin="0 0"},jvm.inherits(jvm.VMLGroupElement,jvm.VMLElement),jvm.VMLGroupElement.prototype.add=function(e){this.node.appendChild(e.node)},jvm.VMLCanvasElement=function(e,t,n){this.classPrefix="VML",jvm.VMLCanvasElement.parentClass.call(this,"group"),jvm.AbstractCanvasElement.apply(this,arguments),this.node.style.position="absolute"},jvm.inherits(jvm.VMLCanvasElement,jvm.VMLElement),jvm.mixin(jvm.VMLCanvasElement,jvm.AbstractCanvasElement),jvm.VMLCanvasElement.prototype.setSize=function(e,t){var n,r,i,s;this.width=e,this.height=t,this.node.style.width=e+"px",this.node.style.height=t+"px",this.node.coordsize=e+" "+t,this.node.coordorigin="0 0";if(this.rootElement){n=this.rootElement.node.getElementsByTagName("shape");for(i=0,s=n.length;i<s;i++)n[i].coordsize=e+" "+t,n[i].style.width=e+"px",n[i].style.height=t+"px";r=this.node.getElementsByTagName("group");for(i=0,s=r.length;i<s;i++)r[i].coordsize=e+" "+t,r[i].style.width=e+"px",r[i].style.height=t+"px"}},jvm.VMLCanvasElement.prototype.applyTransformParams=function(e,t,n){this.scale=e,this.transX=t,this.transY=n,this.rootElement.node.coordorigin=this.width-t-this.width/100+","+(this.height-n-this.height/100),this.rootElement.node.coordsize=this.width/e+","+this.height/e},jvm.VMLShapeElement=function(e,t){jvm.VMLShapeElement.parentClass.call(this,e,t),this.fillElement=new jvm.VMLElement("fill"),this.strokeElement=new jvm.VMLElement("stroke"),this.node.appendChild(this.fillElement.node),this.node.appendChild(this.strokeElement.node),this.node.stroked=!1,jvm.AbstractShapeElement.apply(this,arguments)},jvm.inherits(jvm.VMLShapeElement,jvm.VMLElement),jvm.mixin(jvm.VMLShapeElement,jvm.AbstractShapeElement),jvm.VMLShapeElement.prototype.applyAttr=function(e,t){switch(e){case"fill":this.node.fillcolor=t;break;case"fill-opacity":this.fillElement.node.opacity=Math.round(t*100)+"%";break;case"stroke":t==="none"?this.node.stroked=!1:this.node.stroked=!0,this.node.strokecolor=t;break;case"stroke-opacity":this.strokeElement.node.opacity=Math.round(t*100)+"%";break;case"stroke-width":parseInt(t,10)===0?this.node.stroked=!1:this.node.stroked=!0,this.node.strokeweight=t;break;case"d":this.node.path=jvm.VMLPathElement.pathSvgToVml(t);break;default:jvm.VMLShapeElement.parentClass.prototype.applyAttr.apply(this,arguments)}},jvm.VMLPathElement=function(e,t){var n=new jvm.VMLElement("skew");jvm.VMLPathElement.parentClass.call(this,"shape",e,t),this.node.coordorigin="0 0",n.node.on=!0,n.node.matrix="0.01,0,0,0.01,0,0",n.node.offset="0,0",this.node.appendChild(n.node)},jvm.inherits(jvm.VMLPathElement,jvm.VMLShapeElement),jvm.VMLPathElement.prototype.applyAttr=function(e,t){e==="d"?this.node.path=jvm.VMLPathElement.pathSvgToVml(t):jvm.VMLShapeElement.prototype.applyAttr.call(this,e,t)},jvm.VMLPathElement.pathSvgToVml=function(e){var t="",n=0,r=0,i,s;return e=e.replace(/(-?\d+)e(-?\d+)/g,"0"),e.replace(/([MmLlHhVvCcSs])\s*((?:-?\d*(?:\.\d+)?\s*,?\s*)+)/g,function(e,t,o,u){o=o.replace(/(\d)-/g,"$1,-").replace(/^\s+/g,"").replace(/\s+$/g,"").replace(/\s+/g,",").split(","),o[0]||o.shift();for(var a=0,f=o.length;a<f;a++)o[a]=Math.round(100*o[a]);switch(t){case"m":return n+=o[0],r+=o[1],"t"+o.join(",");case"M":return n=o[0],r=o[1],"m"+o.join(",");case"l":return n+=o[0],r+=o[1],"r"+o.join(",");case"L":return n=o[0],r=o[1],"l"+o.join(",");case"h":return n+=o[0],"r"+o[0]+",0";case"H":return n=o[0],"l"+n+","+r;case"v":return r+=o[0],"r0,"+o[0];case"V":return r=o[0],"l"+n+","+r;case"c":return i=n+o[o.length-4],s=r+o[o.length-3],n+=o[o.length-2],r+=o[o.length-1],"v"+o.join(",");case"C":return i=o[o.length-4],s=o[o.length-3],n=o[o.length-2],r=o[o.length-1],"c"+o.join(",");case"s":return o.unshift(r-s),o.unshift(n-i),i=n+o[o.length-4],s=r+o[o.length-3],n+=o[o.length-2],r+=o[o.length-1],"v"+o.join(",");case"S":return o.unshift(r+r-s),o.unshift(n+n-i),i=o[o.length-4],s=o[o.length-3],n=o[o.length-2],r=o[o.length-1],"c"+o.join(",")}return""}).replace(/z/g,"e")},jvm.VMLCircleElement=function(e,t){jvm.VMLCircleElement.parentClass.call(this,"oval",e,t)},jvm.inherits(jvm.VMLCircleElement,jvm.VMLShapeElement),jvm.VMLCircleElement.prototype.applyAttr=function(e,t){switch(e){case"r":this.node.style.width=t*2+"px",this.node.style.height=t*2+"px",this.applyAttr("cx",this.get("cx")||0),this.applyAttr("cy",this.get("cy")||0);break;case"cx":if(!t)return;this.node.style.left=t-(this.get("r")||0)+"px";break;case"cy":if(!t)return;this.node.style.top=t-(this.get("r")||0)+"px";break;default:jvm.VMLCircleElement.parentClass.prototype.applyAttr.call(this,e,t)}},jvm.VectorCanvas=function(e,t,n){return this.mode=window.SVGAngle?"svg":"vml",this.mode=="svg"?this.impl=new jvm.SVGCanvasElement(e,t,n):this.impl=new jvm.VMLCanvasElement(e,t,n),this.impl},jvm.SimpleScale=function(e){this.scale=e},jvm.SimpleScale.prototype.getValue=function(e){return e},jvm.OrdinalScale=function(e){this.scale=e},jvm.OrdinalScale.prototype.getValue=function(e){return this.scale[e]},jvm.NumericScale=function(e,t,n,r){this.scale=[],t=t||"linear",e&&this.setScale(e),t&&this.setNormalizeFunction(t),n&&this.setMin(n),r&&this.setMax(r)},jvm.NumericScale.prototype={setMin:function(e){this.clearMinValue=e,typeof this.normalize=="function"?this.minValue=this.normalize(e):this.minValue=e},setMax:function(e){this.clearMaxValue=e,typeof this.normalize=="function"?this.maxValue=this.normalize(e):this.maxValue=e},setScale:function(e){var t;for(t=0;t<e.length;t++)this.scale[t]=[e[t]]},setNormalizeFunction:function(e){e==="polynomial"?this.normalize=function(e){return Math.pow(e,.2)}:e==="linear"?delete this.normalize:this.normalize=e,this.setMin(this.clearMinValue),this.setMax(this.clearMaxValue)},getValue:function(e){var t=[],n=0,r,i=0,s;typeof this.normalize=="function"&&(e=this.normalize(e));for(i=0;i<this.scale.length-1;i++)r=this.vectorLength(this.vectorSubtract(this.scale[i+1],this.scale[i])),t.push(r),n+=r;s=(this.maxValue-this.minValue)/n;for(i=0;i<t.length;i++)t[i]*=s;i=0,e-=this.minValue;while(e-t[i]>=0)e-=t[i],i++;return i==this.scale.length-1?e=this.vectorToNum(this.scale[i]):e=this.vectorToNum(this.vectorAdd(this.scale[i],this.vectorMult(this.vectorSubtract(this.scale[i+1],this.scale[i]),e/t[i]))),e},vectorToNum:function(e){var t=0,n;for(n=0;n<e.length;n++)t+=Math.round(e[n])*Math.pow(256,e.length-n-1);return t},vectorSubtract:function(e,t){var n=[],r;for(r=0;r<e.length;r++)n[r]=e[r]-t[r];return n},vectorAdd:function(e,t){var n=[],r;for(r=0;r<e.length;r++)n[r]=e[r]+t[r];return n},vectorMult:function(e,t){var n=[],r;for(r=0;r<e.length;r++)n[r]=e[r]*t;return n},vectorLength:function(e){var t=0,n;for(n=0;n<e.length;n++)t+=e[n]*e[n];return Math.sqrt(t)}},jvm.ColorScale=function(e,t,n,r){jvm.ColorScale.parentClass.apply(this,arguments)},jvm.inherits(jvm.ColorScale,jvm.NumericScale),jvm.ColorScale.prototype.setScale=function(e){var t;for(t=0;t<e.length;t++)this.scale[t]=jvm.ColorScale.rgbToArray(e[t])},jvm.ColorScale.prototype.getValue=function(e){return jvm.ColorScale.numToRgb(jvm.ColorScale.parentClass.prototype.getValue.call(this,e))},jvm.ColorScale.arrayToRgb=function(e){var t="#",n,r;for(r=0;r<e.length;r++)n=e[r].toString(16),t+=n.length==1?"0"+n:n;return t},jvm.ColorScale.numToRgb=function(e){e=e.toString(16);while(e.length<6)e="0"+e;return"#"+e},jvm.ColorScale.rgbToArray=function(e){return e=e.substr(1),[parseInt(e.substr(0,2),16),parseInt(e.substr(2,2),16),parseInt(e.substr(4,2),16)]},jvm.DataSeries=function(e,t){var n;e=e||{},e.attribute=e.attribute||"fill",this.elements=t,this.params=e,e.attributes&&this.setAttributes(e.attributes),jvm.$.isArray(e.scale)?(n=e.attribute==="fill"||e.attribute==="stroke"?jvm.ColorScale:jvm.NumericScale,this.scale=new n(e.scale,e.normalizeFunction,e.min,e.max)):e.scale?this.scale=new jvm.OrdinalScale(e.scale):this.scale=new jvm.SimpleScale(e.scale),this.values=e.values||{},this.setValues(this.values)},jvm.DataSeries.prototype={setAttributes:function(e,t){var n=e,r;if(typeof e=="string")this.elements[e]&&this.elements[e].setStyle(this.params.attribute,t);else for(r in n)this.elements[r]&&this.elements[r].element.setStyle(this.params.attribute,n[r])},setValues:function(e){var t=Number.MIN_VALUE,n=Number.MAX_VALUE,r,i,s={};if(this.scale instanceof jvm.OrdinalScale||this.scale instanceof jvm.SimpleScale)for(i in e)e[i]?s[i]=this.scale.getValue(e[i]):s[i]=this.elements[i].element.style.initial[this.params.attribute];else{if(!this.params.min||!this.params.max){for(i in e)r=parseFloat(e[i]),r>t&&(t=e[i]),r<n&&(n=r);this.params.min||this.scale.setMin(n),this.params.max||this.scale.setMax(t),this.params.min=n,this.params.max=t}for(i in e)r=parseFloat(e[i]),isNaN(r)?s[i]=this.elements[i].element.style.initial[this.params.attribute]:s[i]=this.scale.getValue(r)}this.setAttributes(s),jvm.$.extend(this.values,e)},clear:function(){var e,t={};for(e in this.values)this.elements[e]&&(t[e]=this.elements[e].element.style.initial[this.params.attribute]);this.setAttributes(t),this.values={}},setScale:function(e){this.scale.setScale(e),this.values&&this.setValues(this.values)},setNormalizeFunction:function(e){this.scale.setNormalizeFunction(e),this.values&&this.setValues(this.values)}},jvm.Proj={degRad:180/Math.PI,radDeg:Math.PI/180,radius:6381372,sgn:function(e){return e>0?1:e<0?-1:e},mill:function(e,t,n){return{x:this.radius*(t-n)*this.radDeg,y:-this.radius*Math.log(Math.tan((45+.4*e)*this.radDeg))/.8}},mill_inv:function(e,t,n){return{lat:(2.5*Math.atan(Math.exp(.8*t/this.radius))-5*Math.PI/8)*this.degRad,lng:(n*this.radDeg+e/this.radius)*this.degRad}},merc:function(e,t,n){return{x:this.radius*(t-n)*this.radDeg,y:-this.radius*Math.log(Math.tan(Math.PI/4+e*Math.PI/360))}},merc_inv:function(e,t,n){return{lat:(2*Math.atan(Math.exp(t/this.radius))-Math.PI/2)*this.degRad,lng:(n*this.radDeg+e/this.radius)*this.degRad}},aea:function(e,t,n){var r=0,i=n*this.radDeg,s=29.5*this.radDeg,o=45.5*this.radDeg,u=e*this.radDeg,a=t*this.radDeg,f=(Math.sin(s)+Math.sin(o))/2,l=Math.cos(s)*Math.cos(s)+2*f*Math.sin(s),c=f*(a-i),h=Math.sqrt(l-2*f*Math.sin(u))/f,p=Math.sqrt(l-2*f*Math.sin(r))/f;return{x:h*Math.sin(c)*this.radius,y:-(p-h*Math.cos(c))*this.radius}},aea_inv:function(e,t,n){var r=e/this.radius,i=t/this.radius,s=0,o=n*this.radDeg,u=29.5*this.radDeg,a=45.5*this.radDeg,f=(Math.sin(u)+Math.sin(a))/2,l=Math.cos(u)*Math.cos(u)+2*f*Math.sin(u),c=Math.sqrt(l-2*f*Math.sin(s))/f,h=Math.sqrt(r*r+(c-i)*(c-i)),p=Math.atan(r/(c-i));return{lat:Math.asin((l-h*h*f*f)/(2*f))*this.degRad,lng:(o+p/f)*this.degRad}},lcc:function(e,t,n){var r=0,i=n*this.radDeg,s=t*this.radDeg,o=33*this.radDeg,u=45*this.radDeg,a=e*this.radDeg,f=Math.log(Math.cos(o)*(1/Math.cos(u)))/Math.log(Math.tan(Math.PI/4+u/2)*(1/Math.tan(Math.PI/4+o/2))),l=Math.cos(o)*Math.pow(Math.tan(Math.PI/4+o/2),f)/f,c=l*Math.pow(1/Math.tan(Math.PI/4+a/2),f),h=l*Math.pow(1/Math.tan(Math.PI/4+r/2),f);return{x:c*Math.sin(f*(s-i))*this.radius,y:-(h-c*Math.cos(f*(s-i)))*this.radius}},lcc_inv:function(e,t,n){var r=e/this.radius,i=t/this.radius,s=0,o=n*this.radDeg,u=33*this.radDeg,a=45*this.radDeg,f=Math.log(Math.cos(u)*(1/Math.cos(a)))/Math.log(Math.tan(Math.PI/4+a/2)*(1/Math.tan(Math.PI/4+u/2))),l=Math.cos(u)*Math.pow(Math.tan(Math.PI/4+u/2),f)/f,c=l*Math.pow(1/Math.tan(Math.PI/4+s/2),f),h=this.sgn(f)*Math.sqrt(r*r+(c-i)*(c-i)),p=Math.atan(r/(c-i));return{lat:(2*Math.atan(Math.pow(l/h,1/f))-Math.PI/2)*this.degRad,lng:(o+p/f)*this.degRad}}},jvm.WorldMap=function(e){var t=this,n;this.params=jvm.$.extend(!0,{},jvm.WorldMap.defaultParams,e);if(!jvm.WorldMap.maps[this.params.map])throw new Error("Attempt to use map which was not loaded: "+this.params.map);this.mapData=jvm.WorldMap.maps[this.params.map],this.markers={},this.regions={},this.regionsColors={},this.regionsData={},this.container=jvm.$("<div>").css({width:"100%",height:"100%"}).addClass("jvectormap-container"),this.params.container.append(this.container),this.container.data("mapObject",this),this.container.css({position:"relative",overflow:"hidden"}),this.defaultWidth=this.mapData.width,this.defaultHeight=this.mapData.height,this.setBackgroundColor(this.params.backgroundColor),this.onResize=function(){t.setSize()},jvm.$(window).resize(this.onResize);for(n in jvm.WorldMap.apiEvents)this.params[n]&&this.container.bind(jvm.WorldMap.apiEvents[n]+".jvectormap",this.params[n]);this.canvas=new jvm.VectorCanvas(this.container[0],this.width,this.height),"ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch?this.params.bindTouchEvents&&this.bindContainerTouchEvents():this.bindContainerEvents(),this.bindElementEvents(),this.createLabel(),this.params.zoomButtons&&this.bindZoomButtons(),this.createRegions(),this.createMarkers(this.params.markers||{}),this.setSize(),this.params.focusOn&&(typeof this.params.focusOn=="object"?this.setFocus.call(this,this.params.focusOn.scale,this.params.focusOn.x,this.params.focusOn.y):this.setFocus.call(this,this.params.focusOn)),this.params.selectedRegions&&this.setSelectedRegions(this.params.selectedRegions),this.params.selectedMarkers&&this.setSelectedMarkers(this.params.selectedMarkers),this.params.series&&this.createSeries()},jvm.WorldMap.prototype={transX:0,transY:0,scale:1,baseTransX:0,baseTransY:0,baseScale:1,width:0,height:0,setBackgroundColor:function(e){this.container.css("background-color",e)},resize:function(){var e=this.baseScale;this.width/this.height>this.defaultWidth/this.defaultHeight?(this.baseScale=this.height/this.defaultHeight,this.baseTransX=Math.abs(this.width-this.defaultWidth*this.baseScale)/(2*this.baseScale)):(this.baseScale=this.width/this.defaultWidth,this.baseTransY=Math.abs(this.height-this.defaultHeight*this.baseScale)/(2*this.baseScale)),this.scale*=this.baseScale/e,this.transX*=this.baseScale/e,this.transY*=this.baseScale/e},setSize:function(){this.width=this.container.width(),this.height=this.container.height(),this.resize(),this.canvas.setSize(this.width,this.height),this.applyTransform()},reset:function(){var e,t;for(e in this.series)for(t=0;t<this.series[e].length;t++)this.series[e][t].clear();this.scale=this.baseScale,this.transX=this.baseTransX,this.transY=this.baseTransY,this.applyTransform()},applyTransform:function(){var e,t,n,r;this.defaultWidth*this.scale<=this.width?(e=(this.width-this.defaultWidth*this.scale)/(2*this.scale),n=(this.width-this.defaultWidth*this.scale)/(2*this.scale)):(e=0,n=(this.width-this.defaultWidth*this.scale)/this.scale),this.defaultHeight*this.scale<=this.height?(t=(this.height-this.defaultHeight*this.scale)/(2*this.scale),r=(this.height-this.defaultHeight*this.scale)/(2*this.scale)):(t=0,r=(this.height-this.defaultHeight*this.scale)/this.scale),this.transY>t?this.transY=t:this.transY<r&&(this.transY=r),this.transX>e?this.transX=e:this.transX<n&&(this.transX=n),this.canvas.applyTransformParams(this.scale,this.transX,this.transY),this.markers&&this.repositionMarkers(),this.container.trigger("viewportChange",[this.scale/this.baseScale,this.transX,this.transY])},bindContainerEvents:function(){var e=!1,t,n,r=this;this.container.mousemove(function(i){return e&&(r.transX-=(t-i.pageX)/r.scale,r.transY-=(n-i.pageY)/r.scale,r.applyTransform(),t=i.pageX,n=i.pageY),!1}).mousedown(function(r){return e=!0,t=r.pageX,n=r.pageY,!1}),jvm.$("body").mouseup(function(){e=!1}),this.params.zoomOnScroll&&this.container.mousewheel(function(e,t,n,i){var s=jvm.$(r.container).offset(),o=e.pageX-s.left,u=e.pageY-s.top,a=Math.pow(1.3,i);r.label.hide(),r.setScale(r.scale*a,o,u),e.preventDefault()})},bindContainerTouchEvents:function(){var e,t,n=this,r,i,s,o,u,a=function(a){var f=a.originalEvent.touches,l,c,h,p;a.type=="touchstart"&&(u=0),f.length==1?(u==1&&(h=n.transX,p=n.transY,n.transX-=(r-f[0].pageX)/n.scale,n.transY-=(i-f[0].pageY)/n.scale,n.applyTransform(),n.label.hide(),(h!=n.transX||p!=n.transY)&&a.preventDefault()),r=f[0].pageX,i=f[0].pageY):f.length==2&&(u==2?(c=Math.sqrt(Math.pow(f[0].pageX-f[1].pageX,2)+Math.pow(f[0].pageY-f[1].pageY,2))/t,n.setScale(e*c,s,o),n.label.hide(),a.preventDefault()):(l=jvm.$(n.container).offset(),f[0].pageX>f[1].pageX?s=f[1].pageX+(f[0].pageX-f[1].pageX)/2:s=f[0].pageX+(f[1].pageX-f[0].pageX)/2,f[0].pageY>f[1].pageY?o=f[1].pageY+(f[0].pageY-f[1].pageY)/2:o=f[0].pageY+(f[1].pageY-f[0].pageY)/2,s-=l.left,o-=l.top,e=n.scale,t=Math.sqrt(Math.pow(f[0].pageX-f[1].pageX,2)+Math.pow(f[0].pageY-f[1].pageY,2)))),u=f.length};jvm.$(this.container).bind("touchstart",a),jvm.$(this.container).bind("touchmove",a)},bindElementEvents:function(){var e=this,t;this.container.mousemove(function(){t=!0}),this.container.delegate("[class~='jvectormap-element']","mouseover mouseout",function(t){var n=this,r=jvm.$(this).attr("class").baseVal?jvm.$(this).attr("class").baseVal:jvm.$(this).attr("class"),i=r.indexOf("jvectormap-region")===-1?"marker":"region",s=i=="region"?jvm.$(this).attr("data-code"):jvm.$(this).attr("data-index"),o=i=="region"?e.regions[s].element:e.markers[s].element,u=i=="region"?e.mapData.paths[s].name:e.markers[s].config.name||"",a=jvm.$.Event(i+"LabelShow.jvectormap"),f=jvm.$.Event(i+"Over.jvectormap");t.type=="mouseover"?(e.container.trigger(f,[s]),f.isDefaultPrevented()||o.setHovered(!0),e.label.text(u),e.container.trigger(a,[e.label,s]),a.isDefaultPrevented()||(e.label.show(),e.labelWidth=e.label.width(),e.labelHeight=e.label.height())):(o.setHovered(!1),e.label.hide(),e.container.trigger(i+"Out.jvectormap",[s]))}),this.container.delegate("[class~='jvectormap-element']","mousedown",function(e){t=!1}),this.container.delegate("[class~='jvectormap-element']","mouseup",function(n){var r=this,i=jvm.$(this).attr("class").baseVal?jvm.$(this).attr("class").baseVal:jvm.$(this).attr("class"),s=i.indexOf("jvectormap-region")===-1?"marker":"region",o=s=="region"?jvm.$(this).attr("data-code"):jvm.$(this).attr("data-index"),u=jvm.$.Event(s+"Click.jvectormap"),a=s=="region"?e.regions[o].element:e.markers[o].element;if(!t){e.container.trigger(u,[o]);if(s==="region"&&e.params.regionsSelectable||s==="marker"&&e.params.markersSelectable)u.isDefaultPrevented()||(e.params[s+"sSelectableOne"]&&e.clearSelected(s+"s"),a.setSelected(!a.isSelected))}})},bindZoomButtons:function(){var e=this;jvm.$("<div/>").addClass("jvectormap-zoomin").text("+").appendTo(this.container),jvm.$("<div/>").addClass("jvectormap-zoomout").html("−").appendTo(this.container),this.container.find(".jvectormap-zoomin").click(function(){e.setScale(e.scale*e.params.zoomStep,e.width/2,e.height/2)}),this.container.find(".jvectormap-zoomout").click(function(){e.setScale(e.scale/e.params.zoomStep,e.width/2,e.height/2)})},createLabel:function(){var e=this;this.label=jvm.$("<div/>").addClass("jvectormap-label").appendTo(jvm.$("body")),this.container.mousemove(function(t){var n=t.pageX-15-e.labelWidth,r=t.pageY-15-e.labelHeight;n<5&&(n=t.pageX+15),r<5&&(r=t.pageY+15),e.label.is(":visible")&&e.label.css({left:n,top:r})})},setScale:function(e,t,n,r){var i,s=jvm.$.Event("zoom.jvectormap");e>this.params.zoomMax*this.baseScale?e=this.params.zoomMax*this.baseScale:e<this.params.zoomMin*this.baseScale&&(e=this.params.zoomMin*this.baseScale),typeof t!="undefined"&&typeof n!="undefined"&&(i=e/this.scale,r?(this.transX=t+this.defaultWidth*(this.width/(this.defaultWidth*e))/2,this.transY=n+this.defaultHeight*(this.height/(this.defaultHeight*e))/2):(this.transX-=(i-1)/e*t,this.transY-=(i-1)/e*n)),this.scale=e,this.applyTransform(),this.container.trigger(s,[e/this.baseScale])},setFocus:function(e,t,n){var r,i,s,o,u;if(jvm.$.isArray(e)||this.regions[e]){jvm.$.isArray(e)?o=e:o=[e];for(u=0;u<o.length;u++)this.regions[o[u]]&&(i=this.regions[o[u]].element.getBBox(),i&&(typeof r=="undefined"?r=i:(s={x:Math.min(r.x,i.x),y:Math.min(r.y,i.y),width:Math.max(r.x+r.width,i.x+i.width)-Math.min(r.x,i.x),height:Math.max(r.y+r.height,i.y+i.height)-Math.min(r.y,i.y)},r=s)));this.setScale(Math.min(this.width/r.width,this.height/r.height),-(r.x+r.width/2),-(r.y+r.height/2),!0)}else e*=this.baseScale,this.setScale(e,-t*this.defaultWidth,-n*this.defaultHeight,!0)},getSelected:function(e){var t,n=[];for(t in this[e])this[e][t].element.isSelected&&n.push(t);return n},getSelectedRegions:function(){return this.getSelected("regions")},getSelectedMarkers:function(){return this.getSelected("markers")},setSelected:function(e,t){var n;typeof t!="object"&&(t=[t]);if(jvm.$.isArray(t))for(n=0;n<t.length;n++)this[e][t[n]].element.setSelected(!0);else for(n in t)this[e][n].element.setSelected(!!t[n])},setSelectedRegions:function(e){this.setSelected("regions",e)},setSelectedMarkers:function(e){this.setSelected("markers",e)},clearSelected:function(e){var t={},n=this.getSelected(e),r;for(r=0;r<n.length;r++)t[n[r]]=!1;this.setSelected(e,t)},clearSelectedRegions:function(){this.clearSelected("regions")},clearSelectedMarkers:function(){this.clearSelected("markers")},getMapObject:function(){return this},getRegionName:function(e){return this.mapData.paths[e].name},createRegions:function(){var e,t,n=this;for(e in this.mapData.paths)t=this.canvas.addPath({d:this.mapData.paths[e].path,"data-code":e},jvm.$.extend(!0,{},this.params.regionStyle)),jvm.$(t.node).bind("selected",function(e,t){n.container.trigger("regionSelected.jvectormap",[jvm.$(this).attr("data-code"),t,n.getSelectedRegions()])}),t.addClass("jvectormap-region jvectormap-element"),this.regions[e]={element:t,config:this.mapData.paths[e]}},createMarkers:function(e){var t,n,r,i,s,o=this;this.markersGroup=this.markersGroup||this.canvas.addGroup();if(jvm.$.isArray(e)){s=e.slice(),e={};for(t=0;t<s.length;t++)e[t]=s[t]}for(t in e)i=e[t]instanceof Array?{latLng:e[t]}:e[t],r=this.getMarkerPosition(i),r!==!1&&(n=this.canvas.addCircle({"data-index":t,cx:r.x,cy:r.y},jvm.$.extend(!0,{},this.params.markerStyle,{initial:i.style||{}}),this.markersGroup),n.addClass("jvectormap-marker jvectormap-element"),jvm.$(n.node).bind("selected",function(e,t){o.container.trigger("markerSelected.jvectormap",[jvm.$(this).attr("data-index"),t,o.getSelectedMarkers()])}),this.markers[t]&&this.removeMarkers([t]),this.markers[t]={element:n,config:i})},repositionMarkers:function(){var e,t;for(e in this.markers)t=this.getMarkerPosition(this.markers[e].config),t!==!1&&this.markers[e].element.setStyle({cx:t.x,cy:t.y})},getMarkerPosition:function(e){return jvm.WorldMap.maps[this.params.map].projection?this.latLngToPoint.apply(this,e.latLng||[0,0]):{x:e.coords[0]*this.scale+this.transX*this.scale,y:e.coords[1]*this.scale+this.transY*this.scale}},addMarker:function(e,t,n){var r={},i=[],s,o,n=n||[];r[e]=t;for(o=0;o<n.length;o++)s={},s[e]=n[o],i.push(s);this.addMarkers(r,i)},addMarkers:function(e,t){var n;t=t||[],this.createMarkers(e);for(n=0;n<t.length;n++)this.series.markers[n].setValues(t[n]||{})},removeMarkers:function(e){var t;for(t=0;t<e.length;t++)this.markers[e[t]].element.remove(),delete this.markers[e[t]]},removeAllMarkers:function(){var e,t=[];for(e in this.markers)t.push(e);this.removeMarkers(t)},latLngToPoint:function(e,t){var n,r=jvm.WorldMap.maps[this.params.map].projection,i=r.centralMeridian,s=this.width-this.baseTransX*2*this.baseScale,o=this.height-this.baseTransY*2*this.baseScale,u,a,f=this.scale/this.baseScale;return t<-180+i&&(t+=360),n=jvm.Proj[r.type](e,t,i),u=this.getInsetForPoint(n.x,n.y),u?(a=u.bbox,n.x=(n.x-a[0].x)/(a[1].x-a[0].x)*u.width*this.scale,n.y=(n.y-a[0].y)/(a[1].y-a[0].y)*u.height*this.scale,{x:n.x+this.transX*this.scale+u.left*this.scale,y:n.y+this.transY*this.scale+u.top*this.scale}):!1},pointToLatLng:function(e,t){var n=jvm.WorldMap.maps[this.params.map].projection,r=n.centralMeridian,i=jvm.WorldMap.maps[this.params.map].insets,s,o,u,a,f;for(s=0;s<i.length;s++){o=i[s],u=o.bbox,a=e-(this.transX*this.scale+o.left*this.scale),f=t-(this.transY*this.scale+o.top*this.scale),a=a/(o.width*this.scale)*(u[1].x-u[0].x)+u[0].x,f=f/(o.height*this.scale)*(u[1].y-u[0].y)+u[0].y;if(a>u[0].x&&a<u[1].x&&f>u[0].y&&f<u[1].y)return jvm.Proj[n.type+"_inv"](a,-f,r)}return!1},getInsetForPoint:function(e,t){var n=jvm.WorldMap.maps[this.params.map].insets,r,i;for(r=0;r<n.length;r++){i=n[r].bbox;if(e>i[0].x&&e<i[1].x&&t>i[0].y&&t<i[1].y)return n[r]}},createSeries:function(){var e,t;this.series={markers:[],regions:[]};for(t in this.params.series)for(e=0;e<this.params.series[t].length;e++)this.series[t][e]=new jvm.DataSeries(this.params.series[t][e],this[t])},remove:function(){this.label.remove(),this.container.remove(),jvm.$(window).unbind("resize",this.onResize)}},jvm.WorldMap.maps={},jvm.WorldMap.defaultParams={map:"world_mill_en",backgroundColor:"#505050",zoomButtons:!0,zoomOnScroll:!0,zoomMax:8,zoomMin:1,zoomStep:1.6,regionsSelectable:!1,markersSelectable:!1,bindTouchEvents:!0,regionStyle:{initial:{fill:"white","fill-opacity":1,stroke:"none","stroke-width":0,"stroke-opacity":1},hover:{"fill-opacity":.8},selected:{fill:"yellow"},selectedHover
|
8 |
+
:{}},markerStyle:{initial:{fill:"grey",stroke:"#505050","fill-opacity":1,"stroke-width":1,"stroke-opacity":1,r:5},hover:{stroke:"black","stroke-width":2},selected:{fill:"blue"},selectedHover:{}}},jvm.WorldMap.apiEvents={onRegionLabelShow:"regionLabelShow",onRegionOver:"regionOver",onRegionOut:"regionOut",onRegionClick:"regionClick",onRegionSelected:"regionSelected",onMarkerLabelShow:"markerLabelShow",onMarkerOver:"markerOver",onMarkerOut:"markerOut",onMarkerClick:"markerClick",onMarkerSelected:"markerSelected",onViewportChange:"viewportChange"};
|
admin/static/plugins/jvectormap/jquery-jvectormap-usa-en.js
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
jQuery.fn.vectorMap('addMap', 'us_aea',{"insets": [{"width": 220, "top": 440, "height": 172.3954126857679, "bbox": [{"y": -8441276.54251503, "x": -4774054.664881943}, {"y": -6227982.667213126, "x": -1949590.5739843722}], "left": 0}, {"width": 80, "top": 460, "height": 151.48337407091987, "bbox": [{"y": -4196208.652471859, "x": -5906305.806252358}, {"y": -3657293.3059425415, "x": -5621698.812337889}], "left": 245}, {"width": 900, "top": 0, "height": 550.1122047105795, "bbox": [{"y": -5490816.561605522, "x": -2029882.6485830692}, {"y": -2690009.0242363815, "x": 2552322.14899711}], "left": 0}], "paths": {"US-VA": {"path": "M682.42,289.98l1.61,-0.93l1.65,-0.48l1.12,-0.95l3.57,-1.69l0.74,-2.33l0.82,-0.19l2.32,-1.53l0.05,-1.81l2.04,-1.86l-0.13,-1.58l0.26,-0.41l5.0,-4.09l4.76,-6.0l0.09,0.63l0.96,0.54l0.33,1.37l1.32,0.74l0.71,0.81l1.46,0.09l2.09,1.13l1.41,-0.09l0.79,-0.41l0.76,-1.22l1.17,-0.57l0.53,-1.38l2.72,1.49l1.42,-1.1l2.25,-0.99l0.76,0.06l1.08,-0.97l0.33,-0.82l-0.48,-0.96l0.23,-0.42l1.9,0.58l3.26,-2.62l0.3,-0.1l0.51,0.73l0.66,-0.07l2.38,-2.34l0.17,-0.85l-0.49,-0.51l0.99,-1.12l0.1,-0.6l-0.28,-0.51l-1.0,-0.46l0.71,-3.03l2.6,-4.8l0.55,-2.15l-0.01,-1.91l1.61,-2.55l-0.22,-0.94l0.24,-0.84l0.5,-0.48l0.39,-1.7l-0.0,-3.18l1.22,0.19l1.18,1.73l3.8,0.43l0.59,-0.28l1.05,-2.52l0.2,-2.36l0.71,-1.05l-0.04,-1.61l0.76,-2.3l1.78,0.75l0.65,-0.17l1.3,-3.3l0.57,0.05l0.59,-0.39l0.52,-1.2l0.81,-0.68l0.44,-1.8l1.38,-2.43l-0.35,-2.57l0.54,-1.76l-0.3,-2.01l9.18,4.57l0.59,-0.29l0.63,-4.0l2.6,-0.07l0.63,0.57l1.05,0.23l-0.5,1.74l0.6,0.88l1.61,0.85l2.52,-0.04l1.03,1.18l1.49,0.13l2.24,1.73l-0.0,1.31l0.44,1.27l-1.67,0.96l-0.12,0.65l-0.64,0.14l-0.27,0.45l-0.47,5.03l-0.36,0.13l-0.04,0.48l1.17,0.97l-0.29,0.11l-0.04,0.76l2.03,-0.01l2.41,-1.45l0.49,-0.72l0.34,0.74l-0.52,0.63l1.21,0.88l0.69,0.13l0.42,1.11l1.62,0.52l1.94,-0.2l0.84,0.43l0.82,-0.65l0.89,0.02l0.23,0.6l1.33,0.48l0.46,1.1l1.12,-0.05l0.02,0.3l1.18,0.42l2.84,0.65l0.4,1.01l-0.85,-0.41l-0.57,0.45l0.89,1.74l-0.35,0.57l0.62,0.79l-0.43,0.89l0.24,0.59l-1.36,-0.36l-0.59,-0.72l-0.67,0.18l-0.1,0.43l-2.44,-2.29l-0.56,0.05l-0.37,-0.56l-0.52,0.32l-1.47,-1.32l-1.19,-0.38l-0.43,-0.64l-0.9,-0.39l-0.7,-1.29l-0.77,-0.64l-1.34,-0.12l-1.11,-0.81l-1.17,0.05l-0.39,0.52l0.47,0.71l1.1,-0.01l0.63,0.68l1.33,0.07l0.59,0.42l0.38,1.52l2.73,1.56l1.86,1.88l1.95,0.61l1.59,2.1l0.98,0.24l1.35,-0.45l1.28,0.47l-0.61,0.7l0.3,0.49l2.03,0.34l0.26,0.72l0.47,0.12l0.31,1.96l-0.57,-0.83l-0.52,-0.22l-0.39,0.21l-1.13,-1.0l-0.58,0.3l0.1,0.82l-0.31,0.68l0.7,0.7l-0.18,0.59l0.51,0.28l0.43,-0.14l0.28,0.35l-1.39,0.72l-6.15,-4.74l-0.58,0.11l-0.19,0.81l0.24,0.54l2.28,1.53l2.09,2.14l2.77,1.18l1.26,-0.68l0.45,1.05l1.27,0.26l-0.44,0.67l0.29,0.56l0.93,-0.19l-0.0,1.24l-0.92,0.41l-0.57,0.73l-0.64,-0.88l-3.14,-1.26l-0.42,-1.53l-0.59,-0.59l-0.87,-0.12l-1.2,0.67l-1.71,-0.44l-0.36,-1.15l-0.71,-0.05l-0.05,1.31l-0.33,0.41l-1.42,-1.32l-0.51,0.09l-0.49,0.57l-0.64,-0.4l-0.99,0.45l-2.23,-0.1l-0.37,0.94l0.34,0.46l1.9,0.22l1.4,-0.31l0.85,0.24l0.56,-0.69l0.63,0.88l1.34,0.43l1.95,-0.31l0.82,0.72l0.84,0.12l0.51,-0.55l0.77,2.44l1.35,0.13l0.23,0.43l1.68,0.71l0.45,0.68l-0.57,1.03l0.56,0.44l1.72,-1.32l0.88,-0.02l0.83,0.65l0.8,-0.26l-0.61,-0.9l0.0,-0.82l-0.46,-0.34l3.99,0.08l0.93,-0.73l2.07,3.53l-0.4,0.7l0.65,3.09l-1.19,-0.58l-0.02,0.88l-30.94,7.83l-37.18,8.41l-19.51,3.35l-11.78,1.24l-0.82,0.62l-28.2,5.01ZM781.17,223.48l0.11,0.08l-0.08,0.06l0.0,-0.03l-0.03,-0.11ZM808.02,244.55l0.53,-1.15l-0.62,-0.62l0.58,-0.97l-0.39,-0.71l-0.03,-0.49l0.44,-0.35l-0.17,-0.73l0.62,-0.3l0.23,-0.6l0.14,-2.33l1.01,-0.39l-0.12,-0.9l0.48,-0.14l-0.26,-1.53l-0.79,-0.4l0.87,-0.57l0.1,-0.96l2.64,-1.01l0.31,2.47l-0.97,2.12l-2.32,7.36l-0.58,1.0l0.17,1.12l-0.48,0.31l-0.33,1.09l0.25,4.27l-1.1,-1.81l0.23,-0.94l-0.33,-1.57l0.28,-0.97l-0.38,-0.29Z", "name": "Virginia"}, "US-PA": {"path": "M716.45,159.95l0.63,-0.19l4.3,-3.73l1.12,5.19l0.48,0.31l34.84,-7.93l34.27,-8.64l1.42,0.58l0.71,1.39l0.63,0.13l0.77,-0.33l1.24,0.59l0.14,0.85l0.81,0.41l-0.16,0.58l0.89,2.69l1.9,2.07l2.12,0.75l2.2,-0.2l0.72,0.79l-0.89,0.87l-0.73,1.48l-0.17,2.25l-1.41,3.35l-1.37,1.58l0.04,0.79l1.79,1.72l-0.31,1.65l-0.84,0.43l-0.22,0.66l0.14,1.48l1.04,2.87l0.52,0.25l1.2,-0.18l1.18,2.39l0.95,0.58l0.66,-0.26l0.6,0.9l4.23,2.75l0.12,0.41l-1.29,0.93l-3.71,4.22l-0.23,0.75l0.17,0.9l-1.36,1.13l-0.84,0.15l-1.33,1.08l-0.31,0.66l-1.72,-0.12l-2.03,0.84l-1.15,1.37l-0.41,1.39l-37.22,9.21l-39.1,8.66l-10.03,-48.2l1.92,-1.22l3.07,-3.04Z", "name": "Pennsylvania"}, "US-TN": {"path": "M571.74,341.02l0.86,-0.84l0.29,-1.37l1.0,0.04l0.65,-0.79l-0.99,-4.89l1.41,-1.93l0.06,-1.32l1.18,-0.46l0.36,-0.48l-0.63,-1.31l0.57,-1.21l-0.89,-1.33l2.55,-1.57l1.09,-1.13l-0.14,-0.84l-0.85,-0.53l0.14,-0.19l0.34,-0.16l0.85,0.37l0.46,-0.33l-0.27,-1.31l-0.85,-0.9l0.06,-0.71l0.51,-1.43l1.0,-1.11l-1.35,-2.06l1.37,-0.21l0.61,-0.55l-0.13,-0.64l-1.17,-0.82l0.82,-0.15l0.58,-0.54l0.13,-0.69l-0.58,-1.38l0.02,-0.36l0.37,0.53l0.47,0.08l1.18,-1.15l23.66,-2.81l0.35,-0.41l-0.1,-1.34l-0.84,-2.39l2.98,-0.08l0.82,0.58l22.78,-3.54l7.64,-0.46l7.5,-0.86l8.82,-1.42l24.01,-3.09l1.11,-0.6l29.29,-5.2l0.73,-0.6l3.56,-0.54l-0.4,1.44l0.43,0.85l-0.4,2.0l0.36,0.82l-1.15,-0.03l-1.71,1.79l-1.21,3.89l-0.55,0.7l-0.56,0.08l-0.63,-0.74l-1.44,-0.02l-2.66,1.73l-1.42,2.73l-0.96,0.89l-0.34,-0.34l-0.13,-1.05l-0.73,-0.54l-0.53,0.15l-2.3,1.81l-0.29,1.32l-0.93,-0.24l-0.9,0.48l-0.16,0.77l0.32,0.73l-0.85,2.18l-1.28,0.06l-1.75,1.14l-1.89,2.3l-0.78,0.27l-2.28,2.46l-4.04,0.78l-2.58,1.7l-0.49,1.09l-0.88,0.55l-0.55,0.81l-0.18,2.88l-0.35,0.6l-1.65,0.52l-0.89,-0.16l-1.06,1.14l0.21,5.24l-20.21,3.32l-21.61,3.04l-25.56,2.95l-0.34,0.31l-7.39,0.9l-28.72,3.17Z", "name": "Tennessee"}, "US-WV": {"path": "M693.03,248.37l3.95,-1.54l0.35,-0.71l0.12,-2.77l1.15,-0.22l0.4,-0.61l-0.57,-2.49l-0.61,-1.24l0.49,-0.64l0.36,-2.77l0.68,-1.66l0.45,-0.39l1.24,0.55l0.41,0.71l-0.14,1.13l0.71,0.46l0.78,-0.44l0.48,-1.42l0.49,0.21l0.57,-0.2l0.2,-0.44l-0.63,-2.09l-0.75,-0.55l0.81,-0.79l-0.26,-1.71l0.74,-2.0l1.65,-0.51l0.17,-1.6l1.02,-1.42l0.43,-0.08l0.65,0.79l0.67,0.19l2.28,-1.59l1.5,-1.64l0.79,-1.83l2.45,-2.67l0.37,-2.41l-0.73,-1.0l0.71,-2.33l-0.25,-0.76l0.59,-0.58l-0.27,-3.43l0.47,-3.93l0.53,-0.8l0.08,-1.11l-0.38,-1.21l-0.39,-0.33l-0.04,-2.0l-1.57,-1.9l0.44,-0.54l0.85,-0.1l0.3,-0.33l4.03,19.33l0.47,0.31l16.59,-3.55l2.17,10.68l0.5,0.37l2.06,-2.5l0.97,-0.56l0.34,-1.03l1.63,-1.99l0.25,-1.05l0.52,-0.4l1.19,0.45l0.74,-0.32l1.32,-2.6l0.6,-0.46l-0.04,-0.85l0.42,0.59l1.81,0.52l3.2,-0.57l0.78,-0.86l0.08,-1.46l2.0,-0.74l1.02,-1.69l0.67,-0.1l3.16,1.5l1.8,-0.71l-0.45,1.02l0.56,0.92l1.27,0.42l0.09,0.96l1.13,0.43l0.09,1.2l0.33,0.42l-0.58,3.64l-9.0,-4.48l-0.64,0.24l-0.31,1.14l0.38,1.61l-0.52,1.62l0.41,2.28l-1.36,2.4l-0.42,1.76l-0.72,0.53l-0.42,1.11l-0.27,0.21l-0.61,-0.23l-0.37,0.33l-1.25,3.28l-1.84,-0.78l-0.64,0.25l-0.94,2.77l0.08,1.46l-0.73,1.14l-0.19,2.33l-0.89,2.2l-3.25,-0.36l-1.44,-1.76l-1.71,-0.24l-0.5,0.41l-0.26,2.17l0.19,1.3l-0.32,1.45l-0.49,0.45l-0.31,1.04l0.23,0.92l-1.58,2.44l-0.04,2.1l-0.52,2.0l-2.58,4.73l-0.75,3.16l0.14,0.76l1.13,0.55l-1.08,1.38l0.06,0.6l0.45,0.4l-2.16,2.13l-0.55,-0.7l-0.84,0.15l-3.12,2.53l-1.03,-0.56l-1.32,0.26l-0.44,0.91l0.45,1.17l-0.91,0.91l-0.73,-0.05l-2.27,1.0l-1.21,0.96l-2.18,-1.36l-0.73,-0.01l-0.82,1.58l-1.1,0.49l-1.22,1.46l-1.08,0.08l-1.98,-1.09l-1.3,-0.01l-0.61,-0.74l-1.19,-0.6l-0.31,-1.33l-0.89,-0.55l0.36,-0.67l-0.3,-0.81l-0.85,-0.37l-0.84,0.25l-1.33,-0.17l-1.26,-1.19l-2.06,-0.79l-0.76,-1.43l-1.58,-1.24l-0.7,-1.49l-1.0,-0.6l-0.12,-1.09l-1.38,-0.95l-2.0,-2.27l0.71,-2.03l-0.25,-1.62l-0.66,-1.46Z", "name": "West Virginia"}, "US-NV": {"path": "M139.46,329.14l-12.69,-16.93l-36.58,-51.09l-25.34,-34.51l13.7,-64.18l46.88,9.24l46.98,7.74l-18.71,125.81l-0.9,1.16l-0.99,2.19l-0.44,0.17l-1.34,-0.22l-0.98,-2.24l-0.7,-0.63l-1.41,0.22l-1.95,-1.02l-1.6,0.23l-1.78,0.96l-0.76,2.48l0.88,2.59l-0.6,0.97l-0.24,1.3l0.38,3.12l-0.76,2.54l0.77,3.71l-0.13,3.07l-0.3,1.07l-1.04,0.31l0.2,1.31l-0.52,0.62Z", "name": "Nevada"}, "US-TX": {"path": "M276.24,412.51l33.07,1.98l32.79,1.35l0.41,-0.39l3.6,-98.69l25.86,0.61l26.29,0.22l0.05,42.08l0.44,0.4l1.02,-0.13l0.78,0.28l3.74,3.82l1.66,0.21l0.88,-0.58l2.49,0.64l0.6,-0.68l0.11,-1.05l0.6,0.76l0.92,0.22l0.38,0.93l0.77,0.78l-0.01,1.64l0.52,0.83l2.85,0.42l1.25,-0.2l1.38,0.89l2.78,0.69l1.82,-0.56l0.62,0.1l1.89,1.8l1.4,-0.11l1.25,-1.43l2.43,0.26l1.67,-0.46l0.1,2.28l0.91,0.67l1.62,0.4l-0.04,2.08l1.56,0.79l1.82,-0.66l1.57,-1.67l1.02,-0.65l0.41,0.19l0.45,1.64l2.01,0.2l0.24,1.05l0.72,0.48l1.47,-0.21l0.88,-0.93l0.39,0.33l0.59,-0.08l0.61,-0.99l0.26,0.41l-0.45,1.23l0.14,0.76l0.67,1.14l0.78,0.42l0.57,-0.04l0.6,-0.5l0.68,-2.36l0.91,-0.65l0.35,-1.54l0.57,-0.14l0.4,0.14l0.29,0.99l0.57,0.64l1.21,0.02l0.83,0.5l1.25,-0.2l0.68,-1.34l0.48,0.15l-0.13,0.7l0.49,0.69l1.21,0.45l0.49,0.72l1.52,-0.05l1.49,1.74l0.52,0.02l0.63,-0.62l0.08,-0.71l1.49,-0.1l0.93,-1.43l1.88,-0.41l1.66,-1.13l1.52,0.83l1.51,-0.22l0.29,-0.83l2.29,-0.73l0.52,-0.55l0.5,0.32l0.38,0.88l1.82,0.42l1.69,-0.06l1.86,-1.14l0.41,-1.05l1.06,0.31l2.24,1.56l1.16,0.17l1.79,2.08l2.14,0.41l1.04,0.92l0.76,-0.11l2.48,0.85l1.04,0.04l0.37,0.79l1.38,0.97l1.45,-0.12l0.39,-0.72l0.8,0.36l0.88,-0.4l0.92,0.35l0.76,-0.15l0.64,0.36l2.22,34.02l1.51,1.67l1.3,0.82l1.25,1.87l0.57,1.63l-0.1,2.64l1.0,1.21l0.85,0.4l-0.12,0.85l0.75,0.54l0.28,0.87l0.65,0.7l-0.19,1.17l1.0,1.02l0.59,1.63l0.5,0.34l0.55,-0.1l-0.16,1.71l0.81,1.22l-0.64,0.25l-0.35,0.68l0.77,1.27l-0.55,0.89l0.19,1.39l-0.75,2.69l-0.74,0.85l-0.36,1.54l-0.79,1.13l0.64,2.0l-0.83,2.28l0.17,1.07l0.83,1.2l-0.19,1.01l0.49,1.6l-0.24,1.41l-1.18,1.78l-1.18,0.4l-1.16,2.72l-0.03,2.1l1.39,1.67l-3.43,0.08l-7.37,3.78l-0.02,-0.43l-0.69,-0.24l-0.23,0.23l-0.78,-0.43l-3.38,1.13l0.65,-1.31l0.35,-2.04l-0.34,-1.36l-0.8,-0.78l-1.79,0.16l-1.18,2.58l-0.42,0.15l-0.36,-0.65l-2.38,-1.23l-0.4,0.31l-0.18,0.82l0.23,0.45l1.07,0.38l-0.3,0.82l0.54,0.81l-0.47,0.64l0.04,0.99l1.48,0.76l-0.44,0.47l0.5,1.12l0.91,0.23l0.28,0.37l-0.4,1.25l-0.45,-0.12l-0.97,0.81l-1.72,2.25l-1.18,-0.4l-0.49,0.12l0.32,1.0l0.08,2.54l-1.85,1.49l-1.91,2.11l-0.96,0.37l-4.1,2.9l-3.3,0.44l-2.54,1.07l-0.2,1.12l-0.75,-0.34l-2.04,0.89l-0.33,-0.34l-1.11,0.18l0.43,-0.87l-0.52,-0.6l-1.43,0.22l-1.22,1.08l-0.6,-0.62l-0.11,-1.2l-1.38,-0.81l-0.5,0.44l0.65,1.44l0.01,1.12l-0.71,0.09l-0.54,-0.44l-0.75,-0.0l-0.55,-1.34l-1.46,-0.37l-0.58,0.39l0.04,0.54l0.94,1.7l0.03,1.23l0.58,0.37l0.37,-0.16l1.13,0.78l-0.75,0.37l-0.12,0.9l0.7,0.23l1.08,-0.55l0.96,0.6l-4.27,2.42l-0.57,-0.13l-0.37,-1.44l-0.5,-0.19l-1.13,-1.47l-0.48,-0.03l-1.05,1.99l1.19,1.61l-0.31,1.04l0.33,0.85l-1.66,1.79l-0.37,0.2l0.37,-0.63l-0.18,-0.72l0.25,-0.73l-0.46,-0.67l-0.52,0.17l-0.71,1.1l0.26,0.72l-0.39,0.95l-0.07,-1.13l-0.52,-0.55l-1.95,1.29l-0.78,-0.33l-0.69,0.51l0.07,0.75l-0.81,0.99l0.02,0.49l1.25,0.63l0.03,0.56l0.78,0.29l0.7,-1.41l0.86,-0.41l0.01,0.62l-2.82,4.36l-1.23,-1.0l-1.36,0.39l-0.32,-0.34l-2.4,0.39l-0.46,-0.31l-0.65,0.16l-0.18,0.58l0.41,0.61l0.55,0.38l1.53,0.03l0.54,1.55l2.07,1.03l-2.7,7.63l-0.2,0.1l-0.39,-0.54l-0.33,0.1l0.18,-0.75l-0.57,-0.43l-2.35,1.95l-1.67,-2.31l-1.23,-0.97l-0.61,0.4l0.09,0.52l1.44,2.0l-0.24,0.46l0.36,0.47l-1.17,-0.21l-0.33,0.63l0.5,0.56l0.89,0.23l1.12,-0.16l0.66,0.62l1.37,0.18l1.0,-0.03l0.99,-0.62l-0.34,1.59l0.24,0.77l-0.98,0.7l0.37,1.59l-1.12,0.14l-0.43,0.41l0.4,2.11l-0.33,1.6l0.45,0.64l0.84,0.24l0.87,2.86l0.71,2.8l-0.91,0.82l0.62,0.49l-0.08,1.28l0.71,0.3l0.18,0.61l0.58,0.29l0.4,1.79l0.68,0.31l0.45,3.21l1.46,0.62l-0.52,1.1l0.31,1.08l-0.62,0.77l-0.84,-0.05l-0.54,0.44l0.09,1.3l-0.49,-0.33l-0.49,0.25l-0.39,-0.67l-1.49,-0.45l-2.92,-2.53l-2.2,-0.18l-0.81,-0.51l-4.2,0.09l-0.9,0.42l-0.79,-0.62l-1.64,0.24l-2.12,-0.89l-0.73,-0.97l-0.6,-0.14l-0.21,-0.72l-1.17,-0.49l-0.99,-0.02l-1.98,-0.87l-1.45,0.39l-0.83,-1.09l-0.6,-0.21l-1.43,-1.38l-1.96,0.01l-1.47,-0.64l-0.86,0.11l-1.62,-0.41l0.35,-0.9l-0.3,-0.97l-1.11,-0.7l0.3,-0.29l-0.26,-1.44l0.56,-1.21l-0.35,-0.67l0.88,-0.38l0.12,-0.54l-1.04,-0.54l-0.91,0.67l-0.32,-0.31l0.03,-1.09l-0.59,-0.83l0.31,-0.09l0.53,-1.43l-0.22,-0.71l-0.71,0.09l-1.03,0.96l-0.57,-0.89l-0.85,-0.28l-0.26,-1.34l-1.51,-0.77l0.29,-0.65l-0.24,-0.76l0.34,-2.18l-0.45,-0.96l-1.04,-1.01l0.65,-1.99l0.05,-1.19l-0.18,-0.7l-0.54,-0.33l-0.15,-1.81l-1.85,-1.44l-0.86,0.21l-0.3,-0.41l-0.81,-0.11l-0.74,-1.31l-2.22,-1.71l0.01,-0.69l-0.51,-0.58l0.12,-0.87l-0.97,-0.92l-0.08,-0.75l-1.12,-0.61l-1.3,-2.88l-2.66,-1.48l-0.38,-0.91l-1.13,-0.59l-0.06,-1.16l-0.82,-1.19l-0.59,-1.95l0.41,-0.22l-0.04,-0.72l-1.03,-0.49l-0.26,-1.29l-0.82,-0.58l-0.94,-1.73l-0.61,-2.38l-1.85,-2.36l-0.87,-4.24l-1.81,-1.34l0.05,-0.7l-0.75,-1.21l-4.07,-2.82l-0.29,-1.39l1.68,-0.02l0.79,-0.84l-0.29,-0.39l-0.65,-0.06l-0.09,-0.72l0.08,-0.89l0.64,-0.7l-0.11,-0.74l-0.48,0.05l-0.77,0.72l-0.45,0.69l0.01,0.66l-0.88,0.15l-0.39,1.07l-0.54,-0.04l-1.81,-1.75l0.06,-0.67l-0.41,-0.68l-0.77,-0.2l-0.64,0.29l-0.33,-0.53l-0.73,-0.13l-0.89,-2.16l-1.49,-0.8l-0.85,0.27l-0.44,-0.87l-0.61,0.1l-0.25,0.61l-1.05,0.16l-2.88,-0.47l-0.39,-0.38l-1.48,-0.03l-0.79,0.29l-0.77,-0.44l-2.66,0.27l-2.42,-1.08l-1.14,-0.89l-0.68,-0.07l-1.03,0.82l-0.64,1.61l-1.99,-0.17l-0.51,0.44l-0.49,-0.17l-2.52,0.78l-3.07,6.25l-0.18,1.77l-0.76,0.67l-0.38,1.8l0.35,0.59l-1.97,0.98l-0.75,1.32l-1.07,0.61l-0.62,0.83l-0.29,1.09l-2.91,-0.34l-1.04,-0.87l-0.54,0.3l-1.69,-1.21l-1.31,-1.63l-2.9,-0.85l-1.15,-0.95l-0.02,-0.67l-0.42,-0.4l-2.75,-0.51l-2.28,-1.03l-1.89,-1.75l-0.91,-1.53l-0.96,-0.91l-1.53,-0.29l-1.76,-1.26l-0.22,-0.56l-1.14,-0.97l-0.83,-2.9l-0.86,-1.01l-0.24,-1.1l-0.76,-1.27l-0.26,-2.34l0.52,-3.04l-3.0,-5.07l-0.06,-1.94l-1.26,-2.51l-0.99,-0.44l-0.43,-1.24l-1.43,-0.81l-2.15,-2.17l-1.02,-0.1l-2.01,-1.25l-3.18,-3.35l-0.59,-1.55l-3.13,-2.55l-1.59,-2.45l-1.19,-0.95l-0.61,-1.05l-4.42,-2.6l-2.4,-5.42l-1.37,-1.08l-1.12,-0.08l-1.76,-1.68l-0.79,-3.05ZM502.12,468.09l-0.33,0.17l0.18,-0.16l0.15,-0.02ZM498.72,470.76l-0.09,0.12l-0.04,0.02l0.13,-0.14ZM467.58,489.09l0.03,0.02l-0.02,0.02l-0.0,-0.03ZM453.97,547.08l0.76,-0.5l0.25,-0.68l0.11,1.08l-1.11,0.1Z", "name": "Texas"}, "US-NH": {"path": "M829.91,105.39l0.2,-1.33l-1.43,-5.38l0.53,-1.45l-0.28,-2.22l1.0,-1.86l-0.13,-2.3l0.64,-2.28l-0.44,-0.62l0.29,-2.3l-0.93,-3.8l0.08,-0.7l0.3,-0.45l1.83,-0.8l0.7,-1.39l1.43,-1.62l0.74,-1.8l-0.25,-1.13l0.52,-0.62l-2.34,-3.49l0.87,-3.26l-0.11,-0.78l-0.81,-1.29l0.28,-0.59l-0.23,-0.7l0.48,-3.2l-0.36,-0.82l0.91,-1.49l2.44,0.33l0.65,-0.86l12.99,34.86l0.84,3.65l2.6,2.21l0.88,0.34l0.36,1.6l1.71,1.31l0.0,0.35l0.77,0.23l-0.06,0.58l-0.46,3.09l-1.57,0.24l-1.32,1.19l-0.51,0.94l-0.96,0.37l-0.5,1.68l-1.1,1.44l-17.61,4.74l-1.7,-1.43l-0.41,-0.89l-0.1,-2.0l0.54,-0.59l0.03,-0.52l-1.02,-5.18Z", "name": "New Hampshire"}, "US-NY": {"path": "M821.95,168.59l-0.84,-0.72l0.83,-3.23l1.03,-0.3l0.37,-0.48l0.74,0.21l0.64,-0.32l-0.06,-0.58l0.43,-0.05l0.28,-0.66l0.72,-0.32l-0.21,-1.42l0.73,-0.47l0.35,0.56l1.04,-0.16l0.49,-0.33l0.01,-0.54l1.46,-0.18l0.24,-0.74l1.66,0.02l0.91,-0.54l0.45,-1.21l0.62,0.24l0.43,-0.5l4.32,-1.28l2.35,-1.12l2.36,-2.84l0.18,0.17l-2.53,3.41l-0.01,0.46l0.56,0.38l1.59,-0.33l0.28,0.61l-1.3,1.19l-2.05,0.53l-0.37,0.58l-1.16,0.41l0.23,0.43l-0.24,0.3l-0.68,-0.16l-0.74,0.7l-1.04,0.17l-0.37,0.55l-1.42,0.45l-0.26,0.67l-1.34,0.19l-0.44,0.7l-1.35,0.96l-2.77,1.33l-1.02,0.88l-1.04,0.09l-0.32,0.93l-0.28,0.03l-0.26,-0.68l-1.45,-0.25l-0.88,0.74l0.07,0.96l-0.94,0.56ZM844.29,155.03l0.88,-2.14l1.18,-0.48l0.6,-0.93l0.81,0.34l0.13,-0.83l0.75,0.63l-3.84,3.68l-0.51,-0.28ZM845.16,149.15l0.06,-0.06l0.18,-0.06l-0.11,0.19l-0.13,-0.07ZM722.08,155.52l3.76,-3.85l1.27,-2.19l1.75,-1.86l1.16,-0.78l1.28,-3.35l2.09,-2.13l-0.21,-1.84l-1.61,-2.42l0.42,-1.13l-0.17,-0.78l-0.83,-0.53l-2.09,-0.0l0.04,-0.99l-0.58,-2.23l4.98,-2.94l4.48,-1.79l2.38,-0.2l1.84,-0.74l5.64,-0.24l3.12,1.25l3.16,-1.68l5.49,-1.06l0.59,0.45l0.68,-0.2l0.12,-0.99l3.23,-1.85l0.69,-2.05l1.87,-1.76l0.78,-1.26l1.12,0.03l1.13,-0.52l1.07,-1.63l-0.46,-0.69l0.36,-1.2l-0.25,-0.51l-0.64,0.02l-0.17,-1.18l-0.94,-1.58l-1.01,-0.62l0.12,-0.18l0.59,0.39l0.53,-0.27l0.75,-1.43l-0.01,-0.92l0.81,-0.64l-0.01,-0.98l-0.93,-0.19l-0.6,0.7l-0.28,0.12l0.56,-1.3l-0.81,-0.63l-1.26,0.05l-0.87,0.77l-0.98,-0.7l2.05,-2.51l1.78,-1.47l1.67,-2.63l0.7,-0.56l0.89,-1.54l0.07,-0.56l-0.49,-0.94l0.78,-1.9l4.82,-7.61l4.76,-4.5l2.84,-0.51l19.65,-5.66l0.4,0.87l-0.08,2.01l1.02,1.22l0.43,3.79l2.29,3.25l-0.09,1.89l0.85,2.41l-0.59,1.07l-0.0,3.41l0.71,0.89l1.32,2.76l0.19,1.09l0.62,0.84l0.12,3.92l0.55,0.85l0.54,0.07l0.53,-0.61l0.06,-0.87l0.33,-0.07l1.05,1.12l3.87,14.48l0.11,1.59l0.62,1.09l0.33,14.92l0.6,0.62l3.57,16.23l1.26,1.34l-2.82,3.18l0.03,0.54l1.74,1.62l-1.86,3.37l0.21,1.06l-1.03,0.45l-0.24,-4.26l-0.56,-2.23l-0.74,-1.62l-1.46,-1.1l-0.17,-1.13l-0.7,-0.09l-0.42,1.33l0.8,1.45l0.94,0.69l0.95,2.79l-13.74,-4.06l-1.28,-1.47l-2.39,0.24l-0.63,-0.43l-1.06,-0.15l-1.74,-1.91l-0.75,-2.33l0.12,-0.72l-0.36,-0.63l-0.56,-0.21l0.09,-0.46l-0.35,-0.42l-1.64,-0.68l-1.08,0.32l-0.53,-1.22l-1.92,-0.93l-34.6,8.73l-34.43,7.84l-1.11,-5.15Z", "name": "New York"}, "US-HI": {"path": "M293.44,610.32l-0.16,-1.33l-1.79,-3.5l-1.21,-1.37l0.23,-0.95l-0.21,-0.49l0.64,-1.68l4.55,-5.05l0.88,-5.09l0.45,-0.65l0.48,-2.22l-0.34,-2.5l0.41,-1.79l1.19,-0.79l1.55,-0.08l1.27,-0.5l1.51,0.3l2.68,-1.18l1.51,-0.07l1.15,-1.13l-0.03,-3.17l0.35,-1.25l0.99,-1.6l1.21,-0.53l2.67,2.45l-0.1,1.68l1.07,1.67l0.81,2.19l1.64,1.05l2.04,2.64l3.96,7.75l0.59,3.31l-2.1,3.31l0.14,0.54l0.73,0.44l1.2,0.23l0.29,0.68l-0.01,0.53l-0.8,1.13l-0.09,1.86l0.56,2.06l1.01,1.51l0.17,1.18l-0.37,0.44l-2.35,0.67l-1.45,-0.32l-2.49,0.4l-1.2,-0.39l-2.49,-0.11l-3.15,-1.01l-0.9,-0.94l-1.39,-0.68l-2.87,0.15l-4.73,-0.64l-1.91,0.32l-1.08,1.21l-1.89,0.33l-1.22,0.8l-1.62,0.21ZM302.97,554.35l1.47,-2.4l0.62,-1.93l-0.3,-0.8l-0.55,-0.42l-1.1,0.04l-1.49,-2.22l-0.31,-2.64l0.31,-0.99l0.92,-0.89l0.88,-0.53l1.05,-0.12l0.9,0.44l0.73,1.4l0.05,3.78l1.07,0.23l1.89,1.04l1.66,0.12l1.88,1.67l0.65,3.28l0.56,0.34l0.11,1.09l2.18,2.69l-0.14,1.17l-1.45,1.15l-0.84,-0.19l-0.81,0.3l-0.68,-0.4l-1.7,-0.23l-1.91,-1.3l-3.1,-0.5l-0.96,-1.02l-1.42,-0.79l-0.16,-1.4ZM273.53,509.24l-0.16,-0.35l0.54,-1.85l-0.3,-1.63l0.39,-1.12l-0.31,-1.61l0.83,-1.4l-0.26,-1.26l3.14,2.06l2.55,-0.17l1.08,-0.64l1.25,-0.12l0.77,0.28l0.39,1.22l-0.11,1.03l-0.4,0.54l0.01,2.42l0.41,1.21l-0.78,0.43l-0.61,1.27l0.64,2.46l0.61,0.41l0.56,-0.16l-0.24,0.78l0.3,0.88l-0.35,0.37l-0.14,1.04l0.56,1.3l-1.15,0.14l-0.29,-0.77l-2.67,-0.85l-0.05,-0.86l-0.79,-1.25l0.15,-0.76l-0.26,-0.63l-1.05,0.24l-0.45,-0.78l0.16,-0.27l1.0,0.06l0.45,-0.62l-0.42,-0.96l-0.64,-0.2l-0.35,-0.61l-0.47,0.25l-0.47,-0.55l-0.38,0.32l0.14,1.95l-2.85,-1.22ZM284.15,511.85l0.1,-0.21l-0.0,-0.01l0.1,0.09l-0.19,0.14ZM246.14,461.52l2.01,-0.42l1.12,-0.67l1.33,0.51l3.66,0.37l0.71,1.4l1.04,-0.06l1.12,1.14l0.89,0.21l0.72,0.89l0.28,1.56l-0.23,1.15l-0.51,0.62l-2.05,0.87l-1.37,1.99l-0.6,-0.19l-0.46,0.49l-2.84,0.16l-3.61,-3.83l-0.24,-1.91l-1.68,-2.24l0.05,-1.26l0.66,-0.81Z", "name": "Hawaii"}, "US-VT": {"path": "M805.54,72.68l26.02,-7.96l0.89,1.85l-0.74,2.37l-0.03,1.54l2.22,2.75l-0.51,0.58l0.26,1.13l-0.67,1.6l-1.35,1.49l-0.64,1.32l-1.72,0.7l-0.62,0.92l-0.1,0.98l0.93,3.74l-0.29,2.44l0.4,0.54l-0.6,2.11l0.15,2.19l-1.0,1.87l0.27,2.36l-0.53,1.54l1.43,5.44l-0.22,1.22l1.05,5.3l-0.58,0.85l0.11,2.31l0.6,1.26l1.51,1.1l-11.72,3.08l-4.31,-16.79l-1.72,-1.59l-0.91,0.25l-0.3,1.19l-0.12,-0.26l-0.11,-3.91l-0.68,-1.0l-0.14,-0.98l-1.37,-2.85l-0.63,-0.68l0.01,-3.15l0.6,-1.15l-0.86,-2.57l0.08,-1.93l-0.39,-0.91l-1.55,-1.63l-0.38,-0.81l-0.41,-3.71l-1.03,-1.27l0.11,-1.87l-0.42,-1.0Z", "name": "Vermont"}, "US-NM": {"path": "M230.94,422.8l11.82,-123.64l25.66,2.24l26.09,1.86l26.12,1.45l25.74,1.02l-0.31,10.24l-0.74,0.39l-3.59,98.67l-32.38,-1.34l-33.52,-2.02l-0.44,0.76l0.54,2.31l0.44,1.26l1.0,0.77l-30.53,-2.46l-0.43,0.36l-0.81,9.46l-14.64,-1.33Z", "name": "New Mexico"}, "US-NC": {"path": "M676.72,321.71l0.92,0.17l1.52,-0.39l0.42,-0.39l0.52,-0.97l0.13,-2.7l1.34,-1.19l0.47,-1.05l2.24,-1.47l2.12,-0.52l0.76,0.18l1.32,-0.52l2.36,-2.52l0.78,-0.25l1.84,-2.29l1.48,-1.0l1.55,-0.19l1.15,-2.65l-0.28,-1.22l1.65,0.06l0.51,-1.65l0.93,-0.77l1.08,-0.77l0.51,1.52l1.07,0.33l1.34,-1.17l1.35,-2.64l2.49,-1.59l0.79,0.08l0.82,0.8l1.06,-0.21l0.84,-1.07l1.47,-4.18l1.08,-1.1l1.47,0.09l0.44,-0.31l-0.69,-1.26l0.4,-2.0l-0.42,-0.9l0.38,-1.25l7.42,-0.86l19.54,-3.36l37.21,-8.42l31.11,-7.87l0.4,1.21l3.54,3.24l1.0,1.53l-1.2,-1.0l-0.16,-0.63l-0.92,-0.41l-0.52,0.05l-0.24,0.65l0.66,0.54l0.59,1.56l-0.53,0.01l-0.91,-0.75l-2.31,-0.8l-0.4,-0.48l-0.55,0.13l-0.31,0.69l0.14,0.64l1.37,0.44l1.69,1.38l-1.1,0.66l-2.49,-1.2l-0.35,0.5l0.14,0.42l1.6,1.18l-1.84,-0.33l-2.23,-0.87l-0.46,0.14l0.01,0.48l0.6,0.7l1.7,0.83l-0.97,0.58l0.0,0.6l-0.43,0.53l-1.48,0.75l-0.89,-0.77l-0.61,0.22l-0.1,0.35l-0.2,-0.13l-1.31,-2.32l0.21,-2.63l-0.42,-0.48l-0.89,-0.22l-0.37,0.64l0.62,0.71l-0.43,0.99l-0.02,1.03l0.49,1.73l1.6,2.2l-0.31,1.28l0.48,0.29l2.97,-0.59l2.1,-1.49l0.27,0.01l0.37,0.79l0.76,-0.34l1.56,0.05l0.16,-0.72l-0.57,-0.32l1.29,-0.76l2.04,-0.46l-0.1,1.19l0.64,0.29l-0.6,0.88l0.88,1.19l-0.84,0.1l-0.19,0.66l1.38,0.46l0.26,0.94l-1.21,0.05l-0.19,0.66l0.66,0.59l1.25,-0.16l0.52,0.26l0.41,-0.38l0.18,-1.95l-0.75,-3.33l0.41,-0.48l0.56,0.43l0.94,0.06l0.28,-0.58l-0.29,-0.44l0.48,-0.57l1.71,1.84l-0.01,1.4l0.62,0.9l-0.78,0.65l0.9,1.14l-0.08,0.37l-0.42,0.55l-0.78,0.09l-0.91,-0.86l-0.32,0.34l0.13,1.26l-1.08,1.62l0.2,0.57l-0.33,0.22l-0.15,0.98l-0.74,0.55l0.1,0.91l-0.9,0.97l-1.06,0.21l-0.6,-0.37l-0.52,0.52l-0.93,-0.81l-0.86,0.1l-0.4,-0.82l-0.59,-0.21l-0.52,0.38l0.08,0.94l-0.52,0.22l-1.42,-1.24l1.31,-0.4l0.23,-0.88l-0.57,-0.42l-2.02,0.31l-1.14,1.01l0.29,0.67l0.44,0.16l-0.06,0.39l0.15,0.43l0.35,0.25l-0.03,0.12l-0.57,-0.34l-1.69,0.83l-1.12,-0.43l-1.45,0.06l-3.32,-0.7l0.42,1.08l0.97,0.45l0.36,0.64l1.51,-0.21l4.03,1.02l3.51,0.11l0.47,0.42l-0.06,0.52l-0.99,0.05l-0.25,0.72l-1.62,1.44l0.32,0.58l1.85,0.01l-2.56,3.5l-1.67,0.04l-1.6,-0.98l-0.9,-0.19l-1.21,-1.02l-1.12,0.07l0.07,0.47l1.04,1.14l2.32,2.09l2.68,0.26l1.31,0.49l1.7,-2.16l0.51,0.47l1.17,0.33l0.4,-0.57l-0.55,-0.9l0.87,0.16l0.19,0.57l0.66,0.23l1.63,-1.2l-0.18,0.61l0.29,0.57l-0.29,0.38l-0.43,-0.21l-0.41,0.37l0.03,0.9l-0.97,1.72l0.01,0.78l-0.71,-0.07l-0.06,-0.74l-1.12,-0.61l-0.42,0.47l0.27,1.45l-0.52,-1.1l-0.65,-0.15l-1.22,1.08l-0.21,0.53l0.25,0.27l-2.03,0.32l-2.75,1.84l-0.67,-1.03l-0.75,-0.3l-0.37,0.49l0.43,1.26l-0.57,-0.01l-0.09,0.82l-0.94,1.73l-0.91,0.84l-0.59,-0.26l0.49,-0.69l-0.02,-0.77l-1.06,-0.93l-0.08,-0.52l-1.69,-0.41l-0.16,0.47l0.43,1.16l0.2,0.33l0.58,0.07l0.3,0.61l-0.88,0.37l-0.08,0.71l0.65,0.64l0.77,0.18l-0.01,0.37l-2.12,1.67l-1.91,2.65l-2.0,4.31l-0.34,2.13l0.12,1.33l-0.15,-1.03l-1.0,-1.6l-0.55,-0.17l-0.3,0.48l1.17,3.95l-0.63,2.27l-3.9,0.19l-1.43,0.65l-0.35,-0.52l-0.58,-0.18l-0.54,1.07l-1.9,1.14l-0.61,-0.02l-23.25,-15.36l-1.05,-0.02l-18.68,3.49l-0.65,-2.77l-3.25,-2.84l-0.47,0.08l-1.23,1.31l-0.01,-1.29l-0.82,-0.54l-22.82,3.35l-0.64,-0.27l-0.62,0.46l-0.25,0.65l-3.98,1.92l-0.89,1.23l-1.01,0.08l-4.78,2.66l-20.95,3.93l-0.34,-4.55l0.7,-0.95ZM816.97,271.42l0.19,0.35l0.24,0.38l-0.45,-0.41l0.02,-0.32ZM807.5,290.22l0.2,0.32l-0.16,-0.09l-0.04,-0.24ZM815.28,299.09l0.16,-0.36l0.16,0.07l-0.13,0.29l-0.19,0.01ZM812.72,299.05l-0.06,-0.29l-0.03,-0.11l0.3,0.26l-0.21,0.13Z", "name": "North Carolina"}, "US-ND": {"path": "M438.58,42.78l2.06,6.89l-0.73,2.53l0.57,2.36l-0.27,1.17l0.47,1.99l0.01,3.26l1.42,3.95l0.45,0.54l-0.08,0.97l0.39,1.52l0.62,0.74l1.48,3.74l-0.06,3.9l0.42,0.7l0.5,8.35l0.51,1.54l0.51,0.25l-0.47,2.64l0.36,1.63l-0.14,1.75l0.69,1.1l0.2,2.16l0.49,1.13l1.8,2.56l0.15,2.2l0.51,1.08l0.17,1.39l-0.24,1.36l0.28,1.74l-27.89,0.73l-28.38,0.19l-28.38,-0.37l-28.48,-0.93l2.75,-65.45l23.09,0.78l25.56,0.42l25.56,-0.06l24.09,-0.49Z", "name": "North Dakota"}, "US-NE": {"path": "M422.62,173.98l3.92,2.71l3.93,1.9l1.33,-0.22l0.51,-0.47l0.36,-1.08l0.48,-0.2l2.49,0.34l1.32,-0.47l1.58,0.25l3.45,-0.65l2.37,1.98l1.4,0.14l1.55,0.77l1.45,0.08l0.88,1.1l1.49,0.17l-0.06,0.98l1.68,2.08l3.32,0.6l-0.02,2.55l1.13,1.94l0.01,2.29l1.15,1.07l0.34,1.72l1.73,1.46l0.07,1.88l1.5,2.11l-0.49,2.33l0.44,3.09l0.52,0.54l0.93,-0.2l-0.04,1.25l1.21,0.5l-0.41,2.36l0.21,0.44l1.12,0.4l-0.6,0.77l-0.09,1.01l0.13,0.59l0.82,0.5l0.16,1.45l-0.26,0.92l0.26,1.27l0.55,0.61l0.3,1.93l-0.22,1.33l0.23,0.72l-0.57,0.92l0.02,0.79l0.45,0.88l1.23,0.63l0.25,2.5l1.1,0.51l0.03,0.79l1.18,2.75l-0.23,0.96l1.16,0.21l0.8,0.99l1.1,0.24l-0.15,0.96l1.31,1.68l-0.21,1.12l0.51,0.91l-26.14,1.05l-27.83,0.63l-27.84,0.14l-27.88,-0.35l0.46,-21.65l-0.39,-0.41l-32.35,-1.04l1.85,-43.23l43.35,1.22l44.66,-0.04Z", "name": "Nebraska"}, "US-LA": {"path": "M509.0,412.88l-1.33,-21.76l51.43,-4.07l0.34,0.83l1.48,0.65l-0.92,1.35l-0.25,2.13l0.49,0.72l1.18,0.31l-1.21,0.47l-0.45,0.78l0.45,1.36l1.04,0.84l0.08,2.15l0.46,0.54l1.51,0.74l0.45,1.05l1.42,0.44l-0.87,1.22l-0.85,2.34l-0.75,0.04l-0.52,0.51l-0.02,0.73l0.63,0.72l-0.22,1.16l-1.34,0.96l-1.08,1.89l-1.37,0.67l-0.68,0.83l-0.79,2.42l-0.25,3.52l-1.55,1.74l0.13,1.2l0.62,0.96l-0.35,2.38l-1.61,0.29l-0.6,0.57l0.28,0.97l0.64,0.59l-0.26,1.41l0.98,1.51l-1.18,1.18l-0.08,0.45l0.4,0.23l6.18,-0.55l29.23,-2.92l-0.68,3.47l-0.52,1.02l-0.2,2.24l0.69,0.98l-0.09,0.66l0.6,1.0l1.31,0.7l1.22,1.42l0.14,0.88l0.89,1.39l0.14,1.05l1.11,1.84l-1.85,0.39l-0.38,-0.08l-0.01,-0.56l-0.53,-0.57l-1.28,0.27l-1.18,-0.59l-1.51,0.17l-0.61,-0.98l-1.24,-0.86l-2.84,-0.47l-1.24,0.63l-1.39,2.3l-1.3,1.42l-0.42,0.91l0.07,1.2l0.55,0.89l0.82,0.57l4.25,0.82l3.35,-1.0l1.32,-1.19l0.68,-1.2l0.34,0.59l1.08,0.43l0.59,-0.4l0.81,0.03l0.51,-0.46l-0.76,1.21l-1.12,-0.12l-0.57,0.32l-0.38,0.62l0.0,0.83l0.76,1.22l1.48,-0.02l0.65,0.89l1.1,0.48l1.44,-0.66l0.46,-1.11l-0.02,-1.37l0.93,-0.57l0.42,-0.99l0.23,0.05l0.1,1.16l-0.24,0.25l0.19,0.57l0.42,0.15l-0.07,0.75l1.34,1.08l0.35,-0.16l-0.48,0.59l0.18,0.63l-0.24,0.17l-0.84,-0.72l-0.71,-0.08l-1.0,1.89l-0.84,0.14l-0.46,0.53l0.16,1.19l-1.59,-0.6l-0.43,0.19l0.04,0.46l1.14,1.06l-1.17,-0.14l-0.92,0.6l0.68,0.43l1.26,2.04l2.74,0.97l-0.08,1.2l0.33,0.4l2.07,-0.31l0.77,0.17l0.17,0.53l0.73,0.32l1.35,-0.34l0.53,0.78l1.08,-0.46l1.13,0.73l0.14,0.3l-0.41,0.63l1.54,0.86l-0.39,0.65l0.39,0.58l-0.18,0.62l-0.95,1.49l-1.3,-1.56l-0.68,0.34l0.1,0.66l-0.38,0.12l0.41,-1.88l-1.32,-0.76l-0.51,0.5l0.2,1.17l-0.54,0.45l-0.27,-1.02l-0.57,-0.25l-0.89,-1.27l0.03,-0.77l-0.96,-0.14l-0.47,0.5l-1.41,-0.17l-0.74,-0.77l-2.31,-0.09l0.38,-0.86l-0.13,-0.66l-0.64,-0.69l-0.91,0.04l0.1,-0.96l-0.37,-0.36l-0.91,-0.03l-0.22,0.59l-0.85,-0.38l-0.48,0.27l-2.61,-1.26l-1.24,-0.02l-0.67,-0.64l-0.61,0.18l-0.3,0.56l-0.05,1.25l1.72,0.94l1.67,0.35l-0.16,0.92l0.28,0.4l-0.34,0.34l0.23,0.68l-0.76,0.94l-0.03,0.66l0.81,0.97l-0.95,1.43l-1.33,0.94l-0.76,-1.15l0.22,-1.5l-0.35,-0.92l-0.49,-0.18l-0.4,0.36l-1.15,-1.08l-0.6,0.42l-0.76,-1.05l-0.62,-0.2l-0.64,1.33l-0.85,0.26l-0.89,-0.53l-0.85,0.53l-0.1,0.62l0.48,0.41l-0.67,0.56l-0.13,1.44l-0.46,0.13l-0.4,0.84l-0.92,0.08l-0.11,-0.68l-1.6,-0.4l-0.76,0.97l-1.92,-0.93l-0.3,-0.54l-0.99,0.01l-0.35,0.6l-1.15,-0.51l0.42,-0.4l0.0,-1.46l-0.38,-0.57l-1.9,-1.19l-0.08,-0.54l-0.83,-0.71l-0.09,-0.91l0.73,-1.15l-0.34,-1.14l-0.88,-0.19l-0.34,0.57l0.16,0.43l-0.58,0.81l0.04,0.91l-1.8,-0.4l0.07,-0.39l-0.47,-0.54l-1.97,0.76l-0.7,-2.22l-1.32,0.23l-0.18,-2.12l-1.31,-0.35l-1.89,0.3l-1.08,0.66l-0.21,-0.71l0.84,-0.26l-0.05,-0.8l-0.6,-0.58l-1.03,-0.1l-0.85,0.42l-0.94,-0.15l-0.4,0.8l-2.0,1.11l-0.63,-0.31l-1.29,0.71l0.54,1.37l0.81,0.31l1.04,1.55l-1.27,0.36l-1.82,1.06l-7.63,-0.92l-6.7,-2.31l-3.46,-0.65l-6.85,0.69l-3.41,0.8l-1.57,0.73l-0.91,-1.41l1.2,-0.46l0.79,-0.98l0.27,-2.3l-0.59,-0.84l1.15,-1.62l0.23,-1.59l-0.5,-1.83l0.07,-1.46l-0.66,-0.7l-0.21,-1.04l0.83,-2.21l-0.64,-1.95l0.76,-0.84l0.3,-1.49l0.78,-0.94l0.79,-2.83l-0.18,-1.42l0.58,-0.97l-0.75,-1.33l0.84,-0.39l0.2,-0.44l-0.89,-1.36l0.03,-2.13l-1.07,-0.23l-0.57,-1.57l-0.92,-0.84l0.28,-1.27l-0.81,-0.76l-0.33,-0.95l-0.64,-0.34l0.22,-0.98l-1.16,-0.58l-0.81,-0.93l0.16,-2.46l-0.68,-1.93l-1.33,-1.98l-2.63,-2.21ZM548.97,462.65l0.0,-0.0l0.0,0.0l-0.0,0.0ZM607.49,467.36l-0.03,-0.03l-0.08,-0.04l0.13,-0.01l-0.03,0.08ZM607.51,465.75l-0.02,-0.01l0.03,-0.01l-0.02,0.02ZM567.05,468.89l-2.0,-0.42l-0.66,-0.5l0.73,-0.43l0.35,-0.75l0.39,0.49l0.83,0.21l-0.14,0.6l0.5,0.81Z", "name": "Louisiana"}, "US-SD": {"path": "M336.43,128.81l0.3,-0.53l0.75,-19.92l28.49,0.93l28.39,0.37l28.39,-0.19l27.77,-0.73l-0.18,1.71l-0.73,1.71l-2.9,2.46l-0.42,1.27l1.59,2.13l1.06,2.06l0.55,0.36l1.74,0.24l1.01,0.84l0.57,1.02l1.45,38.83l-1.84,0.09l-0.42,0.56l0.24,1.44l0.88,1.14l0.01,1.45l-0.65,0.36l0.17,1.48l0.48,0.43l1.09,0.04l0.34,1.68l-0.16,0.91l-0.62,0.83l0.02,1.73l-0.68,2.45l-0.49,0.44l-0.67,1.88l0.5,1.1l1.33,1.08l-0.16,0.62l0.64,0.66l0.35,1.15l-1.65,-0.28l-0.34,-0.94l-0.85,-0.73l0.19,-0.61l-0.28,-0.59l-1.58,-0.23l-1.03,-1.18l-1.57,-0.11l-1.51,-0.75l-1.34,-0.12l-2.38,-1.99l-3.78,0.6l-1.65,-0.25l-1.19,0.46l-2.62,-0.33l-0.98,0.48l-0.76,1.45l-0.72,0.05l-3.66,-1.82l-4.13,-2.8l-44.82,0.05l-43.33,-1.22l1.79,-43.19Z", "name": "South Dakota"}, "US-DC": {"path": "M783.1,218.48l-0.45,-0.64l-1.55,-0.67l0.58,-1.01l2.03,1.26l-0.61,1.06Z", "name": "District of Columbia"}, "US-DE": {"path": "M798.42,195.12l0.48,-1.56l0.92,-1.11l1.72,-0.71l1.12,0.06l-0.33,0.56l-0.08,1.38l-0.46,1.09l-0.6,0.54l-0.09,0.77l0.13,0.61l1.03,0.85l0.11,2.31l3.98,3.32l1.13,3.99l1.96,1.68l0.47,1.26l3.17,2.27l1.35,-0.08l0.48,1.21l-0.58,0.27l-0.31,0.67l0.03,0.76l0.36,0.19l-0.82,0.57l-0.08,1.21l0.66,0.21l0.85,-0.73l0.72,0.34l0.3,-0.21l0.59,1.55l-9.84,2.64l-8.37,-25.89Z", "name": "Delaware"}, "US-FL": {"path": "M630.29,423.61l47.18,-6.86l1.52,1.91l0.86,2.72l1.47,1.0l48.78,-5.11l1.03,1.38l0.03,1.09l0.55,1.05l1.04,0.48l1.64,-0.28l0.85,-0.75l-0.14,-4.57l-0.98,-1.49l-0.22,-1.77l0.28,-0.74l0.62,-0.3l0.12,-0.7l5.59,0.96l4.03,-0.16l0.14,1.24l-0.75,-0.12l-0.32,0.43l0.25,1.54l2.11,1.81l0.22,1.01l0.42,0.38l0.3,1.92l5.3,11.5l1.81,3.07l7.14,10.22l0.63,0.36l6.82,7.53l-0.48,-0.02l-0.27,0.61l-1.35,-0.02l-0.34,-0.65l0.38,-1.38l-0.16,-0.56l-2.3,-0.92l-0.46,0.53l1.0,2.8l0.78,0.97l2.14,4.77l9.92,13.71l1.37,3.11l3.66,5.34l-1.38,-0.35l-0.43,0.74l0.8,0.65l0.85,0.24l0.56,-0.22l1.46,0.94l2.05,3.05l-0.5,0.34l-0.12,0.53l1.16,0.53l0.89,1.83l-0.08,1.06l0.59,0.95l0.61,2.64l-0.27,0.75l0.93,8.98l-0.31,1.07l0.46,0.67l0.5,3.1l-0.78,1.26l0.03,2.43l-0.84,0.74l-0.22,1.8l-0.48,0.85l0.21,1.47l-0.31,1.74l0.54,1.74l0.45,0.23l-1.15,1.8l-0.39,1.28l-0.94,0.24l-0.53,-0.22l-1.37,0.45l-0.35,1.06l-0.89,0.3l-0.18,0.58l-0.85,0.67l-1.44,0.14l-0.27,-0.32l-1.23,-0.1l-0.9,1.05l-3.17,1.13l-1.06,-0.59l-0.7,-1.04l0.06,-1.8l1.0,0.84l1.64,0.47l0.26,0.63l0.52,0.07l1.35,-0.72l0.2,-0.69l-0.26,-0.64l-1.58,-1.11l-2.4,-0.26l-0.91,-0.46l-0.85,-1.67l-0.89,-0.72l0.22,-0.98l-0.48,-0.28l-0.53,0.15l-1.38,-2.51l-0.44,-0.3l-0.64,0.07l-0.44,-0.61l0.22,-0.89l-0.7,-0.65l-1.21,-0.6l-1.06,-0.08l-0.75,-0.54l-0.57,0.18l-2.8,-0.59l-0.5,0.64l0.25,-0.91l-0.46,-0.42l-0.87,0.12l-0.26,-0.72l-0.88,-0.65l-0.61,-1.41l-0.55,-0.11l-0.73,-2.95l-0.77,-0.98l-0.16,-1.52l-0.44,-0.83l-0.71,-0.89l-0.49,-0.15l-0.12,0.93l-1.29,-0.26l1.07,-1.3l0.18,-1.37l0.86,-1.46l0.65,-0.34l0.28,-0.83l-0.61,-0.38l-1.42,0.93l-1.03,1.67l-0.28,1.79l-1.37,0.35l-0.2,-1.33l-0.79,-1.33l-0.27,-4.04l-0.86,-0.6l1.63,-1.33l0.22,-0.97l-0.58,-0.42l-3.05,1.92l-0.75,-0.66l-0.4,0.26l-1.27,-0.89l-0.37,0.74l1.13,1.09l0.52,0.1l1.26,2.0l-1.04,0.24l-1.43,-0.38l-0.84,-1.6l-1.13,-0.6l-1.94,-2.54l-1.04,-2.28l-1.28,-0.87l0.1,-0.87l-0.97,-1.8l-1.77,-0.98l0.09,-0.67l0.99,-0.41l-0.35,-0.49l0.44,-0.73l-0.39,-0.35l0.4,-1.21l2.47,-4.47l-1.05,-2.41l-0.68,-0.46l-0.92,0.42l-0.28,0.93l0.29,1.19l-0.24,0.03l-0.73,-2.44l-0.99,-0.28l-1.18,-0.87l-1.52,-0.31l0.29,1.94l-0.48,0.61l0.27,0.59l2.21,0.56l0.24,0.97l-0.37,2.46l-0.31,-0.58l-0.8,-0.21l-2.13,-1.53l-0.41,0.2l-0.29,-0.62l0.59,-2.11l0.07,-2.97l-0.66,-1.97l0.42,-0.51l0.48,-1.91l-0.24,-0.54l0.66,-3.04l-0.37,-5.41l-0.69,-1.56l0.35,-0.47l-0.47,-2.18l-2.1,-1.33l-0.05,-0.53l-0.55,-0.43l-0.1,-1.01l-0.92,-0.73l-0.55,-1.51l-0.64,-0.25l-1.44,0.32l-1.02,-0.2l-1.57,0.54l-1.15,-1.74l-1.5,-0.47l-0.19,-0.6l-1.35,-1.51l-3.81,-1.88l-0.51,-2.75l-3.06,-1.14l-0.65,-0.59l-0.52,-1.23l-2.15,-1.93l-2.19,-1.09l-1.45,-0.12l-3.44,-1.68l-2.85,0.98l-1.01,-0.4l-1.04,0.42l-0.36,0.68l-1.33,0.68l-0.5,0.71l0.03,0.64l-0.73,-0.22l-0.59,0.6l0.67,0.94l1.51,0.08l0.41,0.21l-3.03,0.23l-1.58,1.51l-0.91,0.45l-1.3,1.56l-1.56,1.03l-0.32,0.13l0.2,-0.48l-0.26,-0.54l-0.67,-0.04l-2.07,2.24l-2.2,0.23l-2.11,1.06l-0.78,0.03l-0.27,-2.03l-1.71,-2.23l-2.21,-1.0l-0.18,-0.41l-2.51,-1.5l2.8,1.33l1.21,-0.74l-0.0,-0.74l-1.32,-0.34l-0.35,0.55l-0.21,-1.01l-0.34,-0.1l0.12,-0.52l-0.49,-0.33l-1.4,0.61l-2.3,-0.76l0.65,-1.08l0.83,-0.1l1.03,-1.45l-0.91,-0.96l-0.46,0.13l-0.49,1.02l-0.44,-0.04l-0.81,0.56l-0.72,-0.9l-0.7,0.09l-0.17,0.38l-1.34,0.73l-0.14,0.68l0.28,0.46l-3.95,-1.35l-5.05,-0.71l0.11,-0.24l1.27,0.29l0.61,-0.53l2.1,0.39l0.23,-0.78l-0.94,-1.02l0.09,-0.69l-0.62,-0.29l-0.5,0.32l-0.28,-0.47l-1.9,0.19l-2.25,1.1l0.3,-0.64l-0.41,-0.58l-0.96,0.35l-0.58,-0.25l-0.23,0.44l0.2,0.71l-1.45,0.79l-0.4,0.64l-5.17,0.97l0.32,-0.52l-0.4,-0.52l-1.35,-0.28l-0.72,-0.53l0.69,-0.53l0.01,-0.78l-0.68,-0.13l-0.81,-0.66l-0.46,0.11l0.14,0.76l-0.42,1.77l-1.05,-1.39l-0.69,-0.45l-0.55,0.07l-0.3,0.71l0.82,1.77l-0.25,0.79l-1.39,0.99l-0.05,1.04l-0.6,0.22l-0.17,0.57l-1.48,0.55l0.28,-0.66l-0.22,-0.45l1.14,-1.03l0.07,-0.74l-0.4,-0.58l-1.18,-0.24l-0.42,-0.84l0.3,-1.7l-0.18,-1.61l-2.17,-1.12l-2.39,-2.46l0.32,-1.44l-0.15,-1.04ZM644.36,434.04l-0.94,0.26l0.4,-0.44l0.53,0.18ZM665.13,435.61l0.98,-0.28l0.35,0.31l0.08,0.72l-1.42,-0.75ZM770.53,454.92l0.42,0.56l-0.43,0.75l0.0,-1.31Z", "name": "Florida"}, "US-CT": {"path": "M823.41,156.51l2.83,-3.23l-0.07,-0.54l-1.31,-1.25l-3.5,-15.89l9.81,-2.41l0.6,0.46l0.65,-0.26l0.23,-0.58l14.16,-4.0l3.2,10.18l0.47,1.96l-0.04,1.69l-1.66,0.32l-0.92,0.81l-0.69,-0.36l-0.5,0.1l-0.18,0.91l-1.14,0.07l-1.27,1.27l-0.62,-0.14l-0.56,-1.02l-0.89,-0.09l-0.21,0.67l0.75,0.64l0.08,0.54l-0.89,-0.02l-1.02,0.87l-1.65,0.07l-1.15,0.94l-1.44,0.13l-1.21,0.93l-0.65,-1.0l-0.61,0.11l-1.01,2.46l-1.06,0.61l-0.25,1.02l-0.77,-0.26l-0.96,0.56l-0.09,0.85l-1.72,0.98l-1.94,2.27l-1.19,0.46l-0.24,0.38l-1.4,-1.23Z", "name": "Connecticut"}, "US-WA": {"path": "M38.51,55.06l0.37,-1.08l0.93,0.65l0.55,-0.14l0.54,-0.65l0.49,0.67l0.71,-0.01l0.17,-0.77l-0.98,-1.47l0.85,-0.83l-0.09,-1.36l0.49,-0.39l-0.1,-1.03l0.81,-0.27l0.05,0.5l0.48,0.41l0.95,-0.31l-0.09,-0.68l-1.44,-1.82l-1.84,-0.1l-0.15,0.32l-0.78,-0.82l0.26,-1.62l0.66,0.53l0.52,-0.07l0.29,-0.56l-0.17,-0.68l3.33,-0.52l0.25,-0.68l-2.59,-1.29l-0.05,-0.79l-0.67,-0.57l-1.3,-0.31l0.37,-4.73l-0.5,-1.29l0.25,-0.72l-0.52,-0.48l0.55,-3.93l0.04,-4.38l-0.56,-1.02l-0.04,-0.98l-1.56,-2.34l0.33,-4.24l-0.21,-1.29l0.78,-0.79l0.04,-0.71l0.97,-1.44l-0.6,-1.43l1.04,0.8l0.44,0.0l3.35,3.31l0.99,0.35l2.18,2.41l3.73,1.49l1.21,0.07l0.79,0.71l0.67,0.31l0.6,-0.15l1.57,1.07l1.49,0.47l1.28,0.28l1.22,-0.61l0.53,0.31l0.46,0.71l-0.05,1.24l0.55,0.74l0.8,-0.24l0.07,-0.75l0.44,0.03l0.63,1.39l-0.4,0.58l0.34,0.49l0.56,-0.04l0.73,-0.84l-0.38,-1.7l1.03,-0.24l-0.44,0.23l-0.22,0.69l1.27,4.41l-0.46,0.1l-1.67,1.72l0.22,-1.29l-0.22,-0.41l-1.31,0.31l-0.38,0.81l0.09,0.95l-1.37,1.7l-1.98,1.38l-1.06,1.41l-0.96,0.69l-1.1,1.67l-0.06,0.71l0.62,0.6l0.96,0.12l2.77,-0.48l1.22,-0.58l-0.03,-0.7l-0.64,-0.23l-2.94,0.79l-0.35,-0.3l3.23,-3.42l3.06,-0.88l0.89,-1.51l1.73,-1.54l0.53,0.57l0.54,-0.19l0.22,-1.81l-0.06,2.25l0.26,0.91l-0.98,-0.21l-0.64,0.77l-0.41,-0.73l-0.53,-0.19l-0.39,0.64l0.32,2.34l-0.21,-1.07l-0.67,-0.21l-0.46,0.69l-0.07,0.75l0.46,0.66l-0.63,0.58l-0.0,0.45l0.42,0.17l1.67,-0.57l0.25,1.09l-1.08,1.79l-0.08,1.05l-0.83,0.7l0.13,1.0l-0.85,-0.68l1.12,-1.44l-0.23,-0.96l-1.96,1.08l-0.38,0.64l-0.05,-2.11l-0.52,0.02l-1.03,1.59l-1.26,0.53l-1.14,1.87l-1.51,0.3l-0.46,0.44l-0.21,1.18l1.11,-0.03l-0.25,0.36l0.27,0.37l0.93,0.02l0.06,0.68l0.53,0.47l0.52,-0.27l0.35,-1.76l0.15,0.42l0.83,-0.15l1.11,1.48l1.31,-0.61l1.64,-1.48l0.98,-1.56l0.63,0.78l0.73,0.14l0.44,-0.23l-0.06,-0.86l1.56,-0.55l0.35,-0.94l-0.33,-1.26l0.22,-1.19l-0.18,-1.35l0.83,0.2l0.3,-0.92l-0.19,-0.75l-0.72,-0.63l0.89,-1.13l0.07,-1.75l1.24,-1.24l0.61,-1.37l1.61,-0.49l0.78,-1.15l-0.45,-0.66l-0.51,-0.02l-0.86,-1.3l0.16,-2.09l-0.26,-0.87l0.49,-0.79l0.06,-0.84l-1.15,-1.73l-0.63,-0.4l-0.17,-0.64l0.18,-0.5l0.59,0.24l0.53,-0.33l0.24,-1.8l0.79,-0.24l0.3,-1.0l-0.61,-2.32l0.44,-0.53l-0.03,-0.86l-0.96,-0.88l-0.95,0.3l-1.09,-2.65l0.93,-1.82l41.31,9.4l38.95,7.65l-10.13,55.39l1.04,3.0l0.13,2.0l-1.0,1.3l0.73,1.88l-31.18,-5.92l-1.67,0.79l-7.24,-1.02l-1.68,0.92l-4.19,-0.12l-3.18,0.45l-1.64,0.75l-0.88,-0.26l-1.2,0.3l-1.51,-0.23l-2.43,-0.94l-0.91,0.46l-3.45,0.51l-2.11,-0.71l-1.65,0.3l-0.31,-1.36l-1.09,-0.88l-4.34,-1.46l-2.32,-0.11l-1.15,-0.51l-1.27,0.21l-1.89,0.86l-4.49,0.58l-2.26,-1.01l-1.61,-1.15l-1.84,-0.51l-0.63,-0.81l0.64,-6.82l-0.46,-0.95l-0.22,-1.9l-0.98,-1.35l-1.96,-1.67l-1.59,-0.23l-1.31,0.28l-1.95,-3.24l-2.07,-0.23l-0.56,-0.3l-0.1,-0.52l-0.55,-0.47l-1.22,0.28l-0.81,-0.15l-1.0,0.52l-1.03,-1.77l-0.93,-0.23ZM61.97,39.77l0.16,0.74l-0.42,0.48l0.0,-0.91l0.26,-0.31ZM71.38,20.37l-0.61,0.87l-0.15,0.52l0.18,-1.38l0.58,-0.01ZM71.25,15.62l-0.09,-0.05l0.05,-0.04l0.04,0.1ZM70.48,15.47l-0.77,0.39l0.37,-0.68l-0.07,-0.6l0.22,-0.07l0.25,0.97ZM57.68,42.43l0.04,-0.02l-0.01,0.0l-0.03,0.01Z", "name": "Washington"}, "US-KS": {"path": "M477.93,239.62l0.44,0.63l0.76,0.18l1.04,0.8l2.19,-1.08l-0.0,0.75l1.08,0.79l0.23,1.44l-0.95,-0.15l-0.6,0.31l-0.17,0.97l-1.14,1.37l-0.06,1.14l-0.79,0.5l0.04,0.64l1.56,2.1l2.0,1.49l0.2,1.13l0.42,0.86l0.74,0.56l0.32,1.11l1.89,0.91l1.54,0.26l2.67,46.81l-31.54,1.48l-31.97,0.88l-31.98,0.26l-32.04,-0.37l1.21,-65.46l27.89,0.35l27.85,-0.14l27.84,-0.64l27.67,-1.12l1.65,1.23Z", "name": "Kansas"}, "US-WI": {"path": "M510.09,124.06l0.41,-0.27l0.28,-0.9l-0.45,-1.48l0.04,-1.91l0.7,-1.16l0.53,-2.25l-1.61,-2.91l-0.83,-0.36l-1.28,-0.01l-0.21,-2.31l1.67,-2.26l-0.05,-0.77l0.77,-1.55l1.95,-1.09l0.48,-0.75l0.97,-0.25l0.45,-0.75l1.16,-0.14l1.04,-1.56l-0.97,-12.11l1.03,-0.35l0.22,-1.1l0.73,-0.97l0.78,0.7l1.68,0.64l2.61,-0.56l3.27,-1.57l2.65,-0.82l2.22,-2.12l0.31,0.29l1.39,-0.11l1.25,-1.48l0.79,-0.58l1.04,-0.1l0.4,-0.52l1.07,0.99l-0.48,1.68l-0.67,1.01l0.23,1.61l-1.21,2.21l0.64,0.66l2.5,-1.09l0.72,-0.87l2.15,1.22l2.34,0.47l0.44,0.53l0.86,-0.13l1.6,0.7l2.23,3.54l15.47,2.52l4.65,1.96l1.67,-0.16l1.63,0.42l1.33,-0.59l3.17,0.71l2.18,0.09l0.85,0.41l0.56,0.89l-0.42,1.09l0.41,0.77l3.4,0.63l1.4,1.13l-0.16,0.71l0.59,1.11l-0.36,0.81l0.43,1.25l-0.78,1.25l-0.03,1.76l0.91,0.63l1.38,-0.26l1.02,-0.72l0.2,0.26l-0.79,2.44l0.04,1.31l1.32,1.46l0.84,0.35l-0.24,2.02l-2.42,1.2l-0.51,0.78l0.04,1.26l-1.61,3.49l-0.4,3.5l1.11,0.83l0.91,-0.04l0.5,-0.37l0.49,-1.37l1.82,-1.47l0.66,-2.54l1.06,-1.7l0.59,0.18l0.58,-0.71l0.87,-0.4l1.12,1.12l0.59,0.2l-0.28,2.18l-1.19,2.85l-0.57,5.58l0.23,1.11l0.8,0.93l0.07,0.52l-0.51,0.98l-1.3,1.34l-0.86,3.88l0.15,2.57l0.72,1.2l0.06,1.24l-1.07,3.23l0.12,2.11l-0.73,2.11l-0.28,2.46l0.59,2.02l-0.04,1.32l0.49,0.53l-0.21,1.7l0.92,0.78l0.54,2.44l1.2,1.54l0.08,1.69l-0.33,1.45l0.48,2.95l-44.2,4.6l-0.19,-0.79l-1.56,-2.19l-4.94,-0.84l-1.06,-1.35l-0.36,-1.68l-0.9,-1.21l-0.86,-4.89l1.04,-2.61l-0.09,-0.99l-0.71,-0.79l-1.44,-0.48l-0.71,-1.76l-0.47,-6.02l-0.7,-1.4l-0.52,-2.56l-1.15,-0.6l-1.1,-1.56l-0.93,-0.11l-1.17,-0.75l-1.71,0.09l-2.67,-1.79l-2.3,-3.5l-2.64,-2.1l-2.94,-0.53l-0.73,-1.24l-1.12,-1.0l-3.12,-0.45l-3.53,-2.74l0.45,-1.24l-0.12,-1.61l0.25,-0.81l-0.88,-3.11Z", "name": "Wisconsin"}, "US-OR": {"path": "M10.81,140.09l0.63,-3.94l1.32,-2.52l0.23,-1.22l-0.01,-1.26l-0.46,-0.66l-0.14,-1.12l-0.42,-0.32l-0.11,-1.85l2.73,-3.63l2.2,-4.73l0.1,-1.09l0.42,-0.27l0.01,0.79l0.73,0.1l0.42,-1.11l0.88,-0.84l0.23,0.94l1.39,0.27l-0.51,-2.64l-0.92,0.08l2.09,-3.81l1.11,-0.76l0.8,0.4l0.55,-0.33l-0.66,-1.35l-0.6,-0.3l1.71,-4.39l0.41,-0.38l0.04,-0.96l1.74,-5.49l0.97,-1.98l0.4,0.33l0.67,-0.29l-0.12,-0.97l-0.56,-0.32l0.96,-2.74l0.81,0.17l0.23,-0.45l-0.16,-0.52l-0.52,-0.28l0.54,-2.86l1.58,-2.7l0.83,-3.02l1.14,-1.76l0.97,-3.1l-0.08,-1.04l1.21,-1.1l0.04,-0.6l-0.46,-0.65l0.14,-0.52l0.51,0.64l0.45,0.05l0.39,-0.63l0.17,-1.39l-0.74,-0.72l0.5,-1.2l1.28,-0.78l0.05,-0.46l-0.86,-0.5l-0.26,-1.11l0.86,-2.17l-0.06,-1.44l0.92,-0.59l0.4,-0.85l0.07,-3.75l0.49,0.86l0.9,0.41l-0.04,0.91l0.55,0.53l0.43,-0.82l0.39,-0.14l-0.27,-0.98l1.12,0.84l1.53,0.0l1.45,-0.68l1.44,2.36l1.99,0.78l1.39,-0.67l0.91,0.06l1.72,1.51l0.77,1.04l0.21,1.9l0.43,0.78l-0.03,2.05l-0.39,1.24l0.19,0.93l-0.43,1.74l0.26,1.45l0.79,0.85l1.94,0.56l1.44,1.05l2.4,1.1l4.98,-0.53l2.9,-1.06l1.14,0.51l2.23,0.09l4.24,1.43l0.69,0.54l0.19,1.15l0.57,0.58l1.86,-0.27l2.11,0.71l3.79,-0.55l0.69,-0.42l2.19,0.93l1.64,0.24l1.19,-0.3l0.88,0.26l1.89,-0.78l3.07,-0.43l4.16,0.13l1.61,-0.91l7.16,1.02l0.96,-0.19l0.79,-0.58l31.27,5.93l0.23,1.81l0.93,1.82l1.16,0.63l1.96,1.86l0.57,2.45l-0.16,1.0l-3.69,4.54l-0.4,1.41l-1.39,2.63l-2.21,2.42l-0.65,2.68l-1.49,1.84l-2.23,1.5l-1.92,3.35l-1.49,1.27l-0.62,2.02l-0.12,1.87l0.28,0.92l0.56,0.61l0.54,0.04l0.39,-0.35l0.63,0.76l0.89,-0.05l0.07,0.88l0.8,0.95l-0.46,1.0l-0.65,0.06l-0.33,0.4l0.21,1.8l-1.03,2.56l-1.22,1.41l-6.86,39.15l-26.21,-4.99l-28.89,-6.05l-28.8,-6.61l-28.87,-7.22l-1.54,-2.51l0.26,-2.47l-0.29,-0.87Z", "name": "Oregon"}, "US-KY": {"path": "M583.03,306.53l0.35,-2.18l1.13,0.96l0.72,0.2l0.75,-0.36l0.46,-0.88l0.87,-3.55l-0.54,-1.75l0.38,-0.86l-0.1,-1.87l-1.27,-2.04l1.79,-3.21l1.24,-0.51l0.73,0.06l7.03,2.56l0.81,-0.2l0.65,-0.72l0.24,-1.93l-1.48,-2.14l-0.24,-1.44l0.2,-0.87l0.4,-0.52l1.1,-0.18l1.24,-0.83l3.0,-0.95l0.64,-0.51l0.15,-1.13l-1.53,-2.05l-0.08,-0.68l1.33,-1.97l0.14,-1.16l1.25,0.42l1.12,-1.33l-0.68,-2.0l1.92,0.9l1.72,-0.84l0.03,1.18l1.0,0.46l0.99,-0.94l0.02,-1.36l0.51,0.16l1.9,-0.96l4.41,1.52l0.64,0.94l0.86,0.18l0.59,-0.59l0.73,-2.53l1.38,-0.55l1.39,-1.34l0.86,1.29l0.77,0.42l1.16,-0.13l0.11,0.75l0.95,0.19l0.67,-0.62l0.03,-1.0l0.84,-0.38l0.26,-0.48l-0.25,-2.09l0.84,-0.4l0.34,-0.56l-0.06,-0.69l1.25,-0.56l0.34,-0.72l0.38,1.47l0.61,0.6l1.46,0.64l1.25,-0.0l1.11,0.81l0.53,-0.11l0.26,-0.55l1.1,-0.46l0.53,-0.69l0.04,-3.47l0.85,-2.18l1.02,0.18l1.55,-1.19l0.75,-3.46l1.04,-0.37l1.65,-2.23l0.0,-0.81l-1.18,-2.88l2.78,-0.59l1.54,0.81l3.85,-2.82l2.23,-0.46l-0.18,-1.07l0.36,-1.47l-0.32,-0.36l-1.22,-0.04l0.58,-1.39l-1.09,-1.54l1.65,-1.83l1.81,1.18l0.92,-0.11l1.93,-1.01l0.78,0.88l1.75,0.54l0.57,1.28l0.94,0.92l0.79,1.84l2.6,0.67l1.87,-0.57l1.63,0.27l2.18,1.85l0.96,0.43l1.28,-0.18l0.61,-1.31l0.99,-0.54l1.35,0.5l1.34,0.04l1.33,1.09l1.26,-0.69l1.41,-0.15l1.81,-2.55l1.72,-1.03l0.92,2.35l0.7,0.83l2.45,0.81l1.35,0.97l0.75,1.05l0.93,3.35l-0.37,0.45l0.09,0.72l-0.44,0.61l0.02,0.53l2.24,2.62l1.35,0.92l-0.08,0.89l1.34,0.97l0.58,1.35l1.55,1.2l0.98,1.62l2.14,0.84l1.09,1.12l2.14,0.25l-4.86,6.13l-5.06,4.15l-0.42,0.86l0.22,1.25l-2.07,1.93l0.04,1.64l-3.06,1.63l-0.8,2.38l-1.71,0.6l-2.7,1.83l-1.66,0.48l-3.39,2.42l-23.95,3.09l-8.8,1.42l-7.47,0.86l-7.68,0.46l-22.71,3.52l-0.64,-0.56l-3.63,0.09l-0.41,0.6l1.03,3.57l-22.99,2.73Z", "name": "Kentucky"}, "US-ME": {"path": "M837.01,56.27l0.87,-1.15l1.42,1.7l0.84,0.04l0.39,-2.12l-0.46,-2.19l1.7,0.36l0.73,-0.42l0.21,-0.52l-0.32,-0.7l-1.18,-0.47l-0.44,-0.62l0.19,-1.42l0.86,-2.02l2.08,-2.25l0.01,-0.98l-0.52,-0.93l1.02,-1.64l0.39,-1.51l-0.22,-0.92l-1.02,-0.35l-0.07,-1.42l-0.4,-0.43l0.55,-0.96l-0.04,-0.63l-1.0,-1.26l0.13,-1.73l0.37,-0.63l-0.15,-0.97l1.22,-1.93l-0.96,-6.17l5.58,-18.87l2.25,-0.23l1.14,3.18l0.55,0.43l2.54,0.56l1.83,-1.73l1.68,-0.83l1.24,-1.72l1.25,-0.12l0.64,-0.47l0.25,-1.43l0.42,-0.3l1.36,0.04l3.68,1.41l1.14,0.96l2.36,1.05l8.38,22.7l0.64,0.65l-0.19,1.26l0.64,0.86l-0.1,1.52l-0.33,0.05l-0.24,0.66l1.72,1.13l1.79,0.22l0.82,0.41l1.88,-0.19l1.25,-0.64l0.34,0.86l-0.59,1.43l1.69,1.86l0.28,2.69l2.72,1.68l0.98,-0.1l0.47,-0.74l-0.06,-0.5l0.36,0.08l0.25,0.49l0.64,0.07l1.41,1.11l0.27,0.75l1.27,0.94l0.04,0.47l-0.52,-0.14l-0.39,0.41l0.18,0.77l-0.76,-0.15l-0.35,0.4l0.16,0.63l0.81,0.53l0.55,0.92l0.48,0.17l0.16,-0.88l0.39,-0.17l0.8,0.32l0.25,-0.83l0.34,0.41l-0.31,0.85l-0.53,0.19l-1.21,3.24l-0.63,-0.04l-0.31,0.44l-0.55,-1.05l-0.72,0.03l-0.3,0.5l-0.56,0.06l-0.02,0.49l0.58,0.85l-0.9,-0.45l-0.33,0.63l0.26,0.52l-1.2,-0.28l-0.36,0.3l-0.37,0.78l0.07,0.45l0.44,0.08l0.07,1.21l-0.37,-0.57l-0.55,-0.06l-0.39,0.45l-0.2,1.09l-0.48,-1.53l-1.14,0.01l-0.68,0.75l-0.36,1.48l0.59,0.63l-0.83,0.63l-0.69,-0.46l-0.73,1.04l0.1,0.64l0.99,0.63l-0.35,0.21l-0.1,0.82l-0.46,-0.21l-0.85,-1.82l-1.03,-0.46l-0.39,0.22l-0.45,-0.41l-0.57,0.63l-1.24,-0.19l-0.26,0.85l0.78,0.4l0.01,0.37l-0.51,-0.05l-0.56,0.4l-0.09,0.7l-0.49,-1.02l-1.17,-0.02l-0.16,0.64l0.52,0.88l-1.44,0.96l0.84,1.11l0.08,1.06l0.53,0.65l-0.97,-0.41l-0.96,0.22l-1.2,-0.42l-0.17,-0.91l0.74,-0.28l-0.08,-0.56l-0.42,-0.49l-0.67,-0.12l-0.3,0.33l-0.23,-2.37l-0.37,-0.22l-1.1,0.27l0.04,1.96l-1.85,1.92l0.02,0.49l1.25,1.47l-0.64,0.96l-0.19,3.87l0.77,1.41l-1.08,1.72l-0.8,-0.19l-0.45,0.93l-0.62,-0.06l-0.41,-1.15l-0.73,-0.21l-0.52,1.03l0.11,0.69l-0.45,0.59l0.12,2.41l-0.95,-1.01l0.14,-1.28l-0.24,-0.59l-0.82,0.29l-0.08,2.01l-0.44,-0.25l0.15,-1.54l-0.47,-0.4l-0.68,0.49l-0.76,3.04l-0.77,-1.97l0.17,-1.21l-0.4,-0.27l-0.46,0.21l-1.05,2.59l0.35,0.53l0.85,-0.15l0.95,2.08l-0.28,-0.59l-0.51,-0.23l-0.66,0.3l-0.07,0.64l-1.38,-0.1l-2.16,3.17l-0.53,1.86l0.29,0.6l-0.68,0.65l0.51,0.43l0.91,-0.21l0.37,0.92l-0.77,0.3l-0.2,0.39l-0.4,-0.04l-0.51,0.57l-0.14,1.03l0.67,1.37l-0.08,0.68l-0.79,1.29l-0.94,0.61l-0.54,1.29l0.44,1.56l-0.4,2.81l-0.8,-0.33l-0.42,0.59l-1.02,-0.76l-0.57,-1.85l-0.93,-0.37l-2.36,-1.99l-0.76,-3.45l-13.24,-35.53ZM863.91,81.24l0.08,0.26l-0.08,0.23l0.03,-0.29l-0.04,-0.2ZM865.32,81.46l0.47,0.7l-0.04,0.47l-0.32,-0.25l-0.1,-0.93ZM867.66,78.32l0.42,0.82l-0.16,0.14l-0.42,-0.19l0.16,-0.77ZM877.03,64.89l-0.14,0.2l-0.03,-0.24l0.17,0.04ZM873.08,75.23l0.01,0.02l-0.03,0.03l0.01,-0.06Z", "name": "Maine"}, "US-OH": {"path": "M665.07,178.88l1.66,0.36l0.97,-0.31l1.75,1.07l2.07,0.26l1.47,1.17l1.7,0.24l-2.17,1.18l-0.12,0.47l0.42,0.24l2.45,0.19l1.39,-1.1l1.76,-0.25l3.39,0.96l0.92,-0.08l1.48,-1.3l1.73,-0.59l1.15,-0.97l1.91,-0.97l2.61,-0.03l1.09,-0.62l1.24,-0.06l1.07,-0.8l4.24,-5.46l4.53,-3.47l6.92,-4.36l5.83,28.04l-0.51,0.54l-1.28,0.43l-0.41,0.95l1.65,2.23l0.02,2.11l0.41,0.26l0.31,0.94l-0.04,0.76l-0.54,0.83l-0.5,4.08l0.18,3.21l-0.58,0.41l0.34,1.11l-0.35,1.74l-0.39,0.54l0.76,1.23l-0.25,1.87l-2.41,2.65l-0.82,1.86l-1.37,1.5l-1.24,0.67l-0.6,0.7l-0.87,-0.92l-1.18,0.14l-1.32,1.74l-0.09,1.32l-1.78,0.85l-0.78,2.25l0.28,1.58l-0.94,0.85l0.3,0.67l0.63,0.41l0.27,1.3l-0.8,0.17l-0.5,1.6l0.06,-0.93l-0.91,-1.26l-1.53,-0.55l-1.07,0.71l-0.82,1.98l-0.34,2.69l-0.53,0.82l1.22,3.58l-1.27,0.39l-0.28,0.42l-0.25,3.12l-2.66,1.2l-1.0,0.05l-0.76,-1.06l-1.51,-1.1l-2.34,-0.73l-1.16,-1.92l-0.31,-1.14l-0.42,-0.33l-0.73,0.13l-1.84,1.17l-1.1,1.28l-0.4,1.05l-1.43,0.15l-0.87,0.61l-1.11,-1.0l-3.14,-0.59l-1.37,0.72l-0.53,1.25l-0.71,0.05l-3.04,-2.26l-1.93,-0.29l-1.77,0.56l-2.14,-0.52l-0.55,-1.54l-0.96,-0.97l-0.63,-1.38l-2.03,-0.76l-1.14,-1.01l-0.97,0.26l-1.31,0.89l-0.46,0.03l-1.79,-1.23l-0.61,0.2l-0.6,0.7l-8.67,-55.57l20.65,-4.25ZM675.61,181.3l0.53,-0.79l0.67,0.41l-0.48,0.35l-0.72,0.03Z", "name": "Ohio"}, "US-OK": {"path": "M399.11,359.23l-0.05,-42.02l-0.39,-0.4l-51.81,-0.82l0.31,-10.23l36.69,0.74l35.99,-0.07l35.98,-0.86l35.56,-1.62l0.6,10.68l4.55,24.34l1.41,37.87l-1.2,-0.22l-0.29,-0.36l-2.13,-0.21l-0.82,-0.79l-2.11,-0.39l-1.77,-2.05l-1.23,-0.22l-2.25,-1.56l-1.5,-0.4l-0.8,0.46l-0.23,0.88l-0.82,0.24l-0.46,0.62l-2.47,-0.14l-1.79,-1.48l-2.3,1.29l-1.16,0.2l-0.19,0.56l-0.63,0.28l-2.12,-0.77l-1.7,1.18l-2.06,0.51l-0.83,1.37l-1.48,0.06l-0.57,1.25l-1.26,-1.55l-1.7,-0.1l-0.32,-0.58l-1.21,-0.46l-0.02,-0.96l-0.44,-0.5l-1.24,-0.18l-0.73,1.38l-0.66,0.11l-0.84,-0.5l-0.97,0.07l-0.71,-1.51l-1.09,-0.35l-1.17,0.57l-0.45,1.7l-0.7,-0.08l-0.49,0.43l0.29,0.73l-0.51,1.68l-0.43,0.19l-0.86,-1.45l0.39,-1.65l-0.75,-0.86l-0.8,0.18l-0.49,0.76l-0.84,-0.18l-0.92,0.98l-1.07,0.13l-0.53,-1.36l-1.99,-0.19l-0.3,-1.48l-1.19,-0.53l-0.82,0.33l-2.12,2.15l-1.21,0.51l-0.97,-0.38l0.19,-1.25l-0.28,-1.13l-2.33,-0.67l-0.07,-2.18l-0.43,-0.55l-2.11,0.39l-2.52,-0.25l-0.64,0.26l-0.81,1.21l-0.95,0.06l-1.76,-1.77l-0.97,-0.12l-1.5,0.56l-2.68,-0.63l-1.86,-1.0l-1.05,0.25l-2.46,-0.3l-0.17,-2.12l-0.85,-0.87l-0.43,-1.02l-1.16,-0.41l-0.7,-0.83l-0.83,0.08l-0.44,1.64l-2.22,-0.68l-1.07,0.6l-0.96,-0.09l-3.79,-3.78l-1.12,-0.43l-0.8,0.08Z", "name": "Oklahoma"}, "US-ID": {"path": "M132.48,121.36l-0.34,-0.44l0.08,-1.99l0.53,-1.74l1.42,-1.22l2.11,-3.59l1.68,-0.92l1.39,-1.52l1.08,-2.15l0.05,-1.22l2.21,-2.41l1.43,-2.7l0.37,-1.37l2.04,-2.26l1.89,-2.81l0.03,-1.01l-0.79,-2.95l-2.13,-1.94l-0.87,-0.36l-0.85,-1.61l-0.41,-3.02l-0.59,-1.19l0.94,-1.19l-0.12,-2.35l-1.04,-2.69l10.12,-55.42l13.39,2.35l-3.54,20.71l1.29,2.89l1.0,1.27l0.27,1.55l1.17,1.76l-0.12,0.83l0.39,1.14l-0.99,0.95l0.83,1.76l-0.83,0.11l-0.28,0.71l1.93,1.68l1.03,2.04l2.24,1.22l0.54,1.58l1.09,1.33l1.49,2.79l0.08,0.68l1.64,1.81l0.01,1.88l1.79,1.71l-0.07,1.35l0.74,0.19l0.9,-0.58l0.36,0.46l-0.36,0.55l0.07,0.54l1.11,0.96l1.61,0.15l1.81,-0.36l-0.63,2.61l-0.99,0.54l0.25,1.14l-1.83,3.73l0.06,1.72l-0.81,0.07l-0.37,0.54l0.6,1.33l-0.62,0.9l-0.03,1.16l0.96,0.93l-0.37,0.81l0.28,1.01l-1.57,0.43l-1.21,1.41l0.1,1.11l0.46,0.77l-0.13,0.73l-0.83,0.77l-0.2,1.52l1.48,0.63l1.38,1.79l0.78,0.27l1.08,-0.35l0.56,-0.8l1.85,-0.41l1.21,-1.28l0.81,-0.29l0.15,-0.76l0.78,0.81l0.23,0.71l1.05,0.64l-0.42,1.23l0.73,0.95l-0.34,1.38l0.57,1.34l-0.21,1.61l1.54,2.64l0.31,1.73l0.82,0.37l0.67,2.08l-0.18,0.98l-0.76,0.64l0.51,1.89l1.24,1.16l0.3,0.79l0.81,0.08l0.86,-0.37l1.04,0.93l1.06,2.79l-0.5,0.81l0.89,1.83l-0.28,0.6l0.11,0.98l2.29,2.41l0.97,-0.14l-0.01,-1.14l1.07,-0.89l0.93,-0.22l4.53,1.62l0.69,-0.32l0.67,-1.35l1.19,-0.39l2.25,0.93l3.3,-0.1l0.96,0.88l2.29,-0.58l3.23,0.78l0.45,-0.49l-0.67,-0.76l0.26,-1.06l0.74,-0.48l-0.07,-0.96l1.23,-0.51l0.48,0.37l1.07,2.11l0.12,1.11l1.36,1.95l0.73,0.45l-6.27,53.85l-47.47,-6.31l-46.96,-7.72l6.88,-39.16l1.12,-1.18l1.07,-2.67l-0.21,-1.74l0.74,-0.15l0.77,-1.62l-0.9,-1.27l-0.18,-1.2l-1.24,-0.08l-0.64,-0.81l-0.88,0.29Z", "name": "Idaho"}, "US-WY": {"path": "M218.62,206.98l10.1,-86.59l25.45,2.74l26.79,2.4l26.83,1.91l27.84,1.46l-3.67,87.1l-27.31,-1.41l-28.2,-1.97l-29.69,-2.63l-28.14,-3.02Z", "name": "Wyoming"}, "US-UT": {"path": "M220.28,185.78l-2.51,21.5l0.35,0.45l32.23,3.42l-8.32,87.13l-42.53,-4.67l-42.4,-5.77l16.08,-108.32l47.1,6.26Z", "name": "Utah"}, "US-IN": {"path": "M600.87,189.59l1.42,0.87l2.1,0.15l1.52,-0.38l2.63,-1.39l2.73,-2.1l32.14,-4.8l8.96,57.41l-0.66,1.15l0.3,0.92l0.81,0.79l-0.66,1.14l0.49,0.8l1.12,0.04l-0.36,1.14l0.18,0.51l-1.81,0.29l-3.18,2.55l-0.43,0.17l-1.4,-0.81l-3.46,0.91l-0.09,0.78l1.19,3.1l-1.4,1.88l-1.18,0.49l-0.45,0.89l-0.31,2.6l-1.11,0.88l-1.06,-0.24l-0.47,0.47l-0.85,1.95l0.05,3.13l-0.39,1.0l-1.38,0.85l-0.93,-0.68l-1.24,0.01l-1.47,-0.69l-0.62,-1.84l-1.89,-0.73l-0.44,0.3l-0.04,0.5l0.83,0.68l-0.62,0.31l-0.89,-0.35l-0.36,0.29l0.5,1.42l-1.08,0.68l0.14,2.37l-1.06,0.65l-0.0,0.83l-0.16,0.37l-0.25,-1.01l-1.6,0.18l-1.4,-1.69l-0.5,-0.08l-1.67,1.5l-1.57,0.69l-1.07,2.89l-0.81,-1.07l-2.79,-0.77l-1.11,-0.61l-1.08,-0.18l-1.76,0.92l-0.64,-1.02l-0.58,-0.18l-0.53,0.56l0.64,1.86l-0.34,0.84l-0.28,0.09l-0.02,-1.18l-0.42,-0.4l-0.58,0.01l-1.46,0.79l-1.41,-0.84l-0.85,0.0l-0.48,0.95l0.71,1.55l-0.49,0.74l-1.15,-0.39l-0.07,-0.54l-0.53,-0.44l0.55,-0.63l-0.35,-3.09l0.96,-0.78l-0.07,-0.58l-0.44,-0.23l0.69,-0.46l0.25,-0.61l-1.17,-1.47l0.46,-1.16l0.32,0.19l1.39,-0.55l0.33,-1.8l0.55,-0.4l0.44,-0.92l-0.06,-0.83l1.52,-1.07l0.06,-0.69l-0.41,-0.93l0.57,-0.86l0.14,-1.29l0.87,-0.51l0.4,-1.91l-1.08,-2.54l0.06,-1.91l-0.93,-0.91l-0.61,-1.5l-1.05,-0.78l-0.04,-0.58l0.92,-1.39l-0.63,-2.25l1.27,-1.31l-6.5,-50.67Z", "name": "Indiana"}, "US-IL": {"path": "M540.1,225.5l0.86,-0.35l0.37,-0.67l-0.23,-2.33l-0.73,-0.93l0.15,-0.41l0.72,-0.69l2.42,-0.98l0.71,-0.65l0.63,-1.68l0.17,-2.11l1.65,-2.47l0.27,-0.94l-0.03,-1.22l-0.59,-1.95l-2.23,-1.88l-0.11,-1.77l0.67,-2.38l0.45,-0.37l4.6,-0.85l0.81,-0.41l0.82,-1.12l2.55,-1.0l1.43,-1.56l0.39,-3.28l1.42,-1.46l0.29,-0.74l0.33,-4.37l-0.76,-2.14l-4.02,-2.47l-0.28,-1.5l-0.48,-0.82l-3.64,-2.48l44.57,-4.64l-0.01,2.65l0.57,2.59l1.38,2.49l1.3,0.95l0.76,2.6l1.26,2.71l1.42,1.85l6.6,51.47l-1.22,1.13l-0.1,0.69l0.67,1.76l-0.84,1.09l-0.03,1.11l1.19,1.09l0.56,1.41l0.89,0.82l-0.1,1.8l1.06,2.31l-0.28,1.49l-0.87,0.56l-0.21,1.47l-0.59,0.93l0.34,1.2l-1.48,1.13l-0.23,0.41l0.28,0.7l-0.93,1.17l-0.31,1.19l-1.64,0.67l-0.63,1.67l0.15,0.8l0.97,0.83l-1.27,1.15l0.42,0.76l-0.49,0.23l-0.13,0.54l0.43,2.94l-1.15,0.19l0.08,0.45l0.91,0.78l-0.48,0.17l-0.03,0.64l0.83,0.29l0.04,0.42l-1.31,1.97l-0.25,1.19l0.59,1.22l0.7,0.64l0.37,1.08l-3.31,1.22l-1.19,0.82l-1.24,0.24l-0.77,1.01l-0.18,2.04l1.7,2.81l0.07,0.54l-0.53,1.19l-0.96,0.03l-6.3,-2.43l-1.08,-0.08l-1.57,0.64l-0.68,0.72l-1.44,2.95l0.06,0.66l-1.18,-1.2l-0.79,0.14l-0.35,0.47l0.59,1.13l-1.24,-0.79l-0.01,-0.68l-1.6,-2.21l-0.4,-1.12l-0.75,-0.37l-0.05,-0.49l0.94,-1.35l0.2,-1.03l-0.32,-1.01l-1.44,-2.02l-0.47,-3.18l-2.26,-0.99l-1.55,-2.14l-1.95,-0.82l-1.72,-1.34l-1.56,-0.14l-1.82,-0.96l-2.32,-1.78l-2.34,-2.44l-0.36,-1.95l2.37,-6.85l-0.25,-2.32l0.98,-2.06l-0.38,-0.84l-2.66,-1.45l-2.59,-0.67l-1.29,0.45l-0.86,1.45l-0.9,0.15l-1.3,-1.9l-0.43,-1.52l0.16,-0.87l-0.54,-0.91l-0.29,-1.65l-0.83,-1.36l-0.94,-0.9l-4.11,-2.52l-1.01,-1.64l-4.53,-3.53l-0.73,-1.9l-1.04,-1.21l-0.04,-1.6l-0.96,-1.48l-0.75,-3.54l0.1,-2.94l0.6,-1.28ZM585.53,295.46l0.05,0.05l0.04,0.04l-0.05,-0.0l-0.04,-0.09Z", "name": "Illinois"}, "US-AK": {"path": "M64.88,530.75l0.06,-0.04l0.04,0.06l-0.06,-0.01l-0.05,-0.0ZM66.64,530.24l1.13,0.16l0.11,0.52l-1.21,0.78l-0.23,-0.24l0.3,-0.47l-0.09,-0.76ZM69.51,530.52l0.7,-0.13l0.3,-0.66l2.1,-0.44l2.68,0.09l1.86,0.74l0.99,0.81l0.04,2.23l0.65,0.89l0.77,-0.37l-0.07,-0.76l0.56,0.36l-0.1,0.53l1.05,1.08l-1.24,-0.51l-0.68,0.56l-0.08,-0.76l-1.26,-0.01l-0.76,-0.43l-0.82,0.28l-1.12,-0.26l-0.44,-0.54l0.4,-0.34l0.95,0.84l0.47,-0.03l0.2,-0.5l-0.7,-1.62l-1.11,-0.6l-1.17,0.32l-0.66,0.82l-1.29,0.37l-0.52,-0.37l-0.59,0.38l-0.74,-0.26l-0.58,0.37l0.21,-2.07ZM81.1,534.87l0.81,-0.72l-0.68,-1.59l0.14,-0.29l1.83,-1.05l3.86,-0.11l2.68,0.81l0.57,-0.32l1.04,0.3l0.88,1.1l0.7,-0.06l0.9,-1.66l2.68,-0.78l1.06,0.33l1.28,-0.46l0.86,0.05l-0.14,0.54l0.5,0.59l1.15,0.33l0.6,-0.91l-0.56,-0.35l-0.31,0.15l0.28,-0.7l-0.2,-0.46l2.24,-2.37l1.05,0.07l0.63,0.82l0.66,-0.29l-0.11,-0.63l-1.04,-0.94l0.19,-0.63l0.96,-0.57l3.31,-0.22l-0.15,-0.63l0.81,-0.73l0.76,-0.04l1.14,-1.23l-0.94,-0.25l-0.69,0.62l-0.61,-0.12l-0.59,0.33l-5.45,-1.21l0.08,-1.16l-0.36,-0.69l0.61,-0.46l0.52,-0.18l0.49,0.51l-0.04,1.27l0.91,-0.05l0.15,-0.75l-0.06,-0.85l-0.98,-1.22l0.01,-0.82l-0.67,-0.19l-0.29,0.86l-0.73,0.37l-0.19,0.06l0.24,-0.27l-0.27,-0.52l-0.4,-0.11l-0.76,0.98l-0.97,0.24l-0.67,2.38l-0.33,0.05l-0.36,-0.33l0.03,-4.92l-0.66,-0.64l-1.23,0.46l0.07,-0.72l-0.68,-0.92l0.27,-0.42l-0.12,-1.01l-2.89,-0.21l-0.54,-0.39l-1.37,-0.13l-0.43,-0.56l-1.2,0.69l-0.99,-0.27l-0.29,-0.65l1.23,-0.02l-0.05,-0.92l0.46,-0.72l1.47,-0.11l-0.03,-0.81l-1.33,-0.74l0.14,-0.43l0.85,-0.72l1.34,-0.01l0.43,-0.43l0.58,-4.63l1.27,-1.41l-0.84,-0.73l1.97,-1.03l1.58,0.21l0.44,-0.55l-0.81,-0.46l-0.34,-0.75l-0.6,0.5l-0.57,-0.1l-1.3,0.72l-2.17,0.25l-0.12,0.5l0.5,0.82l-0.72,0.78l-0.48,-0.47l-2.21,-0.3l-2.19,-1.17l-1.56,-1.56l0.03,-0.37l0.7,-0.05l0.04,-0.67l-0.61,-1.28l-0.09,-1.54l0.39,-0.61l-0.72,-0.34l-0.58,-1.19l0.93,-0.28l0.14,-0.6l-1.09,-0.61l1.52,0.14l0.51,-0.46l0.88,0.03l0.05,0.6l1.07,1.2l-1.21,0.44l-0.39,0.39l0.31,0.47l1.11,-0.1l0.47,0.28l1.12,-0.22l0.18,0.15l-0.72,1.13l0.74,0.73l1.63,0.09l0.68,-0.64l-0.26,-0.92l0.44,-0.39l-0.14,-1.27l-0.59,-0.28l-1.31,0.1l-1.81,-1.44l0.01,-0.63l-0.97,-1.12l0.81,0.16l0.53,-0.4l-1.18,-1.08l0.63,-0.51l-0.14,-0.67l1.25,-0.21l0.53,0.32l0.83,-0.05l0.73,-0.46l-0.08,-0.52l-3.03,-0.29l-1.91,0.63l-0.4,0.68l-0.19,-0.22l0.72,-1.02l-0.63,-1.4l0.68,0.09l0.47,-0.54l-0.48,-1.21l0.96,0.46l0.42,-0.51l-0.63,-0.98l1.73,1.01l0.42,-1.53l0.59,-0.35l3.77,-0.6l0.5,0.35l0.25,0.85l-0.36,0.21l0.14,0.47l1.2,0.19l0.3,-0.42l-0.18,-1.0l1.6,-0.11l0.29,-0.63l-1.51,-0.29l0.59,-0.27l0.16,-0.74l0.9,-0.32l1.37,1.16l0.47,-0.57l-0.32,-0.84l0.37,-0.03l1.02,0.42l1.03,1.2l-0.04,0.6l-0.87,-0.06l-0.35,0.64l1.72,0.3l0.1,0.67l1.21,0.8l3.02,0.17l1.92,-0.37l0.11,0.59l2.89,1.88l2.0,0.37l1.83,-0.33l0.67,-0.63l0.41,-1.78l0.72,-1.29l-0.14,-1.81l0.74,0.39l1.24,-0.12l0.86,-0.71l-0.17,-1.62l0.3,-0.04l0.11,-0.44l-0.25,-0.34l-0.83,-0.45l-1.45,0.34l-0.98,-1.22l-1.22,0.1l-0.5,-0.38l-2.79,-0.15l-0.75,0.51l0.35,-0.85l-0.56,-1.94l-1.57,-0.24l-3.01,-2.71l-1.14,-0.28l-0.95,-0.93l-0.77,0.17l-3.27,-3.98l-0.31,-1.07l0.73,-0.34l0.39,-0.82l-0.53,-1.14l0.14,-0.32l0.52,0.26l1.05,-0.26l1.2,1.12l0.36,-0.78l-2.39,-3.21l-1.44,-1.39l-1.03,-2.33l0.73,0.11l1.02,0.72l1.24,-0.42l0.31,0.63l0.57,0.29l1.08,0.2l0.98,-0.22l1.81,0.53l1.37,1.81l1.19,0.53l0.56,-0.47l-0.6,-1.16l1.94,0.62l0.58,0.79l2.66,0.53l1.79,1.18l0.34,0.64l-0.69,0.11l-0.63,0.77l-1.35,-0.42l-0.12,0.69l0.75,0.66l0.19,1.01l2.13,1.87l1.3,0.71l-0.16,0.68l2.13,1.1l0.66,1.36l0.45,0.21l2.16,-0.88l0.7,1.0l-0.4,0.08l0.01,0.51l0.87,0.33l0.96,-0.71l-0.06,-1.11l-0.58,-0.85l0.4,0.0l1.01,2.11l1.88,1.12l0.85,-0.28l0.74,-1.61l-0.17,-0.25l-1.34,-0.47l-0.61,-1.11l-1.03,-0.61l-1.16,0.14l-0.44,-0.38l-0.48,-1.61l1.18,-0.54l0.78,0.4l0.37,-0.59l-0.87,-1.38l-1.35,-0.8l0.0,-1.23l-0.47,-0.25l-1.01,0.43l-3.2,-3.27l0.71,-1.39l0.04,-2.41l-2.35,-5.81l-1.25,-1.7l-0.54,-1.91l1.29,-0.66l1.24,-1.29l3.37,2.86l2.53,1.62l1.6,0.63l4.17,0.25l2.43,-1.65l1.96,0.17l1.51,-0.27l4.46,2.3l3.16,0.43l0.14,0.68l-0.34,0.08l-0.14,0.66l0.53,0.23l0.34,1.4l0.55,-0.29l0.38,-1.21l1.25,0.75l0.88,0.14l0.29,-0.35l-0.22,-0.39l-1.5,-1.03l0.05,-0.38l0.97,-0.06l0.34,0.13l0.34,1.14l0.55,0.33l0.18,-0.22l0.76,0.21l3.84,2.25l2.9,0.43l2.71,-0.19l0.31,0.85l0.85,0.61l0.02,0.66l1.47,0.88l-0.91,-0.04l-0.91,-0.49l-0.93,0.25l0.42,0.83l-0.26,0.43l0.18,0.59l0.73,-0.04l1.12,0.51l1.03,-0.39l1.07,0.65l0.92,-0.02l0.21,0.47l-0.71,0.01l-0.29,0.34l1.75,2.14l1.64,0.18l2.21,1.14l1.47,1.72l0.67,-0.07l0.41,0.37l-1.57,0.55l-0.18,0.63l2.16,1.28l-0.22,0.75l1.74,1.13l0.58,0.79l0.82,-0.05l1.56,0.52l0.51,0.45l0.14,0.61l2.14,0.56l1.96,1.16l1.82,1.63l0.39,0.96l1.19,0.37l1.05,0.92l-0.12,0.41l0.45,0.47l1.93,1.39l4.48,2.43l1.5,1.94l1.21,0.76l1.38,0.67l0.93,0.04l0.77,0.37l0.03,0.38l1.6,0.03l1.23,0.61l0.47,0.58l0.29,-0.26l1.69,1.44l1.68,2.36l1.24,0.84l0.65,1.11l1.25,0.49l-27.91,60.77l0.17,0.48l1.69,1.44l0.83,-0.19l1.44,1.5l2.05,-0.3l2.16,0.82l-0.98,1.08l-0.15,0.61l0.53,1.11l1.01,1.05l0.05,1.28l2.81,5.56l-0.47,2.71l0.54,0.33l1.98,-0.35l0.06,0.23l-1.19,0.71l0.29,0.54l0.84,-0.22l1.03,0.71l0.36,1.46l-0.28,0.03l-0.1,0.51l0.26,0.36l1.11,0.26l-0.24,0.59l0.49,0.49l-0.11,0.51l-0.36,-0.03l-0.12,-0.59l-0.85,-0.8l-0.47,-0.03l-1.0,0.68l-0.32,-0.86l-1.11,-0.57l-1.15,-1.83l0.58,-0.48l-0.09,-0.3l-0.99,-0.27l-0.56,-1.13l-0.02,-1.29l-1.34,-2.12l0.09,-0.76l-1.17,-0.46l-1.47,-1.72l-0.33,-0.8l-1.65,-1.66l1.58,-0.72l-0.4,0.98l0.71,0.53l0.48,-0.34l0.48,-1.49l0.98,0.8l0.73,-0.31l-0.53,-0.92l-0.81,-0.46l-0.73,-1.81l-0.41,-0.17l-2.16,1.02l-2.27,-0.06l-1.73,-1.01l-1.8,-1.85l0.52,-0.4l0.26,-0.96l-0.45,-1.04l-0.92,0.09l-0.12,0.64l-0.81,-0.05l-1.0,-1.05l-3.3,-2.31l-5.2,-1.56l-0.48,-1.29l0.16,-0.55l-1.83,-0.99l-0.64,-1.23l0.85,-0.63l0.26,-0.77l1.16,-0.21l0.15,-0.7l-0.98,-0.3l-2.56,1.0l-1.03,-0.01l-0.22,-0.7l-0.85,-0.75l1.1,-0.51l0.19,-0.4l-0.31,-0.45l-0.64,-0.02l-0.47,-0.8l0.14,-0.59l-0.49,-1.17l-0.45,-0.22l-0.62,0.19l-0.57,-0.49l0.25,-0.73l0.46,-0.09l1.22,0.53l0.42,-0.5l-0.16,-0.48l-1.49,-0.88l-1.82,0.34l-0.6,-0.61l-1.17,-0.28l-0.22,-0.32l0.32,-1.1l-0.72,-0.3l0.35,-0.97l-0.33,-0.29l-2.04,0.78l-0.28,-0.64l-1.38,-0.22l-0.75,0.57l0.31,0.89l-1.75,-0.34l-0.8,0.99l0.26,0.62l0.9,-0.03l-0.2,0.34l-1.52,0.34l-0.23,0.63l0.38,0.29l1.02,-0.16l0.49,0.83l-0.47,0.61l-0.59,-0.24l-0.7,0.58l0.05,0.63l-0.31,0.35l-0.27,-0.15l-0.68,0.39l-1.38,-1.05l0.03,-0.72l-1.08,-0.12l0.11,-0.8l-0.55,-0.46l-1.0,1.06l-1.09,-0.68l-0.44,0.5l-0.48,-0.1l-0.2,0.41l-0.8,-0.43l-0.29,0.55l-0.7,-0.52l-1.3,0.56l-0.16,-0.45l-0.91,-0.04l-0.56,0.81l-1.73,0.25l-1.02,-0.92l-0.6,0.32l-0.44,-0.36l-1.29,0.01l-0.44,-1.08l0.64,0.17l0.17,-0.48l0.68,0.04l0.89,0.91l0.56,-0.11l0.11,-0.54l0.9,0.16l1.67,-0.74l0.32,-0.52l-0.22,-0.4l-2.72,-0.16l-0.79,-1.25l1.54,-1.19l1.91,-0.52l0.81,-0.85l0.52,-0.09l0.76,-1.03l0.15,-1.27l1.37,0.34l3.53,-0.14l0.24,1.07l0.66,0.57l1.41,0.31l2.69,2.59l0.5,-0.37l-0.13,-0.93l-0.99,-0.67l-1.76,-2.54l1.94,-0.66l2.25,0.33l0.05,-0.75l-1.75,-0.86l-1.62,0.15l-0.71,0.63l-1.07,-0.92l-0.7,-0.18l0.17,-0.32l-0.28,-0.7l-1.24,0.32l-1.57,-0.23l-0.99,0.48l-1.49,-0.52l-1.37,0.05l-0.78,0.4l-0.2,0.55l-1.24,-0.08l-1.92,0.49l-0.59,0.81l-0.62,0.26l-0.75,-0.02l-0.97,-1.32l-1.1,-0.29l-0.3,0.28l0.16,0.51l0.44,0.07l0.66,2.11l-0.91,0.44l-2.4,-0.95l-0.46,0.21l0.03,0.68l0.78,0.42l-0.2,0.15l-0.56,0.01l-0.54,-1.57l-0.76,0.74l-0.24,-0.5l-0.88,0.16l-0.13,0.57l-0.85,-0.44l-0.36,0.28l0.3,0.67l-1.93,-0.49l-0.81,1.18l-0.83,0.28l-0.17,1.22l0.33,0.36l0.71,-0.05l1.13,0.82l0.76,1.64l-0.81,0.65l-1.11,0.16l-1.09,-0.54l-0.98,0.53l-0.75,-0.18l-0.37,0.73l-1.4,-0.13l-0.46,0.82l-0.5,-0.62l-0.4,0.44l-1.47,0.04l-1.12,-0.71l-1.09,0.61l-0.67,-0.22l-0.91,0.37l-0.64,-0.78l-0.94,0.73l-0.49,-0.21l-0.32,0.36l-0.62,-0.1l-0.41,-0.5l-0.83,0.37l-2.51,-0.14l-0.57,0.44l0.28,1.17l-0.59,0.14l-1.31,-0.59l-0.58,0.52l-0.3,-0.46l-2.04,0.38l-0.15,-0.68l-0.48,-0.37l-0.79,0.47l-0.83,0.0l-0.29,0.61l-0.03,-0.62l-0.42,-0.3l-1.95,-0.18l-0.77,0.39l-0.34,-0.37l-0.72,-0.1l-1.8,0.43l-0.28,0.75l-0.4,-0.03l-0.82,0.77l-2.9,-0.76l-0.87,-0.79l-0.66,0.16l-0.84,-0.82l-1.36,-0.26l-0.93,0.26ZM89.01,536.65l-0.02,0.01l-0.0,0.03l0.02,-0.04ZM89.06,536.61l0.02,-0.01l-0.01,0.01l-0.0,0.01ZM91.61,484.22l-0.0,0.01l-0.0,-0.01l0.01,0.0ZM87.17,484.0l-0.0,-0.0l0.01,-0.0l-0.0,0.01l-0.01,-0.0ZM186.66,475.29l-0.0,0.02l-0.01,-0.01l0.01,-0.0ZM156.69,531.75l-0.95,1.06l-0.87,0.02l-0.13,-0.28l0.69,-0.51l1.26,-0.28ZM151.45,532.97l-0.11,0.02l0.12,-0.04l-0.01,0.02ZM152.06,535.54l-0.09,-0.14l0.41,-0.11l-0.1,0.3l-0.22,-0.05ZM116.92,535.18l-0.13,0.11l-0.06,-0.02l0.04,-0.19l0.16,0.1ZM90.72,536.66l0.27,-0.19l0.07,0.3l-0.17,0.07l-0.17,-0.19ZM121.46,528.8l-0.0,-0.02l0.04,0.01l-0.03,0.01ZM186.96,558.95l-0.09,-1.09l0.4,-0.11l0.13,0.57l-0.44,0.62ZM196.09,568.76l2.06,0.17l0.88,-0.72l0.4,-0.93l0.62,0.05l0.66,-0.45l0.12,-0.56l3.59,0.11l1.22,2.1l-0.59,0.6l0.11,1.69l1.05,0.86l0.25,0.97l0.46,0.34l0.11,1.76l1.72,2.25l0.24,1.0l-1.26,-0.23l-0.94,0.69l-0.72,1.06l-0.71,-1.34l-1.02,-0.73l0.15,-0.58l-0.32,-1.25l0.48,-1.41l-0.8,-0.55l0.41,-2.32l-0.18,-1.24l0.62,-1.53l-0.66,-0.25l-0.62,0.87l-0.78,-0.09l0.03,0.58l-0.38,0.41l0.37,1.24l-0.41,0.99l0.15,1.56l-0.41,1.27l0.03,2.19l-0.37,0.45l-0.41,-0.46l0.02,-1.59l-0.29,-0.45l-0.66,0.28l-1.11,-0.29l0.47,-0.38l0.24,-0.99l-0.35,-1.47l1.14,0.14l0.45,-0.45l-0.11,-0.36l-0.86,-0.52l-0.27,0.12l-0.01,-1.01l-0.61,-0.4l-0.96,1.15l0.46,0.38l-0.33,0.4l-0.04,-0.54l-0.68,-0.29l0.29,-0.67l-0.28,-0.54l-0.39,-0.02l-0.2,-0.62l-0.47,-0.15l-0.26,0.42l-0.35,-0.7ZM209.19,578.54l0.61,1.19l-0.23,0.77l0.66,1.82l0.05,1.22l1.73,7.29l-0.66,0.56l0.03,0.64l1.0,0.69l-0.59,0.84l0.05,0.52l0.72,0.67l-0.2,1.56l0.37,0.44l1.07,0.31l1.71,2.17l1.4,0.95l0.39,0.88l0.67,0.5l0.09,0.91l1.53,1.02l-0.19,0.84l-1.17,1.01l-0.41,1.68l-0.0,2.19l-2.07,1.87l-1.09,0.57l-0.63,-0.13l-0.02,-1.13l-0.64,0.07l-0.3,1.04l-0.22,0.05l0.16,-1.54l1.09,0.23l2.31,-1.69l-0.23,-0.63l-0.64,0.13l-0.33,-0.61l-0.71,0.13l0.71,-2.09l0.22,-1.84l-0.43,-0.29l-0.4,-1.06l0.62,-0.2l0.58,-0.88l-0.43,-0.27l-1.78,0.52l-0.59,-0.36l-2.75,0.29l-0.13,0.71l0.35,0.37l-0.57,0.72l-0.64,-0.46l-0.2,1.01l-0.3,-0.39l0.1,-0.81l0.89,-0.27l0.51,-0.97l0.54,-0.2l0.43,-1.37l1.49,0.53l1.01,-0.36l-0.17,-0.59l-1.8,-0.6l0.03,-1.02l-0.82,-0.63l0.03,-0.53l-0.51,-0.72l0.35,-0.41l-0.16,-0.68l-0.59,-0.0l0.81,-0.68l0.22,-0.62l-0.41,-0.27l-0.79,0.23l-0.68,-1.21l0.4,-0.26l0.21,-1.19l-0.39,-0.3l-0.8,0.09l-0.48,-1.2l-0.52,-0.26l-0.49,0.27l-0.37,-0.39l0.13,-0.25l1.84,0.29l0.62,-0.37l-0.23,-0.67l-1.19,-0.13l0.23,-0.72l-0.6,-0.28l0.07,-0.27l0.81,-0.01l0.81,1.13l0.62,-0.14l0.04,-0.52l-1.77,-2.58l0.17,-0.56l1.59,1.01l0.37,-0.69l-0.4,-0.48l-1.89,-0.89l0.24,-0.34l-0.2,-0.47l0.54,-0.81l-0.81,-0.3l-0.88,0.87l-0.2,-0.58l0.08,-0.72l0.74,-0.62l0.17,-0.66l0.54,-0.5l0.92,-0.14ZM214.84,608.68l-0.72,0.37l-0.3,-0.26l-0.82,0.1l0.74,-0.58l1.09,0.36ZM207.55,585.56l-0.21,-0.06l0.0,-0.24l0.08,0.17l0.13,0.13ZM124.33,461.82l-0.72,-0.79l0.08,-0.62l0.61,0.33l0.02,1.08ZM96.68,478.86l-0.08,-0.01l0.0,-0.01l0.08,0.02ZM87.61,480.71l-0.14,-0.07l0.02,0.0l0.12,0.07ZM87.75,487.21l-0.01,0.0l-0.04,-0.04l0.05,0.04ZM210.21,605.25l0.95,-0.39l0.15,-0.88l1.01,-0.37l0.59,-1.12l0.76,0.04l0.47,2.53l-1.46,2.49l0.34,-0.93l-0.25,-0.46l0.16,-1.74l-0.39,-0.42l-0.42,0.19l-0.21,0.58l-0.85,0.26l-0.29,1.23l-0.57,-1.01ZM204.53,604.41l0.23,-0.52l-0.58,-0.47l0.16,-0.56l-0.41,-0.26l1.05,-0.38l0.21,-0.67l-2.13,-0.56l1.59,-0.9l0.16,-0.86l-0.36,-0.08l0.35,-1.05l0.21,0.49l1.38,0.95l0.65,1.87l-0.18,0.82l-0.68,0.31l-0.12,0.51l-0.79,0.23l-0.06,0.42l0.07,0.51l0.76,-0.09l-0.11,0.29l0.38,0.45l0.87,0.16l0.31,0.67l-0.54,-0.15l-0.4,0.8l0.23,0.39l0.85,0.22l-1.39,0.74l0.11,0.7l0.57,0.32l-0.22,0.31l0.26,0.63l-0.39,0.4l-0.4,-0.2l0.24,-0.39l-0.45,-1.27l0.19,-0.92l-0.49,-0.5l-0.25,-1.87l-0.67,0.18l-0.2,-0.66ZM204.7,605.12l-0.02,0.03l0.0,-0.0l0.02,-0.03ZM204.91,597.51l-0.15,-0.81l-1.16,-0.79l0.71,0.03l0.44,0.61l0.43,-0.21l0.17,0.98l-0.44,0.18ZM204.03,589.42l1.73,1.0l0.58,0.52l0.11,0.57l0.56,0.15l0.24,-0.39l0.54,0.65l-0.54,1.63l-0.36,-1.55l-0.5,-0.5l-0.56,0.05l-0.21,0.96l0.31,0.54l-0.25,0.39l0.51,0.85l-0.29,0.21l-0.99,-0.68l-0.46,0.33l-0.4,-0.11l0.95,-2.9l-0.98,-1.74ZM204.3,590.82l0.01,0.01l0.01,0.01l-0.01,-0.0l-0.01,-0.01ZM201.28,587.91l0.24,-0.68l0.52,-0.17l-0.03,-0.45l0.42,-0.22l0.35,0.32l0.6,-0.35l-0.0,-0.8l-0.62,-0.4l0.7,-0.07l0.24,-0.65l-1.03,-0.28l-0.02,-1.43l0.48,-2.46l0.45,-0.43l0.87,0.22l0.37,0.4l-0.69,2.23l0.41,0.23l0.08,1.49l0.51,0.53l-0.12,0.39l-0.62,-0.22l-0.31,0.8l-0.69,0.34l0.04,0.32l-0.11,0.42l-0.22,0.32l-1.81,0.61ZM204.42,586.23l0.02,0.16l-0.19,-0.27l0.07,0.06l0.09,0.05ZM203.16,578.77l0.02,-0.02l0.01,0.06l-0.01,0.0l-0.03,-0.05ZM202.08,593.81l-0.03,-0.32l0.05,-0.01l0.09,0.19l-0.11,0.14ZM202.25,593.0l-0.25,-0.54l0.16,-0.07l0.34,0.48l-0.24,0.13ZM201.87,592.45l-0.2,-0.02l-0.02,-0.03l0.04,-0.01l0.17,0.06ZM201.97,591.45l-0.19,-0.44l-0.52,-0.05l0.08,-0.24l1.42,-0.09l-0.01,0.81l-0.39,0.25l-0.38,-0.25ZM195.26,578.67l0.22,-0.17l0.78,1.25l0.56,-0.45l-0.67,-1.58l0.86,0.26l0.05,-1.05l0.36,0.52l1.18,-0.42l0.77,0.97l-0.44,0.2l-0.8,-0.21l-0.17,0.33l-0.79,0.06l0.06,0.48l1.78,2.24l-0.07,0.74l0.9,0.5l1.08,0.01l-0.34,1.59l-0.43,-0.2l-2.75,-3.68l-0.61,0.35l0.09,0.44l-0.28,0.18l0.52,0.86l-0.19,0.56l0.29,0.37l-0.52,0.14l-0.52,-1.4l0.33,-0.19l-0.16,-0.49l-1.1,-2.22ZM197.81,583.65l0.03,-0.01l-0.01,0.04l-0.02,-0.02l-0.0,-0.0ZM197.98,583.86l0.65,0.02l0.94,0.95l0.23,2.78l-0.4,2.69l-0.3,0.89l-0.47,0.37l-0.63,1.95l-0.37,-2.3l1.14,-0.59l-0.06,-0.73l-0.28,-0.06l0.01,-0.56l-0.47,-0.3l-0.19,-0.68l-0.71,-0.04l0.39,-0.63l0.81,-0.06l0.22,-0.32l-0.13,-0.54l-0.66,-0.34l0.68,-0.34l-0.35,-1.27l-0.73,-0.27l0.59,-0.15l0.09,-0.48ZM196.56,583.11l-0.06,-0.04l0.15,-0.08l-0.09,0.12ZM199.05,579.52l1.11,-0.49l0.92,0.47l0.59,0.75l-0.17,0.31l-0.56,-0.63l-0.63,-0.07l-0.13,0.57l0.35,0.67l-1.49,-1.58ZM121.86,538.8l-0.0,-0.01l0.02,0.02l-0.02,-0.01ZM122.16,539.2l0.38,0.41l0.59,-0.1l-0.04,-0.62l0.83,0.53l0.61,-1.11l0.62,0.04l-0.13,0.7l0.46,0.88l-0.67,0.48l-0.23,-0.84l-0.37,-0.03l-0.81,0.68l-0.2,-0.29l-0.67,0.31l-0.36,-1.02ZM125.68,539.91l0.02,-0.0l-0.01,0.0l-0.01,-0.0ZM126.24,540.18l-0.05,-0.09l0.07,0.07l-0.02,0.02ZM126.1,539.97l-0.36,-0.07l0.27,-0.16l0.09,0.23ZM111.97,541.9l0.13,-1.11l-0.41,-0.51l0.57,-0.47l0.58,-0.31l0.5,0.27l1.58,-0.22l0.55,0.47l-0.75,0.07l0.02,0.5l0.56,0.37l-0.31,0.99l0.56,1.75l0.45,0.16l0.28,-0.39l-0.23,-0.7l0.33,-1.09l0.38,0.2l0.37,-0.33l1.06,0.15l0.41,-0.28l0.62,0.17l0.21,0.41l0.91,-0.72l0.49,0.31l-0.22,0.73l0.26,0.4l0.49,-0.02l0.33,-0.47l1.39,0.19l-0.09,0.39l-0.85,0.24l-0.21,0.41l0.21,1.1l0.75,0.33l-0.77,0.3l-2.35,-2.03l-0.88,0.42l-0.02,0.69l-0.56,-0.49l-0.44,0.12l-0.27,0.58l-1.74,-0.5l-0.49,0.58l-0.32,-0.15l-0.13,-0.86l-0.79,-0.03l-1.07,-1.18l-1.1,-0.44ZM119.11,544.38l0.82,0.17l0.33,0.72l-0.52,-0.07l-0.2,-0.66l-0.42,-0.16ZM117.78,540.47l-0.76,-0.83l0.17,-0.28l0.83,0.02l-0.24,1.09ZM121.13,540.99l0.32,0.07l-0.59,0.51l0.31,-0.44l-0.03,-0.14ZM113.0,545.5l-0.71,0.24l-0.07,-0.11l0.36,-0.03l0.42,-0.1ZM111.68,543.33l0.69,-0.15l0.23,0.13l-0.51,0.43l-0.41,-0.41ZM76.93,452.59l0.44,-0.56l0.74,-0.21l0.04,0.98l0.81,0.62l0.81,1.25l1.59,0.48l1.11,0.77l0.29,0.97l-0.62,0.7l1.28,1.78l-0.03,0.76l0.83,0.73l0.06,0.6l-0.76,-0.35l-1.49,0.03l-0.08,-1.15l-0.71,-1.29l0.16,-0.62l-1.2,-2.9l-0.96,-0.77l-1.79,-0.42l-0.51,-1.4ZM84.52,461.74l0.69,0.18l0.56,0.73l-0.43,0.12l-0.82,-1.03ZM75.58,485.5l0.07,-0.44l1.7,1.61l0.78,-0.27l0.53,0.4l0.88,-0.0l-0.06,0.37l0.83,0.24l0.29,0.89l1.02,0.89l-0.67,0.62l-0.55,1.49l-2.66,-1.39l-0.92,-0.99l-0.64,-2.06l-0.55,-0.58l-0.06,-0.77ZM55.82,528.18l0.22,-0.57l1.29,0.26l2.05,-0.81l0.73,0.9l0.76,-0.1l1.99,0.58l0.55,0.5l0.05,0.8l-0.49,1.14l-1.03,0.31l-2.5,-1.87l-2.52,0.16l-1.15,-0.81l0.05,-0.5ZM37.73,525.86l0.44,0.13l0.4,0.44l-0.66,-0.33l-0.17,-0.24ZM43.99,527.71l-0.32,-0.33l-0.55,0.04l0.82,-0.2l0.41,-0.61l-1.11,-1.43l0.35,-0.53l1.55,0.81l-0.4,0.52l0.03,0.83l-0.39,0.13l-0.39,0.76ZM42.84,527.18l-0.0,-0.0l0.0,0.0l0.0,0.0ZM43.98,526.54l0.02,-0.01l0.01,0.01l-0.02,0.0l-0.0,-0.0ZM42.63,527.12l-0.35,0.44l-0.22,-0.21l0.3,-0.36l-0.18,-0.32l0.39,-0.07l0.05,0.51ZM42.72,526.39l-0.0,-0.06l0.01,0.01l-0.01,0.05ZM31.87,524.21l0.91,-0.8l0.8,0.02l0.72,0.69l-1.15,0.35l-1.28,-0.25ZM35.31,524.02l0.44,-0.89l0.8,-0.04l0.97,0.45l0.25,0.65l-0.43,0.37l-2.04,-0.54ZM4.9,508.63l0.28,0.1l-0.04,0.24l-0.12,0.03l-0.12,-0.37ZM6.12,508.53l-0.05,-0.66l0.53,0.07l0.12,0.71l-0.59,-0.13Z", "name": "Alaska"}, "US-NJ": {"path": "M801.65,165.2l1.31,-1.55l0.48,-1.57l0.5,-0.62l0.54,-1.45l0.11,-2.05l0.67,-1.35l0.92,-0.71l14.12,4.16l-0.4,6.03l-0.35,0.55l-0.23,-0.44l-0.7,0.11l-0.26,1.18l-0.76,0.97l0.12,1.42l-0.46,0.6l0.08,1.71l0.58,0.62l1.2,0.29l1.38,-0.43l2.3,0.24l0.9,6.92l-0.56,0.39l0.18,0.66l-0.61,0.95l0.46,0.58l-0.21,0.6l0.53,1.94l-0.47,2.0l0.11,0.61l0.62,0.64l-0.39,1.13l-0.49,0.45l-0.01,0.59l-0.93,1.13l0.02,0.52l-1.07,0.1l0.09,1.21l0.64,0.83l-0.82,0.56l-0.18,1.15l1.05,0.77l-0.31,0.29l-0.17,-0.44l-0.53,-0.18l-0.5,0.22l-0.44,1.51l-1.28,0.61l-0.2,0.45l0.46,0.55l0.8,0.06l-0.66,1.26l-0.26,1.5l-0.68,0.65l0.19,0.48l0.4,0.04l-0.89,1.57l0.07,0.95l-1.65,1.72l-0.12,-1.34l0.36,-2.44l-0.11,-0.87l-0.58,-0.82l-0.89,-0.28l-1.11,0.34l-0.81,-0.35l-1.51,0.88l-0.31,-0.7l-1.62,-0.96l-1.0,0.04l-0.65,-0.71l-0.7,0.07l-3.24,-2.03l-0.06,-1.73l-1.02,-0.94l0.48,-0.68l0.0,-0.87l0.43,-0.83l-0.12,-0.73l0.51,-1.18l1.2,-1.16l2.6,-1.49l0.54,-0.86l-0.38,-0.85l0.5,-0.37l0.47,-1.44l1.24,-1.7l2.52,-2.22l0.18,-0.67l-0.47,-0.82l-4.26,-2.78l-0.75,-1.05l-0.9,0.24l-0.48,-0.33l-1.24,-2.46l-1.62,-0.02l-1.0,-3.44l1.02,-1.03l0.36,-2.23l-1.87,-1.91Z", "name": "New Jersey"}, "US-CO": {"path": "M364.23,239.52l-1.22,65.86l-29.29,-0.9l-29.38,-1.43l-29.35,-1.95l-32.17,-2.75l8.32,-87.13l27.79,2.39l28.22,1.92l29.58,1.46l27.95,0.87l-0.46,21.65Z", "name": "Colorado"}, "US-MD": {"path": "M740.67,219.62l-2.04,-10.06l19.85,-4.49l-0.66,1.29l-0.94,0.08l-1.54,0.81l0.16,0.7l-0.42,0.49l0.23,0.78l-1.76,0.5l-1.48,0.03l-1.14,-0.39l0.21,-0.36l-0.3,-0.49l-1.11,-0.31l-0.47,1.8l-1.63,2.84l-1.37,-0.39l-1.03,0.62l-0.41,1.26l-1.6,1.93l-0.36,1.04l-0.88,0.45l-1.3,1.87ZM760.74,204.54l36.93,-9.13l8.48,26.19l0.45,0.26l1.06,-0.21l8.18,-2.08l-0.9,0.53l0.31,0.64l0.52,0.01l0.37,0.76l0.52,-0.05l-0.38,1.96l-0.12,-0.26l-0.47,0.07l-0.73,0.86l-0.17,2.7l-0.6,0.19l-0.36,0.71l-0.02,1.66l-3.62,1.37l-0.45,0.7l-2.2,0.43l-0.56,0.65l-0.3,-1.09l0.5,-0.31l0.86,-1.84l-0.4,-0.51l-0.45,0.12l0.08,-0.5l-0.44,-0.42l-2.29,0.63l0.3,-0.6l1.15,-0.83l-0.17,-0.69l-1.36,-0.18l0.38,-2.24l-0.18,-1.02l-0.91,0.16l-0.53,1.76l-0.34,-0.68l-0.62,-0.07l-0.44,0.47l-0.5,1.39l0.53,1.02l-2.87,-2.14l-0.43,-0.19l-0.61,0.36l-0.73,-0.76l0.33,-1.67l0.76,-0.6l-0.08,-1.35l2.55,0.23l0.78,-1.5l-0.32,-1.42l-0.72,0.27l-0.28,1.29l-0.98,-0.25l-0.38,-1.07l-0.52,-0.28l-0.55,0.23l-0.22,-0.68l-0.63,0.08l1.0,-0.82l0.22,-1.04l-0.54,-0.55l-0.75,0.83l-0.21,-0.61l1.06,-0.92l-0.25,-0.65l-0.54,-0.08l-0.51,-0.75l-0.42,0.22l-0.53,-0.37l0.83,-1.03l-0.24,-1.02l0.84,-1.95l-0.07,-0.86l-0.46,0.02l-0.66,0.66l-0.56,-0.16l-0.48,0.45l-0.19,0.97l-0.95,-1.2l0.75,-3.46l0.59,-0.51l0.07,-0.74l3.89,-0.78l0.49,-0.41l-0.23,-0.67l-0.45,-0.07l-2.38,0.56l0.88,-1.55l1.42,-0.05l0.35,-0.5l-0.99,-0.67l0.44,-1.9l-0.63,-0.32l-0.48,0.39l-0.87,1.96l0.21,-2.02l-0.59,-0.34l-0.88,1.43l-1.42,0.34l-0.31,1.65l0.39,0.53l0.65,0.12l-1.45,1.92l-0.2,-1.64l-0.64,-0.42l-0.61,0.73l0.07,1.45l-0.85,-0.29l-1.16,0.64l0.02,0.71l1.01,0.27l-0.37,0.54l-0.83,0.22l-0.05,0.34l-0.44,-0.04l-0.35,0.64l1.2,1.22l-0.29,0.17l-1.52,-0.76l-1.33,0.48l0.16,0.69l0.82,0.1l1.26,1.21l1.49,0.58l0.1,0.28l-0.44,0.33l-1.37,0.5l-0.12,1.19l1.83,1.04l0.47,0.63l-0.66,-0.43l-1.05,0.29l0.2,0.64l0.92,0.48l-0.34,0.47l0.4,1.15l0.6,0.09l-0.63,1.26l0.13,0.43l0.63,0.65l1.28,4.18l2.83,2.58l-0.01,0.35l-0.38,0.54l-0.67,-1.23l-1.21,-0.22l-1.69,-0.87l-1.51,-3.64l-0.74,-0.68l-0.28,0.69l1.17,3.94l0.65,0.92l1.45,0.81l1.3,0.31l1.49,1.39l0.89,-0.33l0.37,1.32l1.47,1.47l0.1,1.07l-1.08,-0.68l-0.33,-1.23l-0.63,-0.45l-0.45,0.04l-0.13,0.44l0.27,0.78l-0.74,0.13l-0.62,-0.73l-1.16,-0.38l-1.53,0.0l-0.92,0.43l-0.55,-0.2l-1.0,-2.19l-1.26,-0.71l-0.46,0.14l0.01,0.48l1.19,2.0l-0.67,-0.12l-0.28,-0.5l-0.89,-0.4l-1.61,-2.6l-0.48,-0.14l-0.43,1.47l-0.25,-0.74l-0.62,-0.04l-0.4,0.46l0.33,0.72l-0.18,0.69l-0.64,0.59l-0.57,-0.26l-0.63,-1.86l0.25,-1.14l0.71,-0.37l0.2,-0.51l-0.37,-0.52l0.83,-0.52l0.21,-1.61l1.06,-0.35l0.07,-0.66l-0.33,-0.42l0.23,-0.42l-0.38,-0.38l-0.04,-0.7l1.27,-2.2l-0.14,-0.54l-2.72,-1.68l-0.56,0.14l-0.69,1.19l-1.81,-0.37l-1.09,-1.19l-2.96,-0.09l-1.25,-0.91l0.61,-1.35l-0.4,-0.97l-1.19,-0.3l-0.89,-0.66l-2.69,0.07l-0.36,-0.23l-0.11,-1.26l-1.04,-0.6l0.09,-1.2l-0.51,-0.29l-0.49,0.19l-0.23,-0.64l-0.52,-0.13l0.26,-0.83l-0.45,-0.58l-0.69,-0.12l-1.81,0.67l-2.24,-1.27ZM790.07,212.25l0.29,-0.0l0.93,0.21l-0.44,0.4l-0.78,-0.61ZM796.79,218.15l0.0,0.16l-0.13,-0.11l0.13,-0.06ZM803.02,225.62l-0.02,0.33l-0.21,-0.15l0.23,-0.19ZM806.99,229.08l-0.16,0.3l-0.12,0.07l0.02,-0.25l0.26,-0.12ZM797.54,220.57l-0.06,0.01l-0.09,0.03l0.12,-0.06l0.03,0.02ZM797.21,220.69l-0.26,0.57l-0.18,0.12l0.15,-0.61l0.29,-0.07ZM796.09,217.04l-0.61,0.32l-0.58,-0.42l0.02,-0.53l0.16,-0.23l0.68,0.3l0.32,0.56ZM794.46,213.09l-0.25,0.5l-0.8,0.39l0.15,-1.17l0.9,0.27Z", "name": "Maryland"}, "US-MA": {"path": "M820.4,120.02l30.04,-8.0l1.53,-1.8l0.34,-1.48l0.95,-0.35l0.61,-1.04l1.17,-1.05l1.35,-0.1l-0.44,1.05l1.03,0.32l0.21,1.55l1.17,0.55l-0.06,0.32l0.39,0.28l1.31,0.19l-0.17,0.56l-2.29,1.79l-0.05,1.07l0.45,0.16l-1.11,1.41l0.23,1.08l-1.01,0.96l0.58,1.41l1.4,0.45l0.5,0.63l1.36,-0.57l0.33,-0.59l1.2,0.09l0.79,0.47l0.23,0.68l1.79,1.37l-0.07,1.25l-0.56,0.55l0.12,0.6l1.23,0.66l1.73,-0.23l0.68,1.2l0.21,1.14l0.89,0.68l1.33,0.41l1.48,-0.12l0.43,0.38l1.05,-0.23l2.92,-2.34l0.82,-1.11l0.54,0.02l0.56,1.86l-3.32,1.52l-0.94,0.82l-2.75,0.98l-0.49,1.64l-1.93,1.37l-0.82,-2.64l0.11,-1.34l-0.55,-0.31l-0.5,0.39l-0.93,-0.1l-0.3,0.51l0.25,0.92l-0.26,0.79l-0.4,0.06l-0.63,1.1l-0.6,-0.2l-0.5,0.48l0.22,1.86l-0.9,0.87l-0.63,-0.8l-0.47,0.01l-0.11,0.55l-0.26,0.03l-0.71,-2.03l-1.02,-0.35l0.44,-2.5l-0.21,-0.4l-0.78,0.4l-0.29,1.47l-0.69,0.2l-1.4,-0.64l-0.78,-2.12l-0.8,-0.22l-0.78,-2.15l-0.49,-0.24l-6.13,2.0l-0.3,-0.15l-14.84,4.19l-0.28,0.5l-0.46,-0.28l-0.86,0.17l-9.54,2.36l-0.25,-0.18l-0.32,-14.66ZM860.63,110.12l-0.02,-0.37l-0.14,-0.48l0.51,0.23l-0.35,0.62ZM876.24,122.86l-0.12,-0.42l0.25,0.35l-0.13,0.06ZM875.23,121.15l-0.78,0.0l-0.55,-1.2l0.56,0.44l0.77,0.76ZM871.43,119.57l-0.08,0.14l-0.09,-0.07l0.0,-0.0l0.17,-0.07Z", "name": "Massachusetts"}, "US-AL": {"path": "M608.67,337.4l25.17,-2.91l19.4,-2.75l14.04,43.29l1.01,2.45l1.17,1.59l0.59,1.87l2.24,2.5l0.92,1.8l-0.11,2.13l1.8,1.13l-0.17,0.74l-0.63,0.1l-0.16,0.7l-0.98,0.84l-0.22,2.29l0.25,1.48l-0.76,2.3l-0.14,1.84l1.1,2.94l1.21,1.52l0.53,1.6l-0.08,5.02l-0.25,0.81l0.48,2.03l1.35,1.16l1.14,2.07l-47.64,6.92l-0.42,0.61l-0.08,2.99l2.64,2.75l2.0,0.96l-0.34,2.7l0.56,1.61l0.43,0.39l-0.94,1.69l-1.24,1.0l-1.13,-0.75l-0.34,0.49l0.66,1.46l-2.81,1.05l0.29,-0.63l-0.45,-0.86l-0.99,-0.76l-0.1,-1.11l-0.57,-0.22l-0.52,0.61l-0.32,-0.1l-0.89,-1.53l0.41,-1.67l-0.97,-2.21l-1.32,-0.65l-0.3,-0.89l-0.56,-0.17l-0.37,0.61l0.15,0.35l-0.77,3.1l-0.01,5.08l-0.59,0.0l-0.24,-0.71l-2.22,-0.44l-1.64,0.31l-5.46,-31.98l-0.99,-66.48l-0.02,-0.37l-1.07,-0.63l-0.69,-1.02Z", "name": "Alabama"}, "US-MO": {"path": "M468.72,225.49l24.71,-0.73l18.94,-1.42l22.1,-2.58l0.42,0.35l0.39,0.91l2.43,1.65l0.29,0.74l1.21,0.87l-0.51,1.36l-0.1,3.21l0.78,3.65l0.95,1.44l0.03,1.59l1.11,1.37l0.46,1.55l4.96,4.1l1.06,1.69l4.93,3.31l0.7,1.15l0.27,1.62l0.5,0.82l-0.18,0.69l0.47,1.8l0.97,1.63l0.77,0.73l1.04,0.16l0.83,-0.56l0.84,-1.4l0.57,-0.19l2.41,0.61l1.68,0.76l0.84,0.77l-0.97,1.95l0.26,2.28l-2.37,6.86l0.01,1.02l0.7,1.92l4.67,4.05l1.99,1.05l1.46,0.09l1.66,1.3l1.92,0.8l1.5,2.11l2.04,0.83l0.42,2.96l1.72,2.9l-1.1,1.94l0.18,1.38l0.75,0.33l2.31,4.25l1.94,0.92l0.55,-0.32l0.0,-0.65l0.87,1.1l1.07,-0.08l0.14,1.85l-0.37,1.07l0.53,1.59l-1.07,3.86l-0.51,0.07l-1.37,-1.13l-0.65,0.13l-0.78,3.34l-0.52,0.74l0.13,-1.06l-0.56,-1.09l-0.97,-0.2l-0.74,0.63l0.02,1.05l0.53,0.66l-0.04,0.7l0.58,1.34l-0.2,0.4l-1.2,0.39l-0.17,0.41l0.15,0.55l0.86,0.84l-1.71,0.37l-0.14,0.62l1.53,1.97l-0.89,0.75l-0.63,2.13l-10.61,1.42l1.06,-2.28l0.87,-0.61l0.18,-0.87l1.43,-0.96l0.25,-0.96l0.63,-0.37l0.29,-0.59l-0.22,-2.28l-1.05,-0.75l-0.2,-0.77l-1.09,-1.18l-39.24,3.6l-37.71,2.58l-3.21,-58.18l-1.03,-0.63l-1.2,-0.02l-1.52,-0.73l-0.19,-0.93l-1.11,-1.3l-0.36,-1.55l-0.55,-0.09l-0.3,-0.56l-1.13,-0.66l-1.4,-1.84l0.73,-0.51l0.09,-1.24l1.12,-1.27l0.09,-0.79l1.01,0.16l0.56,-0.43l-0.2,-2.24l-1.02,-0.74l-0.32,-1.1l-1.17,-0.01l-1.31,0.96l-0.81,-0.7l-0.73,-0.17l-2.67,-2.35l-1.05,-0.28l0.13,-1.6l-1.32,-1.72l0.1,-1.01l-0.37,-0.36l-1.01,-0.18l-0.59,-0.85l-0.84,-0.26l0.07,-0.52l-1.24,-2.88l-0.0,-0.74l-0.4,-0.49l-0.85,-0.29l-0.05,-0.54ZM583.78,294.53l-0.1,-0.1l-0.08,-0.15l0.11,-0.01l0.07,0.26Z", "name": "Missouri"}, "US-MN": {"path": "M443.67,67.68l-0.4,-1.37l0.05,-1.19l-0.48,-0.53l-1.36,-3.77l0.0,-3.22l-0.47,-1.97l0.27,-1.12l-0.57,-2.32l0.73,-2.56l-2.06,-6.89l29.55,-1.22l0.47,-0.81l-0.38,-7.12l2.84,0.15l1.24,0.82l0.38,2.69l1.73,5.31l0.13,2.3l0.52,0.86l1.46,1.05l1.3,0.49l3.23,-0.36l0.39,0.85l0.54,0.38l5.25,0.04l0.38,0.24l0.54,1.58l0.72,0.61l4.27,-0.78l0.77,-0.65l0.07,-0.69l0.69,-0.35l1.74,-0.44l3.97,-0.02l1.42,0.7l3.38,0.66l-1.01,0.79l0.0,0.82l0.51,0.45l2.91,-0.06l0.52,2.08l1.58,2.29l0.71,0.05l1.03,-0.78l-0.04,-1.73l2.67,-0.46l1.43,2.16l2.01,0.79l1.54,0.18l0.54,0.57l-0.03,0.83l0.58,0.35l1.32,0.06l0.19,0.75l0.41,0.1l1.2,-0.22l1.12,0.22l2.21,-0.85l2.78,-2.55l2.49,-1.54l1.24,2.52l0.96,0.51l2.23,-0.66l0.87,0.36l5.98,-1.3l0.56,0.18l1.32,1.64l1.24,0.59l0.62,-0.01l1.61,-0.83l1.3,0.1l-0.89,1.0l-4.69,3.07l-6.35,2.82l-3.68,2.47l-2.15,2.49l-0.96,0.57l-6.62,8.67l-0.95,0.61l-1.07,1.56l-1.96,1.97l-4.18,3.55l-0.86,1.78l-0.55,0.44l-0.14,0.96l-0.78,-0.01l-0.46,0.51l0.98,12.22l-0.79,1.2l-1.04,0.08l-0.52,0.82l-0.83,0.15l-0.61,0.83l-2.06,1.19l-0.94,1.86l0.06,0.72l-1.69,2.39l-0.01,2.06l0.38,0.91l2.15,0.39l1.42,2.49l-0.52,1.92l-0.71,1.25l-0.05,2.12l0.45,1.32l-0.71,1.23l0.91,3.14l-0.51,4.08l3.95,3.03l3.02,0.4l1.89,2.25l2.87,0.5l2.45,1.93l2.39,3.59l2.63,1.8l2.09,0.09l1.07,0.71l0.88,0.1l0.82,1.36l1.26,0.84l0.28,2.03l0.68,1.3l0.39,4.82l-40.62,3.2l-40.63,2.09l-1.46,-38.98l-1.52,-2.05l-2.57,-0.79l-0.94,-1.91l-1.46,-1.79l0.21,-0.68l2.82,-2.34l0.93,-2.03l0.43,-2.53l-0.35,-1.58l0.23,-1.86l-0.18,-1.51l-0.5,-1.03l-0.18,-2.33l-1.81,-2.59l-0.47,-1.13l-0.21,-2.16l-0.66,-0.98l0.15,-1.66l-0.35,-1.52l0.53,-2.69l-1.08,-1.85l-0.49,-8.32l-0.42,-0.79l0.06,-3.92l-1.58,-3.95l-0.53,-0.65Z", "name": "Minnesota"}, "US-CA": {"path": "M3.07,175.36l0.87,-1.1l0.96,0.24l1.21,-2.15l0.92,0.12l0.64,-0.23l0.41,-0.57l-0.27,-0.82l-0.71,-0.36l1.52,-2.68l0.12,-0.78l-0.43,-0.48l0.1,-1.34l0.85,-0.88l1.17,-2.25l1.26,-3.01l0.39,-2.1l-0.28,-1.0l0.05,-3.89l-1.25,-1.24l0.92,-1.24l0.94,-2.81l32.73,8.13l32.57,7.34l-13.67,64.67l25.44,34.66l36.59,51.09l13.3,17.72l-0.19,2.73l0.73,0.94l0.21,1.71l0.85,0.63l0.81,2.56l-0.07,0.91l0.63,1.46l-0.16,1.36l3.8,3.82l0.01,0.5l-1.95,1.53l-3.11,1.26l-1.2,1.99l-1.72,1.14l-0.33,0.81l0.38,1.03l-0.51,0.51l-0.1,0.9l0.08,2.29l-0.6,0.72l-0.64,2.44l-2.02,2.47l-1.6,0.14l-0.42,0.51l0.33,0.89l-0.59,1.34l0.54,1.11l-0.01,1.19l-0.78,2.68l0.57,1.02l2.74,1.13l0.34,0.83l-0.19,2.4l-1.18,0.78l-0.42,1.37l-2.27,-0.62l-1.26,0.61l-43.36,-3.35l0.04,-0.76l0.39,-0.07l0.3,-0.56l-0.12,-1.38l-1.1,-1.65l-1.08,0.02l0.16,-1.13l-0.24,-1.11l0.35,-0.13l0.36,-0.93l0.05,-2.47l-0.39,-2.64l-2.46,-5.66l-3.47,-4.07l-1.29,-1.98l-2.42,-2.12l-2.07,-2.86l-2.01,-1.04l-1.23,0.18l-0.29,0.88l-1.56,-0.95l-0.11,-0.38l0.63,-0.52l0.22,-0.95l-0.46,-2.65l-1.0,-1.95l-0.7,-0.58l-2.17,-0.43l-1.45,-0.13l-1.11,0.3l-0.49,-0.59l-1.66,-0.65l-3.05,-1.95l-1.24,-1.35l-0.54,-2.64l-0.89,-0.66l-1.77,-2.24l-1.66,-1.3l-1.92,-0.51l-1.09,0.24l-1.1,-0.72l-1.51,-0.14l-2.0,-1.52l-2.34,-0.84l-5.72,-0.67l-0.4,-1.69l-1.01,-0.93l-0.92,-0.35l1.28,-2.62l-0.33,-1.38l0.84,-2.21l-0.65,-1.27l1.18,-2.39l0.32,-2.41l-0.99,-1.24l-1.32,-0.26l-1.34,-1.39l-0.08,-0.75l1.44,-1.4l-0.5,-2.3l-0.34,-0.54l-1.68,-0.76l-1.88,-4.27l-1.79,-1.16l-0.32,-2.63l-1.62,-2.61l-0.22,-2.75l-1.01,-0.76l-1.13,-3.38l-2.16,-2.3l-0.75,-1.6l0.04,-3.93l0.55,-1.46l-0.54,-0.6l0.52,-0.53l0.56,0.71l0.58,-0.1l0.8,-0.59l0.9,-1.64l0.83,0.01l0.08,-0.52l-0.51,-0.5l0.4,-0.88l-0.05,-0.93l-0.49,-2.22l-0.61,-1.2l-0.6,-0.44l-0.92,0.25l-2.02,-0.43l-1.45,-1.81l-0.86,-2.15l-0.53,-0.38l-0.32,-1.18l-0.46,-0.5l0.04,-1.12l0.85,-2.26l-0.21,-2.94l-0.89,-1.29l1.1,-2.74l0.21,-2.34l1.33,-0.2l0.23,1.52l-0.62,0.31l-0.1,2.71l1.73,1.17l0.7,1.42l1.0,0.72l0.4,1.01l0.89,0.41l0.85,-0.4l-0.19,-1.18l-0.68,-0.51l-0.37,-1.53l0.13,-1.99l-0.54,-1.26l-0.37,-0.02l-0.11,-0.14l0.62,-0.35l-0.0,-0.34l-1.62,-1.2l0.69,-0.67l-0.17,-1.88l-0.94,-0.36l-0.3,-0.61l1.07,-0.66l0.99,-0.01l0.96,-0.71l1.25,1.03l2.63,-0.1l5.01,2.23l0.53,-0.22l0.04,-0.59l0.61,-0.67l-0.3,0.75l0.39,0.76l0.81,-0.06l0.35,-0.49l1.35,1.6l0.7,-0.16l0.02,-0.38l-0.53,-1.14l-0.97,-0.74l-0.27,-0.8l-0.66,-0.38l-1.09,-0.07l0.27,-0.58l-0.25,-0.54l-2.48,1.29l-0.7,-0.34l-0.75,0.18l-0.18,-0.55l-1.09,-0.25l0.28,-0.66l-0.36,-0.69l-1.09,-0.17l-1.86,1.57l-0.34,-0.46l-1.36,-0.54l-0.36,-0.88l-1.36,-1.35l-2.59,0.52l0.1,0.92l-0.7,1.21l0.53,0.72l-0.88,0.92l-0.07,2.28l-0.37,-0.09l-1.52,-2.07l-1.18,-0.34l-1.16,-2.44l-1.41,-1.2l0.09,-0.69l-0.68,-0.18l0.73,-1.18l0.93,2.05l0.44,0.25l0.33,-0.38l-1.77,-5.65l-0.41,-0.59l-0.57,-0.2l0.2,-0.84l-0.53,-2.28l-2.72,-3.32l-1.0,-2.99l-3.45,-6.17l-0.03,-0.38l1.14,-1.43l0.12,-0.85l-0.51,-6.75l0.61,-1.87l1.33,-2.02l0.4,-3.04l-0.36,-1.21l0.19,-2.39l-0.7,-1.04l-1.24,-3.68l-0.57,-0.53l0.1,-0.93l-0.32,-0.88l-1.04,-0.88l-2.01,-3.32l0.52,-1.23l-0.26,-2.71l2.38,-3.44ZM33.36,240.61l0.01,-0.01l0.01,0.01l-0.02,-0.01ZM45.67,326.22l-0.02,0.03l0.02,-0.03l0.01,0.01ZM31.63,240.38l-0.09,0.14l-0.63,0.23l-0.2,-0.07l0.92,-0.3Z", "name": "California"}, "US-IA": {"path": "M452.94,162.22l42.82,-2.19l40.55,-3.19l0.96,2.52l2.0,1.0l0.08,0.59l-0.9,1.8l-0.16,1.04l0.9,5.09l0.92,1.26l0.39,1.75l1.46,1.72l4.94,0.85l1.27,2.03l-0.3,1.03l0.29,0.66l3.61,2.37l0.85,2.41l3.84,2.31l0.62,1.68l-0.31,4.21l-1.64,1.98l-0.5,1.94l0.13,1.28l-1.26,1.36l-2.51,0.97l-0.89,1.18l-0.55,0.25l-4.56,0.83l-0.89,0.73l-0.61,1.71l-0.15,2.55l0.4,1.08l2.01,1.47l0.54,2.65l-1.87,3.25l-0.22,2.24l-0.52,1.42l-2.88,1.39l-1.02,1.02l-0.2,0.99l0.72,0.87l0.2,2.15l-0.58,0.23l-1.34,-0.82l-0.31,-0.76l-1.29,-0.82l-0.29,-0.51l-0.88,-0.36l-0.3,-0.82l-0.95,-0.68l-22.3,2.61l-15.12,1.17l-7.59,0.51l-20.78,0.47l-0.22,-1.06l-1.3,-0.73l-0.33,-0.67l0.58,-1.16l-0.21,-0.95l0.22,-1.39l-0.36,-2.19l-0.6,-0.73l0.07,-3.65l-1.05,-0.5l0.05,-0.91l0.71,-1.02l-0.05,-0.44l-1.31,-0.56l0.33,-2.54l-0.41,-0.45l-0.89,-0.16l0.23,-0.8l-0.3,-0.58l-0.51,-0.25l-0.74,0.23l-0.42,-2.81l0.5,-2.36l-0.2,-0.67l-1.36,-1.71l-0.08,-1.92l-1.78,-1.54l-0.36,-1.74l-1.09,-0.94l0.03,-2.18l-1.1,-1.87l0.21,-1.7l-0.27,-1.08l-1.38,-0.67l-0.87,-2.17l0.05,-0.63l-1.81,-1.82l0.56,-1.61l0.54,-0.47l0.73,-2.68l0.0,-1.68l0.55,-0.69l0.21,-1.19l-0.51,-2.24l-1.33,-0.29l-0.05,-0.73l0.45,-0.56l-0.0,-1.71l-0.95,-1.42l-0.05,-0.87Z", "name": "Iowa"}, "US-MI": {"path": "M612.25,185.8l1.83,-2.17l0.7,-1.59l1.18,-4.4l1.43,-3.05l1.01,-5.05l0.09,-5.37l-0.86,-5.54l-2.4,-5.17l0.6,-0.5l0.3,-0.79l-0.57,-0.42l-1.08,0.55l-3.82,-7.03l-0.21,-1.1l1.13,-2.68l-0.01,-0.97l-0.74,-3.13l-1.29,-1.65l-0.05,-0.62l1.73,-2.73l1.22,-4.14l-0.21,-5.35l-0.77,-1.59l1.09,-1.15l0.81,-0.02l0.56,-0.47l-0.27,-3.49l1.08,-0.11l0.67,-1.43l1.18,0.47l0.66,-0.33l0.76,-2.59l0.82,-1.2l0.56,-1.68l0.55,-0.18l-0.58,0.87l0.6,1.65l-0.71,1.8l0.71,0.42l-0.48,2.61l0.88,1.43l0.73,-0.05l0.52,0.56l0.64,-0.24l0.89,-2.26l0.67,-3.51l-0.08,-2.07l-0.76,-3.42l0.58,-1.02l2.13,-1.64l2.74,-0.55l0.98,-0.63l0.28,-0.64l-0.25,-0.54l-1.76,-0.11l-0.96,-0.86l-0.52,-1.98l1.85,-2.98l-0.1,-0.73l1.72,-0.23l0.74,-0.94l4.16,2.0l0.83,0.12l1.98,-0.4l1.37,0.4l1.19,1.04l0.53,1.15l0.77,0.49l2.41,-0.29l1.7,1.01l1.92,0.09l0.8,0.64l3.27,0.45l1.1,0.77l-0.01,1.12l1.04,1.31l0.64,0.21l0.37,0.91l-0.14,0.55l-0.67,-0.25l-0.94,0.57l-0.23,1.83l0.81,1.29l1.6,0.98l0.69,1.37l0.65,2.26l-0.12,1.73l0.77,5.57l-0.14,0.59l-0.58,0.21l-0.48,0.96l-0.74,0.07l-0.8,0.81l-0.17,4.47l-1.12,0.49l-0.18,0.82l-1.86,0.43l-0.72,0.6l-0.58,2.61l0.26,0.45l-0.21,0.52l0.25,2.57l1.38,1.31l2.89,0.84l0.91,-0.08l1.08,-1.23l0.6,-1.44l0.62,0.19l0.39,-0.24l1.01,-3.59l0.6,-1.06l-0.08,-0.51l0.97,-1.45l1.39,-0.39l1.07,-0.69l0.83,-1.1l0.87,-0.44l2.06,0.59l1.13,0.7l1.0,1.09l1.21,2.16l2.01,5.91l0.82,1.6l1.03,3.71l1.49,3.63l1.29,1.74l-0.34,3.92l0.45,2.48l-0.48,2.79l-0.36,0.45l-0.57,-1.21l0.03,-0.85l-1.46,-0.52l-0.47,0.08l-1.48,1.36l-0.06,0.83l0.55,0.67l-0.82,0.57l-0.29,0.79l0.28,2.94l-0.48,0.75l-1.62,0.92l-1.06,1.85l-0.43,3.73l0.27,1.56l-0.33,0.93l-0.42,0.19l0.02,0.91l-0.64,0.3l-0.89,1.6l-0.5,1.29l-0.02,1.05l-0.52,0.91l-20.5,4.22l-0.15,-0.92l-0.45,-0.33l-31.44,4.71ZM621.47,115.84l0.0,-0.07l0.11,-0.12l-0.01,0.03l-0.11,0.16ZM621.73,114.93l-0.07,-0.16l0.07,-0.14l-0.0,0.3ZM543.5,88.02l4.87,-2.38l3.55,-3.62l5.77,-1.36l1.39,-0.84l2.36,-2.71l0.98,0.04l1.52,-0.73l1.0,-2.24l2.82,-2.85l0.23,1.72l1.85,0.59l0.05,1.44l0.67,0.14l0.51,0.6l-0.17,3.14l0.44,0.95l-0.34,0.47l0.2,0.47l0.74,-0.02l1.08,-2.21l1.08,-0.89l-0.42,1.15l0.58,0.45l0.83,-0.67l0.52,-1.22l1.0,-0.43l3.09,-0.25l1.5,0.21l1.18,0.93l1.54,0.44l0.47,1.05l2.31,2.58l1.17,0.55l0.53,1.55l0.73,0.34l1.87,0.07l0.73,-0.4l1.06,-0.06l1.4,-1.09l1.0,1.11l1.1,0.64l1.01,-0.25l0.68,-0.82l1.87,1.06l0.64,-0.34l1.65,-2.58l2.81,-1.89l1.7,-1.65l0.92,0.11l3.27,-1.21l5.17,-0.25l3.25,-2.09l2.28,-0.88l1.52,-0.11l-0.01,3.24l0.29,0.71l-0.36,1.1l0.46,0.7l0.68,0.28l0.91,-0.41l2.2,0.7l1.14,-0.43l1.03,-0.87l0.66,0.48l0.21,0.7l0.85,0.22l1.22,-0.76l0.79,-1.57l0.69,-0.28l1.06,0.23l1.35,-1.15l0.53,-0.01l0.22,0.08l-0.3,2.02l0.75,1.32l-1.11,-0.04l-0.36,0.5l0.84,1.83l-0.87,1.04l0.12,0.45l0.83,0.79l1.37,-0.42l0.6,0.47l0.62,0.04l0.18,1.19l0.98,0.87l1.53,0.51l-1.17,0.68l-4.96,-0.15l-0.53,0.3l-1.35,-0.17l-0.88,0.41l-0.66,-0.75l-1.63,-0.07l-0.59,0.47l-0.07,1.22l-0.49,0.76l0.38,2.05l-0.92,-0.22l-0.89,-0.92l-0.77,-0.13l-1.96,-1.65l-2.41,-0.6l-1.6,0.04l-1.04,-0.5l-2.89,0.47l-0.61,0.45l-1.18,2.52l-3.47,0.73l-0.57,0.77l-2.06,-0.33l-2.82,0.93l-0.68,0.83l-0.56,2.51l-0.78,0.28l-0.81,0.87l-0.65,0.28l0.16,-1.95l-0.74,-0.91l-1.02,0.34l-0.77,0.92l-0.97,-0.39l-0.68,0.17l-0.37,0.4l0.1,0.82l-0.73,2.01l-1.2,0.59l-0.1,-1.37l-0.46,-1.06l0.34,-1.69l-0.17,-0.37l-0.66,-0.17l-0.45,0.57l-0.6,2.13l-0.22,2.57l-1.12,0.91l-1.26,3.03l-0.62,2.65l-2.55,5.33l-0.69,0.73l0.12,0.91l-1.4,-1.28l0.18,-1.74l0.63,-1.69l-0.41,-0.81l-0.62,-0.31l-1.36,0.85l-1.16,0.1l0.04,-1.29l0.81,-1.45l-0.41,-1.34l0.3,-1.09l-0.58,-0.98l0.15,-0.83l-1.9,-1.55l-1.1,-0.06l-0.59,-0.44l-1.48,-0.0l0.3,-1.36l-0.94,-1.45l-1.13,-0.51l-2.23,-0.1l-3.2,-0.71l-1.55,0.59l-1.43,-0.42l-1.62,0.17l-4.56,-1.94l-15.37,-2.5l-1.99,-3.39l-1.88,-0.96l-0.76,0.26l-0.1,-0.29ZM603.39,98.63l-0.0,0.52l-0.46,0.32l-0.7,1.39l0.08,0.57l-0.65,-0.58l0.91,-2.15l0.83,-0.06ZM570.53,72.73l-0.51,-0.27l-1.16,0.06l-0.04,-1.56l1.0,-1.02l1.18,-2.09l1.83,-1.5l0.63,-0.0l0.53,-0.58l2.08,-0.89l3.34,-0.42l1.1,0.66l-0.54,0.38l-1.32,-0.12l-2.26,0.78l0.15,0.87l0.71,0.13l-1.19,0.98l-1.4,1.89l-0.69,0.28l-0.36,1.45l-1.15,1.36l-0.66,2.04l-0.67,-0.87l0.75,-0.97l0.14,-1.95l-0.84,-0.23l-0.6,0.92l-0.05,0.67Z", "name": "Michigan"}, "US-GA": {"path": "M654.05,331.64l22.02,-3.57l20.65,-3.86l-0.07,0.58l-2.59,3.35l-0.41,1.73l0.11,1.23l0.82,0.78l1.84,0.8l1.03,0.12l2.7,2.03l0.84,0.24l1.9,-0.37l0.6,0.25l0.8,1.64l1.51,1.6l1.04,2.5l1.33,0.82l0.84,1.16l0.56,0.26l1.0,1.77l1.07,0.3l1.17,0.99l3.81,1.85l2.41,3.16l2.25,0.58l2.53,1.67l0.5,2.34l1.25,1.01l0.47,-0.16l0.31,0.49l-0.1,0.62l0.79,0.73l0.79,0.09l0.56,1.2l4.99,1.88l0.4,1.78l1.54,1.73l1.02,2.01l-0.07,0.8l0.48,0.69l0.11,1.24l1.04,0.79l1.16,0.17l1.25,0.62l0.28,0.53l0.57,0.23l1.12,2.56l0.76,0.57l0.08,2.68l0.77,1.48l1.38,0.9l1.52,-0.27l1.44,0.76l1.45,0.12l-0.59,0.78l-0.55,-0.35l-0.47,0.28l-0.4,0.99l0.62,0.91l-0.38,0.48l-1.38,-0.16l-0.77,-0.55l-0.65,0.44l0.26,0.71l-0.49,0.52l0.36,0.6l1.44,0.25l-0.58,1.35l-1.43,0.27l-1.08,-0.44l-0.6,0.21l0.03,0.82l1.45,0.6l-1.76,3.73l0.36,1.73l-0.48,0.97l0.85,1.48l-2.29,-0.19l-0.46,0.29l0.06,0.63l0.55,0.34l2.76,0.24l1.07,0.66l-0.02,0.34l-0.56,0.22l-0.88,1.95l-0.5,-1.41l-0.45,-0.13l-0.6,0.33l-0.15,0.84l0.34,0.96l-0.6,0.12l-0.03,0.84l-0.3,0.16l0.07,0.46l1.34,1.15l-1.09,1.03l0.32,0.47l0.77,0.08l-0.39,0.92l0.06,0.88l-0.46,0.51l1.1,1.66l0.03,0.76l-0.79,0.33l-2.64,-0.17l-4.06,-0.96l-1.31,0.35l-0.18,0.74l-0.68,0.26l-0.35,1.25l0.28,2.08l0.95,1.36l0.13,4.25l-1.97,0.4l-0.54,-0.92l-0.12,-1.3l-1.33,-1.82l-49.21,5.14l-0.72,-0.56l-0.86,-2.7l-0.94,-1.51l-0.56,-0.38l0.16,-0.68l-0.73,-1.51l-1.82,-1.81l-0.43,-1.75l0.25,-0.8l0.06,-5.18l-0.6,-1.81l-1.19,-1.47l-1.03,-2.65l0.12,-1.65l0.78,-2.36l-0.25,-1.53l0.19,-2.11l1.62,-1.33l0.46,-1.47l-0.55,-0.61l-1.42,-0.69l0.09,-2.15l-0.97,-1.87l-2.18,-2.42l-1.03,-2.81l-0.75,-0.68l-0.17,-0.96l-0.77,-1.37l-13.99,-43.11Z", "name": "Georgia"}, "US-AZ": {"path": "M128.51,384.14l0.44,-1.81l1.29,-1.29l0.53,-1.12l0.48,-0.25l1.66,0.62l0.96,-0.03l0.52,-0.46l0.28,-1.17l1.31,-1.0l0.24,-2.73l-0.46,-1.24l-0.84,-0.66l-2.07,-0.66l-0.3,-0.61l0.8,-2.4l0.0,-1.39l-0.52,-1.19l0.57,-0.86l-0.2,-0.87l1.57,-0.27l2.29,-2.81l0.65,-2.43l0.65,-0.81l0.02,-3.17l0.55,-0.62l-0.29,-1.43l1.71,-1.14l1.03,-1.85l3.16,-1.29l2.03,-1.58l0.26,-0.53l-0.13,-1.04l-3.25,-3.49l-0.51,-0.22l0.22,-1.26l-0.66,-1.46l0.07,-0.91l-0.88,-2.76l-0.84,-0.56l-0.19,-1.65l-0.69,-0.8l0.19,-3.54l0.58,-0.87l-0.3,-0.86l1.03,-0.4l0.4,-1.42l0.14,-3.2l-0.76,-3.66l0.76,-2.55l-0.4,-3.0l0.85,-2.56l-0.8,-1.87l-0.03,-0.92l0.78,-1.88l2.54,-0.63l1.75,0.99l1.43,-0.19l0.96,2.24l0.79,0.71l1.54,0.14l1.01,-0.5l1.02,-2.27l0.94,-1.19l2.57,-16.94l42.42,5.78l42.56,4.67l-11.82,123.64l-36.87,-4.05l-36.33,-18.97l-28.43,-15.56Z", "name": "Arizona"}, "US-MT": {"path": "M166.39,57.3l0.69,-0.1l0.33,-0.38l-0.9,-1.99l0.83,-0.96l-0.39,-1.3l0.09,-0.96l-1.24,-1.93l-0.24,-1.49l-1.03,-1.33l-1.19,-2.44l3.53,-20.64l43.67,6.71l43.04,5.23l42.75,3.84l43.13,2.53l-3.53,86.04l-28.1,-1.47l-26.82,-1.91l-26.78,-2.4l-25.83,-2.79l-0.44,0.35l-1.22,10.41l-1.51,-2.01l-0.03,-0.91l-1.18,-2.35l-1.25,-0.74l-1.8,0.92l0.03,1.05l-0.72,0.42l-0.34,1.56l-2.42,-0.41l-1.91,0.57l-0.92,-0.85l-3.36,0.09l-2.38,-0.96l-1.68,0.58l-0.84,1.49l-4.66,-1.6l-1.3,0.37l-1.12,0.9l-0.31,0.67l-1.65,-1.4l0.22,-1.43l-0.9,-1.71l0.4,-0.36l0.07,-0.62l-1.17,-3.08l-1.45,-1.25l-1.44,0.36l-0.21,-0.64l-1.08,-0.9l-0.41,-1.37l0.68,-0.61l0.2,-1.41l-0.77,-2.38l-0.77,-0.35l-0.31,-1.58l-1.51,-2.54l0.23,-1.51l-0.56,-1.26l0.34,-1.4l-0.73,-0.86l0.48,-0.98l-0.21,-0.74l-1.14,-0.75l-0.13,-0.59l-0.85,-0.91l-0.8,-0.4l-0.51,0.37l-0.07,0.74l-0.7,0.27l-1.13,1.22l-1.75,0.37l-1.21,1.07l-1.08,-0.85l-0.64,-1.01l-1.06,-0.44l0.02,-0.86l0.74,-0.63l0.24,-1.06l-0.61,-1.6l0.9,-1.09l1.07,-0.08l0.83,-0.8l-0.26,-1.14l0.38,-1.07l-0.95,-0.81l-0.04,-0.81l0.66,-1.28l-0.59,-1.07l0.74,-0.07l0.38,-0.42l-0.04,-1.77l1.83,-3.73l-0.14,-1.05l0.89,-0.62l0.6,-3.16l-0.78,-0.5l-1.8,0.37l-1.33,-0.11l-0.64,-0.55l0.37,-0.83l-0.62,-0.97l-0.66,-0.23l-0.72,0.35l-0.07,-0.95l-1.74,-1.62l0.04,-1.84l-1.68,-1.82l-0.08,-0.69l-1.55,-2.88l-1.07,-1.29l-0.57,-1.63l-2.35,-1.34l-0.95,-1.95l-1.43,-1.19Z", "name": "Montana"}, "US-MS": {"path": "M555.51,431.02l0.67,-0.97l-1.05,-1.76l0.18,-1.63l-0.81,-0.87l1.69,-0.25l0.47,-0.54l0.4,-2.74l-0.77,-1.82l1.56,-1.79l0.25,-3.58l0.74,-2.26l1.89,-1.25l1.15,-1.97l1.4,-1.04l0.34,-0.78l-0.04,-0.99l-0.63,-0.96l1.14,-0.28l0.96,-2.58l0.91,-1.31l-0.16,-0.86l-1.54,-0.43l-0.35,-0.96l-1.83,-1.04l-0.07,-2.14l-0.93,-0.74l-0.45,-0.84l-0.02,-0.37l1.14,-0.29l0.46,-0.69l-0.26,-0.89l-1.41,-0.49l0.23,-1.77l0.98,-1.54l-0.77,-1.06l-1.08,-0.31l-0.15,-2.82l0.9,-0.54l0.23,-0.8l-0.62,-2.52l-1.25,-0.66l0.7,-1.33l-0.07,-2.22l-2.02,-1.52l1.13,-0.47l0.12,-1.41l-1.34,-0.89l1.58,-2.04l0.93,-0.31l0.36,-0.69l-0.52,-1.56l0.42,-1.35l-0.9,-0.89l2.84,-1.1l0.59,-0.76l-0.09,-1.07l-1.41,-0.95l1.39,-1.08l0.62,-1.77l0.94,-0.17l0.34,-0.97l-0.2,-0.77l1.48,-0.43l1.22,-1.21l0.07,-3.53l-0.46,-1.53l0.36,-1.78l0.73,0.09l0.68,-0.33l0.42,-0.87l-0.41,-1.06l2.72,-1.71l0.58,-1.06l-0.29,-1.28l36.44,-4.1l0.86,1.26l0.85,0.45l0.99,66.49l5.52,32.95l-0.73,0.69l-1.53,-0.3l-0.9,-0.94l-1.32,1.06l-1.23,0.17l-2.17,-1.26l-1.85,-0.19l-0.83,0.36l-0.34,0.44l0.32,0.41l-0.56,0.36l-3.96,1.66l-0.05,-0.5l-0.96,-0.52l-1.0,0.05l-0.58,1.0l0.76,0.61l-1.59,1.21l-0.33,1.28l-0.69,0.3l-1.33,-0.06l-1.16,-1.86l-0.08,-0.89l-0.92,-1.47l-0.21,-1.0l-1.4,-1.63l-1.16,-0.54l-0.47,-0.77l0.1,-0.62l-0.69,-0.92l0.21,-1.99l0.5,-0.93l0.66,-2.98l-0.06,-1.22l-0.43,-0.29l-34.66,3.41Z", "name": "Mississippi"}, "US-SC": {"path": "M697.55,324.05l4.86,-2.69l1.02,-0.05l1.11,-1.38l3.93,-1.9l0.45,-0.88l0.63,0.22l22.71,-3.36l0.07,1.22l0.42,0.57l0.71,0.01l1.21,-1.3l2.82,2.54l0.46,2.48l0.55,0.52l19.74,-3.49l22.74,15.07l0.02,0.55l-2.48,2.18l-2.44,3.67l-2.41,5.72l-0.09,2.74l-1.08,-0.21l0.85,-2.72l-0.63,-0.23l-0.76,0.87l-0.56,1.38l-0.11,1.55l0.83,0.95l1.05,0.23l0.44,0.91l-0.75,0.08l-0.41,0.56l-0.87,0.02l-0.24,0.68l0.94,0.45l-1.1,1.13l-0.07,1.02l-1.34,0.63l-0.5,-0.61l-0.5,-0.08l-1.06,0.87l-0.56,1.77l0.43,0.87l-1.19,1.23l-0.61,1.44l-1.2,1.01l-0.9,-0.4l0.27,-0.6l-0.53,-0.74l-1.37,0.31l0.25,1.2l-0.52,0.03l0.05,0.76l2.02,1.01l-0.12,0.39l-0.88,0.94l-1.22,0.23l-0.24,0.51l0.33,0.45l-2.29,1.34l-1.42,-0.84l-0.56,0.11l-0.1,0.67l1.19,0.78l-1.54,1.57l-0.72,-0.75l-0.5,0.52l-0.0,0.74l-1.54,-0.37l-1.34,-0.84l-0.44,0.5l0.16,0.53l-1.73,0.17l-0.44,0.37l-0.06,0.78l2.07,0.05l-0.26,0.55l0.42,0.25l1.91,-0.15l0.11,0.22l-0.97,0.86l-0.32,0.78l0.57,0.49l0.94,-0.53l0.03,0.21l-1.12,1.09l-0.99,0.43l-0.21,-2.04l-0.69,-0.27l-0.22,-1.54l-0.88,-0.15l-0.3,0.58l0.86,2.69l-1.12,-0.66l-0.63,-1.0l-0.39,-1.76l-0.65,-0.21l-0.52,-0.63l-0.69,0.0l-0.27,0.6l0.84,1.02l0.01,0.68l1.11,1.83l-0.02,0.86l1.22,1.17l-0.62,0.35l0.03,0.98l-1.2,3.56l-1.51,-0.78l-1.52,0.26l-0.97,-0.68l-0.54,-1.03l-0.17,-2.93l-0.86,-0.75l-1.06,-2.47l-1.04,-0.95l-3.23,-1.33l-0.49,-2.65l-1.12,-2.17l-1.43,-1.58l-0.06,-1.07l-0.76,-1.21l-4.81,-1.69l-0.58,-1.27l-1.21,-0.37l0.02,-0.7l-0.53,-0.87l-0.87,0.0l-0.73,-0.61l0.03,-1.21l-0.66,-1.26l-2.7,-1.78l-2.16,-0.52l-2.36,-3.12l-3.93,-1.93l-1.22,-1.03l-0.83,-0.12l-1.04,-1.81l-0.51,-0.22l-0.91,-1.21l-1.18,-0.68l-0.99,-2.42l-1.54,-1.65l-1.02,-1.87l-1.06,-0.37l-1.93,0.37l-0.46,-0.16l-2.75,-2.19l-1.06,0.02l-2.23,-1.27l0.36,-2.22l2.6,-3.31l0.15,-1.07ZM750.36,375.19l0.73,-0.08l0.51,0.45l-1.23,1.9l0.28,-1.22l-0.3,-1.06Z", "name": "South Carolina"}, "US-RI": {"path": "M851.1,141.46l0.22,-0.46l-0.53,-2.22l-3.14,-10.0l5.61,-1.84l0.76,2.06l0.8,0.25l0.19,0.73l0.08,0.42l-0.77,0.25l0.03,0.29l0.51,1.45l0.59,0.5l-0.75,0.28l-0.3,0.6l0.87,0.97l-0.14,1.23l0.89,1.9l0.03,1.67l-0.27,0.71l-0.9,0.16l-3.59,2.35l-0.18,-1.31ZM855.89,131.53l0.26,0.1l0.01,0.1l-0.17,-0.08l-0.1,-0.12ZM857.28,132.21l0.25,0.54l-0.05,0.32l-0.15,0.01l-0.05,-0.87Z", "name": "Rhode Island"}, "US-AR": {"path": "M498.76,376.91l-1.42,-38.01l-4.48,-23.98l37.68,-2.58l39.02,-3.58l0.8,1.6l1.01,0.7l0.11,1.77l-0.77,0.57l-0.22,0.94l-1.42,0.93l-0.29,1.04l-0.83,0.54l-1.19,2.59l0.02,0.7l0.53,0.26l10.94,-1.46l0.86,0.93l-1.18,0.37l-0.52,0.96l0.25,0.49l0.84,0.41l-3.6,2.7l0.02,0.84l0.83,1.04l-0.6,1.15l0.62,0.97l-1.42,0.74l-0.11,1.44l-1.45,2.09l0.12,1.64l0.91,3.1l-0.15,0.27l-1.08,-0.01l-0.33,0.26l-0.51,1.73l-1.52,0.95l-0.04,0.51l0.79,0.91l0.05,0.65l-1.11,1.21l-2.02,1.13l-0.21,0.62l0.43,1.0l-0.19,0.27l-1.23,0.03l-0.42,0.67l-0.32,1.89l0.47,1.57l0.02,3.08l-1.27,1.09l-1.54,0.13l0.23,1.49l-0.21,0.48l-0.93,0.25l-0.59,1.77l-1.49,1.19l-0.02,0.93l1.39,0.76l-0.03,0.7l-1.23,0.3l-2.24,1.23l0.03,0.67l0.99,0.82l-0.45,1.14l0.53,1.38l-1.09,0.62l-1.9,2.57l0.52,0.7l1.0,0.49l0.01,0.58l-0.98,0.29l-0.42,0.64l0.51,0.84l1.63,1.01l0.06,1.77l-0.59,0.98l-0.09,0.84l1.34,0.79l0.5,2.17l-1.09,1.01l0.06,2.11l-51.45,4.07l-0.83,-11.53l-1.18,-0.85l-0.9,0.16l-0.83,-0.35l-0.93,0.39l-1.22,-0.33l-0.57,0.72l-0.47,0.01l-0.49,-0.48l-0.82,-0.15l-0.63,-1.0Z", "name": "Arkansas"}}, "height": 612.395412685768, "projection": {"type": "aea", "centralMeridian": -100.0}, "width": 900.0});
|
admin/static/plugins/jvectormap/jquery-jvectormap-world-mill-en.js
ADDED
The diff for this file is too large to render.
See raw diff
|
|
admin/templates/admin/base.html
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% import 'admin/layout.html' as layout with context -%}
|
2 |
+
{% import 'admin/static.html' as admin_static with context %}
|
3 |
+
<!DOCTYPE html>
|
4 |
+
<html>
|
5 |
+
<head>
|
6 |
+
<title>{% block title %}{% if admin_view.category %}{{ admin_view.category }} - {% endif %}{{ admin_view.name }} - {{ admin_view.admin.name }}{% endblock title%}</title>
|
7 |
+
|
8 |
+
{% block head_meta %}
|
9 |
+
<meta charset="UTF-8">
|
10 |
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
11 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
12 |
+
<meta name="description" content="Flask-Admin dashboard login template">
|
13 |
+
<meta name="author" content="donBarbos">
|
14 |
+
{% endblock head_meta %}
|
15 |
+
|
16 |
+
{% block head_css %}
|
17 |
+
<!-- Bootstrap 3.3.6 -->
|
18 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
|
19 |
+
<!-- Font Awesome -->
|
20 |
+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
21 |
+
<!-- Ionicons -->
|
22 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css">
|
23 |
+
<!-- Theme style -->
|
24 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/AdminLTE.min.css" rel="stylesheet">
|
25 |
+
<!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. -->
|
26 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/2.4.0/css/skins/skin-blue.min.css" integrity="sha512-BkEsw04QmNkr3KQWCcQZX/HMoxo+opbv6ZRudUeh+/DmNoHonbPgDbC10jJyZF5ziwaMre3V23t5aiDN/VtUuQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
27 |
+
<!-- iCheck -->
|
28 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/iCheck/1.0.3/skins/line/blue.min.css" integrity="sha512-8LZI/lrjqgSZthdWQpVeePVUkMaRifkeQHGymi9CMNjP9+Tcf/7fIKxOQmruJOqAsEHpzu3qRW9i/cs6CKrQcA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
29 |
+
<!-- Morris chart -->
|
30 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.0/morris.css" integrity="sha512-fjy4e481VEA/OTVR4+WHMlZ4wcX/+ohNWKpVfb7q+YNnOCS++4ZDn3Vi6EaA2HJ89VXARJt7VvuAKaQ/gs1CbQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
31 |
+
<!-- jvectormap -->
|
32 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jvectormap/1.2.2/jquery-jvectormap.min.css" integrity="sha512-aezjkrRoy3ZR4p7unUG5DU/Hy2EHDQGNpXx58R0SkcpoEnLdQgAVyK1eN5Db8qDEsGqwz3zt6aqQjgo1KX2Uyw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
33 |
+
<!-- Date Picker -->
|
34 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.0/css/datepicker3.min.css" integrity="sha512-8vdZWz6gSr6gJeFbG0xA0bKmX+wpNe4Y/IY42RMdNe9VspA/v5HzBkqjHDOLJ4WCX8CVSyXvHr0+wc1dEluKhQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
35 |
+
<!-- Daterange picker -->
|
36 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-daterangepicker/2.1.19/daterangepicker.min.css" integrity="sha512-7mJKlXWP4Z8eLwYwVeBxxbCR8IDVMAK7ph5V5CpT3YKwCWW0WcVGkoTkeFurwkFjW0SKO/H4uIlLw9XsgwIXTQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
37 |
+
<!-- bootstrap wysihtml5 - text editor -->
|
38 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap3-wysiwyg/0.3.3/bootstrap3-wysihtml5.min.css" integrity="sha512-Bhi4560umtRBUEJCTIJoNDS6ssVIls7oiYyT3PbhxZV+9uBbLVO/mWo56hrBNNbIfMXKvtIPJi/Jg+vpBpA7sg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
39 |
+
<!-- Flask-admin admin styles -->
|
40 |
+
{% if admin_view.extra_css %}
|
41 |
+
{% for css_url in admin_view.extra_css %}
|
42 |
+
<link href="{{ css_url }}" rel="stylesheet">
|
43 |
+
{% endfor %}
|
44 |
+
{% endif %}
|
45 |
+
|
46 |
+
{% endblock head_css%}
|
47 |
+
|
48 |
+
{% block head %}
|
49 |
+
{% endblock head%}
|
50 |
+
|
51 |
+
{% block head_tail %}
|
52 |
+
{% endblock head_tail%}
|
53 |
+
|
54 |
+
<style>
|
55 |
+
body {
|
56 |
+
font-size: 16px;
|
57 |
+
}
|
58 |
+
</style>
|
59 |
+
</head>
|
60 |
+
<body class="hold-transition skin-blue sidebar-mini h-100">
|
61 |
+
|
62 |
+
{% block page_body %}
|
63 |
+
|
64 |
+
<!-- TOP NAVBAR -->
|
65 |
+
<div class="wrapper" style="min-height:100vh;">
|
66 |
+
{% if current_user.is_authenticated %}
|
67 |
+
<header class="main-header">
|
68 |
+
<!-- Logo -->
|
69 |
+
{% block brand %}
|
70 |
+
<a href="{{ admin_view.admin.url }}" class="logo" style="height: 53.45px">
|
71 |
+
<!-- mini logo for sidebar mini 50x50 pixels -->
|
72 |
+
<span class="logo-mini"><b>TG</b></span>
|
73 |
+
<!-- logo for regular state and mobile devices -->
|
74 |
+
<span class="logo-lg"><b>{{ admin_view.admin.name }}</b></span>
|
75 |
+
</a>
|
76 |
+
{% endblock brand%}
|
77 |
+
|
78 |
+
<!-- Header Navbar: style can be found in header.less -->
|
79 |
+
<nav class="navbar navbar-static-top">
|
80 |
+
<!-- Sidebar toggle button-->
|
81 |
+
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
|
82 |
+
<span class="sr-only">Toggle navigation</span>
|
83 |
+
</a>
|
84 |
+
|
85 |
+
<div class="navbar-custom-menu">
|
86 |
+
<ul class="nav navbar-nav">
|
87 |
+
<!-- Control Sidebar Toggle Button -->
|
88 |
+
<li>
|
89 |
+
{% block access_control %}
|
90 |
+
{% endblock %}
|
91 |
+
</li>
|
92 |
+
</ul>
|
93 |
+
|
94 |
+
{% block menu_links %}
|
95 |
+
<ul class="nav navbar-nav navbar-right">
|
96 |
+
{{ layout.menu_links() }}
|
97 |
+
</ul>
|
98 |
+
{% endblock %}
|
99 |
+
|
100 |
+
</div>
|
101 |
+
</nav>
|
102 |
+
</header>
|
103 |
+
<!-- / TOP NAVBAR -->
|
104 |
+
|
105 |
+
<!-- LEFT MENU -->
|
106 |
+
<aside class="main-sidebar">
|
107 |
+
<!-- sidebar: style can be found in sidebar.less -->
|
108 |
+
<section class="sidebar">
|
109 |
+
<!-- sidebar menu: : style can be found in sidebar.less -->
|
110 |
+
<ul class="sidebar-menu">
|
111 |
+
<li class="header">MAIN NAVIGATION</li>
|
112 |
+
{% block main_menu %}
|
113 |
+
{{ layout.menu() }}
|
114 |
+
{% endblock %}
|
115 |
+
</ul>
|
116 |
+
</section>
|
117 |
+
<!-- /.sidebar -->
|
118 |
+
</aside>
|
119 |
+
|
120 |
+
<!-- Content Wrapper. Contains page content color white-->
|
121 |
+
<div class="content-wrapper">
|
122 |
+
{% endif %}
|
123 |
+
|
124 |
+
{% block messages %}
|
125 |
+
{{ layout.messages() }}
|
126 |
+
{% endblock messages %}
|
127 |
+
|
128 |
+
{# store the jinja2 context for form_rules rendering logic #}
|
129 |
+
{% set render_ctx = h.resolve_ctx() %}
|
130 |
+
|
131 |
+
|
132 |
+
{% block body %}
|
133 |
+
|
134 |
+
{% endblock body %}
|
135 |
+
|
136 |
+
{% if current_user.is_authenticated %}
|
137 |
+
</div>
|
138 |
+
|
139 |
+
<footer class="main-footer">
|
140 |
+
<strong>Copyright © 2023 <a href="https://github.com/donBarbos">donBarbos</a>.</strong> All rights reserved.
|
141 |
+
</footer>
|
142 |
+
{% endif %}
|
143 |
+
|
144 |
+
</div>
|
145 |
+
<!-- ./wrapper -->
|
146 |
+
|
147 |
+
{% endblock page_body%}
|
148 |
+
|
149 |
+
{% block tail_js %}
|
150 |
+
<!-- jQuery 2.2.3 -->
|
151 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js" integrity="sha512-SFaNb3xC08k/Wf6CRM1J+O/vv4YWyrPBSdy0o+1nqKzf+uLrIBnaeo8aYoAAOd31nMNHwX8zwVwTMbbCJjA8Kg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
152 |
+
<!-- jQuery UI 1.11.4 -->
|
153 |
+
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
|
154 |
+
<!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip -->
|
155 |
+
<script>
|
156 |
+
$.widget.bridge('uibutton', $.ui.button);
|
157 |
+
</script>
|
158 |
+
<!-- Bootstrap 3.3.6 -->
|
159 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha512-iztkobsvnjKfAtTNdHkGVjAYTrrtlC7mGp/54c40wowO7LhURYl3gVzzcEqGl/qKXQltJ2HwMrdLcNUdo+N/RQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
160 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js" integrity="sha512-bj8HE1pKwchoYNizhD57Vl6B9ExS25Hw21WxoQEzGapNNjLZ0+kgRMEn9KSCD+igbE9+/dJO7x6ZhLrdaQ5P3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
161 |
+
|
162 |
+
{% if admin_view.extra_js %}
|
163 |
+
{% for js_url in admin_view.extra_js %}
|
164 |
+
<script src="{{ js_url }}" type="text/javascript"></script>
|
165 |
+
{% endfor %}
|
166 |
+
{% endif %}
|
167 |
+
|
168 |
+
<!-- Morris.js charts -->
|
169 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
|
170 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.0/morris.min.js" integrity="sha512-9FtP5DAAufVz3oNWHfXGNYv5VP8Rzkq+uVK8TDWtDK8i7rqifXbecSFHPU5Xl0NqwTwSBO1tBh3GKeAXiAVNpg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
171 |
+
<!-- Sparkline -->
|
172 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-sparklines/2.1.2/jquery.sparkline.min.js" integrity="sha512-3PRVLmoBYuBDbCEojg5qdmd9UhkPiyoczSFYjnLhFb2KAFsWWEMlAPt0olX1Nv7zGhDfhGEVkXsu51a55nlYmw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
173 |
+
<!-- jvectormap -->
|
174 |
+
<script src="{{url_for('static',filename='plugins/jvectormap/jquery-jvectormap-1.2.2.min.js')}}"></script>
|
175 |
+
<script src="{{url_for('static',filename='plugins/jvectormap/jquery-jvectormap-world-mill-en.js')}}"></script>
|
176 |
+
<!-- jQuery Knob Chart -->
|
177 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery-Knob/1.2.11/jquery.knob.min.js" integrity="sha512-NhRZzPdzMOMf005Xmd4JonwPftz4Pe99mRVcFeRDcdCtfjv46zPIi/7ZKScbpHD/V0HB1Eb+ZWigMqw94VUVaw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
178 |
+
<!-- daterangepicker -->
|
179 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js"></script>
|
180 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-daterangepicker/2.1.19/daterangepicker.min.js" integrity="sha512-GkQtOaR7sIMWGaYd5snXXfP8/q6dgJPiFTUVSBHEX2NnptoREEnBKT9vL/b8QeCZLazvFaCEE142nb3t3OQwcQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
181 |
+
<!-- datepicker -->
|
182 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.0/js/bootstrap-datepicker.min.js" integrity="sha512-ygaYzcKBzf1YptDaS/7b9P2pY2LW0YCXp22l+IZYHwOjB2opJDrniEMarJ1HsckAdKirYqE9JMpKfSm6NHUcdg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
183 |
+
<!-- Bootstrap WYSIHTML5 -->
|
184 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap3-wysiwyg/0.3.3/bootstrap3-wysihtml5.all.min.js" integrity="sha512-ng0ComxRUMJeeN1JS62sxZ+eSjoavxBVv3l7SG4W/gBVbQj+AfmVRdkFT4BNNlxdDCISRrDBkNDxC7omF0MBLQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
185 |
+
<!-- slimScroll -->
|
186 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery-slimScroll/1.3.8/jquery.slimscroll.min.js" integrity="sha512-cJMgI2OtiquRH4L9u+WQW+mz828vmdp9ljOcm/vKTQ7+ydQUktrPVewlykMgozPP+NUBbHdeifE6iJ6UVjNw5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
187 |
+
<!-- FastClick -->
|
188 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js" integrity="sha512-qH+R6YL4/40iiIrnN5aNZ1sEeEalNAdnzP9jfsxFPBdIslTkwUddkSazjVWhJ3f/3Y26QF6aql0xeneuVw0h/Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
189 |
+
<!-- AdminLTE App -->
|
190 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/app.min.js"></script>
|
191 |
+
{% if admin_view.name=="Home" %}
|
192 |
+
<script src="{{url_for('static',filename='js/pages/dashboard.js')}}"></script>
|
193 |
+
{% endif %}
|
194 |
+
|
195 |
+
{% endblock tail_js%}
|
196 |
+
|
197 |
+
{% block tail %}
|
198 |
+
{% endblock tail %}
|
199 |
+
|
200 |
+
</body>
|
201 |
+
</html>
|
admin/templates/admin/custom_index.html
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends 'admin/master.html' %} {% block body %} {{ super() }} {% if
|
2 |
+
current_user.is_authenticated %}
|
3 |
+
|
4 |
+
<!-- Content Header (Page header) -->
|
5 |
+
<section class="content-header">
|
6 |
+
<h1>
|
7 |
+
Custom View
|
8 |
+
<small>This is a custom view without DB model</small>
|
9 |
+
</h1>
|
10 |
+
<ol class="breadcrumb">
|
11 |
+
<li>
|
12 |
+
<a href="#"><i class="fa fa-dashboard"></i> Home</a>
|
13 |
+
</li>
|
14 |
+
<li class="active">Custom</li>
|
15 |
+
</ol>
|
16 |
+
</section>
|
17 |
+
|
18 |
+
<section class="content">
|
19 |
+
<div class="row">
|
20 |
+
<!-- Left col -->
|
21 |
+
<section class="container">
|
22 |
+
Here you can place your custom data without a database dependence. <br />
|
23 |
+
Find this file in templates/admin/ as custom_index.html
|
24 |
+
</section>
|
25 |
+
<!-- /.Left col -->
|
26 |
+
</div>
|
27 |
+
<!-- /.row (main row) -->
|
28 |
+
</section>
|
29 |
+
<!-- /.content -->
|
30 |
+
{% else %}
|
31 |
+
|
32 |
+
<center>
|
33 |
+
<section class="content" style="color: white">
|
34 |
+
<div class="col-sm-12">
|
35 |
+
<h1>Flask-Admin example</h1>
|
36 |
+
<p class="lead">Authentication</p>
|
37 |
+
<p>
|
38 |
+
This is an admin panel created for managing users, moderating and
|
39 |
+
viewing telegram bot analytics. <br />
|
40 |
+
If you have not yet changed the standard email/password for the first
|
41 |
+
<br />
|
42 |
+
superuser and/or this is your first authorization, you can log in under
|
43 |
+
it.
|
44 |
+
</p>
|
45 |
+
{% if not current_user.is_authenticated %}
|
46 |
+
<p>
|
47 |
+
You can register as a regular user, or log in as a superuser with the
|
48 |
+
following credentials: <br /><br />
|
49 |
+
|
50 |
+
email: <b>admin</b> <br />
|
51 |
+
password: <b>admin</b> <br />
|
52 |
+
<br />
|
53 |
+
</p>
|
54 |
+
|
55 |
+
<p>
|
56 |
+
<a class="btn btn-primary" href="{{ url_for('security.login') }}"
|
57 |
+
>Login</a
|
58 |
+
>
|
59 |
+
<a class="btn btn-default" href="{{ url_for('security.register') }}"
|
60 |
+
>Register</a
|
61 |
+
>
|
62 |
+
</p>
|
63 |
+
{% endif %}
|
64 |
+
<br />
|
65 |
+
<p>
|
66 |
+
<a class="btn btn-primary" href="/"
|
67 |
+
><i class="glyphicon glyphicon-chevron-left"></i> Back</a
|
68 |
+
>
|
69 |
+
</p>
|
70 |
+
</div>
|
71 |
+
</section>
|
72 |
+
</center>
|
73 |
+
|
74 |
+
<br /><br /><br /><br /><br /><br /><br /><br /><br />
|
75 |
+
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
|
76 |
+
{% endif %} {% endblock body %}
|
admin/templates/admin/index.html
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends 'admin/master.html' %} {% block body %} {{ super() }} {% if
|
2 |
+
current_user.is_authenticated %}
|
3 |
+
|
4 |
+
<!-- Content Header (Page header) -->
|
5 |
+
<section class="content-header">
|
6 |
+
<h1>
|
7 |
+
Dashboard
|
8 |
+
<small>Control panel</small>
|
9 |
+
</h1>
|
10 |
+
<ol class="breadcrumb">
|
11 |
+
<li>
|
12 |
+
<a href="#"><i class="fa fa-dashboard"></i> Home</a>
|
13 |
+
</li>
|
14 |
+
<li class="active">Dashboard</li>
|
15 |
+
</ol>
|
16 |
+
</section>
|
17 |
+
|
18 |
+
<section class="content">
|
19 |
+
<!-- Small boxes (Stat box) -->
|
20 |
+
<div class="row">
|
21 |
+
<div class="col-lg-3 col-xs-6">
|
22 |
+
<!-- small box -->
|
23 |
+
<div class="small-box bg-aqua">
|
24 |
+
<div class="inner">
|
25 |
+
<h3>{{ order_count }}</h3>
|
26 |
+
<p>Orders Count</p>
|
27 |
+
</div>
|
28 |
+
<div class="icon">
|
29 |
+
<i class="ion ion-bag"></i>
|
30 |
+
</div>
|
31 |
+
<a href="{{ 'orders' }}" class="small-box-footer"
|
32 |
+
>More info <i class="fa fa-arrow-circle-right"></i
|
33 |
+
></a>
|
34 |
+
</div>
|
35 |
+
</div>
|
36 |
+
<!-- ./col -->
|
37 |
+
<div class="col-lg-3 col-xs-6">
|
38 |
+
<!-- small box -->
|
39 |
+
<div class="small-box bg-green">
|
40 |
+
<div class="inner">
|
41 |
+
<h3>53<sup style="font-size: 20px">%</sup></h3>
|
42 |
+
|
43 |
+
<p>Bounce Rate</p>
|
44 |
+
</div>
|
45 |
+
<div class="icon">
|
46 |
+
<i class="ion ion-stats-bars"></i>
|
47 |
+
</div>
|
48 |
+
<a href="#" class="small-box-footer"
|
49 |
+
>More info <i class="fa fa-arrow-circle-right"></i
|
50 |
+
></a>
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
+
<!-- ./col -->
|
54 |
+
<div class="col-lg-3 col-xs-6">
|
55 |
+
<!-- small box -->
|
56 |
+
<div class="small-box bg-yellow">
|
57 |
+
<div class="inner">
|
58 |
+
<h3>{{ new_user_count }}</h3>
|
59 |
+
|
60 |
+
<p>New users per day</p>
|
61 |
+
</div>
|
62 |
+
<div class="icon">
|
63 |
+
<i class="ion ion-person-add"></i>
|
64 |
+
</div>
|
65 |
+
<a
|
66 |
+
href="{{ 'users/?flt2_10=' ~ period_start.strftime('%Y-%m-%d+%H:%M:%S') }}"
|
67 |
+
class="small-box-footer"
|
68 |
+
>More info <i class="fa fa-arrow-circle-right"></i
|
69 |
+
></a>
|
70 |
+
</div>
|
71 |
+
</div>
|
72 |
+
<!-- ./col -->
|
73 |
+
<div class="col-lg-3 col-xs-6">
|
74 |
+
<!-- small box -->
|
75 |
+
<div class="small-box bg-red">
|
76 |
+
<div class="inner">
|
77 |
+
<h3>{{ user_count }}</h3>
|
78 |
+
|
79 |
+
<p>Unique users</p>
|
80 |
+
</div>
|
81 |
+
<div class="icon">
|
82 |
+
<i class="ion ion-pie-graph"></i>
|
83 |
+
</div>
|
84 |
+
<a href="{{ 'users' }}" class="small-box-footer"
|
85 |
+
>More info <i class="fa fa-arrow-circle-right"></i
|
86 |
+
></a>
|
87 |
+
</div>
|
88 |
+
</div>
|
89 |
+
<!-- ./col -->
|
90 |
+
</div>
|
91 |
+
<!-- /.row -->
|
92 |
+
<!-- Main row -->
|
93 |
+
<div class="row">
|
94 |
+
<!-- Left col -->
|
95 |
+
<section class="col-lg-7 connectedSortable">
|
96 |
+
<!-- Custom tabs (Charts with tabs)-->
|
97 |
+
<div class="nav-tabs-custom">
|
98 |
+
<!-- Tabs within a box -->
|
99 |
+
<ul class="nav nav-tabs pull-right">
|
100 |
+
<li class="active">
|
101 |
+
<a href="#revenue-chart" data-toggle="tab">Area</a>
|
102 |
+
</li>
|
103 |
+
<li><a href="#sales-chart" data-toggle="tab">Donut</a></li>
|
104 |
+
<li class="pull-left header"><i class="fa fa-inbox"></i> Sales</li>
|
105 |
+
</ul>
|
106 |
+
<div class="tab-content no-padding">
|
107 |
+
<!-- Morris chart - Sales -->
|
108 |
+
<div
|
109 |
+
class="chart tab-pane active"
|
110 |
+
id="revenue-chart"
|
111 |
+
style="position: relative; height: 300px"
|
112 |
+
></div>
|
113 |
+
<div
|
114 |
+
class="chart tab-pane"
|
115 |
+
id="sales-chart"
|
116 |
+
style="position: relative; height: 300px"
|
117 |
+
></div>
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
<!-- /.nav-tabs-custom -->
|
121 |
+
</section>
|
122 |
+
<!-- /.Left col -->
|
123 |
+
<!-- right col (We are only adding the ID to make the widgets sortable)-->
|
124 |
+
<section class="col-lg-5 connectedSortable">
|
125 |
+
<!-- Map box -->
|
126 |
+
<div class="box box-solid bg-light-blue-gradient">
|
127 |
+
<div class="box-header">
|
128 |
+
<!-- tools box -->
|
129 |
+
<div class="pull-right box-tools">
|
130 |
+
<button
|
131 |
+
type="button"
|
132 |
+
class="btn btn-primary btn-sm daterange pull-right"
|
133 |
+
data-toggle="tooltip"
|
134 |
+
title="Date range"
|
135 |
+
>
|
136 |
+
<i class="fa fa-calendar"></i>
|
137 |
+
</button>
|
138 |
+
<button
|
139 |
+
type="button"
|
140 |
+
class="btn btn-primary btn-sm pull-right"
|
141 |
+
data-widget="collapse"
|
142 |
+
data-toggle="tooltip"
|
143 |
+
title="Collapse"
|
144 |
+
style="margin-right: 5px"
|
145 |
+
>
|
146 |
+
<i class="fa fa-minus"></i>
|
147 |
+
</button>
|
148 |
+
</div>
|
149 |
+
<!-- /. tools -->
|
150 |
+
|
151 |
+
<i class="fa fa-map-marker"></i>
|
152 |
+
|
153 |
+
<h3 class="box-title">Visitors</h3>
|
154 |
+
</div>
|
155 |
+
<div class="box-body">
|
156 |
+
<div id="world-map" style="height: 250px; width: 100%"></div>
|
157 |
+
</div>
|
158 |
+
<!-- /.box-body-->
|
159 |
+
<div class="box-footer no-border">
|
160 |
+
<div class="row">
|
161 |
+
<div
|
162 |
+
class="col-xs-4 text-center"
|
163 |
+
style="border-right: 1px solid #f4f4f4"
|
164 |
+
>
|
165 |
+
<div id="sparkline-1"></div>
|
166 |
+
<div class="knob-label">Visitors</div>
|
167 |
+
</div>
|
168 |
+
<!-- ./col -->
|
169 |
+
<div
|
170 |
+
class="col-xs-4 text-center"
|
171 |
+
style="border-right: 1px solid #f4f4f4"
|
172 |
+
>
|
173 |
+
<div id="sparkline-2"></div>
|
174 |
+
<div class="knob-label">Online</div>
|
175 |
+
</div>
|
176 |
+
<!-- ./col -->
|
177 |
+
<div class="col-xs-4 text-center">
|
178 |
+
<div id="sparkline-3"></div>
|
179 |
+
<div class="knob-label">Exists</div>
|
180 |
+
</div>
|
181 |
+
<!-- ./col -->
|
182 |
+
</div>
|
183 |
+
<!-- /.row -->
|
184 |
+
</div>
|
185 |
+
</div>
|
186 |
+
<!-- /.box -->
|
187 |
+
</section>
|
188 |
+
<!-- right col -->
|
189 |
+
</div>
|
190 |
+
<!-- /.row (main row) -->
|
191 |
+
</section>
|
192 |
+
<!-- /.content -->
|
193 |
+
{% else %} {% if not current_user.is_authenticated %}
|
194 |
+
<section
|
195 |
+
class="content"
|
196 |
+
style="color: white; height: 100vh; display: flex; align-items: center"
|
197 |
+
>
|
198 |
+
<div class="col-sm-12 text-center">
|
199 |
+
<h1>Telegram Bot Admin Panel</h1>
|
200 |
+
<p class="lead">Authentication</p>
|
201 |
+
<p>
|
202 |
+
This is an admin panel created for managing users, moderating and viewing
|
203 |
+
telegram bot analytics. <br />
|
204 |
+
</p>
|
205 |
+
<p>
|
206 |
+
Default email/password for first superuser:<br /><br />
|
207 |
+
|
208 |
+
email: <b>{{ default_email }}</b> <br />
|
209 |
+
password: <b>{{ default_password }}</b> <br />
|
210 |
+
<br />
|
211 |
+
</p>
|
212 |
+
|
213 |
+
<p>
|
214 |
+
<a class="btn btn-primary" href="{{ url_for('security.login') }}"
|
215 |
+
>Login</a
|
216 |
+
>
|
217 |
+
<a class="btn btn-default" href="{{ url_for('security.register') }}"
|
218 |
+
>Register</a
|
219 |
+
>
|
220 |
+
</p>
|
221 |
+
</div>
|
222 |
+
</section>
|
223 |
+
{% endif %} {% endif %} {% endblock body %}
|
admin/templates/my_master.html
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends 'admin/base.html' %} {% block access_control %} {% if
|
2 |
+
current_user.is_authenticated %}
|
3 |
+
<!-- User Account: style can be found in dropdown.less -->
|
4 |
+
|
5 |
+
<li class="dropdown user user-menu">
|
6 |
+
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
7 |
+
<i class="fa fa-user-circle" style="color: white; font-size: 1.4em"></i>
|
8 |
+
<span class="hidden-xs">
|
9 |
+
{% if current_user.first_name %} {{ current_user.first_name }} {% else %}
|
10 |
+
{{ current_user.email }} {% endif %}
|
11 |
+
</span>
|
12 |
+
</a>
|
13 |
+
<ul class="dropdown-menu">
|
14 |
+
<!-- User image -->
|
15 |
+
<li class="user-header">
|
16 |
+
<i class="fa fa-user-circle" style="color: white; font-size: 7em"></i>
|
17 |
+
<p>
|
18 |
+
{% if current_user.first_name %} {{ current_user.first_name }} {% else
|
19 |
+
%} {{ current_user.email }} {% endif %}
|
20 |
+
<small
|
21 |
+
>Member since {{ current_user.confirmed_at.strftime("%Y-%m-%d %H:%M")
|
22 |
+
}}</small
|
23 |
+
>
|
24 |
+
</p>
|
25 |
+
</li>
|
26 |
+
<!-- Menu Footer-->
|
27 |
+
<li class="user-footer">
|
28 |
+
<div class="pull-left">
|
29 |
+
<a
|
30 |
+
href="{{ url_for('admins.details_view', id=current_user.id) }}"
|
31 |
+
class="btn btn-default btn-flat"
|
32 |
+
>Profile</a
|
33 |
+
>
|
34 |
+
</div>
|
35 |
+
<div class="pull-right">
|
36 |
+
<a
|
37 |
+
href="{{ url_for('security.logout') }}"
|
38 |
+
class="btn btn-default btn-flat"
|
39 |
+
>Sign out</a
|
40 |
+
>
|
41 |
+
</div>
|
42 |
+
</li>
|
43 |
+
</ul>
|
44 |
+
</li>
|
45 |
+
|
46 |
+
{% endif %} {% endblock %}
|
admin/templates/security/_macros.html
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% macro render_field_with_errors(field) %}
|
2 |
+
|
3 |
+
<div class="form-group">
|
4 |
+
{{ field.label }} {{ field(class_='form-control', **kwargs)|safe }}
|
5 |
+
{% if field.errors %}
|
6 |
+
<ul>
|
7 |
+
{% for error in field.errors %}
|
8 |
+
<li>{{ error }}</li>
|
9 |
+
{% endfor %}
|
10 |
+
</ul>
|
11 |
+
{% endif %}
|
12 |
+
</div>
|
13 |
+
{% endmacro %}
|
14 |
+
|
15 |
+
{% macro render_field(field) %}
|
16 |
+
<p>{{ field(class_='form-control', **kwargs)|safe }}</p>
|
17 |
+
{% endmacro %}
|
18 |
+
|
19 |
+
{% macro render_checkbox_field(field) -%}
|
20 |
+
<div class="form-group">
|
21 |
+
<div class="checkbox">
|
22 |
+
<label style="padding-left: 0px">
|
23 |
+
{{ field(type='checkbox', style='margin-left: 0px;', **kwargs) }} {{ field.label }}
|
24 |
+
</label>
|
25 |
+
</div>
|
26 |
+
</div>
|
27 |
+
{%- endmacro %}
|
admin/templates/security/_menu.html
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% if security.registerable or security.recoverable or security.confirmable %}
|
2 |
+
<h2>Menu</h2>
|
3 |
+
<ul>
|
4 |
+
<li><a href="{{ url_for_security('login') }}{% if 'next' in request.args %}?next={{ request.args.next|urlencode }}{% endif %}">Login</a></li>
|
5 |
+
{% if security.registerable %}
|
6 |
+
<li><a href="{{ url_for_security('register') }}{% if 'next' in request.args %}?next={{ request.args.next|urlencode }}{% endif %}">Register</a><br/></li>
|
7 |
+
{% endif %}
|
8 |
+
{% if security.recoverable %}
|
9 |
+
<li><a href="{{ url_for_security('forgot_password') }}">Forgot password</a><br/></li>
|
10 |
+
{% endif %}
|
11 |
+
{% if security.confirmable %}
|
12 |
+
<li><a href="{{ url_for_security('send_confirmation') }}">Confirm account</a></li>
|
13 |
+
{% endif %}
|
14 |
+
</ul>
|
15 |
+
{% endif %}
|
admin/templates/security/_messages.html
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{%- with messages = get_flashed_messages(with_categories=true) -%}
|
2 |
+
{% if messages %}
|
3 |
+
<ul class="flashes">
|
4 |
+
{% for category, message in messages %}
|
5 |
+
<li class="{{ category }}">{{ message }}</li>
|
6 |
+
{% endfor %}
|
7 |
+
</ul>
|
8 |
+
{% endif %}
|
9 |
+
{%- endwith %}
|
admin/templates/security/login_user.html
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends 'admin/master.html' %}
|
2 |
+
{% from "security/_macros.html" import render_field, render_field_with_errors, render_checkbox_field %}
|
3 |
+
{% include "security/_messages.html" %}
|
4 |
+
{% block body %}
|
5 |
+
{{ super() }}
|
6 |
+
<section class="content" style="max-width: 800px; max-height: 800px">
|
7 |
+
<div class="col-sm-8 col-sm-offset-2" style="margin-top: calc(100% / 6)">
|
8 |
+
<div class="well" style="padding: 44px">
|
9 |
+
<h1 class="text-center">Login</h1>
|
10 |
+
<form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
|
11 |
+
{{ login_user_form.hidden_tag() }}
|
12 |
+
{{ render_field_with_errors(login_user_form.email) }}
|
13 |
+
{{ render_field_with_errors(login_user_form.password) }}
|
14 |
+
{{ render_checkbox_field(login_user_form.remember) }}
|
15 |
+
{{ render_field(login_user_form.next) }}
|
16 |
+
{{ render_field(login_user_form.submit, class="btn btn-primary btn-block") }}
|
17 |
+
</form>
|
18 |
+
<p>Don't have an account? <a href="{{ url_for('security.register') }}">Create One</a></p>
|
19 |
+
</div>
|
20 |
+
</div>
|
21 |
+
</section>
|
22 |
+
{% endblock body %}
|
admin/templates/security/register_user.html
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends 'admin/master.html' %}
|
2 |
+
{% from "security/_macros.html" import render_field_with_errors, render_field %}
|
3 |
+
{% include "security/_messages.html" %}
|
4 |
+
{% block body %}
|
5 |
+
{{ super() }}
|
6 |
+
<section class="content" style="max-width: 800px; max-height: 800px">
|
7 |
+
<div class="col-sm-8 col-sm-offset-2" style="margin-top: calc(100% / 6)">
|
8 |
+
<div class="well" style="padding: 44px">
|
9 |
+
<h1 class="text-center">Register</h1>
|
10 |
+
<form action="{{ url_for_security('register') }}" method="POST" name="register_user_form">
|
11 |
+
{{ register_user_form.hidden_tag() }}
|
12 |
+
{{ render_field_with_errors(register_user_form.email) }}
|
13 |
+
{{ render_field_with_errors(register_user_form.password) }}
|
14 |
+
{% if register_user_form.password_confirm %}
|
15 |
+
{{ render_field_with_errors(register_user_form.password_confirm) }}
|
16 |
+
{% endif %}
|
17 |
+
{{ render_field(register_user_form.submit, class="btn btn-primary btn-block") }}
|
18 |
+
</form>
|
19 |
+
<p> Already have an account? <a href="{{ url_for('security.login') }}">Login</a></p>
|
20 |
+
</div>
|
21 |
+
</div>
|
22 |
+
</section>
|
23 |
+
{% endblock body %}
|
admin/views/__init__.py
ADDED
File without changes
|
admin/views/users.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ruff: noqa: RUF012
|
2 |
+
from flask_admin.contrib.sqla import ModelView
|
3 |
+
|
4 |
+
|
5 |
+
class UserView(ModelView):
|
6 |
+
can_delete = True
|
7 |
+
can_create = False
|
8 |
+
can_edit = True
|
9 |
+
can_view_details = True
|
10 |
+
edit_modal = True
|
11 |
+
can_export = True
|
12 |
+
details_modal = True
|
13 |
+
export_types = ["csv", "xlsx", "json", "yaml"]
|
14 |
+
|
15 |
+
column_searchable_list = ["id", "username", "first_name", "last_name"]
|
16 |
+
column_filters = ["is_admin", "is_suspicious", "is_block", "is_premium", "created_at"]
|
17 |
+
column_list = [
|
18 |
+
"id",
|
19 |
+
"username",
|
20 |
+
"first_name",
|
21 |
+
"last_name",
|
22 |
+
"language_code",
|
23 |
+
"is_admin",
|
24 |
+
"is_suspicious",
|
25 |
+
"is_block",
|
26 |
+
"is_premium",
|
27 |
+
"created_at",
|
28 |
+
]
|
29 |
+
column_default_sort = ("created_at", True)
|
alembic.ini
ADDED
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# A generic, single database configuration.
|
2 |
+
|
3 |
+
[alembic]
|
4 |
+
# path to migration scripts
|
5 |
+
script_location = migrations
|
6 |
+
|
7 |
+
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
8 |
+
# Uncomment the line below if you want the files to be prepended with date and time
|
9 |
+
file_template = %%(year)d-%%(month).2d-%%(day).2d_%%(slug)s
|
10 |
+
|
11 |
+
# sys.path path, will be prepended to sys.path if present.
|
12 |
+
# defaults to the current working directory.
|
13 |
+
prepend_sys_path = .
|
14 |
+
|
15 |
+
# timezone to use when rendering the date within the migration file
|
16 |
+
# as well as the filename.
|
17 |
+
# If specified, requires the python>=3.9 or backports.zoneinfo library.
|
18 |
+
# Any required deps can installed by adding `alembic[tz]` to the pip requirements
|
19 |
+
# string value is passed to ZoneInfo()
|
20 |
+
# leave blank for localtime
|
21 |
+
# timezone =
|
22 |
+
|
23 |
+
# max length of characters to apply to the
|
24 |
+
# "slug" field
|
25 |
+
# truncate_slug_length = 40
|
26 |
+
|
27 |
+
# set to 'true' to run the environment during
|
28 |
+
# the 'revision' command, regardless of autogenerate
|
29 |
+
# revision_environment = false
|
30 |
+
|
31 |
+
# set to 'true' to allow .pyc and .pyo files without
|
32 |
+
# a source .py file to be detected as revisions in the
|
33 |
+
# versions/ directory
|
34 |
+
# sourceless = false
|
35 |
+
|
36 |
+
# version location specification; This defaults
|
37 |
+
# to migrations/versions. When using multiple version
|
38 |
+
# directories, initial revisions must be specified with --version-path.
|
39 |
+
# The path separator used here should be the separator specified by "version_path_separator" below.
|
40 |
+
# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions
|
41 |
+
|
42 |
+
# version path separator; As mentioned above, this is the character used to split
|
43 |
+
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
|
44 |
+
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
|
45 |
+
# Valid values for version_path_separator are:
|
46 |
+
#
|
47 |
+
# version_path_separator = :
|
48 |
+
# version_path_separator = ;
|
49 |
+
# version_path_separator = space
|
50 |
+
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
|
51 |
+
|
52 |
+
# set to 'true' to search source files recursively
|
53 |
+
# in each "version_locations" directory
|
54 |
+
# new in Alembic version 1.10
|
55 |
+
# recursive_version_locations = false
|
56 |
+
|
57 |
+
# the output encoding used when revision files
|
58 |
+
# are written from script.py.mako
|
59 |
+
# output_encoding = utf-8
|
60 |
+
|
61 |
+
sqlalchemy.url = driver://user:pass@localhost/dbname
|
62 |
+
|
63 |
+
|
64 |
+
[post_write_hooks]
|
65 |
+
# post_write_hooks defines scripts or Python functions that are run
|
66 |
+
# on newly generated revision scripts. See the documentation for further
|
67 |
+
# detail and examples
|
68 |
+
|
69 |
+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
70 |
+
# hooks = black
|
71 |
+
# black.type = console_scripts
|
72 |
+
# black.entrypoint = black
|
73 |
+
# black.options = -l 79 REVISION_SCRIPT_FILENAME
|
74 |
+
|
75 |
+
# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
|
76 |
+
# hooks = ruff, ruff_format
|
77 |
+
|
78 |
+
# lint with attempts to fix using "ruff"
|
79 |
+
# ruff.type = exec
|
80 |
+
# ruff.executable = %(here)s/.venv/bin/ruff
|
81 |
+
# ruff.options = --fix REVISION_SCRIPT_FILENAME
|
82 |
+
|
83 |
+
# format using "ruff" - use the exec runner, execute a binary
|
84 |
+
# ruff_format.type = exec
|
85 |
+
# ruff_format.executable = %(here)s/.venv/bin/ruff
|
86 |
+
# ruff_format.options = format REVISION_SCRIPT_FILENAME
|
87 |
+
|
88 |
+
# Logging configuration
|
89 |
+
[loggers]
|
90 |
+
keys = root,sqlalchemy,alembic
|
91 |
+
|
92 |
+
[handlers]
|
93 |
+
keys = console
|
94 |
+
|
95 |
+
[formatters]
|
96 |
+
keys = generic
|
97 |
+
|
98 |
+
[logger_root]
|
99 |
+
level = WARN
|
100 |
+
handlers = console
|
101 |
+
qualname =
|
102 |
+
|
103 |
+
[logger_sqlalchemy]
|
104 |
+
level = WARN
|
105 |
+
handlers =
|
106 |
+
qualname = sqlalchemy.engine
|
107 |
+
|
108 |
+
[logger_alembic]
|
109 |
+
level = INFO
|
110 |
+
handlers =
|
111 |
+
qualname = alembic
|
112 |
+
|
113 |
+
[handler_console]
|
114 |
+
class = StreamHandler
|
115 |
+
args = (sys.stderr,)
|
116 |
+
level = NOTSET
|
117 |
+
formatter = generic
|
118 |
+
|
119 |
+
[formatter_generic]
|
120 |
+
format = %(levelname)-5.5s [%(name)s] %(message)s
|
121 |
+
datefmt = %H:%M:%S
|
bot/__init__.py
ADDED
File without changes
|
bot/__main__.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
import asyncio
|
3 |
+
|
4 |
+
import sentry_sdk
|
5 |
+
import uvloop
|
6 |
+
from loguru import logger
|
7 |
+
from sentry_sdk.integrations.loguru import LoggingLevels, LoguruIntegration
|
8 |
+
|
9 |
+
from bot.core.config import settings
|
10 |
+
from bot.core.loader import app, bot, dp
|
11 |
+
from bot.handlers import get_handlers_router
|
12 |
+
from bot.handlers.metrics import MetricsView
|
13 |
+
from bot.keyboards.default_commands import remove_default_commands, set_default_commands
|
14 |
+
from bot.middlewares import register_middlewares
|
15 |
+
from bot.middlewares.prometheus import prometheus_middleware_factory
|
16 |
+
|
17 |
+
|
18 |
+
async def on_startup() -> None:
|
19 |
+
logger.info("bot starting...")
|
20 |
+
|
21 |
+
register_middlewares(dp)
|
22 |
+
|
23 |
+
dp.include_router(get_handlers_router())
|
24 |
+
|
25 |
+
if settings.USE_WEBHOOK:
|
26 |
+
app.middlewares.append(prometheus_middleware_factory())
|
27 |
+
app.router.add_route("GET", "/metrics", MetricsView)
|
28 |
+
|
29 |
+
await set_default_commands(bot)
|
30 |
+
|
31 |
+
bot_info = await bot.get_me()
|
32 |
+
|
33 |
+
logger.info(f"Name - {bot_info.full_name}")
|
34 |
+
logger.info(f"Username - @{bot_info.username}")
|
35 |
+
logger.info(f"ID - {bot_info.id}")
|
36 |
+
|
37 |
+
states: dict[bool | None, str] = {
|
38 |
+
True: "Enabled",
|
39 |
+
False: "Disabled",
|
40 |
+
None: "Unknown (This's not a bot)",
|
41 |
+
}
|
42 |
+
|
43 |
+
logger.info(f"Groups Mode - {states[bot_info.can_join_groups]}")
|
44 |
+
logger.info(f"Privacy Mode - {states[not bot_info.can_read_all_group_messages]}")
|
45 |
+
logger.info(f"Inline Mode - {states[bot_info.supports_inline_queries]}")
|
46 |
+
|
47 |
+
logger.info("bot started")
|
48 |
+
|
49 |
+
|
50 |
+
async def on_shutdown() -> None:
|
51 |
+
logger.info("bot stopping...")
|
52 |
+
|
53 |
+
await remove_default_commands(bot)
|
54 |
+
|
55 |
+
await dp.storage.close()
|
56 |
+
await dp.fsm.storage.close()
|
57 |
+
|
58 |
+
await bot.delete_webhook()
|
59 |
+
await bot.session.close()
|
60 |
+
|
61 |
+
logger.info("bot stopped")
|
62 |
+
|
63 |
+
|
64 |
+
async def setup_webhook() -> None:
|
65 |
+
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application
|
66 |
+
from aiohttp.web import AppRunner, TCPSite
|
67 |
+
|
68 |
+
await bot.set_webhook(
|
69 |
+
settings.webhook_url,
|
70 |
+
allowed_updates=dp.resolve_used_update_types(),
|
71 |
+
secret_token=settings.WEBHOOK_SECRET,
|
72 |
+
)
|
73 |
+
|
74 |
+
webhook_requests_handler = SimpleRequestHandler(
|
75 |
+
dispatcher=dp,
|
76 |
+
bot=bot,
|
77 |
+
secret_token=settings.WEBHOOK_SECRET,
|
78 |
+
)
|
79 |
+
webhook_requests_handler.register(app, path=settings.WEBHOOK_PATH)
|
80 |
+
setup_application(app, dp, bot=bot)
|
81 |
+
|
82 |
+
runner = AppRunner(app)
|
83 |
+
await runner.setup()
|
84 |
+
site = TCPSite(runner, host=settings.WEBHOOK_HOST, port=settings.WEBHOOK_PORT)
|
85 |
+
await site.start()
|
86 |
+
|
87 |
+
await asyncio.Event().wait()
|
88 |
+
|
89 |
+
|
90 |
+
async def main() -> None:
|
91 |
+
if settings.SENTRY_DSN:
|
92 |
+
sentry_loguru = LoguruIntegration(
|
93 |
+
level=LoggingLevels.INFO.value,
|
94 |
+
event_level=LoggingLevels.INFO.value,
|
95 |
+
)
|
96 |
+
sentry_sdk.init(
|
97 |
+
dsn=settings.SENTRY_DSN,
|
98 |
+
enable_tracing=True,
|
99 |
+
traces_sample_rate=1.0,
|
100 |
+
profiles_sample_rate=1.0,
|
101 |
+
integrations=[sentry_loguru],
|
102 |
+
)
|
103 |
+
|
104 |
+
logger.add(
|
105 |
+
"logs/telegram_bot.log",
|
106 |
+
level="DEBUG",
|
107 |
+
format="{time} | {level} | {module}:{function}:{line} | {message}",
|
108 |
+
rotation="100 KB",
|
109 |
+
compression="zip",
|
110 |
+
)
|
111 |
+
|
112 |
+
dp.startup.register(on_startup)
|
113 |
+
dp.shutdown.register(on_shutdown)
|
114 |
+
|
115 |
+
if settings.USE_WEBHOOK:
|
116 |
+
await setup_webhook()
|
117 |
+
else:
|
118 |
+
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())
|
119 |
+
|
120 |
+
|
121 |
+
if __name__ == "__main__":
|
122 |
+
uvloop.run(main())
|
bot/analytics/__init__.py
ADDED
File without changes
|
bot/analytics/amplitude/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from .client import AmplitudeTelegramLogger
|
2 |
+
|
3 |
+
__all__ = ["AmplitudeTelegramLogger"]
|
bot/analytics/amplitude/client.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import orjson
|
4 |
+
from aiohttp import ClientSession, ClientTimeout
|
5 |
+
from loguru import logger
|
6 |
+
|
7 |
+
from bot.analytics.types import AbstractAnalyticsLogger, BaseEvent
|
8 |
+
|
9 |
+
AMPLITUDE_ENDPOINT = "https://api2.amplitude.com/2/httpapi"
|
10 |
+
|
11 |
+
|
12 |
+
class AmplitudeTelegramLogger(AbstractAnalyticsLogger):
|
13 |
+
def __init__(self, api_token: str, base_url: str = AMPLITUDE_ENDPOINT) -> None:
|
14 |
+
self._api_token: str = api_token
|
15 |
+
self._base_url: str = base_url
|
16 |
+
self._headers = {"Content-Type": "application/json", "Accept": "*/*"}
|
17 |
+
self._timeout = ClientTimeout(total=15)
|
18 |
+
self.SUCCESS_STATUS_CODE = 200
|
19 |
+
|
20 |
+
async def _send_request(
|
21 |
+
self,
|
22 |
+
event: BaseEvent,
|
23 |
+
) -> None:
|
24 |
+
"""Implementation of interaction with Amplitude API."""
|
25 |
+
data = {"api_key": self._api_token, "events": [event.to_dict()]}
|
26 |
+
|
27 |
+
async with (
|
28 |
+
ClientSession() as session,
|
29 |
+
session.post(
|
30 |
+
self._base_url,
|
31 |
+
headers=self._headers,
|
32 |
+
data=orjson.dumps(data),
|
33 |
+
timeout=self._timeout,
|
34 |
+
) as response,
|
35 |
+
):
|
36 |
+
json_response = await response.json(content_type="application/json")
|
37 |
+
|
38 |
+
self._validate_response(json_response)
|
39 |
+
|
40 |
+
def _validate_response(self, response: dict[str, str | int]) -> None:
|
41 |
+
"""Validate response."""
|
42 |
+
if response.get("code") != self.SUCCESS_STATUS_CODE:
|
43 |
+
error = response.get("error")
|
44 |
+
code = response.get("code")
|
45 |
+
|
46 |
+
logger.error(f"get error from amplitude api | error: {error} | code: {code}")
|
47 |
+
msg = f"Error in amplitude api call | error: {error} | code: {code}"
|
48 |
+
raise ValueError(msg)
|
49 |
+
|
50 |
+
logger.info(f"successfully send to Amplitude | server_upload_time: {response['server_upload_time']}")
|
51 |
+
|
52 |
+
async def log_event(
|
53 |
+
self,
|
54 |
+
event: BaseEvent,
|
55 |
+
) -> None:
|
56 |
+
"""Use this method to sends event to Amplitude."""
|
57 |
+
await self._send_request(event)
|
bot/analytics/google/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from .client import GoogleAnalyticsTelegramLogger
|
2 |
+
|
3 |
+
__all__ = ["GoogleAnalyticsTelegramLogger"]
|
bot/analytics/google/client.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from aiohttp import ClientSession
|
2 |
+
from loguru import logger
|
3 |
+
|
4 |
+
from bot.analytics.types import AbstractAnalyticsLogger, BaseEvent
|
5 |
+
|
6 |
+
GOOGLE_ANALYTICS_ENDPOINT = "https://www.google-analytics.com"
|
7 |
+
|
8 |
+
|
9 |
+
class GoogleAnalyticsTelegramLogger(AbstractAnalyticsLogger):
|
10 |
+
def __init__(self, api_secret: str, measurement_id: str, base_url: str = GOOGLE_ANALYTICS_ENDPOINT) -> None:
|
11 |
+
self._api_secret: str = api_secret
|
12 |
+
self._measurement_id: str = measurement_id
|
13 |
+
self._base_url: str = base_url
|
14 |
+
self._headers = {"Content-Type": "application/json", "Accept": "*/*"}
|
15 |
+
|
16 |
+
async def _send_request(
|
17 |
+
self,
|
18 |
+
event: BaseEvent,
|
19 |
+
) -> dict:
|
20 |
+
url = f"{self._base_url}/mp/collect?measurement_id={self._measurement_id}&api_secret={self._api_secret}"
|
21 |
+
params = dict(event)
|
22 |
+
|
23 |
+
async with ClientSession() as session, session.post(url, headers=self._headers, json=params) as response:
|
24 |
+
json_response = await response.json(content_type="application/json")
|
25 |
+
|
26 |
+
logger.info("Send record to Google Analytics")
|
27 |
+
logger.info(f"{json_response=}")
|
28 |
+
|
29 |
+
return self._validate_response(json_response)
|
30 |
+
|
31 |
+
@staticmethod
|
32 |
+
def _validate_response(response: dict) -> dict:
|
33 |
+
"""Validate response."""
|
34 |
+
if not response.get("ok"):
|
35 |
+
name = response["error"]["name"]
|
36 |
+
code = response["error"]["code"]
|
37 |
+
|
38 |
+
logger.error(f"get error from cryptopay api | name: {name} | code: {code}")
|
39 |
+
msg = f"Error in CryptoPay API call | name: {name} | code: {code}"
|
40 |
+
raise ValueError(msg)
|
41 |
+
|
42 |
+
logger.info(f"got response | ok: {response['ok']} | result: {response['result']}")
|
43 |
+
return response
|
44 |
+
|
45 |
+
async def log_event(
|
46 |
+
self,
|
47 |
+
event: BaseEvent,
|
48 |
+
) -> None:
|
49 |
+
"""Use this method to sends event to Google Analytics."""
|
50 |
+
await self._send_request(event)
|
bot/analytics/posthog/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from .client import PosthogTelegramLogger
|
2 |
+
|
3 |
+
__all__ = ["PosthogTelegramLogger"]
|