Compare commits
37 Commits
beta_2025-
...
fix/search
| Author | SHA1 | Date | |
|---|---|---|---|
| eb6c5ade29 | |||
| 305fdc41fb | |||
| 9deca8867e | |||
| df6056fb86 | |||
| c1553d9cd4 | |||
| 2b79adc2f7 | |||
| ddf1fd3515 | |||
| 34589efbde | |||
| 1cccefa991 | |||
| e26d5a21e3 | |||
| 98d62e1d1f | |||
| 13ed86a780 | |||
| f1b4c5aadb | |||
| 37e0e18a28 | |||
| de44c22606 | |||
| a952c08469 | |||
| 551cfc7768 | |||
| 8fda2577ee | |||
| 819a94aced | |||
| 376fd65785 | |||
| d5ebb23622 | |||
| 93dd811e39 | |||
| 9a4735246f | |||
| 1f863fdcd6 | |||
| 1effaeb342 | |||
| 386098b8a6 | |||
| ef697ac5f5 | |||
| 68a3f3b982 | |||
| afeb56622c | |||
| 22f0bbe10b | |||
| 36879c266b | |||
| c2c46fbfa7 | |||
| d2f4fdc58a | |||
| 3f2b046bd6 | |||
| 7ad4112343 | |||
| 3f5bb76633 | |||
| b757a07f91 |
22
.env.local.example
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Django settings
|
||||||
|
SECRET_KEY='a-secure-secret-key-for-development'
|
||||||
|
DEBUG=True
|
||||||
|
ALLOWED_HOSTS=*
|
||||||
|
|
||||||
|
# Database settings (using PostgreSQL for local development)
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=postgres
|
||||||
|
POSTGRES_DB=envipath
|
||||||
|
POSTGRES_SERVICE_NAME=localhost
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
# Celery settings
|
||||||
|
CELERY_BROKER_URL='redis://localhost:6379/0'
|
||||||
|
CELERY_RESULT_BACKEND='redis://localhost:6379/0'
|
||||||
|
FLAG_CELERY_PRESENT=False
|
||||||
|
|
||||||
|
# Other settings
|
||||||
|
LOG_LEVEL='INFO'
|
||||||
|
SERVER_URL='http://localhost:8000'
|
||||||
|
PLUGINS_ENABLED=True
|
||||||
|
EP_DATA_DIR='data'
|
||||||
@ -16,4 +16,5 @@ POSTGRES_PORT=
|
|||||||
# MAIL
|
# MAIL
|
||||||
EMAIL_HOST_USER=
|
EMAIL_HOST_USER=
|
||||||
EMAIL_HOST_PASSWORD=
|
EMAIL_HOST_PASSWORD=
|
||||||
|
# MATOMO
|
||||||
|
MATOMO_SITE_ID
|
||||||
116
.gitea/workflows/ci.yaml
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: ${{ vars.POSTGRES_USER }}
|
||||||
|
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
||||||
|
POSTGRES_DB: ${{ vars.POSTGRES_DB }}
|
||||||
|
ports:
|
||||||
|
- ${{ vars.POSTGRES_PORT}}:5432
|
||||||
|
options: >-
|
||||||
|
--health-cmd="pg_isready -U postgres"
|
||||||
|
--health-interval=10s
|
||||||
|
--health-timeout=5s
|
||||||
|
--health-retries=5
|
||||||
|
|
||||||
|
#redis:
|
||||||
|
# image: redis:7
|
||||||
|
# ports:
|
||||||
|
# - 6379:6379
|
||||||
|
# options: >-
|
||||||
|
# --health-cmd "redis-cli ping"
|
||||||
|
# --health-interval=10s
|
||||||
|
# --health-timeout=5s
|
||||||
|
# --health-retries=5
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
EP_DATA_DIR: /opt/enviPy/
|
||||||
|
ALLOWED_HOSTS: 127.0.0.1,localhost
|
||||||
|
DEBUG: True
|
||||||
|
LOG_LEVEL: DEBUG
|
||||||
|
MODEL_BUILDING_ENABLED: True
|
||||||
|
APPLICABILITY_DOMAIN_ENABLED: True
|
||||||
|
ENVIFORMER_PRESENT: True
|
||||||
|
ENVIFORMER_DEVICE: cpu
|
||||||
|
FLAG_CELERY_PRESENT: False
|
||||||
|
PLUGINS_ENABLED: True
|
||||||
|
SERVER_URL: http://localhost:8000
|
||||||
|
ADMIN_APPROVAL_REQUIRED: True
|
||||||
|
REGISTRATION_MANDATORY: True
|
||||||
|
LOG_DIR: ''
|
||||||
|
# DB
|
||||||
|
POSTGRES_SERVICE_NAME: postgres
|
||||||
|
POSTGRES_DB: ${{ vars.POSTGRES_DB }}
|
||||||
|
POSTGRES_USER: ${{ vars.POSTGRES_USER }}
|
||||||
|
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
# SENTRY
|
||||||
|
SENTRY_ENABLED: False
|
||||||
|
# MS ENTRA
|
||||||
|
MS_ENTRA_ENABLED: False
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install system tools via apt
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y postgresql-client redis-tools openjdk-11-jre-headless
|
||||||
|
|
||||||
|
- name: Setup ssh
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.ENVIPY_CI_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
|
||||||
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
|
ssh-keyscan git.envipath.com >> ~/.ssh/known_hosts
|
||||||
|
eval $(ssh-agent -s)
|
||||||
|
ssh-add ~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 10
|
||||||
|
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: Install uv
|
||||||
|
uses: astral-sh/setup-uv@v6
|
||||||
|
with:
|
||||||
|
enable-cache: true
|
||||||
|
|
||||||
|
- name: Setup venv
|
||||||
|
run: |
|
||||||
|
uv sync --locked --all-extras --dev
|
||||||
|
|
||||||
|
- name: Wait for services
|
||||||
|
run: |
|
||||||
|
until pg_isready -h postgres -U postgres; do sleep 2; done
|
||||||
|
# until redis-cli -h redis ping; do sleep 2; done
|
||||||
|
|
||||||
|
- name: Run Django Migrations
|
||||||
|
run: |
|
||||||
|
source .venv/bin/activate
|
||||||
|
python manage.py migrate --noinput
|
||||||
|
|
||||||
|
- name: Run Django tests
|
||||||
|
run: |
|
||||||
|
source .venv/bin/activate
|
||||||
|
python manage.py test tests --exclude-tag slow
|
||||||
9
.gitignore
vendored
@ -6,3 +6,12 @@ static/django_extensions/
|
|||||||
.env
|
.env
|
||||||
debug.log
|
debug.log
|
||||||
scratches/
|
scratches/
|
||||||
|
|
||||||
|
data/
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
node_modules/
|
||||||
|
static/css/output.css
|
||||||
|
|
||||||
|
*.code-workspace
|
||||||
|
|||||||
40
.pre-commit-config.yaml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v3.2.0
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: check-yaml
|
||||||
|
- id: check-added-large-files
|
||||||
|
exclude: ^static/images/
|
||||||
|
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.13.3
|
||||||
|
hooks:
|
||||||
|
# Run the linter.
|
||||||
|
- id: ruff-check
|
||||||
|
types_or: [python, pyi]
|
||||||
|
args: [--fix]
|
||||||
|
# Run the formatter.
|
||||||
|
- id: ruff-format
|
||||||
|
types_or: [python, pyi]
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: prettier-jinja-templates
|
||||||
|
name: Format Jinja templates with Prettier
|
||||||
|
entry: pnpm exec prettier --plugin=prettier-plugin-jinja-template --parser=jinja-template --write
|
||||||
|
language: system
|
||||||
|
types: [file]
|
||||||
|
files: ^templates/.*\.html$
|
||||||
|
|
||||||
|
# - repo: local
|
||||||
|
# hooks:
|
||||||
|
# - id: django-check
|
||||||
|
# name: Run Django Check
|
||||||
|
# entry: uv run python manage.py check
|
||||||
|
# language: system
|
||||||
|
# pass_filenames: false
|
||||||
|
# types: [python]
|
||||||
11
.prettierrc.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["prettier-plugin-jinja-template", "prettier-plugin-tailwindcss"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "templates/**/*.html",
|
||||||
|
"options": {
|
||||||
|
"parser": "jinja-template"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1 +1 @@
|
|||||||
3.10
|
3.12
|
||||||
|
|||||||
101
README.md
@ -1,2 +1,103 @@
|
|||||||
# enviPy
|
# enviPy
|
||||||
|
|
||||||
|
## Local Development Setup
|
||||||
|
|
||||||
|
These instructions will guide you through setting up the project for local development.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Python 3.11 or later
|
||||||
|
- [uv](https://github.com/astral-sh/uv) - Python package manager
|
||||||
|
- **Docker and Docker Compose** - Required for running PostgreSQL database
|
||||||
|
- Git
|
||||||
|
- Make
|
||||||
|
|
||||||
|
> **Note:** This application requires PostgreSQL (uses `ArrayField`). Docker is the easiest way to run PostgreSQL locally.
|
||||||
|
|
||||||
|
|
||||||
|
### 1. Install Dependencies
|
||||||
|
|
||||||
|
This project uses `uv` to manage dependencies and `poe-the-poet` for task running. First, [install `uv` if you don't have it yet](https://docs.astral.sh/uv/guides/install-python/).
|
||||||
|
|
||||||
|
Then, sync the project dependencies. This will create a virtual environment in `.venv` and install all necessary packages, including `poe-the-poet`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv sync --dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Note on RDkit installation: if you have rdkit installed on your system globally with a different version of python, the installation will try to link against that and subsequent calls fail. Only option remove global rdkit and rerun sync.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The frontend requires `pnpm` to correctly display in development.
|
||||||
|
[Install it here](https://pnpm.io/installation).
|
||||||
|
|
||||||
|
### 2. Set Up Environment File
|
||||||
|
|
||||||
|
Copy the example environment file for local setup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.local.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
This file contains the necessary environment variables for local development.
|
||||||
|
|
||||||
|
### 3. Quick Setup with Poe
|
||||||
|
|
||||||
|
The easiest way to set up the development environment is by using the `poe` task runner, which is executed via `uv run`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run poe setup
|
||||||
|
```
|
||||||
|
|
||||||
|
This single command will:
|
||||||
|
|
||||||
|
1. Start the PostgreSQL database using Docker Compose.
|
||||||
|
2. Run database migrations.
|
||||||
|
3. Bootstrap initial data (anonymous user, default packages, models).
|
||||||
|
|
||||||
|
After setup, start the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run poe dev
|
||||||
|
```
|
||||||
|
|
||||||
|
This will start the css-watcher as well as the django-development server,
|
||||||
|
The application will be available at `http://localhost:8000`.
|
||||||
|
|
||||||
|
**Note:** The development server automatically starts a CSS watcher (`pnpm run dev`) alongside the Django server to rebuild CSS files when changes are detected. This ensures your styles are always up-to-date during development.
|
||||||
|
|
||||||
|
#### Other useful Poe commands
|
||||||
|
|
||||||
|
You can list all available commands by running `uv run poe --help`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run poe db-up # Start PostgreSQL only
|
||||||
|
uv run poe db-down # Stop PostgreSQL
|
||||||
|
uv run poe migrate # Run migrations only
|
||||||
|
uv run poe bootstrap # Bootstrap data only
|
||||||
|
uv run poe shell # Open the Django shell
|
||||||
|
uv run poe build # Build frontend assets and collect static files
|
||||||
|
uv run poe clean # Remove database volumes (WARNING: destroys all data)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
* **Docker Connection Error:** If you see an error like `open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified` (on Windows), it likely means your Docker Desktop application is not running. Please start Docker Desktop and try the command again.
|
||||||
|
|
||||||
|
* **SSH Keys for Git Dependencies:** Some dependencies are installed from private git repositories and require SSH authentication. Ensure your SSH keys are configured correctly for Git.
|
||||||
|
* For a general guide, see [GitHub's official documentation](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).
|
||||||
|
* **Windows Users:** If `uv sync` hangs while fetching git dependencies, you may need to explicitly configure Git to use the Windows OpenSSH client and use the `ssh-agent` to manage your key's passphrase.
|
||||||
|
|
||||||
|
1. **Point Git to the correct SSH executable:**
|
||||||
|
```powershell
|
||||||
|
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
|
||||||
|
```
|
||||||
|
2. **Enable and use the SSH agent:**
|
||||||
|
```powershell
|
||||||
|
# Run these commands in an administrator PowerShell
|
||||||
|
Get-Service ssh-agent | Set-Service -StartupType Automatic -PassThru | Start-Service
|
||||||
|
|
||||||
|
# Add your key to the agent. It will prompt for the passphrase once.
|
||||||
|
ssh-add
|
||||||
|
```
|
||||||
|
|||||||
20
docker-compose.dev.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:15
|
||||||
|
container_name: envipath-postgres
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_DB: envipath
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
@ -2,4 +2,4 @@
|
|||||||
# Django starts so that shared_task will use this app.
|
# Django starts so that shared_task will use this app.
|
||||||
from .celery import app as celery_app
|
from .celery import app as celery_app
|
||||||
|
|
||||||
__all__ = ('celery_app',)
|
__all__ = ("celery_app",)
|
||||||
|
|||||||
@ -4,8 +4,6 @@ from ninja import NinjaAPI
|
|||||||
|
|
||||||
api = NinjaAPI()
|
api = NinjaAPI()
|
||||||
|
|
||||||
from ninja import NinjaAPI
|
|
||||||
|
|
||||||
api_v1 = NinjaAPI(title="API V1 Docs", urls_namespace="api-v1")
|
api_v1 = NinjaAPI(title="API V1 Docs", urls_namespace="api-v1")
|
||||||
api_legacy = NinjaAPI(title="Legacy API Docs", urls_namespace="api-legacy")
|
api_legacy = NinjaAPI(title="Legacy API Docs", urls_namespace="api-legacy")
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,6 @@ import os
|
|||||||
|
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'envipath.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "envipath.settings")
|
||||||
|
|
||||||
application = get_asgi_application()
|
application = get_asgi_application()
|
||||||
|
|||||||
@ -4,15 +4,15 @@ from celery import Celery
|
|||||||
from celery.signals import setup_logging
|
from celery.signals import setup_logging
|
||||||
|
|
||||||
# Set the default Django settings module for the 'celery' program.
|
# Set the default Django settings module for the 'celery' program.
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'envipath.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "envipath.settings")
|
||||||
|
|
||||||
app = Celery('envipath')
|
app = Celery("envipath")
|
||||||
|
|
||||||
# Using a string here means the worker doesn't have to serialize
|
# Using a string here means the worker doesn't have to serialize
|
||||||
# the configuration object to child processes.
|
# the configuration object to child processes.
|
||||||
# - namespace='CELERY' means all celery-related configuration keys
|
# - namespace='CELERY' means all celery-related configuration keys
|
||||||
# should have a `CELERY_` prefix.
|
# should have a `CELERY_` prefix.
|
||||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||||
|
|
||||||
|
|
||||||
@setup_logging.connect
|
@setup_logging.connect
|
||||||
|
|||||||
@ -9,6 +9,7 @@ https://docs.djangoproject.com/en/4.2/topics/settings/
|
|||||||
For the full list of settings and their values, see
|
For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/4.2/ref/settings/
|
https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -20,34 +21,35 @@ from sklearn.tree import DecisionTreeClassifier
|
|||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
load_dotenv(BASE_DIR / '.env', override=False)
|
load_dotenv(BASE_DIR / ".env", override=False)
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = '7!VTW`aZqg/UBLsM.P=m)2]lWqg>{+:xUgG1"WO@bCyaHR2Up8XW&g<*3.F4l2gi9c.E3}dHyA0D`&z?u#U%^7HYbj],eP"g_MS|3BNMD[mI>s#<i/%2ngZ~Oy+/w&@]'
|
SECRET_KEY = os.environ.get("SECRET_KEY", "secret-key")
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
|
DEBUG = os.environ.get("DEBUG", "False") == "True"
|
||||||
ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split(',')
|
|
||||||
|
ALLOWED_HOSTS = os.environ["ALLOWED_HOSTS"].split(",")
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'django.contrib.admin',
|
"django.contrib.admin",
|
||||||
'django.contrib.auth',
|
"django.contrib.auth",
|
||||||
'django.contrib.contenttypes',
|
"django.contrib.contenttypes",
|
||||||
'django.contrib.sessions',
|
"django.contrib.sessions",
|
||||||
'django.contrib.messages',
|
"django.contrib.messages",
|
||||||
'django.contrib.staticfiles',
|
"django.contrib.staticfiles",
|
||||||
# 3rd party
|
# 3rd party
|
||||||
'django_extensions',
|
"django_extensions",
|
||||||
'oauth2_provider',
|
"oauth2_provider",
|
||||||
# Custom
|
# Custom
|
||||||
'epdb',
|
"epdb",
|
||||||
'migration',
|
"migration",
|
||||||
'epauth',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
@ -55,42 +57,45 @@ AUTHENTICATION_BACKENDS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'django.middleware.common.CommonMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
'oauth2_provider.middleware.OAuth2TokenMiddleware',
|
"oauth2_provider.middleware.OAuth2TokenMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
OAUTH2_PROVIDER = {
|
OAUTH2_PROVIDER = {
|
||||||
"PKCE_REQUIRED": False, # Accept PKCE requests but dont require them
|
"PKCE_REQUIRED": False, # Accept PKCE requests but dont require them
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.environ.get('REGISTRATION_MANDATORY', False) == 'True':
|
if os.environ.get("REGISTRATION_MANDATORY", False) == "True":
|
||||||
MIDDLEWARE.append('epdb.middleware.login_required_middleware.LoginRequiredMiddleware')
|
MIDDLEWARE.append("epdb.middleware.login_required_middleware.LoginRequiredMiddleware")
|
||||||
|
|
||||||
ROOT_URLCONF = 'envipath.urls'
|
ROOT_URLCONF = "envipath.urls"
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
'DIRS': (os.path.join(BASE_DIR, 'templates'),),
|
"DIRS": (os.path.join(BASE_DIR, "templates"),),
|
||||||
'APP_DIRS': True,
|
"APP_DIRS": True,
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.contrib.auth.context_processors.auth',
|
"django.contrib.auth.context_processors.auth",
|
||||||
'django.contrib.messages.context_processors.messages',
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
"epdb.context_processors.package_context",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = 'envipath.wsgi.application'
|
ALLOWED_HTML_TAGS = {"b", "i", "u", "br", "em", "mark", "p", "s", "strong"}
|
||||||
|
|
||||||
|
WSGI_APPLICATION = "envipath.wsgi.application"
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||||
@ -98,11 +103,11 @@ WSGI_APPLICATION = 'envipath.wsgi.application'
|
|||||||
DATABASES = {
|
DATABASES = {
|
||||||
"default": {
|
"default": {
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
"USER": os.environ['POSTGRES_USER'],
|
"USER": os.environ["POSTGRES_USER"],
|
||||||
"NAME": os.environ['POSTGRES_DB'],
|
"NAME": os.environ["POSTGRES_DB"],
|
||||||
"PASSWORD": os.environ['POSTGRES_PASSWORD'],
|
"PASSWORD": os.environ["POSTGRES_PASSWORD"],
|
||||||
"HOST": os.environ['POSTGRES_SERVICE_NAME'],
|
"HOST": os.environ["POSTGRES_SERVICE_NAME"],
|
||||||
"PORT": os.environ['POSTGRES_PORT']
|
"PORT": os.environ["POSTGRES_PORT"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,96 +115,87 @@ DATABASES = {
|
|||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
{
|
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
|
||||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
|
||||||
},
|
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||||
{
|
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
TIME_ZONE = 'UTC'
|
TIME_ZONE = "UTC"
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|
||||||
|
EMAIL_SUBJECT_PREFIX = "[enviPath] "
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
else:
|
else:
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
EMAIL_USE_TLS = True
|
EMAIL_USE_TLS = True
|
||||||
EMAIL_HOST = 'mail.gandi.net'
|
EMAIL_HOST = "mail.gandi.net"
|
||||||
EMAIL_HOST_USER = os.environ['EMAIL_HOST_USER']
|
EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"]
|
||||||
EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD']
|
EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"]
|
||||||
EMAIL_PORT = 587
|
EMAIL_PORT = 587
|
||||||
|
DEFAULT_FROM_EMAIL = os.environ["DEFAULT_FROM_EMAIL"]
|
||||||
|
SERVER_EMAIL = os.environ["SERVER_EMAIL"]
|
||||||
|
|
||||||
AUTH_USER_MODEL = "epdb.User"
|
AUTH_USER_MODEL = "epdb.User"
|
||||||
ADMIN_APPROVAL_REQUIRED = os.environ.get('ADMIN_APPROVAL_REQUIRED', 'False') == 'True'
|
ADMIN_APPROVAL_REQUIRED = os.environ.get("ADMIN_APPROVAL_REQUIRED", "False") == "True"
|
||||||
|
|
||||||
# # SESAME
|
# # SESAME
|
||||||
# SESAME_MAX_AGE = 300
|
# SESAME_MAX_AGE = 300
|
||||||
# # TODO set to "home"
|
# # TODO set to "home"
|
||||||
# LOGIN_REDIRECT_URL = "/"
|
# LOGIN_REDIRECT_URL = "/"
|
||||||
LOGIN_URL = '/login/'
|
LOGIN_URL = "/login/"
|
||||||
|
|
||||||
SERVER_URL = os.environ.get('SERVER_URL', 'http://localhost:8000')
|
SERVER_URL = os.environ.get("SERVER_URL", "http://localhost:8000")
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = [SERVER_URL]
|
CSRF_TRUSTED_ORIGINS = [SERVER_URL]
|
||||||
|
|
||||||
AMBIT_URL = 'http://localhost:9001'
|
AMBIT_URL = "http://localhost:9001"
|
||||||
DEFAULT_VALUES = {
|
DEFAULT_VALUES = {"description": "no description"}
|
||||||
'description': 'no description'
|
|
||||||
}
|
|
||||||
|
|
||||||
EP_DATA_DIR = os.environ['EP_DATA_DIR']
|
EP_DATA_DIR = os.environ["EP_DATA_DIR"]
|
||||||
MODEL_DIR = os.path.join(EP_DATA_DIR, 'models')
|
if not os.path.exists(EP_DATA_DIR):
|
||||||
|
os.mkdir(EP_DATA_DIR)
|
||||||
|
|
||||||
|
MODEL_DIR = os.path.join(EP_DATA_DIR, "models")
|
||||||
if not os.path.exists(MODEL_DIR):
|
if not os.path.exists(MODEL_DIR):
|
||||||
os.mkdir(MODEL_DIR)
|
os.mkdir(MODEL_DIR)
|
||||||
|
|
||||||
STATIC_DIR = os.path.join(EP_DATA_DIR, 'static')
|
STATIC_DIR = os.path.join(EP_DATA_DIR, "static")
|
||||||
if not os.path.exists(STATIC_DIR):
|
if not os.path.exists(STATIC_DIR):
|
||||||
os.mkdir(STATIC_DIR)
|
os.mkdir(STATIC_DIR)
|
||||||
|
|
||||||
LOG_DIR = os.path.join(EP_DATA_DIR, 'log')
|
LOG_DIR = os.path.join(EP_DATA_DIR, "log")
|
||||||
if not os.path.exists(LOG_DIR):
|
if not os.path.exists(LOG_DIR):
|
||||||
os.mkdir(LOG_DIR)
|
os.mkdir(LOG_DIR)
|
||||||
|
|
||||||
PLUGIN_DIR = os.path.join(EP_DATA_DIR, 'plugins')
|
PLUGIN_DIR = os.path.join(EP_DATA_DIR, "plugins")
|
||||||
if not os.path.exists(PLUGIN_DIR):
|
if not os.path.exists(PLUGIN_DIR):
|
||||||
os.mkdir(PLUGIN_DIR)
|
os.mkdir(PLUGIN_DIR)
|
||||||
|
|
||||||
# Set this as our static root dir
|
# Set this as our static root dir
|
||||||
STATIC_ROOT = STATIC_DIR
|
STATIC_ROOT = STATIC_DIR
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
# Where the sources are stored...
|
# Where the sources are stored...
|
||||||
STATICFILES_DIRS = (
|
STATICFILES_DIRS = (BASE_DIR / "static",)
|
||||||
BASE_DIR / 'static',
|
|
||||||
)
|
|
||||||
|
|
||||||
FIXTURE_DIRS = (
|
FIXTURE_DIRS = (BASE_DIR / "fixtures",)
|
||||||
BASE_DIR / 'fixtures',
|
|
||||||
)
|
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
@ -207,8 +203,8 @@ LOGGING = {
|
|||||||
"disable_existing_loggers": True,
|
"disable_existing_loggers": True,
|
||||||
"formatters": {
|
"formatters": {
|
||||||
"simple": {
|
"simple": {
|
||||||
'format': '[%(asctime)s] %(levelname)s %(module)s - %(message)s',
|
"format": "[%(asctime)s] %(levelname)s %(module)s - %(message)s",
|
||||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"handlers": {
|
"handlers": {
|
||||||
@ -221,7 +217,7 @@ LOGGING = {
|
|||||||
"level": "DEBUG", # Or higher
|
"level": "DEBUG", # Or higher
|
||||||
"class": "logging.FileHandler",
|
"class": "logging.FileHandler",
|
||||||
"filename": os.path.join(LOG_DIR, "debug.log"),
|
"filename": os.path.join(LOG_DIR, "debug.log"),
|
||||||
"formatter": "simple"
|
"formatter": "simple",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"loggers": {
|
"loggers": {
|
||||||
@ -229,72 +225,67 @@ LOGGING = {
|
|||||||
"epdb": {
|
"epdb": {
|
||||||
"handlers": ["file"], # "console",
|
"handlers": ["file"], # "console",
|
||||||
"propagate": True,
|
"propagate": True,
|
||||||
"level": os.environ.get('LOG_LEVEL', 'INFO')
|
"level": os.environ.get("LOG_LEVEL", "INFO"),
|
||||||
},
|
},
|
||||||
# For everything under envipath/ loaded via getlogger(__name__)
|
# For everything under envipath/ loaded via getlogger(__name__)
|
||||||
'envipath': {
|
"envipath": {
|
||||||
'handlers': ['file', 'console'],
|
"handlers": ["file", "console"],
|
||||||
'propagate': True,
|
"propagate": True,
|
||||||
'level': os.environ.get('LOG_LEVEL', 'INFO')
|
"level": os.environ.get("LOG_LEVEL", "INFO"),
|
||||||
},
|
},
|
||||||
# For everything under utilities/ loaded via getlogger(__name__)
|
# For everything under utilities/ loaded via getlogger(__name__)
|
||||||
'utilities': {
|
"utilities": {
|
||||||
'handlers': ['file', 'console'],
|
"handlers": ["file", "console"],
|
||||||
'propagate': True,
|
"propagate": True,
|
||||||
'level': os.environ.get('LOG_LEVEL', 'INFO')
|
"level": os.environ.get("LOG_LEVEL", "INFO"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Flags
|
# Flags
|
||||||
ENVIFORMER_PRESENT = os.environ.get('ENVIFORMER_PRESENT', 'False') == 'True'
|
ENVIFORMER_PRESENT = os.environ.get("ENVIFORMER_PRESENT", "False") == "True"
|
||||||
if ENVIFORMER_PRESENT:
|
ENVIFORMER_DEVICE = os.environ.get("ENVIFORMER_DEVICE", "cpu")
|
||||||
print("Loading enviFormer")
|
|
||||||
device = os.environ.get('ENVIFORMER_DEVICE', 'cpu')
|
|
||||||
from enviformer import load
|
|
||||||
ENVIFORMER_INSTANCE = load(device=device)
|
|
||||||
print("loaded")
|
|
||||||
|
|
||||||
|
|
||||||
# If celery is not present set always eager to true which will cause delayed tasks to block until finished
|
# If celery is not present set always eager to true which will cause delayed tasks to block until finished
|
||||||
FLAG_CELERY_PRESENT = os.environ.get('FLAG_CELERY_PRESENT', 'False') == 'True'
|
FLAG_CELERY_PRESENT = os.environ.get("FLAG_CELERY_PRESENT", "False") == "True"
|
||||||
if not FLAG_CELERY_PRESENT:
|
if not FLAG_CELERY_PRESENT:
|
||||||
CELERY_TASK_ALWAYS_EAGER = True
|
CELERY_TASK_ALWAYS_EAGER = True
|
||||||
|
|
||||||
# Celery Configuration Options
|
# Celery Configuration Options
|
||||||
CELERY_TIMEZONE = "Europe/Berlin"
|
CELERY_TIMEZONE = "Europe/Berlin"
|
||||||
# Celery Configuration
|
# Celery Configuration
|
||||||
CELERY_BROKER_URL = 'redis://localhost:6379/0' # Use Redis as message broker
|
CELERY_BROKER_URL = "redis://localhost:6379/0" # Use Redis as message broker
|
||||||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
|
CELERY_RESULT_BACKEND = "redis://localhost:6379/1"
|
||||||
CELERY_ACCEPT_CONTENT = ['json']
|
CELERY_ACCEPT_CONTENT = ["json"]
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = "json"
|
||||||
|
|
||||||
MODEL_BUILDING_ENABLED = os.environ.get('MODEL_BUILDING_ENABLED', 'False') == 'True'
|
MODEL_BUILDING_ENABLED = os.environ.get("MODEL_BUILDING_ENABLED", "False") == "True"
|
||||||
APPLICABILITY_DOMAIN_ENABLED = os.environ.get('APPLICABILITY_DOMAIN_ENABLED', 'False') == 'True'
|
APPLICABILITY_DOMAIN_ENABLED = os.environ.get("APPLICABILITY_DOMAIN_ENABLED", "False") == "True"
|
||||||
DEFAULT_RF_MODEL_PARAMS = {
|
DEFAULT_RF_MODEL_PARAMS = {
|
||||||
'base_clf': RandomForestClassifier(
|
"base_clf": RandomForestClassifier(
|
||||||
n_estimators=100,
|
n_estimators=100,
|
||||||
max_features='log2',
|
max_features="log2",
|
||||||
random_state=42,
|
random_state=42,
|
||||||
criterion='entropy',
|
criterion="entropy",
|
||||||
ccp_alpha=0.0,
|
ccp_alpha=0.0,
|
||||||
max_depth=3,
|
max_depth=3,
|
||||||
min_samples_leaf=1
|
min_samples_leaf=1,
|
||||||
),
|
),
|
||||||
'num_chains': 10,
|
"num_chains": 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_MODEL_PARAMS = {
|
DEFAULT_MODEL_PARAMS = {
|
||||||
'base_clf': DecisionTreeClassifier(
|
"base_clf": DecisionTreeClassifier(
|
||||||
criterion='entropy',
|
criterion="entropy",
|
||||||
max_depth=3,
|
max_depth=3,
|
||||||
min_samples_split=5,
|
min_samples_split=5,
|
||||||
# min_samples_leaf=5,
|
# min_samples_leaf=5,
|
||||||
max_features='sqrt',
|
max_features="sqrt",
|
||||||
# class_weight='balanced',
|
# class_weight='balanced',
|
||||||
random_state=42
|
random_state=42,
|
||||||
),
|
),
|
||||||
'num_chains': 10,
|
"num_chains": 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_MAX_NUMBER_OF_NODES = 30
|
DEFAULT_MAX_NUMBER_OF_NODES = 30
|
||||||
@ -302,9 +293,10 @@ DEFAULT_MAX_DEPTH = 5
|
|||||||
DEFAULT_MODEL_THRESHOLD = 0.25
|
DEFAULT_MODEL_THRESHOLD = 0.25
|
||||||
|
|
||||||
# Loading Plugins
|
# Loading Plugins
|
||||||
PLUGINS_ENABLED = os.environ.get('PLUGINS_ENABLED', 'False') == 'True'
|
PLUGINS_ENABLED = os.environ.get("PLUGINS_ENABLED", "False") == "True"
|
||||||
if PLUGINS_ENABLED:
|
if PLUGINS_ENABLED:
|
||||||
from utilities.plugin import discover_plugins
|
from utilities.plugin import discover_plugins
|
||||||
|
|
||||||
CLASSIFIER_PLUGINS = discover_plugins(_cls=Classifier)
|
CLASSIFIER_PLUGINS = discover_plugins(_cls=Classifier)
|
||||||
PROPERTY_PLUGINS = discover_plugins(_cls=Property)
|
PROPERTY_PLUGINS = discover_plugins(_cls=Property)
|
||||||
DESCRIPTOR_PLUGINS = discover_plugins(_cls=Descriptor)
|
DESCRIPTOR_PLUGINS = discover_plugins(_cls=Descriptor)
|
||||||
@ -313,56 +305,70 @@ else:
|
|||||||
PROPERTY_PLUGINS = {}
|
PROPERTY_PLUGINS = {}
|
||||||
DESCRIPTOR_PLUGINS = {}
|
DESCRIPTOR_PLUGINS = {}
|
||||||
|
|
||||||
SENTRY_ENABLED = os.environ.get('SENTRY_ENABLED', 'False') == 'True'
|
SENTRY_ENABLED = os.environ.get("SENTRY_ENABLED", "False") == "True"
|
||||||
if SENTRY_ENABLED:
|
if SENTRY_ENABLED:
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
|
|
||||||
def before_send(event, hint):
|
def before_send(event, hint):
|
||||||
# Check if was a handled exception by one of our loggers
|
# Check if was a handled exception by one of our loggers
|
||||||
if event.get('logger'):
|
if event.get("logger"):
|
||||||
for log_path in LOGGING.get('loggers').keys():
|
for log_path in LOGGING.get("loggers").keys():
|
||||||
if event['logger'].startswith(log_path):
|
if event["logger"].startswith(log_path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
dsn=os.environ.get('SENTRY_DSN'),
|
dsn=os.environ.get("SENTRY_DSN"),
|
||||||
# Add data like request headers and IP for users,
|
# Add data like request headers and IP for users,
|
||||||
# see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
|
# see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
|
||||||
send_default_pii=True,
|
send_default_pii=True,
|
||||||
environment=os.environ.get('SENTRY_ENVIRONMENT', 'development'),
|
environment=os.environ.get("SENTRY_ENVIRONMENT", "development"),
|
||||||
before_send=before_send,
|
before_send=before_send,
|
||||||
)
|
)
|
||||||
|
|
||||||
# compile into digestible flags
|
# compile into digestible flags
|
||||||
FLAGS = {
|
FLAGS = {
|
||||||
'MODEL_BUILDING': MODEL_BUILDING_ENABLED,
|
"MODEL_BUILDING": MODEL_BUILDING_ENABLED,
|
||||||
'CELERY': FLAG_CELERY_PRESENT,
|
"CELERY": FLAG_CELERY_PRESENT,
|
||||||
'PLUGINS': PLUGINS_ENABLED,
|
"PLUGINS": PLUGINS_ENABLED,
|
||||||
'SENTRY': SENTRY_ENABLED,
|
"SENTRY": SENTRY_ENABLED,
|
||||||
'ENVIFORMER': ENVIFORMER_PRESENT,
|
"ENVIFORMER": ENVIFORMER_PRESENT,
|
||||||
'APPLICABILITY_DOMAIN': APPLICABILITY_DOMAIN_ENABLED,
|
"APPLICABILITY_DOMAIN": APPLICABILITY_DOMAIN_ENABLED,
|
||||||
}
|
}
|
||||||
|
|
||||||
# path of the URL are checked via "startswith"
|
# path of the URL are checked via "startswith"
|
||||||
# -> /password_reset/done is covered as well
|
# -> /password_reset/done is covered as well
|
||||||
LOGIN_EXEMPT_URLS = [
|
LOGIN_EXEMPT_URLS = [
|
||||||
'/register',
|
"/register",
|
||||||
'/api/legacy/',
|
"/api/legacy/",
|
||||||
'/o/token/',
|
"/o/token/",
|
||||||
'/o/userinfo/',
|
"/o/userinfo/",
|
||||||
'/password_reset/',
|
"/password_reset/",
|
||||||
'/reset/',
|
"/reset/",
|
||||||
'/microsoft/',
|
"/microsoft/",
|
||||||
|
"/terms",
|
||||||
|
"/privacy",
|
||||||
|
"/cookie-policy",
|
||||||
|
"/about",
|
||||||
|
"/contact",
|
||||||
|
"/jobs",
|
||||||
|
"/cite",
|
||||||
|
"/legal",
|
||||||
]
|
]
|
||||||
|
|
||||||
# MS AD/Entra
|
# MS AD/Entra
|
||||||
MS_ENTRA_ENABLED = os.environ.get('MS_ENTRA_ENABLED', 'False') == 'True'
|
MS_ENTRA_ENABLED = os.environ.get("MS_ENTRA_ENABLED", "False") == "True"
|
||||||
if MS_ENTRA_ENABLED:
|
if MS_ENTRA_ENABLED:
|
||||||
MS_ENTRA_CLIENT_ID = os.environ['MS_CLIENT_ID']
|
# Add app to installed apps
|
||||||
MS_ENTRA_CLIENT_SECRET = os.environ['MS_CLIENT_SECRET']
|
INSTALLED_APPS.append("epauth")
|
||||||
MS_ENTRA_TENANT_ID = os.environ['MS_TENANT_ID']
|
# Set vars required by app
|
||||||
|
MS_ENTRA_CLIENT_ID = os.environ["MS_CLIENT_ID"]
|
||||||
|
MS_ENTRA_CLIENT_SECRET = os.environ["MS_CLIENT_SECRET"]
|
||||||
|
MS_ENTRA_TENANT_ID = os.environ["MS_TENANT_ID"]
|
||||||
MS_ENTRA_AUTHORITY = f"https://login.microsoftonline.com/{MS_ENTRA_TENANT_ID}"
|
MS_ENTRA_AUTHORITY = f"https://login.microsoftonline.com/{MS_ENTRA_TENANT_ID}"
|
||||||
MS_ENTRA_REDIRECT_URI = os.environ['MS_REDIRECT_URI']
|
MS_ENTRA_REDIRECT_URI = os.environ["MS_REDIRECT_URI"]
|
||||||
MS_ENTRA_SCOPES = os.environ.get('MS_SCOPES', '').split(',')
|
MS_ENTRA_SCOPES = os.environ.get("MS_SCOPES", "").split(",")
|
||||||
|
|
||||||
|
# Site ID 10 -> beta.envipath.org
|
||||||
|
MATOMO_SITE_ID = os.environ.get("MATOMO_SITE_ID", "10")
|
||||||
|
|||||||
@ -14,13 +14,14 @@ Including another URLconf
|
|||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from django.conf import settings as s
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
from .api import api_v1, api_legacy
|
from .api import api_v1, api_legacy
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", include("epauth.urls")),
|
|
||||||
path("", include("epdb.urls")),
|
path("", include("epdb.urls")),
|
||||||
path("", include("migration.urls")),
|
path("", include("migration.urls")),
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
@ -28,3 +29,6 @@ urlpatterns = [
|
|||||||
path("api/legacy/", api_legacy.urls),
|
path("api/legacy/", api_legacy.urls),
|
||||||
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if s.MS_ENTRA_ENABLED:
|
||||||
|
urlpatterns.append(path("", include("epauth.urls")))
|
||||||
|
|||||||
@ -11,6 +11,6 @@ import os
|
|||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'envipath.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "envipath.settings")
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from .models import (
|
|||||||
GroupPackagePermission,
|
GroupPackagePermission,
|
||||||
Package,
|
Package,
|
||||||
MLRelativeReasoning,
|
MLRelativeReasoning,
|
||||||
|
EnviFormer,
|
||||||
Compound,
|
Compound,
|
||||||
CompoundStructure,
|
CompoundStructure,
|
||||||
SimpleAmbitRule,
|
SimpleAmbitRule,
|
||||||
@ -16,12 +17,16 @@ from .models import (
|
|||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
Scenario,
|
Scenario,
|
||||||
Setting
|
Setting,
|
||||||
|
ExternalDatabase,
|
||||||
|
ExternalIdentifier,
|
||||||
|
JobLog,
|
||||||
|
License,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(admin.ModelAdmin):
|
class UserAdmin(admin.ModelAdmin):
|
||||||
pass
|
list_display = ["username", "email", "is_active"]
|
||||||
|
|
||||||
|
|
||||||
class UserPackagePermissionAdmin(admin.ModelAdmin):
|
class UserPackagePermissionAdmin(admin.ModelAdmin):
|
||||||
@ -36,17 +41,32 @@ class GroupPackagePermissionAdmin(admin.ModelAdmin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JobLogAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class EPAdmin(admin.ModelAdmin):
|
class EPAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', 'description']
|
search_fields = ["name", "description"]
|
||||||
|
list_display = ["name", "url", "created"]
|
||||||
|
ordering = ["-created"]
|
||||||
|
|
||||||
|
|
||||||
class PackageAdmin(EPAdmin):
|
class PackageAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MLRelativeReasoningAdmin(EPAdmin):
|
class MLRelativeReasoningAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EnviFormerAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LicenseAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ["cc_string", "link", "image_link"]
|
||||||
|
|
||||||
|
|
||||||
class CompoundAdmin(EPAdmin):
|
class CompoundAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -87,12 +107,23 @@ class SettingAdmin(EPAdmin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalDatabaseAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalIdentifierAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
admin.site.register(UserPackagePermission, UserPackagePermissionAdmin)
|
admin.site.register(UserPackagePermission, UserPackagePermissionAdmin)
|
||||||
admin.site.register(Group, GroupAdmin)
|
admin.site.register(Group, GroupAdmin)
|
||||||
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
||||||
|
admin.site.register(JobLog, JobLogAdmin)
|
||||||
admin.site.register(Package, PackageAdmin)
|
admin.site.register(Package, PackageAdmin)
|
||||||
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
||||||
|
admin.site.register(EnviFormer, EnviFormerAdmin)
|
||||||
|
admin.site.register(License, LicenseAdmin)
|
||||||
admin.site.register(Compound, CompoundAdmin)
|
admin.site.register(Compound, CompoundAdmin)
|
||||||
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
||||||
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
||||||
@ -103,3 +134,5 @@ admin.site.register(Node, NodeAdmin)
|
|||||||
admin.site.register(Edge, EdgeAdmin)
|
admin.site.register(Edge, EdgeAdmin)
|
||||||
admin.site.register(Setting, SettingAdmin)
|
admin.site.register(Setting, SettingAdmin)
|
||||||
admin.site.register(Scenario, ScenarioAdmin)
|
admin.site.register(Scenario, ScenarioAdmin)
|
||||||
|
admin.site.register(ExternalDatabase, ExternalDatabaseAdmin)
|
||||||
|
admin.site.register(ExternalIdentifier, ExternalIdentifierAdmin)
|
||||||
|
|||||||
13
epdb/api.py
@ -21,7 +21,7 @@ class BearerTokenAuth(HttpBearer):
|
|||||||
def _anonymous_or_real(request):
|
def _anonymous_or_real(request):
|
||||||
if request.user.is_authenticated and not request.user.is_anonymous:
|
if request.user.is_authenticated and not request.user.is_anonymous:
|
||||||
return request.user
|
return request.user
|
||||||
return get_user_model().objects.get(username='anonymous')
|
return get_user_model().objects.get(username="anonymous")
|
||||||
|
|
||||||
|
|
||||||
router = Router(auth=BearerTokenAuth())
|
router = Router(auth=BearerTokenAuth())
|
||||||
@ -85,7 +85,9 @@ def get_package(request, package_uuid):
|
|||||||
try:
|
try:
|
||||||
return PackageManager.get_package_by_id(request.auth, package_id=package_uuid)
|
return PackageManager.get_package_by_id(request.auth, package_id=package_uuid)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 403, {'message': f'Getting Package with id {package_uuid} failed due to insufficient rights!'}
|
return 403, {
|
||||||
|
"message": f"Getting Package with id {package_uuid} failed due to insufficient rights!"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/compound", response={200: List[CompoundSchema], 403: Error})
|
@router.get("/compound", response={200: List[CompoundSchema], 403: Error})
|
||||||
@ -97,7 +99,9 @@ def get_compounds(request):
|
|||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
@router.get("/package/{uuid:package_uuid}/compound", response={200: List[CompoundSchema], 403: Error})
|
@router.get(
|
||||||
|
"/package/{uuid:package_uuid}/compound", response={200: List[CompoundSchema], 403: Error}
|
||||||
|
)
|
||||||
@paginate
|
@paginate
|
||||||
def get_package_compounds(request, package_uuid):
|
def get_package_compounds(request, package_uuid):
|
||||||
try:
|
try:
|
||||||
@ -105,4 +109,5 @@ def get_package_compounds(request, package_uuid):
|
|||||||
return Compound.objects.filter(package=p)
|
return Compound.objects.filter(package=p)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 403, {
|
return 403, {
|
||||||
'message': f'Getting Compounds for Package with id {package_uuid} failed due to insufficient rights!'}
|
"message": f"Getting Compounds for Package with id {package_uuid} failed due to insufficient rights!"
|
||||||
|
}
|
||||||
|
|||||||
@ -2,8 +2,8 @@ from django.apps import AppConfig
|
|||||||
|
|
||||||
|
|
||||||
class EPDBConfig(AppConfig):
|
class EPDBConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = 'epdb'
|
name = "epdb"
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
import epdb.signals # noqa: F401
|
import epdb.signals # noqa: F401
|
||||||
|
|||||||
32
epdb/context_processors.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"""
|
||||||
|
Context processors for enviPy application.
|
||||||
|
|
||||||
|
Context processors automatically make variables available to all templates.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .logic import PackageManager
|
||||||
|
from .models import Package
|
||||||
|
|
||||||
|
|
||||||
|
def package_context(request):
|
||||||
|
"""
|
||||||
|
Provides package data for the search modal which is included globally
|
||||||
|
in framework_modern.html.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Context dictionary with reviewed and unreviewed packages
|
||||||
|
"""
|
||||||
|
current_user = request.user
|
||||||
|
|
||||||
|
reviewed_package_qs = PackageManager.get_reviewed_packages()
|
||||||
|
|
||||||
|
unreviewed_package_qs = Package.objects.none()
|
||||||
|
|
||||||
|
# Only get user-specific packages if user is authenticated
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
unreviewed_package_qs = PackageManager.get_all_readable_packages(current_user)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"reviewed_packages": reviewed_package_qs,
|
||||||
|
"unreviewed_packages": unreviewed_package_qs,
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
|
|
||||||
|
|
||||||
class EmailLoginForm(forms.Form):
|
|
||||||
email = forms.EmailField()
|
|
||||||
1091
epdb/logic.py
@ -5,32 +5,55 @@ from django.core.management.base import BaseCommand
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from epdb.logic import UserManager, GroupManager, PackageManager, SettingManager
|
from epdb.logic import UserManager, GroupManager, PackageManager, SettingManager
|
||||||
from epdb.models import UserSettingPermission, MLRelativeReasoning, EnviFormer, Permission, User, ExternalDatabase
|
from epdb.models import (
|
||||||
|
UserSettingPermission,
|
||||||
|
MLRelativeReasoning,
|
||||||
|
EnviFormer,
|
||||||
|
Permission,
|
||||||
|
User,
|
||||||
|
ExternalDatabase,
|
||||||
|
License,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"-ol", "--only-licenses", action="store_true", help="Only create licenses."
|
||||||
|
)
|
||||||
|
|
||||||
def create_users(self):
|
def create_users(self):
|
||||||
|
|
||||||
# Anonymous User
|
# Anonymous User
|
||||||
if not User.objects.filter(email='anon@envipath.com').exists():
|
if not User.objects.filter(email="anon@envipath.com").exists():
|
||||||
anon = UserManager.create_user("anonymous", "anon@envipath.com", "SuperSafe",
|
anon = UserManager.create_user(
|
||||||
is_active=True, add_to_group=False, set_setting=False)
|
"anonymous",
|
||||||
|
"anon@envipath.com",
|
||||||
|
"SuperSafe",
|
||||||
|
is_active=True,
|
||||||
|
add_to_group=False,
|
||||||
|
set_setting=False,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
anon = User.objects.get(email='anon@envipath.com')
|
anon = User.objects.get(email="anon@envipath.com")
|
||||||
|
|
||||||
# Admin User
|
# Admin User
|
||||||
if not User.objects.filter(email='admin@envipath.com').exists():
|
if not User.objects.filter(email="admin@envipath.com").exists():
|
||||||
admin = UserManager.create_user("admin", "admin@envipath.com", "SuperSafe",
|
admin = UserManager.create_user(
|
||||||
is_active=True, add_to_group=False, set_setting=False)
|
"admin",
|
||||||
|
"admin@envipath.com",
|
||||||
|
"SuperSafe",
|
||||||
|
is_active=True,
|
||||||
|
add_to_group=False,
|
||||||
|
set_setting=False,
|
||||||
|
)
|
||||||
admin.is_staff = True
|
admin.is_staff = True
|
||||||
admin.is_superuser = True
|
admin.is_superuser = True
|
||||||
admin.save()
|
admin.save()
|
||||||
else:
|
else:
|
||||||
admin = User.objects.get(email='admin@envipath.com')
|
admin = User.objects.get(email="admin@envipath.com")
|
||||||
|
|
||||||
# System Group
|
# System Group
|
||||||
g = GroupManager.create_group(admin, 'enviPath Users', 'All enviPath Users')
|
g = GroupManager.create_group(admin, "enviPath Users", "All enviPath Users")
|
||||||
g.public = True
|
g.public = True
|
||||||
g.save()
|
g.save()
|
||||||
|
|
||||||
@ -43,14 +66,20 @@ class Command(BaseCommand):
|
|||||||
admin.default_group = g
|
admin.default_group = g
|
||||||
admin.save()
|
admin.save()
|
||||||
|
|
||||||
if not User.objects.filter(email='user0@envipath.com').exists():
|
if not User.objects.filter(email="user0@envipath.com").exists():
|
||||||
user0 = UserManager.create_user("user0", "user0@envipath.com", "SuperSafe",
|
user0 = UserManager.create_user(
|
||||||
is_active=True, add_to_group=False, set_setting=False)
|
"user0",
|
||||||
|
"user0@envipath.com",
|
||||||
|
"SuperSafe",
|
||||||
|
is_active=True,
|
||||||
|
add_to_group=False,
|
||||||
|
set_setting=False,
|
||||||
|
)
|
||||||
user0.is_staff = True
|
user0.is_staff = True
|
||||||
user0.is_superuser = True
|
user0.is_superuser = True
|
||||||
user0.save()
|
user0.save()
|
||||||
else:
|
else:
|
||||||
user0 = User.objects.get(email='user0@envipath.com')
|
user0 = User.objects.get(email="user0@envipath.com")
|
||||||
|
|
||||||
g.user_member.add(user0)
|
g.user_member.add(user0)
|
||||||
g.save()
|
g.save()
|
||||||
@ -60,19 +89,32 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
return anon, admin, g, user0
|
return anon, admin, g, user0
|
||||||
|
|
||||||
|
def create_licenses(self):
|
||||||
|
"""Create the six default licenses supported by enviPath"""
|
||||||
|
cc_strings = ["by", "by-nc", "by-nc-nd", "by-nc-sa", "by-nd", "by-sa"]
|
||||||
|
for cc_string in cc_strings:
|
||||||
|
if not License.objects.filter(cc_string=cc_string).exists():
|
||||||
|
new_license = License()
|
||||||
|
new_license.cc_string = cc_string
|
||||||
|
new_license.link = f"https://creativecommons.org/licenses/{cc_string}/4.0/"
|
||||||
|
new_license.image_link = f"https://licensebuttons.net/l/{cc_string}/4.0/88x31.png"
|
||||||
|
new_license.save()
|
||||||
|
|
||||||
def import_package(self, data, owner):
|
def import_package(self, data, owner):
|
||||||
return PackageManager.import_legacy_package(data, owner, keep_ids=True, add_import_timestamp=False, trust_reviewed=True)
|
return PackageManager.import_legacy_package(
|
||||||
|
data, owner, keep_ids=True, add_import_timestamp=False, trust_reviewed=True
|
||||||
|
)
|
||||||
|
|
||||||
def create_default_setting(self, owner, packages):
|
def create_default_setting(self, owner, packages):
|
||||||
s = SettingManager.create_setting(
|
s = SettingManager.create_setting(
|
||||||
owner,
|
owner,
|
||||||
name='Global Default Setting',
|
name="Global Default Setting",
|
||||||
description='Global Default Setting containing BBD Rules and Max 30 Nodes and Max Depth of 8',
|
description="Global Default Setting containing BBD Rules and Max 30 Nodes and Max Depth of 8",
|
||||||
max_nodes=30,
|
max_nodes=30,
|
||||||
max_depth=5,
|
max_depth=5,
|
||||||
rule_packages=packages,
|
rule_packages=packages,
|
||||||
model=None,
|
model=None,
|
||||||
model_threshold=None
|
model_threshold=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
@ -84,57 +126,58 @@ class Command(BaseCommand):
|
|||||||
"""
|
"""
|
||||||
databases = [
|
databases = [
|
||||||
{
|
{
|
||||||
'name': 'PubChem Compound',
|
"name": "PubChem Compound",
|
||||||
'full_name': 'PubChem Compound Database',
|
"full_name": "PubChem Compound Database",
|
||||||
'description': 'Chemical database of small organic molecules',
|
"description": "Chemical database of small organic molecules",
|
||||||
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
|
"base_url": "https://pubchem.ncbi.nlm.nih.gov",
|
||||||
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/compound/{id}'
|
"url_pattern": "https://pubchem.ncbi.nlm.nih.gov/compound/{id}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'PubChem Substance',
|
"name": "PubChem Substance",
|
||||||
'full_name': 'PubChem Substance Database',
|
"full_name": "PubChem Substance Database",
|
||||||
'description': 'Database of chemical substances',
|
"description": "Database of chemical substances",
|
||||||
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
|
"base_url": "https://pubchem.ncbi.nlm.nih.gov",
|
||||||
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/substance/{id}'
|
"url_pattern": "https://pubchem.ncbi.nlm.nih.gov/substance/{id}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'ChEBI',
|
"name": "ChEBI",
|
||||||
'full_name': 'Chemical Entities of Biological Interest',
|
"full_name": "Chemical Entities of Biological Interest",
|
||||||
'description': 'Dictionary of molecular entities',
|
"description": "Dictionary of molecular entities",
|
||||||
'base_url': 'https://www.ebi.ac.uk/chebi',
|
"base_url": "https://www.ebi.ac.uk/chebi",
|
||||||
'url_pattern': 'https://www.ebi.ac.uk/chebi/searchId.do?chebiId=CHEBI:{id}'
|
"url_pattern": "https://www.ebi.ac.uk/chebi/searchId.do?chebiId=CHEBI:{id}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'RHEA',
|
"name": "RHEA",
|
||||||
'full_name': 'RHEA Reaction Database',
|
"full_name": "RHEA Reaction Database",
|
||||||
'description': 'Comprehensive resource of biochemical reactions',
|
"description": "Comprehensive resource of biochemical reactions",
|
||||||
'base_url': 'https://www.rhea-db.org',
|
"base_url": "https://www.rhea-db.org",
|
||||||
'url_pattern': 'https://www.rhea-db.org/rhea/{id}'
|
"url_pattern": "https://www.rhea-db.org/rhea/{id}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'KEGG Reaction',
|
"name": "KEGG Reaction",
|
||||||
'full_name': 'KEGG Reaction Database',
|
"full_name": "KEGG Reaction Database",
|
||||||
'description': 'Database of biochemical reactions',
|
"description": "Database of biochemical reactions",
|
||||||
'base_url': 'https://www.genome.jp',
|
"base_url": "https://www.genome.jp",
|
||||||
'url_pattern': 'https://www.genome.jp/entry/reaction+{id}'
|
"url_pattern": "https://www.genome.jp/entry/{id}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'UniProt',
|
"name": "UniProt",
|
||||||
'full_name': 'MetaCyc Metabolic Pathway Database',
|
"full_name": "MetaCyc Metabolic Pathway Database",
|
||||||
'description': 'UniProt is a freely accessible database of protein sequence and functional information',
|
"description": "UniProt is a freely accessible database of protein sequence and functional information",
|
||||||
'base_url': 'https://www.uniprot.org',
|
"base_url": "https://www.uniprot.org",
|
||||||
'url_pattern': 'https://www.uniprot.org/uniprotkb?query="{id}"'
|
"url_pattern": 'https://www.uniprot.org/uniprotkb?query="{id}"',
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
for db_info in databases:
|
for db_info in databases:
|
||||||
ExternalDatabase.objects.get_or_create(
|
ExternalDatabase.objects.get_or_create(name=db_info["name"], defaults=db_info)
|
||||||
name=db_info['name'],
|
|
||||||
defaults=db_info
|
|
||||||
)
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
# Create licenses
|
||||||
|
self.create_licenses()
|
||||||
|
if options.get("only_licenses", False):
|
||||||
|
return
|
||||||
# Create users
|
# Create users
|
||||||
anon, admin, g, user0 = self.create_users()
|
anon, admin, g, user0 = self.create_users()
|
||||||
|
|
||||||
@ -142,20 +185,24 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Import Packages
|
# Import Packages
|
||||||
packages = [
|
packages = [
|
||||||
'EAWAG-BBD.json',
|
"EAWAG-BBD.json",
|
||||||
'EAWAG-SOIL.json',
|
"EAWAG-SOIL.json",
|
||||||
'EAWAG-SLUDGE.json',
|
"EAWAG-SLUDGE.json",
|
||||||
'EAWAG-SEDIMENT.json',
|
"EAWAG-SEDIMENT.json",
|
||||||
]
|
]
|
||||||
|
|
||||||
mapping = {}
|
mapping = {}
|
||||||
for p in packages:
|
for p in packages:
|
||||||
print(f"Importing {p}...")
|
print(f"Importing {p}...")
|
||||||
package_data = json.loads(open(s.BASE_DIR / 'fixtures' / 'packages' / '2025-07-18' / p).read())
|
package_data = json.loads(
|
||||||
|
open(
|
||||||
|
s.BASE_DIR / "fixtures" / "packages" / "2025-07-18" / p, encoding="utf-8"
|
||||||
|
).read()
|
||||||
|
)
|
||||||
imported_package = self.import_package(package_data, admin)
|
imported_package = self.import_package(package_data, admin)
|
||||||
mapping[p.replace('.json', '')] = imported_package
|
mapping[p.replace(".json", "")] = imported_package
|
||||||
|
|
||||||
setting = self.create_default_setting(admin, [mapping['EAWAG-BBD']])
|
setting = self.create_default_setting(admin, [mapping["EAWAG-BBD"]])
|
||||||
setting.public = True
|
setting.public = True
|
||||||
setting.save()
|
setting.save()
|
||||||
setting.make_global_default()
|
setting.make_global_default()
|
||||||
@ -171,26 +218,28 @@ class Command(BaseCommand):
|
|||||||
usp.save()
|
usp.save()
|
||||||
|
|
||||||
# Create Model Package
|
# Create Model Package
|
||||||
pack = PackageManager.create_package(admin, "Public Prediction Models",
|
pack = PackageManager.create_package(
|
||||||
"Package to make Prediction Models publicly available")
|
admin,
|
||||||
|
"Public Prediction Models",
|
||||||
|
"Package to make Prediction Models publicly available",
|
||||||
|
)
|
||||||
pack.reviewed = True
|
pack.reviewed = True
|
||||||
pack.save()
|
pack.save()
|
||||||
|
|
||||||
# Create RR
|
# Create RR
|
||||||
ml_model = MLRelativeReasoning.create(
|
ml_model = MLRelativeReasoning.create(
|
||||||
package=pack,
|
package=pack,
|
||||||
rule_packages=[mapping['EAWAG-BBD']],
|
rule_packages=[mapping["EAWAG-BBD"]],
|
||||||
data_packages=[mapping['EAWAG-BBD']],
|
data_packages=[mapping["EAWAG-BBD"]],
|
||||||
eval_packages=[],
|
eval_packages=[],
|
||||||
threshold=0.5,
|
threshold=0.5,
|
||||||
name='ECC - BBD - T0.5',
|
name="ECC - BBD - T0.5",
|
||||||
description='ML Relative Reasoning',
|
description="ML Relative Reasoning",
|
||||||
)
|
)
|
||||||
|
|
||||||
ml_model.build_dataset()
|
ml_model.build_dataset()
|
||||||
ml_model.build_model()
|
ml_model.build_model()
|
||||||
# ml_model.evaluate_model()
|
|
||||||
|
|
||||||
# If available, create EnviFormerModel
|
# If available, create EnviFormerModel
|
||||||
if s.ENVIFORMER_PRESENT:
|
if s.ENVIFORMER_PRESENT:
|
||||||
enviFormer_model = EnviFormer.create(pack, 'EnviFormer - T0.5', 'EnviFormer Model with Threshold 0.5', 0.5)
|
EnviFormer.create(pack, "EnviFormer - T0.5", "EnviFormer Model with Threshold 0.5", 0.5)
|
||||||
|
|||||||
119
epdb/management/commands/create_ml_models.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
from django.conf import settings as s
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import MLRelativeReasoning, EnviFormer, Package
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
"""This command can be run with
|
||||||
|
`python manage.py create_ml_models [model_names] -d [data_packages] FOR MLRR ONLY: -r [rule_packages]
|
||||||
|
OPTIONAL: -e [eval_packages] -t threshold`
|
||||||
|
For example, to train both EnviFormer and MLRelativeReasoning on BBD and SOIL and evaluate them on SLUDGE with a
|
||||||
|
threshold of 0.6, the below command would be used:
|
||||||
|
`python manage.py create_ml_models enviformer mlrr -d bbd soil -e sludge -t 0.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"model_names",
|
||||||
|
nargs="+",
|
||||||
|
type=str,
|
||||||
|
help="The names of models to train. Options are: enviformer, mlrr",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", "--data-packages", nargs="+", type=str, help="Packages for training"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-e", "--eval-packages", nargs="*", type=str, help="Packages for evaluation", default=[]
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-r",
|
||||||
|
"--rule-packages",
|
||||||
|
nargs="*",
|
||||||
|
type=str,
|
||||||
|
help="Rule Packages mandatory for MLRR",
|
||||||
|
default=[],
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--threshold",
|
||||||
|
type=float,
|
||||||
|
help="Model prediction threshold",
|
||||||
|
default=0.5,
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
# Find Public Prediction Models package to add new models to
|
||||||
|
try:
|
||||||
|
pack = Package.objects.filter(name="Public Prediction Models")[0]
|
||||||
|
bbd = Package.objects.filter(name="EAWAG-BBD")[0]
|
||||||
|
soil = Package.objects.filter(name="EAWAG-SOIL")[0]
|
||||||
|
sludge = Package.objects.filter(name="EAWAG-SLUDGE")[0]
|
||||||
|
sediment = Package.objects.filter(name="EAWAG-SEDIMENT")[0]
|
||||||
|
except IndexError:
|
||||||
|
raise IndexError(
|
||||||
|
"Can't find correct packages. They should be created with the bootstrap command"
|
||||||
|
)
|
||||||
|
|
||||||
|
def decode_packages(package_list):
|
||||||
|
"""Decode package strings into their respective packages"""
|
||||||
|
packages = []
|
||||||
|
for p in package_list:
|
||||||
|
p = p.lower()
|
||||||
|
if p == "bbd":
|
||||||
|
packages.append(bbd)
|
||||||
|
elif p == "soil":
|
||||||
|
packages.append(soil)
|
||||||
|
elif p == "sludge":
|
||||||
|
packages.append(sludge)
|
||||||
|
elif p == "sediment":
|
||||||
|
packages.append(sediment)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown package {p}")
|
||||||
|
return packages
|
||||||
|
|
||||||
|
# Iteratively create models in options["model_names"]
|
||||||
|
print(f"Creating models: {options['model_names']}\n"
|
||||||
|
f"Data packages: {options['data_packages']}\n"
|
||||||
|
f"Rule Packages (only for MLRR): {options['rule_packages']}\n"
|
||||||
|
f"Eval Packages: {options['eval_packages']}\n"
|
||||||
|
f"Threshold: {options['threshold']:.2f}")
|
||||||
|
data_packages = decode_packages(options["data_packages"])
|
||||||
|
eval_packages = decode_packages(options["eval_packages"])
|
||||||
|
rule_packages = decode_packages(options["rule_packages"])
|
||||||
|
for model_name in options["model_names"]:
|
||||||
|
model_name = model_name.lower()
|
||||||
|
if model_name == "enviformer" and s.ENVIFORMER_PRESENT:
|
||||||
|
model = EnviFormer.create(
|
||||||
|
pack,
|
||||||
|
data_packages=data_packages,
|
||||||
|
eval_packages=eval_packages,
|
||||||
|
threshold=options['threshold'],
|
||||||
|
name=f"EnviFormer - {', '.join(options['data_packages'])} - T{options['threshold']:.2f}",
|
||||||
|
description=f"EnviFormer transformer trained on {options['data_packages']} "
|
||||||
|
f"evaluated on {options['eval_packages']}.",
|
||||||
|
)
|
||||||
|
elif model_name == "mlrr":
|
||||||
|
model = MLRelativeReasoning.create(
|
||||||
|
package=pack,
|
||||||
|
rule_packages=rule_packages,
|
||||||
|
data_packages=data_packages,
|
||||||
|
eval_packages=eval_packages,
|
||||||
|
threshold=options['threshold'],
|
||||||
|
name=f"ECC - {', '.join(options['data_packages'])} - T{options['threshold']:.2f}",
|
||||||
|
description=f"ML Relative Reasoning trained on {options['data_packages']} with rules from "
|
||||||
|
f"{options['rule_packages']} and evaluated on {options['eval_packages']}.",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Cannot create model of type {model_name}, unknown model type")
|
||||||
|
# Build the dataset for the model, train it, evaluate it and save it
|
||||||
|
print(f"Building dataset for {model_name}")
|
||||||
|
model.build_dataset()
|
||||||
|
print(f"Training {model_name}")
|
||||||
|
model.build_model()
|
||||||
|
print(f"Evaluating {model_name}")
|
||||||
|
model.evaluate_model(False, eval_packages=eval_packages)
|
||||||
|
print(f"Saving {model_name}")
|
||||||
|
model.save()
|
||||||
59
epdb/management/commands/dump_enviformer.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import tarfile
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from django.conf import settings as s
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import EnviFormer
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"model",
|
||||||
|
type=str,
|
||||||
|
help="Model UUID of the Model to Dump",
|
||||||
|
)
|
||||||
|
parser.add_argument("--output", type=str)
|
||||||
|
|
||||||
|
def package_dict_and_folder(self, dict_data, folder_path, output_path):
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
dict_filename = os.path.join(tmpdir, "data.json")
|
||||||
|
|
||||||
|
with open(dict_filename, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(dict_data, f, indent=2)
|
||||||
|
|
||||||
|
with tarfile.open(output_path, "w:gz") as tar:
|
||||||
|
tar.add(dict_filename, arcname="data.json")
|
||||||
|
tar.add(folder_path, arcname=os.path.basename(folder_path))
|
||||||
|
|
||||||
|
os.remove(dict_filename)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
output = options["output"]
|
||||||
|
|
||||||
|
if os.path.exists(output):
|
||||||
|
raise ValueError(f"Output file {output} already exists")
|
||||||
|
|
||||||
|
model = EnviFormer.objects.get(uuid=options["model"])
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"uuid": str(model.uuid),
|
||||||
|
"name": model.name,
|
||||||
|
"description": model.description,
|
||||||
|
"kv": model.kv,
|
||||||
|
"data_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
||||||
|
"eval_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
||||||
|
"threshold": model.threshold,
|
||||||
|
"eval_results": model.eval_results,
|
||||||
|
"multigen_eval": model.multigen_eval,
|
||||||
|
"model_status": model.model_status,
|
||||||
|
}
|
||||||
|
|
||||||
|
model_folder = os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid))
|
||||||
|
|
||||||
|
self.package_dict_and_folder(data, model_folder, output)
|
||||||
58
epdb/management/commands/import_external_identifiers.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from csv import DictReader
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import Compound, CompoundStructure, Reaction, ExternalDatabase, ExternalIdentifier
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
STR_TO_MODEL = {
|
||||||
|
"Compound": Compound,
|
||||||
|
"CompoundStructure": CompoundStructure,
|
||||||
|
"Reaction": Reaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
STR_TO_DATABASE = {
|
||||||
|
"ChEBI": ExternalDatabase.objects.get(name="ChEBI"),
|
||||||
|
"RHEA": ExternalDatabase.objects.get(name="RHEA"),
|
||||||
|
"KEGG Reaction": ExternalDatabase.objects.get(name="KEGG Reaction"),
|
||||||
|
"PubChem Compound": ExternalDatabase.objects.get(name="PubChem Compound"),
|
||||||
|
"PubChem Substance": ExternalDatabase.objects.get(name="PubChem Substance"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"--data",
|
||||||
|
type=str,
|
||||||
|
help="Path of the ID Mapping file.",
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--replace-host",
|
||||||
|
type=str,
|
||||||
|
help="Replace https://envipath.org/ with this host, e.g. http://localhost:8000/",
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
with open(options["data"]) as fh:
|
||||||
|
reader = DictReader(fh)
|
||||||
|
for row in reader:
|
||||||
|
clz = self.STR_TO_MODEL[row["model"]]
|
||||||
|
|
||||||
|
url = row["url"]
|
||||||
|
if options["replace_host"]:
|
||||||
|
url = url.replace("https://envipath.org/", options["replace_host"])
|
||||||
|
|
||||||
|
instance = clz.objects.get(url=url)
|
||||||
|
db = self.STR_TO_DATABASE[row["identifier_type"]]
|
||||||
|
|
||||||
|
ExternalIdentifier.objects.create(
|
||||||
|
content_object=instance,
|
||||||
|
database=db,
|
||||||
|
identifier_value=row["identifier_value"],
|
||||||
|
url=db.url_pattern.format(id=row["identifier_value"]),
|
||||||
|
is_primary=False,
|
||||||
|
)
|
||||||
@ -1,27 +1,29 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from epdb.logic import PackageManager
|
from epdb.logic import PackageManager
|
||||||
from epdb.models import *
|
from epdb.models import User
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--data',
|
"--data",
|
||||||
type=str,
|
type=str,
|
||||||
help='Path of the Package to import.',
|
help="Path of the Package to import.",
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--owner',
|
"--owner",
|
||||||
type=str,
|
type=str,
|
||||||
help='Username of the desired Owner.',
|
help="Username of the desired Owner.",
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
owner = User.objects.get(username=options['owner'])
|
owner = User.objects.get(username=options["owner"])
|
||||||
package_data = json.load(open(options['data']))
|
package_data = json.load(open(options["data"]))
|
||||||
PackageManager.import_legacy_package(package_data, owner)
|
PackageManager.import_legacy_package(package_data, owner)
|
||||||
|
|||||||
81
epdb/management/commands/load_enviformer.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tarfile
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from django.conf import settings as s
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import EnviFormer, Package
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"input",
|
||||||
|
type=str,
|
||||||
|
help=".tar.gz file containing the Model dump.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"package",
|
||||||
|
type=str,
|
||||||
|
help="Package UUID where the Model should be loaded to.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def read_dict_and_folder_from_archive(self, archive_path, extract_to="extracted_folder"):
|
||||||
|
with tarfile.open(archive_path, "r:gz") as tar:
|
||||||
|
tar.extractall(extract_to)
|
||||||
|
|
||||||
|
dict_path = os.path.join(extract_to, "data.json")
|
||||||
|
|
||||||
|
if not os.path.exists(dict_path):
|
||||||
|
raise FileNotFoundError("data.json not found in the archive.")
|
||||||
|
|
||||||
|
with open(dict_path, "r", encoding="utf-8") as f:
|
||||||
|
data_dict = json.load(f)
|
||||||
|
|
||||||
|
extracted_items = os.listdir(extract_to)
|
||||||
|
folders = [item for item in extracted_items if item != "data.json"]
|
||||||
|
folder_path = os.path.join(extract_to, folders[0]) if folders else None
|
||||||
|
|
||||||
|
return data_dict, folder_path
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if not os.path.exists(options["input"]):
|
||||||
|
raise ValueError(f"Input file {options['input']} does not exist.")
|
||||||
|
|
||||||
|
target_package = Package.objects.get(uuid=options["package"])
|
||||||
|
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
data, folder = self.read_dict_and_folder_from_archive(options["input"], tmpdir)
|
||||||
|
|
||||||
|
model = EnviFormer()
|
||||||
|
model.package = target_package
|
||||||
|
# model.uuid = data["uuid"]
|
||||||
|
model.name = data["name"]
|
||||||
|
model.description = data["description"]
|
||||||
|
model.kv = data["kv"]
|
||||||
|
model.threshold = float(data["threshold"])
|
||||||
|
model.eval_results = data["eval_results"]
|
||||||
|
model.multigen_eval = data["multigen_eval"]
|
||||||
|
model.model_status = data["model_status"]
|
||||||
|
model.save()
|
||||||
|
|
||||||
|
for p_uuid in data["data_packages_uuids"]:
|
||||||
|
p = Package.objects.get(uuid=p_uuid)
|
||||||
|
model.data_packages.add(p)
|
||||||
|
|
||||||
|
for p_uuid in data["eval_packages_uuids"]:
|
||||||
|
p = Package.objects.get(uuid=p_uuid)
|
||||||
|
model.eval_packages.add(p)
|
||||||
|
|
||||||
|
target_folder = os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid))
|
||||||
|
|
||||||
|
shutil.copytree(folder, target_folder)
|
||||||
|
os.rename(
|
||||||
|
os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid), f"{data['uuid']}.ckpt"),
|
||||||
|
os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid), f"{model.uuid}.ckpt"),
|
||||||
|
)
|
||||||
@ -1,51 +1,64 @@
|
|||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
from django.db.models import F, Value
|
from django.db.models import F, Value, TextField, JSONField
|
||||||
from django.db.models.functions import Replace
|
from django.db.models.functions import Replace, Cast
|
||||||
|
|
||||||
|
from epdb.models import EnviPathModel
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--old',
|
"--old",
|
||||||
type=str,
|
type=str,
|
||||||
help='Old Host, most likely https://envipath.org/',
|
help="Old Host, most likely https://envipath.org/",
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--new',
|
"--new",
|
||||||
type=str,
|
type=str,
|
||||||
help='New Host, most likely http://localhost:8000/',
|
help="New Host, most likely http://localhost:8000/",
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
MODELS = [
|
MODELS = [
|
||||||
'User',
|
"User",
|
||||||
'Group',
|
"Group",
|
||||||
'Package',
|
"Package",
|
||||||
'Compound',
|
"Compound",
|
||||||
'CompoundStructure',
|
"CompoundStructure",
|
||||||
'Pathway',
|
"Pathway",
|
||||||
'Edge',
|
"Edge",
|
||||||
'Node',
|
"Node",
|
||||||
'Reaction',
|
"Reaction",
|
||||||
'SimpleAmbitRule',
|
"SimpleAmbitRule",
|
||||||
'SimpleRDKitRule',
|
"SimpleRDKitRule",
|
||||||
'ParallelRule',
|
"ParallelRule",
|
||||||
'SequentialRule',
|
"SequentialRule",
|
||||||
'Scenario',
|
"Scenario",
|
||||||
'Setting',
|
"Setting",
|
||||||
'MLRelativeReasoning',
|
"MLRelativeReasoning",
|
||||||
'RuleBasedRelativeReasoning',
|
"RuleBasedRelativeReasoning",
|
||||||
'EnviFormer',
|
"EnviFormer",
|
||||||
'ApplicabilityDomain',
|
"ApplicabilityDomain",
|
||||||
|
"EnzymeLink",
|
||||||
]
|
]
|
||||||
for model in MODELS:
|
for model in MODELS:
|
||||||
obj_cls = apps.get_model("epdb", model)
|
obj_cls = apps.get_model("epdb", model)
|
||||||
print(f"Localizing urls for {model}")
|
print(f"Localizing urls for {model}")
|
||||||
obj_cls.objects.update(
|
obj_cls.objects.update(
|
||||||
url=Replace(F('url'), Value(options['old']), Value(options['new']))
|
url=Replace(F("url"), Value(options["old"]), Value(options["new"]))
|
||||||
)
|
)
|
||||||
|
if issubclass(obj_cls, EnviPathModel):
|
||||||
|
obj_cls.objects.update(
|
||||||
|
kv=Cast(
|
||||||
|
Replace(
|
||||||
|
Cast(F("kv"), output_field=TextField()),
|
||||||
|
Value(options["old"]),
|
||||||
|
Value(options["new"]),
|
||||||
|
),
|
||||||
|
output_field=JSONField(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
38
epdb/management/commands/update_job_logs.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import JobLog
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"--cleanup",
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help="Remove all logs older than this number of days. Default is None, which does not remove any logs.",
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if options["cleanup"] is not None:
|
||||||
|
cleanup_dt = date.today() - timedelta(days=options["cleanup"])
|
||||||
|
print(JobLog.objects.filter(created__lt=cleanup_dt).delete())
|
||||||
|
|
||||||
|
logs = JobLog.objects.filter(status="INITIAL")
|
||||||
|
print(f"Found {logs.count()} logs to update")
|
||||||
|
updated = 0
|
||||||
|
for log in logs:
|
||||||
|
res = log.check_for_update()
|
||||||
|
if res:
|
||||||
|
updated += 1
|
||||||
|
|
||||||
|
print(f"Updated {updated} logs")
|
||||||
|
|
||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
|
qs = JobLog.objects.values("status").annotate(total=Count("status"))
|
||||||
|
for r in qs:
|
||||||
|
print(r["status"], r["total"])
|
||||||
@ -3,22 +3,25 @@ from django.shortcuts import redirect
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
|
||||||
class LoginRequiredMiddleware:
|
class LoginRequiredMiddleware:
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
self.exempt_urls = [
|
self.exempt_urls = [
|
||||||
reverse('login'),
|
reverse("login"),
|
||||||
reverse('logout'),
|
reverse("logout"),
|
||||||
reverse('admin:login'),
|
reverse("admin:login"),
|
||||||
reverse('admin:index'),
|
reverse("admin:index"),
|
||||||
] + getattr(settings, 'LOGIN_EXEMPT_URLS', [])
|
] + getattr(settings, "LOGIN_EXEMPT_URLS", [])
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
path = request.path_info
|
path = request.path_info
|
||||||
if not any(path.startswith(url) for url in self.exempt_urls):
|
if not any(path.startswith(url) for url in self.exempt_urls):
|
||||||
if request.method == 'GET':
|
if request.method == "GET":
|
||||||
if request.get_full_path() and request.get_full_path() != '/':
|
if request.get_full_path() and request.get_full_path() != "/":
|
||||||
return redirect(f"{settings.LOGIN_URL}?next={quote(request.get_full_path())}")
|
return redirect(
|
||||||
|
f"{settings.LOGIN_URL}?next={quote(request.get_full_path())}"
|
||||||
|
)
|
||||||
return redirect(settings.LOGIN_URL)
|
return redirect(settings.LOGIN_URL)
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-10-07 08:19
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('epdb', '0006_mlrelativereasoning_multigen_eval_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='enviformer',
|
||||||
|
options={},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='app_domain',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='epdb.applicabilitydomain'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='data_packages',
|
||||||
|
field=models.ManyToManyField(related_name='%(app_label)s_%(class)s_data_packages', to='epdb.package', verbose_name='Data Packages'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='eval_packages',
|
||||||
|
field=models.ManyToManyField(related_name='%(app_label)s_%(class)s_eval_packages', to='epdb.package', verbose_name='Evaluation Packages'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='eval_results',
|
||||||
|
field=models.JSONField(blank=True, default=dict, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='model_status',
|
||||||
|
field=models.CharField(choices=[('INITIAL', 'Initial'), ('INITIALIZING', 'Model is initializing.'), ('BUILDING', 'Model is building.'), ('BUILT_NOT_EVALUATED', 'Model is built and can be used for predictions, Model is not evaluated yet.'), ('EVALUATING', 'Model is evaluating'), ('FINISHED', 'Model has finished building and evaluation.'), ('ERROR', 'Model has failed.')], default='INITIAL'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='multigen_eval',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='enviformer',
|
||||||
|
name='rule_packages',
|
||||||
|
field=models.ManyToManyField(related_name='%(app_label)s_%(class)s_rule_packages', to='epdb.package', verbose_name='Rule Packages'),
|
||||||
|
),
|
||||||
|
]
|
||||||
64
epdb/migrations/0008_enzymelink.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-10 06:58
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import model_utils.fields
|
||||||
|
import uuid
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("epdb", "0007_alter_enviformer_options_enviformer_app_domain_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="EnzymeLink",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="created"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4, unique=True, verbose_name="UUID of this object"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField(default="no name", verbose_name="Name")),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
models.TextField(default="no description", verbose_name="Descriptions"),
|
||||||
|
),
|
||||||
|
("url", models.TextField(null=True, unique=True, verbose_name="URL")),
|
||||||
|
("kv", models.JSONField(blank=True, default=dict, null=True)),
|
||||||
|
("ec_number", models.TextField(verbose_name="EC Number")),
|
||||||
|
("classification_level", models.IntegerField(verbose_name="Classification Level")),
|
||||||
|
("linking_method", models.TextField(verbose_name="Linking Method")),
|
||||||
|
("edge_evidence", models.ManyToManyField(to="epdb.edge")),
|
||||||
|
("reaction_evidence", models.ManyToManyField(to="epdb.reaction")),
|
||||||
|
(
|
||||||
|
"rule",
|
||||||
|
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="epdb.rule"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
66
epdb/migrations/0009_joblog.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-27 09:39
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import model_utils.fields
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("epdb", "0008_enzymelink"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="JobLog",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="created"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("task_id", models.UUIDField(unique=True)),
|
||||||
|
("job_name", models.TextField()),
|
||||||
|
(
|
||||||
|
"status",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("INITIAL", "Initial"),
|
||||||
|
("SUCCESS", "Success"),
|
||||||
|
("FAILURE", "Failure"),
|
||||||
|
("REVOKED", "Revoked"),
|
||||||
|
("IGNORED", "Ignored"),
|
||||||
|
],
|
||||||
|
default="INITIAL",
|
||||||
|
max_length=20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("done_at", models.DateTimeField(blank=True, default=None, null=True)),
|
||||||
|
("task_result", models.TextField(blank=True, default=None, null=True)),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
18
epdb/migrations/0010_license_cc_string.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-11-11 14:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("epdb", "0009_joblog"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="license",
|
||||||
|
name="cc_string",
|
||||||
|
field=models.TextField(default="by-nc-sa", verbose_name="CC string"),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
59
epdb/migrations/0011_auto_20251111_1413.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-11-11 14:13
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.contrib.postgres.aggregates import ArrayAgg
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db.models import Min
|
||||||
|
|
||||||
|
|
||||||
|
def set_cc(apps, schema_editor):
|
||||||
|
License = apps.get_model("epdb", "License")
|
||||||
|
|
||||||
|
# For all existing licenses extract cc_string from link
|
||||||
|
for license in License.objects.all():
|
||||||
|
pattern = r"/licenses/([^/]+)/4\.0"
|
||||||
|
match = re.search(pattern, license.link)
|
||||||
|
if match:
|
||||||
|
license.cc_string = match.group(1)
|
||||||
|
license.save()
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Could not find license for {license.link}")
|
||||||
|
|
||||||
|
# Ensure we have all licenses
|
||||||
|
cc_strings = ["by", "by-nc", "by-nc-nd", "by-nc-sa", "by-nd", "by-sa"]
|
||||||
|
for cc_string in cc_strings:
|
||||||
|
if not License.objects.filter(cc_string=cc_string).exists():
|
||||||
|
new_license = License()
|
||||||
|
new_license.cc_string = cc_string
|
||||||
|
new_license.link = f"https://creativecommons.org/licenses/{cc_string}/4.0/"
|
||||||
|
new_license.image_link = f"https://licensebuttons.net/l/{cc_string}/4.0/88x31.png"
|
||||||
|
new_license.save()
|
||||||
|
|
||||||
|
# As we might have existing Licenses representing the same License,
|
||||||
|
# get min pk and all pks as a list
|
||||||
|
license_lookup_qs = License.objects.values("cc_string").annotate(
|
||||||
|
lowest_pk=Min("id"), all_pks=ArrayAgg("id", order_by=("id",))
|
||||||
|
)
|
||||||
|
|
||||||
|
license_lookup = {
|
||||||
|
row["cc_string"]: (row["lowest_pk"], row["all_pks"]) for row in license_lookup_qs
|
||||||
|
}
|
||||||
|
|
||||||
|
Packages = apps.get_model("epdb", "Package")
|
||||||
|
|
||||||
|
for k, v in license_lookup.items():
|
||||||
|
# Set min pk to all packages pointing to any of the duplicates
|
||||||
|
Packages.objects.filter(pk__in=v[1]).update(license_id=v[0])
|
||||||
|
# remove the min pk from "other" pks as we use them for deletion
|
||||||
|
v[1].remove(v[0])
|
||||||
|
# Delete redundant License objects
|
||||||
|
License.objects.filter(pk__in=v[1]).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("epdb", "0010_license_cc_string"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [migrations.RunPython(set_cc)]
|
||||||
2436
epdb/models.py
242
epdb/tasks.py
@ -1,58 +1,154 @@
|
|||||||
|
import csv
|
||||||
|
import io
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Any, Callable, List, Optional
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from epdb.models import Pathway, Node, Edge, EPModel, Setting
|
from celery.utils.functional import LRUCache
|
||||||
from epdb.logic import SPathway
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from epdb.logic import SPathway
|
||||||
|
from epdb.models import Edge, EPModel, JobLog, Node, Package, Pathway, Rule, Setting, User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
ML_CACHE = LRUCache(3) # Cache the three most recent ML models to reduce load times.
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='background')
|
def get_ml_model(model_pk: int):
|
||||||
|
if model_pk not in ML_CACHE:
|
||||||
|
ML_CACHE[model_pk] = EPModel.objects.get(id=model_pk)
|
||||||
|
return ML_CACHE[model_pk]
|
||||||
|
|
||||||
|
|
||||||
|
def dispatch_eager(user: "User", job: Callable, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
x = job(*args, **kwargs)
|
||||||
|
log = JobLog()
|
||||||
|
log.user = user
|
||||||
|
log.task_id = uuid4()
|
||||||
|
log.job_name = job.__name__
|
||||||
|
log.status = "SUCCESS"
|
||||||
|
log.done_at = timezone.now()
|
||||||
|
log.task_result = str(x) if x else None
|
||||||
|
log.save()
|
||||||
|
|
||||||
|
return x
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
def dispatch(user: "User", job: Callable, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
x = job.delay(*args, **kwargs)
|
||||||
|
log = JobLog()
|
||||||
|
log.user = user
|
||||||
|
log.task_id = x.task_id
|
||||||
|
log.job_name = job.__name__
|
||||||
|
log.status = "INITIAL"
|
||||||
|
log.save()
|
||||||
|
|
||||||
|
return x.result
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(queue="background")
|
||||||
def mul(a, b):
|
def mul(a, b):
|
||||||
return a * b
|
return a * b
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='predict')
|
@shared_task(queue="predict")
|
||||||
def predict_simple(model_pk: int, smiles: str):
|
def predict_simple(model_pk: int, smiles: str):
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = get_ml_model(model_pk)
|
||||||
res = mod.predict(smiles)
|
res = mod.predict(smiles)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='background')
|
@shared_task(queue="background")
|
||||||
def send_registration_mail(user_pk: int):
|
def send_registration_mail(user_pk: int):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='model')
|
@shared_task(bind=True, queue="model")
|
||||||
def build_model(model_pk: int):
|
def build_model(self, model_pk: int):
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = EPModel.objects.get(id=model_pk)
|
||||||
mod.build_dataset()
|
|
||||||
mod.build_model()
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="RUNNING", task_result=mod.url)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mod.build_dataset()
|
||||||
|
mod.build_model()
|
||||||
|
except Exception as e:
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(
|
||||||
|
status="FAILED", task_result=mod.url
|
||||||
|
)
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="SUCCESS", task_result=mod.url)
|
||||||
|
|
||||||
|
return mod.url
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='model')
|
@shared_task(bind=True, queue="model")
|
||||||
def evaluate_model(model_pk: int):
|
def evaluate_model(self, model_pk: int, multigen: bool, package_pks: Optional[list] = None):
|
||||||
|
packages = None
|
||||||
|
|
||||||
|
if package_pks:
|
||||||
|
packages = Package.objects.filter(pk__in=package_pks)
|
||||||
|
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = EPModel.objects.get(id=model_pk)
|
||||||
mod.evaluate_model()
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="RUNNING", task_result=mod.url)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mod.evaluate_model(multigen, eval_packages=packages)
|
||||||
|
except Exception as e:
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(
|
||||||
|
status="FAILED", task_result=mod.url
|
||||||
|
)
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="SUCCESS", task_result=mod.url)
|
||||||
|
|
||||||
|
return mod.url
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='model')
|
@shared_task(queue="model")
|
||||||
def retrain(model_pk: int):
|
def retrain(model_pk: int):
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = EPModel.objects.get(id=model_pk)
|
||||||
mod.retrain()
|
mod.retrain()
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='predict')
|
@shared_task(bind=True, queue="predict")
|
||||||
def predict(pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_pk: Optional[int] = None) -> Pathway:
|
def predict(
|
||||||
|
self,
|
||||||
|
pw_pk: int,
|
||||||
|
pred_setting_pk: int,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
node_pk: Optional[int] = None,
|
||||||
|
) -> Pathway:
|
||||||
pw = Pathway.objects.get(id=pw_pk)
|
pw = Pathway.objects.get(id=pw_pk)
|
||||||
setting = Setting.objects.get(id=pred_setting_pk)
|
setting = Setting.objects.get(id=pred_setting_pk)
|
||||||
|
# If the setting has a model add/restore it from the cache
|
||||||
|
if setting.model is not None:
|
||||||
|
setting.model = get_ml_model(setting.model.pk)
|
||||||
|
|
||||||
pw.kv.update(**{'status': 'running'})
|
pw.kv.update(**{"status": "running"})
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="RUNNING", task_result=pw.url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# regular prediction
|
# regular prediction
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
@ -74,12 +170,114 @@ def predict(pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Neither limit nor node_pk given!")
|
raise ValueError("Neither limit nor node_pk given!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pw.kv.update({'status': 'failed'})
|
pw.kv.update({"status": "failed"})
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(
|
||||||
|
status="FAILED", task_result=pw.url
|
||||||
|
)
|
||||||
|
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
pw.kv.update(**{'status': 'completed'})
|
pw.kv.update(**{"status": "completed"})
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="SUCCESS", task_result=pw.url)
|
||||||
|
|
||||||
|
return pw.url
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True, queue="background")
|
||||||
|
def identify_missing_rules(
|
||||||
|
self,
|
||||||
|
pw_pks: List[int],
|
||||||
|
rule_package_pk: int,
|
||||||
|
):
|
||||||
|
from utilities.misc import PathwayUtils
|
||||||
|
|
||||||
|
rules = Package.objects.get(pk=rule_package_pk).get_applicable_rules()
|
||||||
|
|
||||||
|
rows: List[Any] = []
|
||||||
|
header = [
|
||||||
|
"Package Name",
|
||||||
|
"Pathway Name",
|
||||||
|
"Educt Name",
|
||||||
|
"Educt SMILES",
|
||||||
|
"Reaction Name",
|
||||||
|
"Reaction SMIRKS",
|
||||||
|
"Triggered Rules",
|
||||||
|
"Reactant SMARTS",
|
||||||
|
"Product SMARTS",
|
||||||
|
"Product Names",
|
||||||
|
"Product SMILES",
|
||||||
|
]
|
||||||
|
|
||||||
|
rows.append(header)
|
||||||
|
|
||||||
|
for pw in Pathway.objects.filter(pk__in=pw_pks):
|
||||||
|
pu = PathwayUtils(pw)
|
||||||
|
|
||||||
|
missing_rules = pu.find_missing_rules(rules)
|
||||||
|
|
||||||
|
package_name = pw.package.name
|
||||||
|
pathway_name = pw.name
|
||||||
|
|
||||||
|
for edge_url, rule_chain in missing_rules.items():
|
||||||
|
row: List[Any] = [package_name, pathway_name]
|
||||||
|
edge = Edge.objects.get(url=edge_url)
|
||||||
|
educts = edge.start_nodes.all()
|
||||||
|
|
||||||
|
for educt in educts:
|
||||||
|
row.append(educt.default_node_label.name)
|
||||||
|
row.append(educt.default_node_label.smiles)
|
||||||
|
|
||||||
|
row.append(edge.edge_label.name)
|
||||||
|
row.append(edge.edge_label.smirks())
|
||||||
|
|
||||||
|
rule_names = []
|
||||||
|
reactant_smarts = []
|
||||||
|
product_smarts = []
|
||||||
|
|
||||||
|
for r in rule_chain:
|
||||||
|
r = Rule.objects.get(url=r[0])
|
||||||
|
rule_names.append(r.name)
|
||||||
|
|
||||||
|
rs = r.reactants_smarts
|
||||||
|
if isinstance(rs, set):
|
||||||
|
rs = list(rs)
|
||||||
|
|
||||||
|
ps = r.products_smarts
|
||||||
|
if isinstance(ps, set):
|
||||||
|
ps = list(ps)
|
||||||
|
|
||||||
|
reactant_smarts.append(rs)
|
||||||
|
product_smarts.append(ps)
|
||||||
|
|
||||||
|
row.append(rule_names)
|
||||||
|
row.append(reactant_smarts)
|
||||||
|
row.append(product_smarts)
|
||||||
|
|
||||||
|
products = edge.end_nodes.all()
|
||||||
|
product_names = []
|
||||||
|
product_smiles = []
|
||||||
|
|
||||||
|
for product in products:
|
||||||
|
product_names.append(product.default_node_label.name)
|
||||||
|
product_smiles.append(product.default_node_label.smiles)
|
||||||
|
|
||||||
|
row.append(product_names)
|
||||||
|
row.append(product_smiles)
|
||||||
|
|
||||||
|
rows.append(row)
|
||||||
|
|
||||||
|
buffer = io.StringIO()
|
||||||
|
|
||||||
|
writer = csv.writer(buffer)
|
||||||
|
writer.writerows(rows)
|
||||||
|
|
||||||
|
buffer.seek(0)
|
||||||
|
|
||||||
|
return buffer.getvalue()
|
||||||
|
|||||||
@ -1,7 +1,21 @@
|
|||||||
from django import template
|
from django import template
|
||||||
|
from pydantic import AnyHttpUrl, ValidationError
|
||||||
|
from pydantic.type_adapter import TypeAdapter
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
url_adapter = TypeAdapter(AnyHttpUrl)
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def classname(obj):
|
def classname(obj):
|
||||||
return obj.__class__.__name__
|
return obj.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def is_url(value):
|
||||||
|
try:
|
||||||
|
url_adapter.validate_python(value)
|
||||||
|
return True
|
||||||
|
except ValidationError:
|
||||||
|
return False
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
257
epdb/urls.py
@ -1,99 +1,206 @@
|
|||||||
from django.urls import path, re_path
|
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
|
from django.urls import path, re_path
|
||||||
|
|
||||||
from . import views as v
|
from . import views as v
|
||||||
|
|
||||||
UUID = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}'
|
UUID = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Home
|
# Home
|
||||||
re_path(r'^$', v.index, name='index'),
|
re_path(r"^$", v.index, name="index"),
|
||||||
|
|
||||||
# Login
|
# Login
|
||||||
re_path(r'^login', v.login, name='login'),
|
re_path(r"^login", v.login, name="login"),
|
||||||
re_path(r'^logout', v.logout, name='logout'),
|
re_path(r"^logout", v.logout, name="logout"),
|
||||||
re_path(r'^register', v.register, name='register'),
|
re_path(r"^register", v.register, name="register"),
|
||||||
|
# Built-In views
|
||||||
# Built In views
|
path(
|
||||||
path('password_reset/', auth_views.PasswordResetView.as_view(
|
"password_reset/",
|
||||||
template_name='static/password_reset_form.html'
|
auth_views.PasswordResetView.as_view(template_name="static/password_reset_form.html"),
|
||||||
), name='password_reset'),
|
name="password_reset",
|
||||||
|
),
|
||||||
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(
|
path(
|
||||||
template_name='static/password_reset_done.html'
|
"password_reset/done/",
|
||||||
), name='password_reset_done'),
|
auth_views.PasswordResetDoneView.as_view(template_name="static/password_reset_done.html"),
|
||||||
|
name="password_reset_done",
|
||||||
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(
|
),
|
||||||
template_name='static/password_reset_confirm.html'
|
path(
|
||||||
), name='password_reset_confirm'),
|
"reset/<uidb64>/<token>/",
|
||||||
|
auth_views.PasswordResetConfirmView.as_view(
|
||||||
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(
|
template_name="static/password_reset_confirm.html"
|
||||||
template_name='static/password_reset_complete.html'
|
),
|
||||||
), name='password_reset_complete'),
|
name="password_reset_confirm",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"reset/done/",
|
||||||
|
auth_views.PasswordResetCompleteView.as_view(
|
||||||
|
template_name="static/password_reset_complete.html"
|
||||||
|
),
|
||||||
|
name="password_reset_complete",
|
||||||
|
),
|
||||||
# Top level urls
|
# Top level urls
|
||||||
re_path(r'^package$', v.packages, name='packages'),
|
re_path(r"^package$", v.packages, name="packages"),
|
||||||
re_path(r'^compound$', v.compounds, name='compounds'),
|
re_path(r"^compound$", v.compounds, name="compounds"),
|
||||||
re_path(r'^rule$', v.rules, name='rules'),
|
re_path(r"^rule$", v.rules, name="rules"),
|
||||||
re_path(r'^reaction$', v.reactions, name='reactions'),
|
re_path(r"^reaction$", v.reactions, name="reactions"),
|
||||||
re_path(r'^pathway$', v.pathways, name='pathways'),
|
re_path(r"^pathway$", v.pathways, name="pathways"),
|
||||||
re_path(r'^scenario$', v.scenarios, name='scenarios'),
|
re_path(r"^scenario$", v.scenarios, name="scenarios"),
|
||||||
re_path(r'^model$', v.models, name='model'),
|
re_path(r"^model$", v.models, name="model"),
|
||||||
re_path(r'^user$', v.users, name='users'),
|
re_path(r"^user$", v.users, name="users"),
|
||||||
re_path(r'^group$', v.groups, name='groups'),
|
re_path(r"^group$", v.groups, name="groups"),
|
||||||
re_path(r'^search$', v.search, name='search'),
|
re_path(r"^search$", v.search, name="search"),
|
||||||
|
re_path(r"^predict$", v.predict_pathway, name="predict_pathway"),
|
||||||
|
|
||||||
# User Detail
|
# User Detail
|
||||||
re_path(rf'^user/(?P<user_uuid>{UUID})', v.user, name='user'),
|
re_path(rf"^user/(?P<user_uuid>{UUID})", v.user, name="user"),
|
||||||
# Group Detail
|
# Group Detail
|
||||||
re_path(rf'^group/(?P<group_uuid>{UUID})$', v.group, name='group_detail'),
|
re_path(rf"^group/(?P<group_uuid>{UUID})$", v.group, name="group detail"),
|
||||||
|
|
||||||
# "in package" urls
|
# "in package" urls
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})$', v.package, name='package_detail'),
|
re_path(rf"^package/(?P<package_uuid>{UUID})$", v.package, name="package detail"),
|
||||||
# Compound
|
# Compound
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/compound$', v.package_compounds, name='package compound list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})$', v.package_compound, name='package compound detail'),
|
rf"^package/(?P<package_uuid>{UUID})/compound$",
|
||||||
|
v.package_compounds,
|
||||||
|
name="package compound list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})$",
|
||||||
|
v.package_compound,
|
||||||
|
name="package compound detail",
|
||||||
|
),
|
||||||
# Compound Structure
|
# Compound Structure
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})/structure$', v.package_compound_structures, name='package compound structure list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})/structure/(?P<structure_uuid>{UUID})$', v.package_compound_structure, name='package compound structure detail'),
|
rf"^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})/structure$",
|
||||||
|
v.package_compound_structures,
|
||||||
|
name="package compound structure list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})/structure/(?P<structure_uuid>{UUID})$",
|
||||||
|
v.package_compound_structure,
|
||||||
|
name="package compound structure detail",
|
||||||
|
),
|
||||||
# Rule
|
# Rule
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/rule$', v.package_rules, name='package rule list'),
|
re_path(rf"^package/(?P<package_uuid>{UUID})/rule$", v.package_rules, name="package rule list"),
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/simple-ambit-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
|
rf"^package/(?P<package_uuid>{UUID})/rule/(?P<rule_uuid>{UUID})$",
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
|
v.package_rule,
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
|
name="package rule detail",
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/simple-ambit-rule/(?P<rule_uuid>{UUID})$",
|
||||||
|
v.package_rule,
|
||||||
|
name="package rule detail",
|
||||||
|
),
|
||||||
|
# re_path(
|
||||||
|
# rf"^package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$",
|
||||||
|
# v.package_rule,
|
||||||
|
# name="package rule detail",
|
||||||
|
# ),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$",
|
||||||
|
v.package_rule,
|
||||||
|
name="package rule detail",
|
||||||
|
),
|
||||||
|
# re_path(
|
||||||
|
# rf"^package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$",
|
||||||
|
# v.package_rule,
|
||||||
|
# name="package rule detail",
|
||||||
|
# ),
|
||||||
|
# EnzymeLinks
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/rule/(?P<rule_uuid>{UUID})/enzymelink/(?P<enzymelink_uuid>{UUID})$",
|
||||||
|
v.package_rule_enzymelink,
|
||||||
|
name="package rule enzymelink detail",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/simple-ambit-rule/(?P<rule_uuid>{UUID})/enzymelink/(?P<enzymelink_uuid>{UUID})$",
|
||||||
|
v.package_rule_enzymelink,
|
||||||
|
name="package rule enzymelink detail",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})/enzymelink/(?P<enzymelink_uuid>{UUID})$",
|
||||||
|
v.package_rule_enzymelink,
|
||||||
|
name="package rule enzymelink detail",
|
||||||
|
),
|
||||||
# Reaction
|
# Reaction
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/reaction$', v.package_reactions, name='package reaction list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/reaction/(?P<reaction_uuid>{UUID})$', v.package_reaction, name='package reaction detail'),
|
rf"^package/(?P<package_uuid>{UUID})/reaction$",
|
||||||
|
v.package_reactions,
|
||||||
|
name="package reaction list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/reaction/(?P<reaction_uuid>{UUID})$",
|
||||||
|
v.package_reaction,
|
||||||
|
name="package reaction detail",
|
||||||
|
),
|
||||||
# # Pathway
|
# # Pathway
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway$', v.package_pathways, name='package pathway list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})$', v.package_pathway, name='package pathway detail'),
|
rf"^package/(?P<package_uuid>{UUID})/pathway$",
|
||||||
|
v.package_pathways,
|
||||||
|
name="package pathway list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})$",
|
||||||
|
v.package_pathway,
|
||||||
|
name="package pathway detail",
|
||||||
|
),
|
||||||
# Pathway Nodes
|
# Pathway Nodes
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/node$', v.package_pathway_nodes, name='package pathway node list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/node/(?P<node_uuid>{UUID})$', v.package_pathway_node, name='package pathway node detail'),
|
rf"^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/node$",
|
||||||
|
v.package_pathway_nodes,
|
||||||
|
name="package pathway node list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/node/(?P<node_uuid>{UUID})$",
|
||||||
|
v.package_pathway_node,
|
||||||
|
name="package pathway node detail",
|
||||||
|
),
|
||||||
# Pathway Edges
|
# Pathway Edges
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/edge$', v.package_pathway_edges, name='package pathway edge list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/edge/(?P<edge_uuid>{UUID})$', v.package_pathway_edge, name='package pathway edge detail'),
|
rf"^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/edge$",
|
||||||
|
v.package_pathway_edges,
|
||||||
|
name="package pathway edge list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/edge/(?P<edge_uuid>{UUID})$",
|
||||||
|
v.package_pathway_edge,
|
||||||
|
name="package pathway edge detail",
|
||||||
|
),
|
||||||
# Scenario
|
# Scenario
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/scenario$', v.package_scenarios, name='package scenario list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/scenario/(?P<scenario_uuid>{UUID})$', v.package_scenario, name='package scenario detail'),
|
rf"^package/(?P<package_uuid>{UUID})/scenario$",
|
||||||
|
v.package_scenarios,
|
||||||
|
name="package scenario list",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/scenario/(?P<scenario_uuid>{UUID})$",
|
||||||
|
v.package_scenario,
|
||||||
|
name="package scenario detail",
|
||||||
|
),
|
||||||
# Model
|
# Model
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/model$', v.package_models, name='package model list'),
|
re_path(
|
||||||
re_path(rf'^package/(?P<package_uuid>{UUID})/model/(?P<model_uuid>{UUID})$', v.package_model,name='package model detail'),
|
rf"^package/(?P<package_uuid>{UUID})/model$", v.package_models, name="package model list"
|
||||||
|
),
|
||||||
re_path(r'^setting$', v.settings, name='settings'),
|
re_path(
|
||||||
re_path(rf'^setting/(?P<setting_uuid>{UUID})', v.setting, name='setting'),
|
rf"^package/(?P<package_uuid>{UUID})/model/(?P<model_uuid>{UUID})$",
|
||||||
|
v.package_model,
|
||||||
re_path(r'^indigo/info$', v.indigo, name='indigo_info'),
|
name="package model detail",
|
||||||
re_path(r'^indigo/aromatize$', v.aromatize, name='indigo_aromatize'),
|
),
|
||||||
re_path(r'^indigo/dearomatize$', v.dearomatize, name='indigo_dearomatize'),
|
re_path(r"^setting$", v.settings, name="settings"),
|
||||||
re_path(r'^indigo/layout$', v.layout, name='indigo_layout'),
|
re_path(rf"^setting/(?P<setting_uuid>{UUID})", v.setting, name="setting"),
|
||||||
|
re_path(r"^indigo/info$", v.indigo, name="indigo_info"),
|
||||||
re_path(r'^depict$', v.depict, name='depict'),
|
re_path(r"^indigo/aromatize$", v.aromatize, name="indigo_aromatize"),
|
||||||
|
re_path(r"^indigo/dearomatize$", v.dearomatize, name="indigo_dearomatize"),
|
||||||
|
re_path(r"^indigo/layout$", v.layout, name="indigo_layout"),
|
||||||
|
re_path(r"^depict$", v.depict, name="depict"),
|
||||||
|
re_path(r"^jobs", v.jobs, name="jobs"),
|
||||||
# OAuth Stuff
|
# OAuth Stuff
|
||||||
path("o/userinfo/", v.userinfo, name="oauth_userinfo"),
|
path("o/userinfo/", v.userinfo, name="oauth_userinfo"),
|
||||||
|
# Static Pages
|
||||||
|
re_path(r"^terms$", v.static_terms_of_use, name="terms_of_use"),
|
||||||
|
re_path(r"^privacy$", v.static_privacy_policy, name="privacy_policy"),
|
||||||
|
re_path(r"^cookie-policy$", v.static_cookie_policy, name="cookie_policy"),
|
||||||
|
re_path(r"^about$", v.static_about_us, name="about_us"),
|
||||||
|
re_path(r"^contact$", v.static_contact_support, name="contact_support"),
|
||||||
|
re_path(r"^careers$", v.static_careers, name="careers"),
|
||||||
|
re_path(r"^cite$", v.static_cite, name="cite"),
|
||||||
|
re_path(r"^legal$", v.static_legal, name="legal"),
|
||||||
]
|
]
|
||||||
|
|||||||
2655
epdb/views.py
BIN
fixtures/models/2750eaca-bc13-4018-81c2-f7f9d94bc435_ds.pkl
Normal file
BIN
fixtures/models/2750eaca-bc13-4018-81c2-f7f9d94bc435_mod.pkl
Normal file
8328
fixtures/packages/2025-07-18/external_identifiers.csv
Normal file
BIN
fixtures/test_fixtures_incl_model.jsonl.gz
Normal file
@ -12,4 +12,5 @@ urlpatterns = [
|
|||||||
re_path(rf'^migration/package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$', v.migration_detail, name='migration detail'),
|
re_path(rf'^migration/package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$', v.migration_detail, name='migration detail'),
|
||||||
re_path(rf'^migration/package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$', v.migration_detail, name='migration detail'),
|
re_path(rf'^migration/package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$', v.migration_detail, name='migration detail'),
|
||||||
re_path(rf'^migration/package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$', v.migration_detail, name='migration detail'),
|
re_path(rf'^migration/package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$', v.migration_detail, name='migration detail'),
|
||||||
|
re_path(rf'^migration/compare$', v.compare, name='compare'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,80 +1,123 @@
|
|||||||
import gzip
|
import gzip
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from django.conf import settings as s
|
from django.conf import settings as s
|
||||||
|
from django.http import HttpResponseNotAllowed
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
from epdb.logic import PackageManager
|
from epdb.logic import PackageManager
|
||||||
from epdb.models import Rule
|
from epdb.models import Rule, SimpleAmbitRule, Package, CompoundStructure
|
||||||
from epdb.views import get_base_context, _anonymous_or_real
|
from epdb.views import get_base_context, _anonymous_or_real
|
||||||
from utilities.chem import FormatConverter
|
from utilities.chem import FormatConverter
|
||||||
|
|
||||||
|
|
||||||
|
from rdkit import Chem
|
||||||
|
from rdkit.Chem.MolStandardize import rdMolStandardize
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_smiles(smiles):
|
||||||
|
m1 = Chem.MolFromSmiles(smiles)
|
||||||
|
if m1 is None:
|
||||||
|
print("Couldnt read smi: ", smiles)
|
||||||
|
return smiles
|
||||||
|
Chem.RemoveStereochemistry(m1)
|
||||||
|
# Normalizer takes care of charge/tautomer/resonance standardization
|
||||||
|
normalizer = rdMolStandardize.Normalizer()
|
||||||
|
return Chem.MolToSmiles(normalizer.normalize(m1), canonical=True)
|
||||||
|
|
||||||
|
|
||||||
|
def run_both_engines(SMILES, SMIRKS):
|
||||||
|
from envipy_ambit import apply
|
||||||
|
|
||||||
|
ambit_res = apply(SMIRKS, SMILES)
|
||||||
|
# ambit_res, ambit_errors = FormatConverter.sanitize_smiles([str(s) for s in ambit_res])
|
||||||
|
|
||||||
|
ambit_res = list(
|
||||||
|
set(
|
||||||
|
[
|
||||||
|
normalize_smiles(str(x))
|
||||||
|
for x in FormatConverter.sanitize_smiles([str(s) for s in ambit_res])[0]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
products = FormatConverter.apply(SMILES, SMIRKS)
|
||||||
|
|
||||||
|
all_rdkit_prods = []
|
||||||
|
for ps in products:
|
||||||
|
for p in ps:
|
||||||
|
all_rdkit_prods.append(p)
|
||||||
|
|
||||||
|
all_rdkit_prods = list(set(all_rdkit_prods))
|
||||||
|
# all_rdkit_res, rdkit_errors = FormatConverter.sanitize_smiles(all_rdkit_prods)
|
||||||
|
all_rdkit_res = list(
|
||||||
|
set(
|
||||||
|
[
|
||||||
|
normalize_smiles(str(x))
|
||||||
|
for x in FormatConverter.sanitize_smiles(
|
||||||
|
[str(s) for s in all_rdkit_prods]
|
||||||
|
)[0]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# return ambit_res, ambit_errors, all_rdkit_res, rdkit_errors
|
||||||
|
return ambit_res, 0, all_rdkit_res, 0
|
||||||
|
|
||||||
|
|
||||||
def migration(request):
|
def migration(request):
|
||||||
if request.method == 'GET':
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
|
|
||||||
if os.path.exists(s.BASE_DIR / 'fixtures' / 'migration_status_per_rule.json') and request.GET.get(
|
if (
|
||||||
"force") is None:
|
os.path.exists(s.BASE_DIR / "fixtures" / "migration_status_per_rule.json")
|
||||||
migration_status = json.load(open(s.BASE_DIR / 'fixtures' / 'migration_status_per_rule.json'))
|
and request.GET.get("force") is None
|
||||||
|
):
|
||||||
|
migration_status = json.load(
|
||||||
|
open(s.BASE_DIR / "fixtures" / "migration_status_per_rule.json")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
data = json.load(gzip.open(s.BASE_DIR / 'fixtures' / 'ambit_rules.json.gz', 'rb'))
|
BBD = Package.objects.get(
|
||||||
|
url="http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1"
|
||||||
results = []
|
)
|
||||||
|
ALL_SMILES = [
|
||||||
|
cs.smiles
|
||||||
|
for cs in CompoundStructure.objects.filter(compound__package=BBD)
|
||||||
|
]
|
||||||
|
RULES = SimpleAmbitRule.objects.filter(package=BBD)
|
||||||
|
|
||||||
|
results = list()
|
||||||
|
num_rules = len(RULES)
|
||||||
success = 0
|
success = 0
|
||||||
error = 0
|
error = 0
|
||||||
total = 0
|
total = 0
|
||||||
|
|
||||||
num_keys = len(data.keys())
|
for i, r in enumerate(RULES):
|
||||||
for i, bt_rule_name in enumerate(data.keys()):
|
logger.debug(f"\r{i + 1:03d}/{num_rules}")
|
||||||
print(f"{i + 1}/{num_keys}")
|
|
||||||
bt_rule = data[bt_rule_name]
|
|
||||||
smirks = bt_rule['smirks']
|
|
||||||
|
|
||||||
all_prods = set()
|
|
||||||
|
|
||||||
res = True
|
res = True
|
||||||
|
for smiles in ALL_SMILES:
|
||||||
|
try:
|
||||||
|
ambit_res, _, rdkit_res, _ = run_both_engines(smiles, r.smirks)
|
||||||
|
|
||||||
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
res &= set(ambit_res) == set(rdkit_res)
|
||||||
|
except Exception as e:
|
||||||
products = FormatConverter.apply(comp['smiles'], smirks)
|
logger.error(e)
|
||||||
|
|
||||||
all_rdkit_prods = []
|
|
||||||
for ps in products:
|
|
||||||
for p in ps:
|
|
||||||
all_rdkit_prods.append(p)
|
|
||||||
|
|
||||||
all_rdkit_prods = list(set(all_rdkit_prods))
|
|
||||||
|
|
||||||
ambit_smiles, ambit_errors = FormatConverter.sanitize_smiles(ambit_prod)
|
|
||||||
rdkit_smiles, rdkit_errors = FormatConverter.sanitize_smiles(all_rdkit_prods)
|
|
||||||
|
|
||||||
for x in ambit_smiles:
|
|
||||||
all_prods.add(x)
|
|
||||||
|
|
||||||
# TODO mode "intersection"
|
|
||||||
# partial_res = (len(set(ambit_smiles).intersection(set(rdkit_smiles))) > 0) or (len(ambit_smiles) == 0)
|
|
||||||
# FAILED (failures=37)
|
|
||||||
|
|
||||||
# TODO mode = "full ambit"
|
|
||||||
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(ambit_smiles)
|
|
||||||
# FAILED (failures=46)
|
|
||||||
|
|
||||||
# TODO mode = "equality"
|
|
||||||
partial_res = set(ambit_smiles) == set(rdkit_smiles)
|
|
||||||
# FAILED (failures=69)
|
|
||||||
|
|
||||||
res &= partial_res
|
|
||||||
|
|
||||||
results.append(
|
results.append(
|
||||||
{
|
{
|
||||||
'name': bt_rule_name,
|
"name": r.name,
|
||||||
'id': bt_rule['id'].split('/')[-1],
|
"detail_url": s.SERVER_URL
|
||||||
'url': bt_rule['id'],
|
+ "/migration/"
|
||||||
'status': res,
|
+ r.url.replace("https://envipath.org/", "").replace(
|
||||||
'detail_url': s.SERVER_URL + '/migration/' + bt_rule['id'].replace('https://envipath.org/', '')
|
"http://localhost:8000/", ""
|
||||||
|
),
|
||||||
|
"id": str(r.uuid),
|
||||||
|
"url": r.url,
|
||||||
|
"status": res,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -84,95 +127,82 @@ def migration(request):
|
|||||||
error += 1
|
error += 1
|
||||||
|
|
||||||
total += 1
|
total += 1
|
||||||
|
results = sorted(results, key=lambda x: (x["status"], x["name"]))
|
||||||
results = sorted(results, key=lambda x: (x['status'], x['name']))
|
|
||||||
|
|
||||||
migration_status = {
|
migration_status = {
|
||||||
'results': results,
|
"results": results,
|
||||||
'success': success,
|
"success": success,
|
||||||
'error': error,
|
"error": error,
|
||||||
'total': total
|
"total": total,
|
||||||
}
|
}
|
||||||
|
|
||||||
json.dump(migration_status, open(s.BASE_DIR / 'fixtures' / 'migration_status_per_rule.json', 'w'))
|
json.dump(
|
||||||
|
migration_status,
|
||||||
|
open(s.BASE_DIR / "fixtures" / "migration_status_per_rule.json", "w"),
|
||||||
|
)
|
||||||
|
|
||||||
for r in migration_status['results']:
|
for r in migration_status["results"]:
|
||||||
r['detail_url'] = r['detail_url'].replace('http://localhost:8000', s.SERVER_URL)
|
r["detail_url"] = r["detail_url"].replace(
|
||||||
|
"http://localhost:8000", s.SERVER_URL
|
||||||
|
)
|
||||||
|
|
||||||
context.update(**migration_status)
|
context.update(**migration_status)
|
||||||
|
|
||||||
return render(request, 'migration.html', context)
|
return render(request, "migration.html", context)
|
||||||
|
|
||||||
|
|
||||||
def migration_detail(request, package_uuid, rule_uuid):
|
def migration_detail(request, package_uuid, rule_uuid):
|
||||||
current_user = _anonymous_or_real(request)
|
current_user = _anonymous_or_real(request)
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == "GET":
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
|
|
||||||
p = PackageManager.get_package_by_id(current_user, package_uuid)
|
BBD = Package.objects.get(name="EAWAG-BBD")
|
||||||
rule = Rule.objects.get(package=p, uuid=rule_uuid)
|
STRUCTURES = CompoundStructure.objects.filter(compound__package=BBD)
|
||||||
|
rule = Rule.objects.get(package=BBD, uuid=rule_uuid)
|
||||||
|
|
||||||
bt_rule_name = rule.name
|
bt_rule_name = rule.name
|
||||||
|
smirks = rule.smirks
|
||||||
data = json.load(gzip.open(s.BASE_DIR / 'fixtures' / 'ambit_rules.json.gz', 'rb'))
|
|
||||||
|
|
||||||
bt_rule = data[bt_rule_name]
|
|
||||||
smirks = bt_rule['smirks']
|
|
||||||
|
|
||||||
results = []
|
|
||||||
|
|
||||||
res = True
|
res = True
|
||||||
|
results = []
|
||||||
|
|
||||||
all_prods = set()
|
all_prods = set()
|
||||||
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
for structure in STRUCTURES:
|
||||||
# if comp['smiles'] != 'CC1=C(C(=C(C=N1)CO)C=O)O':
|
ambit_smiles, ambit_errors, rdkit_smiles, rdkit_errors = run_both_engines(
|
||||||
# continue
|
structure.smiles, smirks
|
||||||
|
)
|
||||||
products = FormatConverter.apply(comp['smiles'], smirks)
|
|
||||||
|
|
||||||
all_rdkit_prods = []
|
|
||||||
for ps in products:
|
|
||||||
for p in ps:
|
|
||||||
all_rdkit_prods.append(p)
|
|
||||||
|
|
||||||
all_rdkit_prods = list(set(all_rdkit_prods))
|
|
||||||
|
|
||||||
ambit_smiles, ambit_errors = FormatConverter.sanitize_smiles(ambit_prod)
|
|
||||||
rdkit_smiles, rdkit_errors = FormatConverter.sanitize_smiles(all_rdkit_prods)
|
|
||||||
|
|
||||||
for x in ambit_smiles:
|
for x in ambit_smiles:
|
||||||
all_prods.add(x)
|
all_prods.add(x)
|
||||||
|
|
||||||
# TODO mode "intersection"
|
# TODO mode "intersection"
|
||||||
# partial_res = (len(set(ambit_smiles).intersection(set(rdkit_smiles))) > 0) or (len(ambit_smiles) == 0)
|
# partial_res = (len(set(ambit_smiles).intersection(set(rdkit_smiles))) > 0) or (len(ambit_smiles) == 0)
|
||||||
# FAILED (failures=37)
|
# FAILED (failures=18)
|
||||||
|
|
||||||
# TODO mode = "full ambit"
|
# TODO mode = "full ambit"
|
||||||
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(ambit_smiles)
|
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(set(ambit_smiles))
|
||||||
# FAILED (failures=46)
|
# FAILED (failures=34)
|
||||||
|
|
||||||
# TODO mode = "equality"
|
# TODO mode = "equality"
|
||||||
partial_res = set(ambit_smiles) == set(rdkit_smiles)
|
partial_res = set(ambit_smiles) == set(rdkit_smiles)
|
||||||
# FAILED (failures=69)
|
# FAILED (failures=30)
|
||||||
|
|
||||||
#
|
|
||||||
if len(ambit_smiles) or len(rdkit_smiles):
|
if len(ambit_smiles) or len(rdkit_smiles):
|
||||||
temp = {
|
temp = {
|
||||||
'url': comp['id'],
|
"url": structure.url,
|
||||||
'id': comp['id'].split('/')[-1],
|
"id": str(structure.uuid),
|
||||||
'name': comp['name'],
|
"name": structure.name,
|
||||||
'initial_smiles': comp['smiles'],
|
"initial_smiles": structure.smiles,
|
||||||
'ambit_smiles': sorted(list(ambit_smiles)),
|
"ambit_smiles": sorted(list(ambit_smiles)),
|
||||||
'rdkit_smiles': sorted(list(rdkit_smiles)),
|
"rdkit_smiles": sorted(list(rdkit_smiles)),
|
||||||
'status': set(ambit_smiles) == set(rdkit_smiles),
|
"status": set(ambit_smiles) == set(rdkit_smiles),
|
||||||
}
|
}
|
||||||
|
detail = f"""
|
||||||
if set(ambit_smiles) != set(rdkit_smiles):
|
|
||||||
detail = f"""
|
|
||||||
BT: {bt_rule_name}
|
BT: {bt_rule_name}
|
||||||
SMIRKS: {bt_rule['smirks']}
|
SMIRKS: {smirks}
|
||||||
Compound: {comp['smiles']}
|
Compound: {structure.smiles}
|
||||||
Compound URL: {comp['id']}
|
Compound URL: {structure.url}
|
||||||
Num ambit: {len(set(ambit_smiles))}
|
Num ambit: {len(set(ambit_smiles))}
|
||||||
Num rdkit: {len(set(rdkit_smiles))}
|
Num rdkit: {len(set(rdkit_smiles))}
|
||||||
Num Intersection A: {len(set(ambit_smiles).intersection(set(rdkit_smiles)))}
|
Num Intersection A: {len(set(ambit_smiles).intersection(set(rdkit_smiles)))}
|
||||||
@ -185,15 +215,63 @@ def migration_detail(request, package_uuid, rule_uuid):
|
|||||||
rdkit_errors: {rdkit_errors}
|
rdkit_errors: {rdkit_errors}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
temp['detail'] = '\n'.join([x.strip() for x in detail.split('\n')])
|
temp["detail"] = "\n".join([x.strip() for x in detail.split("\n")])
|
||||||
# print(detail.strip())
|
|
||||||
|
|
||||||
results.append(temp)
|
results.append(temp)
|
||||||
|
|
||||||
res &= partial_res
|
res &= partial_res
|
||||||
|
|
||||||
results = sorted(results, key=lambda x: x['status'])
|
results = sorted(results, key=lambda x: x["status"])
|
||||||
context['results'] = results
|
context["results"] = results
|
||||||
context['res'] = res
|
context["res"] = res
|
||||||
context['bt_rule_name'] = bt_rule_name
|
context["bt_rule_name"] = bt_rule_name
|
||||||
return render(request, 'migration_detail.html', context)
|
return render(request, "migration_detail.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
def compare(request):
|
||||||
|
context = get_base_context(request)
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
context["smirks"] = (
|
||||||
|
"[#1,#6:6][#7;X3;!$(NC1CC1)!$([N][C]=O)!$([!#8]CNC=O):1]([#1,#6:7])[#6;A;X4:2][H:3]>>[#1,#6:6][#7;X3:1]([#1,#6:7])[H:3].[#6;A:2]=O"
|
||||||
|
)
|
||||||
|
context["smiles"] = (
|
||||||
|
"C(CC(=O)N[C@@H](CS[Se-])C(=O)NCC(=O)[O-])[C@@H](C(=O)[O-])N"
|
||||||
|
)
|
||||||
|
return render(request, "compare.html", context)
|
||||||
|
|
||||||
|
elif request.method == "POST":
|
||||||
|
smiles = request.POST.get("smiles")
|
||||||
|
smirks = request.POST.get("smirks")
|
||||||
|
|
||||||
|
from envipy_ambit import apply
|
||||||
|
|
||||||
|
ambit_res = apply(smirks, smiles)
|
||||||
|
ambit_res, _ = FormatConverter.sanitize_smiles([str(x) for x in ambit_res])
|
||||||
|
|
||||||
|
products = FormatConverter.apply(smiles, smirks)
|
||||||
|
|
||||||
|
all_rdkit_prods = []
|
||||||
|
for ps in products:
|
||||||
|
for p in ps:
|
||||||
|
all_rdkit_prods.append(p)
|
||||||
|
|
||||||
|
all_rdkit_prods = list(set(all_rdkit_prods))
|
||||||
|
|
||||||
|
rdkit_res, _ = FormatConverter.sanitize_smiles(all_rdkit_prods)
|
||||||
|
context["result"] = True
|
||||||
|
context["ambit_res"] = sorted(set(ambit_res))
|
||||||
|
context["rdkit_res"] = sorted(set(rdkit_res))
|
||||||
|
context["diff"] = sorted(set(ambit_res).difference(set(rdkit_res)))
|
||||||
|
context["smirks"] = smirks
|
||||||
|
context["smiles"] = smiles
|
||||||
|
|
||||||
|
r = SimpleAmbitRule.objects.filter(smirks=smirks)
|
||||||
|
|
||||||
|
if r.exists():
|
||||||
|
context["rule"] = r.first()
|
||||||
|
|
||||||
|
return render(request, "compare.html", context)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return HttpResponseNotAllowed(["GET", "POST"])
|
||||||
|
|||||||
25
package.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "envipy",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "enviPath UI - Tailwind CSS + DaisyUI",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tailwindcss -i static/css/input.css -o static/css/output.css --watch=always",
|
||||||
|
"build": "tailwindcss -i static/css/input.css -o static/css/output.css --minify"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/cli": "^4.1.16",
|
||||||
|
"@tailwindcss/postcss": "^4.1.16",
|
||||||
|
"daisyui": "^5.4.3",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"prettier": "^3.6.2",
|
||||||
|
"prettier-plugin-jinja-template": "^2.1.0",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.7.1",
|
||||||
|
"tailwindcss": "^4.1.16"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"django",
|
||||||
|
"tailwindcss",
|
||||||
|
"daisyui"
|
||||||
|
]
|
||||||
|
}
|
||||||
740
pnpm-lock.yaml
generated
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
devDependencies:
|
||||||
|
'@tailwindcss/cli':
|
||||||
|
specifier: ^4.1.16
|
||||||
|
version: 4.1.16
|
||||||
|
'@tailwindcss/postcss':
|
||||||
|
specifier: ^4.1.16
|
||||||
|
version: 4.1.16
|
||||||
|
daisyui:
|
||||||
|
specifier: ^5.4.3
|
||||||
|
version: 5.4.3
|
||||||
|
postcss:
|
||||||
|
specifier: ^8.5.6
|
||||||
|
version: 8.5.6
|
||||||
|
prettier:
|
||||||
|
specifier: ^3.6.2
|
||||||
|
version: 3.6.2
|
||||||
|
prettier-plugin-jinja-template:
|
||||||
|
specifier: ^2.1.0
|
||||||
|
version: 2.1.0(prettier@3.6.2)
|
||||||
|
prettier-plugin-tailwindcss:
|
||||||
|
specifier: ^0.7.1
|
||||||
|
version: 0.7.1(prettier@3.6.2)
|
||||||
|
tailwindcss:
|
||||||
|
specifier: ^4.1.16
|
||||||
|
version: 4.1.16
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@alloc/quick-lru@5.2.0':
|
||||||
|
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||||
|
|
||||||
|
'@jridgewell/remapping@2.3.5':
|
||||||
|
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2':
|
||||||
|
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
|
'@parcel/watcher-android-arm64@2.5.1':
|
||||||
|
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@parcel/watcher-darwin-arm64@2.5.1':
|
||||||
|
resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@parcel/watcher-darwin-x64@2.5.1':
|
||||||
|
resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@parcel/watcher-freebsd-x64@2.5.1':
|
||||||
|
resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm-glibc@2.5.1':
|
||||||
|
resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm-musl@2.5.1':
|
||||||
|
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
||||||
|
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
||||||
|
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
||||||
|
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-x64-musl@2.5.1':
|
||||||
|
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@parcel/watcher-win32-arm64@2.5.1':
|
||||||
|
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@parcel/watcher-win32-ia32@2.5.1':
|
||||||
|
resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@parcel/watcher-win32-x64@2.5.1':
|
||||||
|
resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@parcel/watcher@2.5.1':
|
||||||
|
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
||||||
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
|
'@tailwindcss/cli@4.1.16':
|
||||||
|
resolution: {integrity: sha512-dsnANPrh2ZooHyZ/8uJhc9ecpcYtufToc21NY09NS9vF16rxPCjJ8dP7TUAtPqlUJTHSmRkN2hCdoYQIlgh4fw==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@tailwindcss/node@4.1.16':
|
||||||
|
resolution: {integrity: sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==}
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-android-arm64@4.1.16':
|
||||||
|
resolution: {integrity: sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-arm64@4.1.16':
|
||||||
|
resolution: {integrity: sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-x64@4.1.16':
|
||||||
|
resolution: {integrity: sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-freebsd-x64@4.1.16':
|
||||||
|
resolution: {integrity: sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16':
|
||||||
|
resolution: {integrity: sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-gnu@4.1.16':
|
||||||
|
resolution: {integrity: sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-musl@4.1.16':
|
||||||
|
resolution: {integrity: sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-gnu@4.1.16':
|
||||||
|
resolution: {integrity: sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-musl@4.1.16':
|
||||||
|
resolution: {integrity: sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-wasm32-wasi@4.1.16':
|
||||||
|
resolution: {integrity: sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [wasm32]
|
||||||
|
bundledDependencies:
|
||||||
|
- '@napi-rs/wasm-runtime'
|
||||||
|
- '@emnapi/core'
|
||||||
|
- '@emnapi/runtime'
|
||||||
|
- '@tybys/wasm-util'
|
||||||
|
- '@emnapi/wasi-threads'
|
||||||
|
- tslib
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-arm64-msvc@4.1.16':
|
||||||
|
resolution: {integrity: sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-x64-msvc@4.1.16':
|
||||||
|
resolution: {integrity: sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide@4.1.16':
|
||||||
|
resolution: {integrity: sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
|
'@tailwindcss/postcss@4.1.16':
|
||||||
|
resolution: {integrity: sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A==}
|
||||||
|
|
||||||
|
braces@3.0.3:
|
||||||
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
daisyui@5.4.3:
|
||||||
|
resolution: {integrity: sha512-dfDCJnN4utErGoWfElgdEE252FtfHV9Mxj5Dq1+JzUq3nVkluWdF3JYykP0Xy/y/yArnPXYztO1tLNCow3kjmg==}
|
||||||
|
|
||||||
|
detect-libc@1.0.3:
|
||||||
|
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
detect-libc@2.1.2:
|
||||||
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
enhanced-resolve@5.18.3:
|
||||||
|
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
fill-range@7.1.1:
|
||||||
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
graceful-fs@4.2.11:
|
||||||
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
|
||||||
|
is-extglob@2.1.1:
|
||||||
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-glob@4.0.3:
|
||||||
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-number@7.0.0:
|
||||||
|
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
||||||
|
engines: {node: '>=0.12.0'}
|
||||||
|
|
||||||
|
jiti@2.6.1:
|
||||||
|
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
lightningcss-android-arm64@1.30.2:
|
||||||
|
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
lightningcss-darwin-arm64@1.30.2:
|
||||||
|
resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
lightningcss-darwin-x64@1.30.2:
|
||||||
|
resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
lightningcss-freebsd-x64@1.30.2:
|
||||||
|
resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||||
|
resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-gnu@1.30.2:
|
||||||
|
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-musl@1.30.2:
|
||||||
|
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
lightningcss-linux-x64-gnu@1.30.2:
|
||||||
|
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
lightningcss-linux-x64-musl@1.30.2:
|
||||||
|
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
lightningcss-win32-arm64-msvc@1.30.2:
|
||||||
|
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
lightningcss-win32-x64-msvc@1.30.2:
|
||||||
|
resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
lightningcss@1.30.2:
|
||||||
|
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
|
micromatch@4.0.8:
|
||||||
|
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||||
|
engines: {node: '>=8.6'}
|
||||||
|
|
||||||
|
mri@1.2.0:
|
||||||
|
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
nanoid@3.3.11:
|
||||||
|
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||||
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
node-addon-api@7.1.1:
|
||||||
|
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
|
picomatch@2.3.1:
|
||||||
|
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||||
|
engines: {node: '>=8.6'}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
prettier-plugin-jinja-template@2.1.0:
|
||||||
|
resolution: {integrity: sha512-mzoCp2Oy9BDSug80fw3B3J4n4KQj1hRvoQOL1akqcDKBb5nvYxrik9zUEDs4AEJ6nK7QDTGoH0y9rx7AlnQ78Q==}
|
||||||
|
peerDependencies:
|
||||||
|
prettier: ^3.0.0
|
||||||
|
|
||||||
|
prettier-plugin-tailwindcss@0.7.1:
|
||||||
|
resolution: {integrity: sha512-Bzv1LZcuiR1Sk02iJTS1QzlFNp/o5l2p3xkopwOrbPmtMeh3fK9rVW5M3neBQzHq+kGKj/4LGQMTNcTH4NGPtQ==}
|
||||||
|
engines: {node: '>=20.19'}
|
||||||
|
peerDependencies:
|
||||||
|
'@ianvs/prettier-plugin-sort-imports': '*'
|
||||||
|
'@prettier/plugin-hermes': '*'
|
||||||
|
'@prettier/plugin-oxc': '*'
|
||||||
|
'@prettier/plugin-pug': '*'
|
||||||
|
'@shopify/prettier-plugin-liquid': '*'
|
||||||
|
'@trivago/prettier-plugin-sort-imports': '*'
|
||||||
|
'@zackad/prettier-plugin-twig': '*'
|
||||||
|
prettier: ^3.0
|
||||||
|
prettier-plugin-astro: '*'
|
||||||
|
prettier-plugin-css-order: '*'
|
||||||
|
prettier-plugin-jsdoc: '*'
|
||||||
|
prettier-plugin-marko: '*'
|
||||||
|
prettier-plugin-multiline-arrays: '*'
|
||||||
|
prettier-plugin-organize-attributes: '*'
|
||||||
|
prettier-plugin-organize-imports: '*'
|
||||||
|
prettier-plugin-sort-imports: '*'
|
||||||
|
prettier-plugin-svelte: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@ianvs/prettier-plugin-sort-imports':
|
||||||
|
optional: true
|
||||||
|
'@prettier/plugin-hermes':
|
||||||
|
optional: true
|
||||||
|
'@prettier/plugin-oxc':
|
||||||
|
optional: true
|
||||||
|
'@prettier/plugin-pug':
|
||||||
|
optional: true
|
||||||
|
'@shopify/prettier-plugin-liquid':
|
||||||
|
optional: true
|
||||||
|
'@trivago/prettier-plugin-sort-imports':
|
||||||
|
optional: true
|
||||||
|
'@zackad/prettier-plugin-twig':
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-astro:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-css-order:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-jsdoc:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-marko:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-multiline-arrays:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-organize-attributes:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-organize-imports:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-sort-imports:
|
||||||
|
optional: true
|
||||||
|
prettier-plugin-svelte:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
prettier@3.6.2:
|
||||||
|
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
source-map-js@1.2.1:
|
||||||
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
tailwindcss@4.1.16:
|
||||||
|
resolution: {integrity: sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==}
|
||||||
|
|
||||||
|
tapable@2.3.0:
|
||||||
|
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
to-regex-range@5.0.1:
|
||||||
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
|
engines: {node: '>=8.0'}
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@alloc/quick-lru@5.2.0': {}
|
||||||
|
|
||||||
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
|
|
||||||
|
'@jridgewell/remapping@2.3.5':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/gen-mapping': 0.3.13
|
||||||
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2': {}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@parcel/watcher-android-arm64@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-darwin-arm64@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-darwin-x64@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-freebsd-x64@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm-glibc@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm-musl@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-linux-x64-musl@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-win32-arm64@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-win32-ia32@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher-win32-x64@2.5.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@parcel/watcher@2.5.1':
|
||||||
|
dependencies:
|
||||||
|
detect-libc: 1.0.3
|
||||||
|
is-glob: 4.0.3
|
||||||
|
micromatch: 4.0.8
|
||||||
|
node-addon-api: 7.1.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@parcel/watcher-android-arm64': 2.5.1
|
||||||
|
'@parcel/watcher-darwin-arm64': 2.5.1
|
||||||
|
'@parcel/watcher-darwin-x64': 2.5.1
|
||||||
|
'@parcel/watcher-freebsd-x64': 2.5.1
|
||||||
|
'@parcel/watcher-linux-arm-glibc': 2.5.1
|
||||||
|
'@parcel/watcher-linux-arm-musl': 2.5.1
|
||||||
|
'@parcel/watcher-linux-arm64-glibc': 2.5.1
|
||||||
|
'@parcel/watcher-linux-arm64-musl': 2.5.1
|
||||||
|
'@parcel/watcher-linux-x64-glibc': 2.5.1
|
||||||
|
'@parcel/watcher-linux-x64-musl': 2.5.1
|
||||||
|
'@parcel/watcher-win32-arm64': 2.5.1
|
||||||
|
'@parcel/watcher-win32-ia32': 2.5.1
|
||||||
|
'@parcel/watcher-win32-x64': 2.5.1
|
||||||
|
|
||||||
|
'@tailwindcss/cli@4.1.16':
|
||||||
|
dependencies:
|
||||||
|
'@parcel/watcher': 2.5.1
|
||||||
|
'@tailwindcss/node': 4.1.16
|
||||||
|
'@tailwindcss/oxide': 4.1.16
|
||||||
|
enhanced-resolve: 5.18.3
|
||||||
|
mri: 1.2.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
tailwindcss: 4.1.16
|
||||||
|
|
||||||
|
'@tailwindcss/node@4.1.16':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/remapping': 2.3.5
|
||||||
|
enhanced-resolve: 5.18.3
|
||||||
|
jiti: 2.6.1
|
||||||
|
lightningcss: 1.30.2
|
||||||
|
magic-string: 0.30.21
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
tailwindcss: 4.1.16
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-android-arm64@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-arm64@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-x64@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-freebsd-x64@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-gnu@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-musl@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-gnu@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-musl@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-wasm32-wasi@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-arm64-msvc@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-x64-msvc@4.1.16':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide@4.1.16':
|
||||||
|
optionalDependencies:
|
||||||
|
'@tailwindcss/oxide-android-arm64': 4.1.16
|
||||||
|
'@tailwindcss/oxide-darwin-arm64': 4.1.16
|
||||||
|
'@tailwindcss/oxide-darwin-x64': 4.1.16
|
||||||
|
'@tailwindcss/oxide-freebsd-x64': 4.1.16
|
||||||
|
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.16
|
||||||
|
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.16
|
||||||
|
'@tailwindcss/oxide-linux-arm64-musl': 4.1.16
|
||||||
|
'@tailwindcss/oxide-linux-x64-gnu': 4.1.16
|
||||||
|
'@tailwindcss/oxide-linux-x64-musl': 4.1.16
|
||||||
|
'@tailwindcss/oxide-wasm32-wasi': 4.1.16
|
||||||
|
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.16
|
||||||
|
'@tailwindcss/oxide-win32-x64-msvc': 4.1.16
|
||||||
|
|
||||||
|
'@tailwindcss/postcss@4.1.16':
|
||||||
|
dependencies:
|
||||||
|
'@alloc/quick-lru': 5.2.0
|
||||||
|
'@tailwindcss/node': 4.1.16
|
||||||
|
'@tailwindcss/oxide': 4.1.16
|
||||||
|
postcss: 8.5.6
|
||||||
|
tailwindcss: 4.1.16
|
||||||
|
|
||||||
|
braces@3.0.3:
|
||||||
|
dependencies:
|
||||||
|
fill-range: 7.1.1
|
||||||
|
|
||||||
|
daisyui@5.4.3: {}
|
||||||
|
|
||||||
|
detect-libc@1.0.3: {}
|
||||||
|
|
||||||
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
|
enhanced-resolve@5.18.3:
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
tapable: 2.3.0
|
||||||
|
|
||||||
|
fill-range@7.1.1:
|
||||||
|
dependencies:
|
||||||
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
|
graceful-fs@4.2.11: {}
|
||||||
|
|
||||||
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
|
is-glob@4.0.3:
|
||||||
|
dependencies:
|
||||||
|
is-extglob: 2.1.1
|
||||||
|
|
||||||
|
is-number@7.0.0: {}
|
||||||
|
|
||||||
|
jiti@2.6.1: {}
|
||||||
|
|
||||||
|
lightningcss-android-arm64@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-darwin-arm64@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-darwin-x64@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-freebsd-x64@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-arm-gnueabihf@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-gnu@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-musl@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-x64-gnu@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-x64-musl@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-win32-arm64-msvc@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-win32-x64-msvc@1.30.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss@1.30.2:
|
||||||
|
dependencies:
|
||||||
|
detect-libc: 2.1.2
|
||||||
|
optionalDependencies:
|
||||||
|
lightningcss-android-arm64: 1.30.2
|
||||||
|
lightningcss-darwin-arm64: 1.30.2
|
||||||
|
lightningcss-darwin-x64: 1.30.2
|
||||||
|
lightningcss-freebsd-x64: 1.30.2
|
||||||
|
lightningcss-linux-arm-gnueabihf: 1.30.2
|
||||||
|
lightningcss-linux-arm64-gnu: 1.30.2
|
||||||
|
lightningcss-linux-arm64-musl: 1.30.2
|
||||||
|
lightningcss-linux-x64-gnu: 1.30.2
|
||||||
|
lightningcss-linux-x64-musl: 1.30.2
|
||||||
|
lightningcss-win32-arm64-msvc: 1.30.2
|
||||||
|
lightningcss-win32-x64-msvc: 1.30.2
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
micromatch@4.0.8:
|
||||||
|
dependencies:
|
||||||
|
braces: 3.0.3
|
||||||
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
mri@1.2.0: {}
|
||||||
|
|
||||||
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
|
node-addon-api@7.1.1: {}
|
||||||
|
|
||||||
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
|
picomatch@2.3.1: {}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.11
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
prettier-plugin-jinja-template@2.1.0(prettier@3.6.2):
|
||||||
|
dependencies:
|
||||||
|
prettier: 3.6.2
|
||||||
|
|
||||||
|
prettier-plugin-tailwindcss@0.7.1(prettier@3.6.2):
|
||||||
|
dependencies:
|
||||||
|
prettier: 3.6.2
|
||||||
|
|
||||||
|
prettier@3.6.2: {}
|
||||||
|
|
||||||
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
tailwindcss@4.1.16: {}
|
||||||
|
|
||||||
|
tapable@2.3.0: {}
|
||||||
|
|
||||||
|
to-regex-range@5.0.1:
|
||||||
|
dependencies:
|
||||||
|
is-number: 7.0.0
|
||||||
@ -3,7 +3,7 @@ name = "envipy"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"celery>=5.5.2",
|
"celery>=5.5.2",
|
||||||
"django>=5.2.1",
|
"django>=5.2.1",
|
||||||
@ -12,9 +12,9 @@ dependencies = [
|
|||||||
"django-ninja>=1.4.1",
|
"django-ninja>=1.4.1",
|
||||||
"django-oauth-toolkit>=3.0.1",
|
"django-oauth-toolkit>=3.0.1",
|
||||||
"django-polymorphic>=4.1.0",
|
"django-polymorphic>=4.1.0",
|
||||||
"django-stubs>=5.2.4",
|
|
||||||
"enviformer",
|
"enviformer",
|
||||||
"envipy-additional-information",
|
"envipy-additional-information",
|
||||||
|
"envipy-ambit>=0.1.0",
|
||||||
"envipy-plugins",
|
"envipy-plugins",
|
||||||
"epam-indigo>=1.30.1",
|
"epam-indigo>=1.30.1",
|
||||||
"gunicorn>=23.0.0",
|
"gunicorn>=23.0.0",
|
||||||
@ -27,12 +27,103 @@ dependencies = [
|
|||||||
"scikit-learn>=1.6.1",
|
"scikit-learn>=1.6.1",
|
||||||
"sentry-sdk[django]>=2.32.0",
|
"sentry-sdk[django]>=2.32.0",
|
||||||
"setuptools>=80.8.0",
|
"setuptools>=80.8.0",
|
||||||
|
"nh3==0.3.2",
|
||||||
|
"polars==1.35.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
enviformer = { git = "ssh://git@git.envipath.com/enviPath/enviformer.git", rev = "v0.1.0" }
|
enviformer = { git = "ssh://git@git.envipath.com/enviPath/enviformer.git", rev = "v0.1.4" }
|
||||||
envipy-plugins = { git = "ssh://git@git.envipath.com/enviPath/enviPy-plugins.git", rev = "v0.1.0" }
|
envipy-plugins = { git = "ssh://git@git.envipath.com/enviPath/enviPy-plugins.git", rev = "v0.1.0" }
|
||||||
envipy-additional-information = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git", rev = "v0.1.4"}
|
envipy-additional-information = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git", rev = "v0.1.7"}
|
||||||
|
envipy-ambit = { git = "ssh://git@git.envipath.com/enviPath/enviPy-ambit.git" }
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
ms-login = ["msal>=1.33.0"]
|
ms-login = ["msal>=1.33.0"]
|
||||||
|
dev = [
|
||||||
|
"celery-stubs==0.1.3",
|
||||||
|
"django-stubs>=5.2.4",
|
||||||
|
"poethepoet>=0.37.0",
|
||||||
|
"pre-commit>=4.3.0",
|
||||||
|
"ruff>=0.13.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 100
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
# Allow fix for all enabled rules (when `--fix`) is provided.
|
||||||
|
fixable = ["ALL"]
|
||||||
|
# Allow unused variables when underscore-prefixed.
|
||||||
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
|
# 4. Ignore `E402` (import violations) in all `__init__.py` files, and in selected subdirectories.
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"__init__.py" = ["E402"]
|
||||||
|
"**/{tests,docs,tools}/*" = ["E402"]
|
||||||
|
|
||||||
|
[tool.poe.tasks]
|
||||||
|
# Main tasks
|
||||||
|
setup = { sequence = ["db-up", "migrate", "bootstrap"], help = "Complete setup: start database, run migrations, and bootstrap data" }
|
||||||
|
dev = { shell = """
|
||||||
|
# Start pnpm CSS watcher in background
|
||||||
|
pnpm run dev &
|
||||||
|
PNPM_PID=$!
|
||||||
|
echo "Started CSS watcher (PID: $PNPM_PID)"
|
||||||
|
|
||||||
|
# Cleanup function
|
||||||
|
cleanup() {
|
||||||
|
echo "\nShutting down..."
|
||||||
|
if kill -0 $PNPM_PID 2>/dev/null; then
|
||||||
|
kill $PNPM_PID
|
||||||
|
echo "✓ CSS watcher stopped"
|
||||||
|
fi
|
||||||
|
if [ ! -z "${DJ_PID:-}" ] && kill -0 $DJ_PID 2>/dev/null; then
|
||||||
|
kill $DJ_PID
|
||||||
|
echo "✓ Django server stopped"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set trap for cleanup
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
|
# Start Django dev server in background
|
||||||
|
uv run python manage.py runserver &
|
||||||
|
DJ_PID=$!
|
||||||
|
|
||||||
|
# Wait for Django to finish
|
||||||
|
wait $DJ_PID
|
||||||
|
""", help = "Start the development server with CSS watcher", deps = ["db-up", "js-deps"] }
|
||||||
|
build = { sequence = ["build-frontend", "collectstatic"], help = "Build frontend assets and collect static files" }
|
||||||
|
|
||||||
|
# Database tasks
|
||||||
|
db-up = { cmd = "docker compose -f docker-compose.dev.yml up -d", help = "Start PostgreSQL database using Docker Compose" }
|
||||||
|
db-down = { cmd = "docker compose -f docker-compose.dev.yml down", help = "Stop PostgreSQL database" }
|
||||||
|
|
||||||
|
# Frontend tasks
|
||||||
|
js-deps = { cmd = "pnpm install", help = "Install frontend dependencies" }
|
||||||
|
|
||||||
|
# Full cleanup tasks
|
||||||
|
clean = { sequence = ["clean-db"], help = "Remove model files and database volumes (WARNING: destroys all data!)" }
|
||||||
|
clean-db = { cmd = "docker compose -f docker-compose.dev.yml down -v", help = "Removes the database container and volume." }
|
||||||
|
|
||||||
|
# Django tasks
|
||||||
|
migrate = { cmd = "uv run python manage.py migrate", help = "Run database migrations" }
|
||||||
|
bootstrap = { shell = """
|
||||||
|
echo "Bootstrapping initial data..."
|
||||||
|
echo "This will take a bit ⏱️. Get yourself some coffee..."
|
||||||
|
uv run python manage.py bootstrap
|
||||||
|
echo "✓ Bootstrap complete"
|
||||||
|
echo ""
|
||||||
|
echo "Default admin credentials:"
|
||||||
|
echo " Username: admin"
|
||||||
|
echo " Email: admin@envipath.com"
|
||||||
|
echo " Password: SuperSafe"
|
||||||
|
""", help = "Bootstrap initial data (anonymous user, packages, models)" }
|
||||||
|
shell = { cmd = "uv run python manage.py shell", help = "Open Django shell" }
|
||||||
|
|
||||||
|
# Build tasks
|
||||||
|
build-frontend = { cmd = "pnpm run build", help = "Build frontend assets using pnpm", deps = ["js-deps"] }
|
||||||
|
collectstatic = { cmd = "uv run python manage.py collectstatic --noinput", help = "Collect static files for production", deps = ["build-frontend"] }
|
||||||
|
|||||||
84
static/css/daisyui-theme.css
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* DaisyUI Themes - Generated by Style Dictionary
|
||||||
|
* Theme mappings defined in tokens/daisyui-themes.json
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Light theme (default) */
|
||||||
|
@plugin "daisyui/theme" {
|
||||||
|
name: "envipath";
|
||||||
|
default: true;
|
||||||
|
color-scheme: light;
|
||||||
|
|
||||||
|
--color-base-100: var(--color-neutral-50);
|
||||||
|
--color-base-200: var(--color-neutral-100);
|
||||||
|
--color-base-300: var(--color-neutral-200);
|
||||||
|
--color-base-content: var(--color-neutral-900);
|
||||||
|
--color-primary: var(--color-primary-500);
|
||||||
|
--color-primary-content: var(--color-primary-50);
|
||||||
|
--color-secondary: var(--color-secondary-500);
|
||||||
|
--color-secondary-content: var(--color-secondary-50);
|
||||||
|
--color-accent: var(--color-accent-500);
|
||||||
|
--color-accent-content: var(--color-accent-50);
|
||||||
|
--color-neutral: var(--color-neutral-950);
|
||||||
|
--color-neutral-content: var(--color-neutral-100);
|
||||||
|
--color-info: var(--color-info-500);
|
||||||
|
--color-info-content: var(--color-info-950);
|
||||||
|
--color-success: var(--color-success-500);
|
||||||
|
--color-success-content: var(--color-success-950);
|
||||||
|
--color-warning: var(--color-warning-500);
|
||||||
|
--color-warning-content: var(--color-warning-950);
|
||||||
|
--color-error: var(--color-error-500);
|
||||||
|
--color-error-content: var(--color-error-950);
|
||||||
|
|
||||||
|
/* border radius */
|
||||||
|
--radius-selector: 1rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
|
||||||
|
/* base sizes */
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
|
||||||
|
/* border size */
|
||||||
|
--border: 1px;
|
||||||
|
|
||||||
|
/* effects */
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark theme (prefers-color-scheme: dark) */
|
||||||
|
@plugin "daisyui/theme" {
|
||||||
|
name: "envipath-dark";
|
||||||
|
prefersdark: true;
|
||||||
|
color-scheme: dark;
|
||||||
|
|
||||||
|
--color-primary: var(--color-primary-400);
|
||||||
|
--color-primary-content: var(--color-neutral-950);
|
||||||
|
--color-secondary: var(--color-secondary-400);
|
||||||
|
--color-secondary-content: var(--color-neutral-950);
|
||||||
|
--color-accent: var(--color-primary-500);
|
||||||
|
--color-accent-content: var(--color-neutral-950);
|
||||||
|
--color-neutral: var(--color-neutral-300);
|
||||||
|
--color-neutral-content: var(--color-neutral-900);
|
||||||
|
--color-base-100: var(--color-neutral-900);
|
||||||
|
--color-base-200: var(--color-neutral-800);
|
||||||
|
--color-base-300: var(--color-neutral-700);
|
||||||
|
--color-base-content: var(--color-neutral-50);
|
||||||
|
--color-info: var(--color-primary-400);
|
||||||
|
--color-info-content: var(--color-neutral-950);
|
||||||
|
--color-success: var(--color-success-400);
|
||||||
|
--color-success-content: var(--color-neutral-950);
|
||||||
|
--color-warning: var(--color-warning-400);
|
||||||
|
--color-warning-content: var(--color-neutral-950);
|
||||||
|
--color-error: var(--color-error-400);
|
||||||
|
--color-error-content: var(--color-neutral-950);
|
||||||
|
--radius-selector: 1rem;
|
||||||
|
--radius-field: 0.25rem;
|
||||||
|
--radius-box: 0.5rem;
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
--border: 1px;
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
36
static/css/input.css
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
/* fira-code-latin-wght-normal */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Fira Code Variable';
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 300 700;
|
||||||
|
src: url(https://cdn.jsdelivr.net/fontsource/fonts/fira-code:vf@latest/latin-wght-normal.woff2) format('woff2-variations');
|
||||||
|
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inter-latin-wght-normal */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter Variable';
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 100 900;
|
||||||
|
src: url(https://cdn.jsdelivr.net/fontsource/fonts/inter:vf@latest/latin-wght-normal.woff2) format('woff2-variations');
|
||||||
|
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Tell Tailwind where to find Django templates and Python files */
|
||||||
|
@source "../../templates";
|
||||||
|
|
||||||
|
/* Custom theme configuration - must come before plugins */
|
||||||
|
@import "./theme.css";
|
||||||
|
|
||||||
|
/* Import DaisyUI plugin */
|
||||||
|
@plugin "daisyui" {
|
||||||
|
logs: true;
|
||||||
|
exclude: rootscrollgutter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "./daisyui-theme.css";
|
||||||
111
static/css/theme.css
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Tailwind v4 Theme - Generated by Style Dictionary
|
||||||
|
* This creates Tailwind utility classes from design tokens
|
||||||
|
*/
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
/* Colors */
|
||||||
|
--color-primary-50: oklch(0.98 0.02 201);
|
||||||
|
--color-primary-100: oklch(0.96 0.04 203);
|
||||||
|
--color-primary-200: oklch(0.92 0.08 205);
|
||||||
|
--color-primary-300: oklch(0.87 0.12 207);
|
||||||
|
--color-primary-400: oklch(0.80 0.13 212);
|
||||||
|
--color-primary-500: oklch(0.71 0.13 215);
|
||||||
|
--color-primary-600: oklch(0.61 0.11 222);
|
||||||
|
--color-primary-700: oklch(0.52 0.09 223);
|
||||||
|
--color-primary-800: oklch(0.45 0.08 224);
|
||||||
|
--color-primary-900: oklch(0.40 0.07 227);
|
||||||
|
--color-primary-950: oklch(0.30 0.05 230);
|
||||||
|
--color-secondary-50: oklch(0.98 0.02 166);
|
||||||
|
--color-secondary-100: oklch(0.95 0.05 163);
|
||||||
|
--color-secondary-200: oklch(0.90 0.09 164);
|
||||||
|
--color-secondary-300: oklch(0.85 0.13 165);
|
||||||
|
--color-secondary-400: oklch(0.77 0.15 163);
|
||||||
|
--color-secondary-500: oklch(0.70 0.15 162);
|
||||||
|
--color-secondary-600: oklch(0.60 0.13 163);
|
||||||
|
--color-secondary-700: oklch(0.51 0.10 166);
|
||||||
|
--color-secondary-800: oklch(0.43 0.09 167);
|
||||||
|
--color-secondary-900: oklch(0.38 0.07 169);
|
||||||
|
--color-secondary-950: oklch(0.26 0.05 173);
|
||||||
|
--color-success-50: oklch(0.98 0.02 156);
|
||||||
|
--color-success-100: oklch(0.96 0.04 157);
|
||||||
|
--color-success-200: oklch(0.93 0.08 156);
|
||||||
|
--color-success-300: oklch(0.87 0.14 154);
|
||||||
|
--color-success-400: oklch(0.80 0.18 152);
|
||||||
|
--color-success-500: oklch(0.72 0.19 150);
|
||||||
|
--color-success-600: oklch(0.63 0.17 149);
|
||||||
|
--color-success-700: oklch(0.53 0.14 150);
|
||||||
|
--color-success-800: oklch(0.45 0.11 151);
|
||||||
|
--color-success-900: oklch(0.39 0.09 153);
|
||||||
|
--color-success-950: oklch(0.27 0.06 153);
|
||||||
|
--color-warning-50: oklch(0.99 0.03 102);
|
||||||
|
--color-warning-100: oklch(0.97 0.07 103);
|
||||||
|
--color-warning-200: oklch(0.95 0.12 102);
|
||||||
|
--color-warning-300: oklch(0.91 0.17 98);
|
||||||
|
--color-warning-400: oklch(0.86 0.17 92);
|
||||||
|
--color-warning-500: oklch(0.80 0.16 86);
|
||||||
|
--color-warning-600: oklch(0.68 0.14 76);
|
||||||
|
--color-warning-700: oklch(0.55 0.12 66);
|
||||||
|
--color-warning-800: oklch(0.48 0.10 62);
|
||||||
|
--color-warning-900: oklch(0.42 0.09 58);
|
||||||
|
--color-warning-950: oklch(0.29 0.06 54);
|
||||||
|
--color-error-50: oklch(0.97 0.01 17);
|
||||||
|
--color-error-100: oklch(0.94 0.03 18);
|
||||||
|
--color-error-200: oklch(0.88 0.06 18);
|
||||||
|
--color-error-300: oklch(0.81 0.10 20);
|
||||||
|
--color-error-400: oklch(0.71 0.17 22);
|
||||||
|
--color-error-500: oklch(0.64 0.21 25);
|
||||||
|
--color-error-600: oklch(0.58 0.22 27);
|
||||||
|
--color-error-700: oklch(0.51 0.19 28);
|
||||||
|
--color-error-800: oklch(0.44 0.16 27);
|
||||||
|
--color-error-900: oklch(0.40 0.13 26);
|
||||||
|
--color-error-950: oklch(0.26 0.09 26);
|
||||||
|
--color-neutral-50: oklch(0.98 0.00 248);
|
||||||
|
--color-neutral-100: oklch(0.97 0.01 248);
|
||||||
|
--color-neutral-200: oklch(0.93 0.01 256);
|
||||||
|
--color-neutral-300: oklch(0.87 0.02 253);
|
||||||
|
--color-neutral-400: oklch(0.71 0.04 257);
|
||||||
|
--color-neutral-500: oklch(0.55 0.04 257);
|
||||||
|
--color-neutral-600: oklch(0.45 0.04 257);
|
||||||
|
--color-neutral-700: oklch(0.37 0.04 257);
|
||||||
|
--color-neutral-800: oklch(0.28 0.04 260);
|
||||||
|
--color-neutral-900: oklch(0.28 0.04 260);
|
||||||
|
--color-neutral-950: oklch(0.28 0.04 260);
|
||||||
|
|
||||||
|
/* Spacing */
|
||||||
|
--spacing-0: 0;
|
||||||
|
--spacing-1: 0.25rem;
|
||||||
|
--spacing-2: 0.5rem;
|
||||||
|
--spacing-3: 0.75rem;
|
||||||
|
--spacing-4: 1rem;
|
||||||
|
--spacing-5: 1.25rem;
|
||||||
|
--spacing-6: 1.5rem;
|
||||||
|
--spacing-7: 1.75rem;
|
||||||
|
--spacing-8: 2rem;
|
||||||
|
--spacing-10: 2.5rem;
|
||||||
|
--spacing-12: 3rem;
|
||||||
|
--spacing-16: 4rem;
|
||||||
|
--spacing-20: 5rem;
|
||||||
|
--spacing-24: 6rem;
|
||||||
|
--spacing-32: 8rem;
|
||||||
|
--spacing-40: 10rem;
|
||||||
|
--spacing-48: 12rem;
|
||||||
|
--spacing-56: 14rem;
|
||||||
|
--spacing-64: 16rem;
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
--font-family-sans: 'Inter Variable', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
--font-family-mono: 'Fira Code Variable', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace;
|
||||||
|
--font-family-base: 'Inter Variable', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
--font-size-xs: 0.75rem;
|
||||||
|
--font-size-sm: 0.875rem;
|
||||||
|
--font-size-base: 1rem;
|
||||||
|
--font-size-lg: 1.125rem;
|
||||||
|
--font-size-xl: 1.25rem;
|
||||||
|
--font-size-2xl: 1.5rem;
|
||||||
|
--font-size-3xl: 1.875rem;
|
||||||
|
--font-size-4xl: 2.25rem;
|
||||||
|
--font-size-5xl: 3rem;
|
||||||
|
--font-size-6xl: 3.75rem;
|
||||||
|
--font-size-7xl: 4.5rem;
|
||||||
|
}
|
||||||
BIN
static/images/UoA-Logo-Primary-RGB-Large.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
static/images/UoA-Logo-Primary-RGB-Reversed-Large.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
static/images/UoA-Logo-Primary-RGB-Reversed-Small.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
static/images/UoA-Logo-Primary-RGB-Small.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
static/images/ep-rule-artwork.png
Normal file
|
After Width: | Height: | Size: 252 KiB |
BIN
static/images/hero.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
static/images/linkedin.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
3
static/images/logo-eawag.svg
Normal file
|
After Width: | Height: | Size: 21 KiB |
@ -1,225 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
version="1.1"
|
|
||||||
width="314.98749"
|
|
||||||
height="28.8125"
|
|
||||||
id="svg3004"
|
|
||||||
xml:space="preserve"><metadata
|
|
||||||
id="metadata3010"><rdf:RDF><cc:Work
|
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
|
||||||
id="defs3008" /><g
|
|
||||||
transform="matrix(1.25,0,0,-1.25,0,28.8125)"
|
|
||||||
id="g3012"><g
|
|
||||||
transform="scale(0.1,0.1)"
|
|
||||||
id="g3014"><path
|
|
||||||
d="m 957.473,175.816 0,-4.296 -18.453,0 0,-48.614 -5.04,0 0,48.614 -18.378,0 0,4.296 41.871,0"
|
|
||||||
id="path3016"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 969.695,175.816 0,-22.968 31.425,0 0,22.968 5.04,0 0,-52.91 -5.04,0 0,25.637 -31.425,0 0,-25.637 -5.039,0 0,52.91 5.039,0"
|
|
||||||
id="path3018"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1055.58,175.816 0,-4.296 -31.49,0 0,-19.122 29.49,0 0,-4.293 -29.49,0 0,-20.898 31.87,0 0,-4.301 -36.91,0 0,52.91 36.53,0"
|
|
||||||
id="path3020"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1124.58,175.816 0,-4.296 -31.5,0 0,-19.122 29.49,0 0,-4.293 -29.49,0 0,-20.898 31.87,0 0,-4.301 -36.91,0 0,52.91 36.54,0"
|
|
||||||
id="path3022"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1139.76,175.816 30.83,-44.757 0.15,0 0,44.757 5.04,0 0,-52.91 -5.64,0 -30.82,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.63,0"
|
|
||||||
id="path3024"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1188.15,175.816 17.19,-47.355 0.15,0 17.06,47.355 5.34,0 -19.65,-52.91 -5.86,0 -19.56,52.91 5.33,0"
|
|
||||||
id="path3026"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1235.15,122.906 5.043,0 0,52.9102 -5.043,0 0,-52.9102 z"
|
|
||||||
id="path3028"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1277.3,150.691 c 1.54,0 2.99,0.243 4.38,0.711 1.39,0.469 2.59,1.145 3.63,2.036 1.04,0.886 1.86,1.968 2.48,3.222 0.63,1.258 0.92,2.703 0.92,4.336 0,3.262 -0.94,5.824 -2.81,7.703 -1.88,1.875 -4.74,2.821 -8.6,2.821 l -18.82,0 0,-20.829 18.82,0 z m 0.38,25.125 c 2.16,0 4.23,-0.269 6.19,-0.816 1.95,-0.543 3.65,-1.367 5.1,-2.48 1.46,-1.118 2.62,-2.54 3.49,-4.297 0.86,-1.758 1.29,-3.821 1.29,-6.192 0,-3.359 -0.86,-6.273 -2.6,-8.742 -1.72,-2.473 -4.29,-4.055 -7.69,-4.746 l 0,-0.145 c 1.73,-0.25 3.16,-0.703 4.29,-1.367 1.14,-0.668 2.06,-1.527 2.78,-2.558 0.72,-1.035 1.23,-2.239 1.56,-3.594 0.31,-1.363 0.53,-2.832 0.62,-4.41 0.05,-0.887 0.1,-1.977 0.16,-3.262 0.05,-1.285 0.15,-2.582 0.29,-3.891 0.15,-1.312 0.38,-2.543 0.71,-3.711 0.32,-1.156 0.74,-2.054 1.3,-2.699 l -5.56,0 c -0.29,0.496 -0.54,1.098 -0.7,1.809 -0.18,0.723 -0.31,1.461 -0.37,2.234 -0.08,0.762 -0.14,1.512 -0.2,2.254 -0.05,0.742 -0.1,1.387 -0.14,1.926 -0.09,1.875 -0.26,3.742 -0.49,5.598 -0.22,1.851 -0.69,3.503 -1.4,4.961 -0.72,1.46 -1.76,2.632 -3.11,3.523 -1.36,0.887 -3.23,1.281 -5.6,1.191 l -19.12,0 0,-23.496 -5.03,0 0,52.91 24.23,0"
|
|
||||||
id="path3030"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1308.46,140.879 c 0.77,-2.793 1.95,-5.289 3.56,-7.484 1.61,-2.2 3.66,-3.965 6.19,-5.301 2.52,-1.336 5.54,-2.004 9.04,-2.004 3.51,0 6.51,0.668 9,2.004 2.5,1.336 4.55,3.101 6.15,5.301 1.6,2.195 2.8,4.691 3.56,7.484 0.77,2.789 1.15,5.613 1.15,8.48 0,2.914 -0.38,5.758 -1.15,8.52 -0.76,2.769 -1.96,5.25 -3.56,7.449 -1.6,2.199 -3.65,3.969 -6.15,5.297 -2.49,1.336 -5.49,2.008 -9,2.008 -3.5,0 -6.52,-0.672 -9.04,-2.008 -2.53,-1.328 -4.58,-3.098 -6.19,-5.297 -1.61,-2.199 -2.79,-4.68 -3.56,-7.449 -0.75,-2.762 -1.15,-5.606 -1.15,-8.52 0,-2.867 0.4,-5.691 1.15,-8.48 z m -4.63,18.934 c 1.04,3.308 2.6,6.23 4.67,8.777 2.08,2.547 4.68,4.57 7.82,6.078 3.14,1.504 6.79,2.254 10.93,2.254 4.15,0 7.78,-0.75 10.89,-2.254 3.11,-1.508 5.71,-3.531 7.78,-6.078 2.08,-2.547 3.64,-5.469 4.67,-8.777 1.05,-3.313 1.56,-6.797 1.56,-10.454 0,-3.656 -0.51,-7.136 -1.56,-10.449 -1.03,-3.308 -2.59,-6.226 -4.67,-8.738 -2.07,-2.52 -4.67,-4.531 -7.78,-6.043 -3.11,-1.5 -6.74,-2.266 -10.89,-2.266 -4.14,0 -7.79,0.766 -10.93,2.266 -3.14,1.512 -5.74,3.523 -7.82,6.043 -2.07,2.512 -3.63,5.43 -4.67,8.738 -1.04,3.313 -1.54,6.793 -1.54,10.449 0,3.657 0.5,7.141 1.54,10.454"
|
|
||||||
id="path3032"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1367.77,175.816 30.84,-44.757 0.15,0 0,44.757 5.05,0 0,-52.91 -5.64,0 -30.83,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.62,0"
|
|
||||||
id="path3034"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1423.89,175.816 18.3,-46.386 18.22,46.386 7.41,0 0,-52.91 -5.03,0 0,45.723 -0.15,0 -18.09,-45.723 -4.74,0 -18.15,45.723 -0.15,0 0,-45.723 -5.04,0 0,52.91 7.42,0"
|
|
||||||
id="path3036"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1517.1,175.816 0,-4.296 -31.48,0 0,-19.122 29.48,0 0,-4.293 -29.48,0 0,-20.898 31.86,0 0,-4.301 -36.9,0 0,52.91 36.52,0"
|
|
||||||
id="path3038"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1532.29,175.816 30.82,-44.757 0.14,0 0,44.757 5.03,0 0,-52.91 -5.62,0 -30.81,44.754 -0.15,0 0,-44.754 -5.03,0 0,52.91 5.62,0"
|
|
||||||
id="path3040"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1617.34,175.816 0,-4.296 -18.44,0 0,-48.614 -5.04,0 0,48.614 -18.38,0 0,4.296 41.86,0"
|
|
||||||
id="path3042"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1647.8,143.656 -10.22,27.121 -10.6,-27.121 20.82,0 z m -7.18,32.16 20.74,-52.91 -5.4,0 -6.46,16.449 -24.07,0 -6.38,-16.449 -5.33,0 21.26,52.91 5.64,0"
|
|
||||||
id="path3044"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1673.44,175.816 0,-48.609 29.65,0 0,-4.301 -34.68,0 0,52.91 5.03,0"
|
|
||||||
id="path3046"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1769.74,165.254 c -1.02,1.605 -2.25,2.953 -3.71,4.043 -1.46,1.082 -3.06,1.914 -4.81,2.48 -1.76,0.567 -3.6,0.856 -5.52,0.856 -3.51,0 -6.53,-0.672 -9.05,-2.008 -2.52,-1.328 -4.58,-3.098 -6.18,-5.297 -1.61,-2.199 -2.8,-4.68 -3.56,-7.449 -0.77,-2.762 -1.15,-5.606 -1.15,-8.52 0,-2.867 0.38,-5.691 1.15,-8.48 0.76,-2.793 1.95,-5.289 3.56,-7.484 1.6,-2.2 3.66,-3.965 6.18,-5.301 2.52,-1.336 5.54,-2.004 9.05,-2.004 2.46,0 4.69,0.449 6.66,1.336 1.98,0.89 3.68,2.101 5.12,3.633 1.43,1.523 2.59,3.324 3.48,5.371 0.89,2.05 1.45,4.261 1.71,6.633 l 5.03,0 c -0.35,-3.258 -1.11,-6.204 -2.3,-8.821 -1.18,-2.617 -2.7,-4.84 -4.59,-6.664 -1.88,-1.824 -4.08,-3.238 -6.63,-4.223 -2.54,-0.992 -5.37,-1.492 -8.48,-1.492 -4.17,0 -7.81,0.766 -10.93,2.266 -3.15,1.512 -5.76,3.523 -7.83,6.043 -2.07,2.512 -3.62,5.43 -4.65,8.738 -1.04,3.313 -1.57,6.793 -1.57,10.449 0,3.657 0.53,7.141 1.57,10.454 1.03,3.308 2.58,6.23 4.65,8.777 2.07,2.547 4.68,4.57 7.83,6.078 3.12,1.504 6.76,2.254 10.93,2.254 2.52,0 4.97,-0.371 7.38,-1.106 2.39,-0.738 4.56,-1.843 6.51,-3.296 1.95,-1.461 3.58,-3.254 4.89,-5.372 1.3,-2.125 2.13,-4.574 2.47,-7.335 l -5.04,0 c -0.43,2.019 -1.16,3.839 -2.17,5.441"
|
|
||||||
id="path3048"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1791.01,140.879 c 0.76,-2.793 1.95,-5.289 3.56,-7.484 1.6,-2.2 3.66,-3.965 6.18,-5.301 2.52,-1.336 5.53,-2.004 9.04,-2.004 3.51,0 6.5,0.668 9.01,2.004 2.49,1.336 4.54,3.101 6.14,5.301 1.61,2.195 2.79,4.691 3.57,7.484 0.75,2.789 1.14,5.613 1.14,8.48 0,2.914 -0.39,5.758 -1.14,8.52 -0.78,2.769 -1.96,5.25 -3.57,7.449 -1.6,2.199 -3.65,3.969 -6.14,5.297 -2.51,1.336 -5.5,2.008 -9.01,2.008 -3.51,0 -6.52,-0.672 -9.04,-2.008 -2.52,-1.328 -4.58,-3.098 -6.18,-5.297 -1.61,-2.199 -2.8,-4.68 -3.56,-7.449 -0.78,-2.762 -1.16,-5.606 -1.16,-8.52 0,-2.867 0.38,-5.691 1.16,-8.48 z m -4.64,18.934 c 1.04,3.308 2.6,6.23 4.67,8.777 2.08,2.547 4.68,4.57 7.82,6.078 3.13,1.504 6.77,2.254 10.93,2.254 4.15,0 7.78,-0.75 10.89,-2.254 3.11,-1.508 5.72,-3.531 7.79,-6.078 2.07,-2.547 3.62,-5.469 4.66,-8.777 1.04,-3.313 1.56,-6.797 1.56,-10.454 0,-3.656 -0.52,-7.136 -1.56,-10.449 -1.04,-3.308 -2.59,-6.226 -4.66,-8.738 -2.07,-2.52 -4.68,-4.531 -7.79,-6.043 -3.11,-1.5 -6.74,-2.266 -10.89,-2.266 -4.16,0 -7.8,0.766 -10.93,2.266 -3.14,1.512 -5.74,3.523 -7.82,6.043 -2.07,2.512 -3.63,5.43 -4.67,8.738 -1.04,3.313 -1.56,6.793 -1.56,10.449 0,3.657 0.52,7.141 1.56,10.454"
|
|
||||||
id="path3050"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1850.33,175.816 30.82,-44.757 0.15,0 0,44.757 5.04,0 0,-52.91 -5.64,0 -30.82,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.64,0"
|
|
||||||
id="path3052"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1935.39,175.816 0,-4.296 -18.45,0 0,-48.614 -5.04,0 0,48.614 -18.37,0 0,4.296 41.86,0"
|
|
||||||
id="path3054"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1965.86,143.656 -10.23,27.121 -10.6,-27.121 20.83,0 z m -7.21,32.16 20.76,-52.91 -5.41,0 -6.44,16.449 -24.08,0 -6.38,-16.449 -5.33,0 21.26,52.91 5.62,0"
|
|
||||||
id="path3056"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1993.71,175.816 18.3,-46.386 18.24,46.386 7.41,0 0,-52.91 -5.04,0 0,45.723 -0.15,0 -18.09,-45.723 -4.73,0 -18.16,45.723 -0.14,0 0,-45.723 -5.05,0 0,52.91 7.41,0"
|
|
||||||
id="path3058"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2050.78,122.906 5.0273,0 0,52.9102 -5.0273,0 0,-52.9102 z"
|
|
||||||
id="path3060"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2074.63,175.816 30.83,-44.757 0.15,0 0,44.757 5.04,0 0,-52.91 -5.63,0 -30.83,44.754 -0.15,0 0,-44.754 -5.04,0 0,52.91 5.63,0"
|
|
||||||
id="path3062"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2151.78,143.656 -10.24,27.121 -10.58,-27.121 20.82,0 z m -7.2,32.16 20.76,-52.91 -5.41,0 -6.45,16.449 -24.09,0 -6.36,-16.449 -5.34,0 21.27,52.91 5.62,0"
|
|
||||||
id="path3064"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2177.93,175.816 30.82,-44.757 0.16,0 0,44.757 5.05,0 0,-52.91 -5.64,0 -30.84,44.754 -0.14,0 0,-44.754 -5.04,0 0,52.91 5.63,0"
|
|
||||||
id="path3066"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2263.01,175.816 0,-4.296 -18.46,0 0,-48.614 -5.04,0 0,48.614 -18.38,0 0,4.296 41.88,0"
|
|
||||||
id="path3068"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 945.785,32.6602 c 1.875,0 3.656,0.1562 5.336,0.4804 1.676,0.3164 3.16,0.8985 4.445,1.7383 1.286,0.8477 2.301,1.9649 3.043,3.375 0.739,1.4102 1.11,3.1719 1.11,5.2969 0,3.4101 -1.203,5.9648 -3.602,7.668 -2.387,1.7031 -5.836,2.5585 -10.332,2.5585 l -17.344,0 0,-21.1171 17.344,0 z m 0,25.414 c 2.028,0 3.778,0.2344 5.262,0.711 1.48,0.4609 2.719,1.1015 3.711,1.9218 0.98,0.8125 1.726,1.7696 2.215,2.8555 0.5,1.082 0.742,2.2422 0.742,3.4766 0,6.6211 -3.977,9.9375 -11.93,9.9375 l -17.344,0 0,-18.9024 17.344,0 z m 0,23.1953 c 2.223,0 4.36,-0.2109 6.41,-0.6289 2.051,-0.4218 3.852,-1.1328 5.41,-2.1484 1.559,-1.0156 2.805,-2.3438 3.743,-4 0.937,-1.6563 1.406,-3.7227 1.406,-6.1914 0,-1.3867 -0.219,-2.7305 -0.668,-4.0391 -0.445,-1.3086 -1.074,-2.4961 -1.887,-3.5547 -0.808,-1.0625 -1.781,-1.9687 -2.89,-2.7031 -1.114,-0.7422 -2.36,-1.2617 -3.739,-1.5586 l 0,-0.1523 c 3.403,-0.4453 6.121,-1.8321 8.145,-4.1797 2.031,-2.3477 3.043,-5.25 3.043,-8.711 0,-0.8398 -0.074,-1.7851 -0.227,-2.8515 -0.144,-1.0625 -0.437,-2.1524 -0.886,-3.2617 -0.446,-1.1133 -1.086,-2.2149 -1.93,-3.2969 -0.836,-1.0859 -1.957,-2.0391 -3.363,-2.8516 -1.414,-0.8203 -3.141,-1.4883 -5.192,-2.0039 -2.051,-0.5195 -4.508,-0.7812 -7.375,-0.7812 l -22.379,0 0,52.914 22.379,0"
|
|
||||||
id="path3070"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 975.426,28.3555 5.04297,0 0,52.9141 -5.04297,0 0,-52.9141 z"
|
|
||||||
id="path3072"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 997.105,46.3281 c 0.762,-2.789 1.95,-5.2812 3.555,-7.4804 1.6,-2.1993 3.67,-3.9688 6.18,-5.2969 2.53,-1.3399 5.54,-2.0039 9.04,-2.0039 3.51,0 6.52,0.664 9.01,2.0039 2.5,1.3281 4.54,3.0976 6.15,5.2969 1.61,2.1992 2.79,4.6914 3.55,7.4804 0.77,2.793 1.16,5.6211 1.16,8.4844 0,2.918 -0.39,5.7578 -1.16,8.5273 -0.76,2.7618 -1.94,5.2461 -3.55,7.4454 -1.61,2.2031 -3.65,3.9648 -6.15,5.3007 -2.49,1.3321 -5.5,2 -9.01,2 -3.5,0 -6.51,-0.6679 -9.04,-2 -2.51,-1.3359 -4.58,-3.0976 -6.18,-5.3007 -1.605,-2.1993 -2.793,-4.6836 -3.555,-7.4454 -0.773,-2.7695 -1.152,-5.6093 -1.152,-8.5273 0,-2.8633 0.379,-5.6914 1.152,-8.4844 z m -4.632,18.9336 c 1.035,3.3125 2.59,6.2383 4.668,8.7813 2.074,2.5429 4.679,4.5742 7.819,6.0781 3.13,1.5078 6.77,2.2578 10.92,2.2578 4.15,0 7.79,-0.75 10.9,-2.2578 3.11,-1.5039 5.71,-3.5352 7.78,-6.0781 2.08,-2.543 3.63,-5.4688 4.67,-8.7813 1.04,-3.3047 1.56,-6.789 1.56,-10.4492 0,-3.6602 -0.52,-7.1406 -1.56,-10.4414 -1.04,-3.3164 -2.59,-6.2305 -4.67,-8.7461 -2.07,-2.5195 -4.67,-4.5312 -7.78,-6.0391 -3.11,-1.5039 -6.75,-2.2656 -10.9,-2.2656 -4.15,0 -7.79,0.7617 -10.92,2.2656 -3.14,1.5079 -5.745,3.5196 -7.819,6.0391 -2.078,2.5156 -3.633,5.4297 -4.668,8.7461 -1.035,3.3008 -1.559,6.7812 -1.559,10.4414 0,3.6602 0.524,7.1445 1.559,10.4492"
|
|
||||||
id="path3074"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1087.1,81.2695 0,-4.2929 -18.45,0 0,-48.6211 -5.04,0 0,48.6211 -18.38,0 0,4.2929 41.87,0"
|
|
||||||
id="path3076"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1118.15,56.1484 c 1.53,0 2.99,0.2383 4.37,0.7071 1.39,0.4687 2.6,1.1484 3.63,2.0351 1.04,0.8907 1.86,1.9688 2.49,3.2227 0.61,1.2617 0.93,2.7109 0.93,4.332 0,3.2656 -0.95,5.836 -2.82,7.7031 -1.88,1.8829 -4.75,2.8282 -8.6,2.8282 l -18.82,0 0,-20.8282 18.82,0 z m 0.37,25.1211 c 2.17,0 4.23,-0.2695 6.19,-0.8203 1.95,-0.539 3.65,-1.3633 5.11,-2.4765 1.46,-1.1133 2.62,-2.543 3.49,-4.3008 0.86,-1.7578 1.29,-3.8125 1.29,-6.1875 0,-3.3594 -0.86,-6.2696 -2.59,-8.7461 -1.73,-2.4688 -4.3,-4.0469 -7.71,-4.7383 l 0,-0.1484 c 1.73,-0.25 3.16,-0.7032 4.3,-1.3672 1.14,-0.668 2.06,-1.5235 2.78,-2.5586 0.71,-1.0391 1.23,-2.2344 1.55,-3.5977 0.33,-1.3593 0.54,-2.8281 0.63,-4.4062 0.05,-0.8867 0.1,-1.9766 0.15,-3.2656 0.05,-1.2852 0.15,-2.5782 0.3,-3.8868 0.15,-1.3125 0.38,-2.5468 0.71,-3.707 0.31,-1.1562 0.74,-2.0586 1.29,-2.707 l -5.56,0 c -0.29,0.5 -0.53,1.1015 -0.7,1.8203 -0.17,0.7187 -0.3,1.4531 -0.37,2.2265 -0.07,0.7618 -0.14,1.5118 -0.19,2.25 -0.04,0.7461 -0.1,1.3946 -0.15,1.9297 -0.1,1.875 -0.26,3.7461 -0.48,5.6016 -0.22,1.8555 -0.69,3.5 -1.41,4.9609 -0.71,1.4532 -1.75,2.6289 -3.11,3.5235 -1.36,0.8906 -3.22,1.2812 -5.59,1.1875 l -19.12,0 0,-23.5 -5.04,0 0,52.914 24.23,0"
|
|
||||||
id="path3078"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1174.25,49.1055 -10.23,27.125 -10.6,-27.125 20.83,0 z m -7.19,32.164 20.75,-52.914 -5.41,0 -6.45,16.457 -24.08,0 -6.38,-16.457 -5.33,0 21.27,52.914 5.63,0"
|
|
||||||
id="path3080"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1200.41,81.2695 30.83,-44.7617 0.15,0 0,44.7617 5.04,0 0,-52.914 -5.63,0 -30.84,44.7578 -0.15,0 0,-44.7578 -5.04,0 0,52.914 5.64,0"
|
|
||||||
id="path3082"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1252.87,38.9609 c 0.9,-1.8281 2.12,-3.289 3.67,-4.375 1.57,-1.0898 3.4,-1.8671 5.52,-2.3359 2.12,-0.4727 4.4,-0.7031 6.83,-0.7031 1.37,0 2.89,0.1914 4.52,0.5976 1.62,0.3907 3.14,1.0196 4.55,1.8828 1.42,0.8711 2.58,1.9727 3.52,3.336 0.94,1.3515 1.41,3.0039 1.41,4.9258 0,1.4843 -0.33,2.7695 -1.01,3.8593 -0.66,1.086 -1.53,1.9961 -2.58,2.7383 -1.07,0.7422 -2.24,1.3438 -3.53,1.8164 -1.28,0.4688 -2.55,0.8555 -3.78,1.1524 l -11.78,2.8789 c -1.54,0.4062 -3.02,0.8906 -4.49,1.4922 -1.44,0.5898 -2.72,1.375 -3.81,2.3672 -1.09,0.9843 -1.95,2.2031 -2.63,3.6289 -0.67,1.4336 -1,3.1875 -1,5.2617 0,1.289 0.25,2.7929 0.74,4.5234 0.49,1.7266 1.42,3.3594 2.79,4.8906 1.35,1.5274 3.21,2.8243 5.59,3.8907 2.37,1.0625 5.4,1.5898 9.1,1.5898 2.62,0 5.13,-0.3398 7.49,-1.0351 2.38,-0.6915 4.47,-1.7305 6.22,-3.1133 1.8,-1.3789 3.21,-3.0977 4.26,-5.1446 1.08,-2.0546 1.6,-4.4453 1.6,-7.1601 l -5.03,0 c -0.1,2.0351 -0.56,3.7969 -1.37,5.3047 -0.82,1.5039 -1.88,2.7617 -3.19,3.7773 -1.3,1.0117 -2.81,1.7852 -4.53,2.3008 -1.7,0.5195 -3.49,0.7773 -5.37,0.7773 -1.72,0 -3.39,-0.1914 -5,-0.5586 -1.61,-0.371 -3.01,-0.9609 -4.22,-1.7812 -1.21,-0.8164 -2.18,-1.8906 -2.93,-3.2227 -0.74,-1.332 -1.11,-2.9882 -1.11,-4.9648 0,-1.2305 0.22,-2.3086 0.64,-3.2227 0.42,-0.914 0.98,-1.6953 1.72,-2.332 0.75,-0.6484 1.61,-1.1601 2.56,-1.5547 0.98,-0.4023 1.99,-0.7226 3.08,-0.9687 l 12.9,-3.1875 c 1.88,-0.4883 3.64,-1.0938 5.3,-1.8164 1.65,-0.711 3.11,-1.6055 4.37,-2.6602 1.27,-1.0625 2.24,-2.3633 2.97,-3.8945 0.71,-1.5313 1.07,-3.3867 1.07,-5.5586 0,-0.5899 -0.07,-1.3828 -0.2,-2.3672 -0.11,-0.9922 -0.41,-2.0313 -0.87,-3.1523 -0.47,-1.1133 -1.14,-2.2344 -2,-3.3711 -0.87,-1.1368 -2.06,-2.1602 -3.56,-3.0782 -1.51,-0.9062 -3.37,-1.6562 -5.6,-2.2226 -2.22,-0.5586 -4.88,-0.8516 -8,-0.8516 -3.11,0 -6,0.3594 -8.68,1.0781 -2.65,0.7188 -4.94,1.8125 -6.81,3.2969 -1.88,1.4844 -3.32,3.3789 -4.34,5.707 -1,2.3204 -1.43,5.1055 -1.3,8.375 l 5.05,0 c -0.06,-2.7148 0.37,-4.9921 1.25,-6.8164"
|
|
||||||
id="path3084"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1331.72,81.2695 0,-4.2929 -28.53,0 0,-19.1211 25.35,0 0,-4.3008 -25.35,0 0,-25.1992 -5.04,0 0,52.914 33.57,0"
|
|
||||||
id="path3086"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1343.54,46.3281 c 0.78,-2.789 1.95,-5.2812 3.55,-7.4804 1.6,-2.1993 3.68,-3.9688 6.2,-5.2969 2.51,-1.3399 5.53,-2.0039 9.03,-2.0039 3.51,0 6.51,0.664 9.01,2.0039 2.5,1.3281 4.55,3.0976 6.15,5.2969 1.6,2.1992 2.78,4.6914 3.56,7.4804 0.76,2.793 1.15,5.6211 1.15,8.4844 0,2.918 -0.39,5.7578 -1.15,8.5273 -0.78,2.7618 -1.96,5.2461 -3.56,7.4454 -1.6,2.2031 -3.65,3.9648 -6.15,5.3007 -2.5,1.3321 -5.5,2 -9.01,2 -3.5,0 -6.52,-0.6679 -9.03,-2 -2.52,-1.3359 -4.6,-3.0976 -6.2,-5.3007 -1.6,-2.1993 -2.77,-4.6836 -3.55,-7.4454 -0.77,-2.7695 -1.14,-5.6093 -1.14,-8.5273 0,-2.8633 0.37,-5.6914 1.14,-8.4844 z m -4.63,18.9336 c 1.03,3.3125 2.59,6.2383 4.66,8.7813 2.09,2.5429 4.69,4.5742 7.82,6.0781 3.14,1.5078 6.79,2.2578 10.93,2.2578 4.15,0 7.8,-0.75 10.9,-2.2578 3.11,-1.5039 5.7,-3.5352 7.78,-6.0781 2.09,-2.543 3.63,-5.4688 4.66,-8.7813 1.04,-3.3047 1.57,-6.789 1.57,-10.4492 0,-3.6602 -0.53,-7.1406 -1.57,-10.4414 -1.03,-3.3164 -2.57,-6.2305 -4.66,-8.7461 -2.08,-2.5195 -4.67,-4.5312 -7.78,-6.0391 -3.1,-1.5039 -6.75,-2.2656 -10.9,-2.2656 -4.14,0 -7.79,0.7617 -10.93,2.2656 -3.13,1.5079 -5.73,3.5196 -7.82,6.0391 -2.07,2.5156 -3.63,5.4297 -4.66,8.7461 -1.04,3.3008 -1.56,6.7812 -1.56,10.4414 0,3.6602 0.52,7.1445 1.56,10.4492"
|
|
||||||
id="path3088"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1421.16,56.1484 c 1.54,0 3,0.2383 4.39,0.7071 1.37,0.4687 2.58,1.1484 3.62,2.0351 1.04,0.8907 1.87,1.9688 2.49,3.2227 0.61,1.2617 0.91,2.7109 0.91,4.332 0,3.2656 -0.93,5.836 -2.81,7.7031 -1.88,1.8829 -4.73,2.8282 -8.6,2.8282 l -18.83,0 0,-20.8282 18.83,0 z m 0.37,25.1211 c 2.18,0 4.24,-0.2695 6.18,-0.8203 1.96,-0.539 3.67,-1.3633 5.12,-2.4765 1.47,-1.1133 2.63,-2.543 3.49,-4.3008 0.86,-1.7578 1.3,-3.8125 1.3,-6.1875 0,-3.3594 -0.87,-6.2696 -2.6,-8.7461 -1.72,-2.4688 -4.3,-4.0469 -7.71,-4.7383 l 0,-0.1484 c 1.74,-0.25 3.17,-0.7032 4.3,-1.3672 1.13,-0.668 2.06,-1.5235 2.78,-2.5586 0.72,-1.0391 1.24,-2.2344 1.56,-3.5977 0.32,-1.3593 0.52,-2.8281 0.63,-4.4062 0.05,-0.8867 0.1,-1.9766 0.15,-3.2656 0.05,-1.2852 0.15,-2.5782 0.29,-3.8868 0.16,-1.3125 0.38,-2.5468 0.7,-3.707 0.33,-1.1562 0.76,-2.0586 1.3,-2.707 l -5.55,0 c -0.31,0.5 -0.54,1.1015 -0.71,1.8203 -0.17,0.7187 -0.29,1.4531 -0.37,2.2265 -0.08,0.7618 -0.13,1.5118 -0.18,2.25 -0.05,0.7461 -0.1,1.3946 -0.15,1.9297 -0.1,1.875 -0.25,3.7461 -0.48,5.6016 -0.22,1.8555 -0.7,3.5 -1.41,4.9609 -0.73,1.4532 -1.76,2.6289 -3.12,3.5235 -1.36,0.8906 -3.21,1.2812 -5.59,1.1875 l -19.13,0 0,-23.5 -5.03,0 0,52.914 24.23,0"
|
|
||||||
id="path3090"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1456.21,81.2695 18.3,-46.3906 18.24,46.3906 7.41,0 0,-52.914 -5.04,0 0,45.7265 -0.15,0 -18.08,-45.7265 -4.74,0 -18.17,45.7265 -0.13,0 0,-45.7265 -5.05,0 0,52.914 7.41,0"
|
|
||||||
id="path3092"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1541.21,49.1055 -10.22,27.125 -10.6,-27.125 20.82,0 z m -7.19,32.164 20.74,-52.914 -5.42,0 -6.42,16.457 -24.08,0 -6.38,-16.457 -5.33,0 21.27,52.914 5.62,0"
|
|
||||||
id="path3094"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1593,81.2695 0,-4.2929 -18.47,0 0,-48.6211 -5.04,0 0,48.6211 -18.37,0 0,4.2929 41.88,0"
|
|
||||||
id="path3096"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1600.55,28.3555 5.0391,0 0,52.9141 -5.0391,0 0,-52.9141 z"
|
|
||||||
id="path3098"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1622.23,46.3281 c 0.76,-2.789 1.94,-5.2812 3.55,-7.4804 1.6,-2.1993 3.67,-3.9688 6.19,-5.2969 2.52,-1.3399 5.53,-2.0039 9.04,-2.0039 3.5,0 6.5,0.664 9.01,2.0039 2.48,1.3281 4.54,3.0976 6.14,5.2969 1.61,2.1992 2.8,4.6914 3.56,7.4804 0.76,2.793 1.15,5.6211 1.15,8.4844 0,2.918 -0.39,5.7578 -1.15,8.5273 -0.76,2.7618 -1.95,5.2461 -3.56,7.4454 -1.6,2.2031 -3.66,3.9648 -6.14,5.3007 -2.51,1.3321 -5.51,2 -9.01,2 -3.51,0 -6.52,-0.6679 -9.04,-2 -2.52,-1.3359 -4.59,-3.0976 -6.19,-5.3007 -1.61,-2.1993 -2.79,-4.6836 -3.55,-7.4454 -0.77,-2.7695 -1.16,-5.6093 -1.16,-8.5273 0,-2.8633 0.39,-5.6914 1.16,-8.4844 z m -4.64,18.9336 c 1.03,3.3125 2.6,6.2383 4.68,8.7813 2.07,2.5429 4.67,4.5742 7.8,6.0781 3.14,1.5078 6.79,2.2578 10.94,2.2578 4.16,0 7.78,-0.75 10.88,-2.2578 3.13,-1.5039 5.72,-3.5352 7.8,-6.0781 2.07,-2.543 3.62,-5.4688 4.66,-8.7813 1.03,-3.3047 1.55,-6.789 1.55,-10.4492 0,-3.6602 -0.52,-7.1406 -1.55,-10.4414 -1.04,-3.3164 -2.59,-6.2305 -4.66,-8.7461 -2.08,-2.5195 -4.67,-4.5312 -7.8,-6.0391 -3.1,-1.5039 -6.72,-2.2656 -10.88,-2.2656 -4.15,0 -7.8,0.7617 -10.94,2.2656 -3.13,1.5079 -5.73,3.5196 -7.8,6.0391 -2.08,2.5156 -3.65,5.4297 -4.68,8.7461 -1.03,3.3008 -1.55,6.7812 -1.55,10.4414 0,3.6602 0.52,7.1445 1.55,10.4492"
|
|
||||||
id="path3100"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1681.55,81.2695 30.82,-44.7617 0.15,0 0,44.7617 5.04,0 0,-52.914 -5.64,0 -30.82,44.7578 -0.15,0 0,-44.7578 -5.03,0 0,52.914 5.63,0"
|
|
||||||
id="path3102"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1775.58,55.332 c 3.51,0 6.35,0.8946 8.52,2.6719 2.17,1.7774 3.26,4.4922 3.26,8.1484 0,3.6602 -1.09,6.3711 -3.26,8.1485 -2.17,1.7851 -5.01,2.6758 -8.52,2.6758 l -17.35,0 0,-21.6446 17.35,0 z m 1.12,25.9375 c 2.36,0 4.51,-0.3359 6.43,-0.9961 1.94,-0.6679 3.58,-1.6562 4.99,-2.9648 1.37,-1.3125 2.43,-2.9063 3.17,-4.7852 0.74,-1.875 1.11,-4.0039 1.11,-6.3711 0,-2.3671 -0.37,-4.4921 -1.11,-6.371 -0.74,-1.8829 -1.8,-3.4766 -3.17,-4.7852 -1.41,-1.3047 -3.05,-2.293 -4.99,-2.9609 -1.92,-0.6641 -4.07,-0.9961 -6.43,-0.9961 l -18.47,0 0,-22.6836 -5.04,0 0,52.914 23.51,0"
|
|
||||||
id="path3104"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1824.93,49.1055 -10.22,27.125 -10.6,-27.125 20.82,0 z m -7.19,32.164 20.76,-52.914 -5.41,0 -6.45,16.457 -24.09,0 -6.38,-16.457 -5.33,0 21.28,52.914 5.62,0"
|
|
||||||
id="path3106"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1876.73,81.2695 0,-4.2929 -18.45,0 0,-48.6211 -5.04,0 0,48.6211 -18.38,0 0,4.2929 41.87,0"
|
|
||||||
id="path3108"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1888.96,81.2695 0,-22.9687 31.41,0 0,22.9687 5.04,0 0,-52.914 -5.04,0 0,25.6445 -31.41,0 0,-25.6445 -5.04,0 0,52.914 5.04,0"
|
|
||||||
id="path3110"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 1938.38,81.2695 12.01,-46.3125 0.15,0 12.9,46.3125 6.3,0 12.96,-46.3125 0.15,0 12.07,46.3125 5.04,0 -14.59,-52.914 -5.34,0 -13.42,47.3515 -0.14,0 -13.34,-47.3515 -5.48,0 -14.67,52.914 5.4,0"
|
|
||||||
id="path3112"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2034.73,49.1055 -10.24,27.125 -10.59,-27.125 20.83,0 z m -7.2,32.164 20.75,-52.914 -5.41,0 -6.44,16.457 -24.09,0 -6.37,-16.457 -5.34,0 21.27,52.914 5.63,0"
|
|
||||||
id="path3114"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2043.84,81.2695 5.93,0 17.41,-26.8281 17.33,26.8281 6.01,0 -20.9,-31.125 0,-21.789 -5.04,0 0,21.789 -20.74,31.125"
|
|
||||||
id="path3116"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2144.01,56.1484 c 1.55,0 3,0.2383 4.38,0.7071 1.39,0.4687 2.6,1.1484 3.63,2.0351 1.05,0.8907 1.88,1.9688 2.48,3.2227 0.62,1.2617 0.93,2.7109 0.93,4.332 0,3.2656 -0.94,5.836 -2.81,7.7031 -1.89,1.8829 -4.75,2.8282 -8.61,2.8282 l -18.81,0 0,-20.8282 18.81,0 z m 0.38,25.1211 c 2.18,0 4.23,-0.2695 6.19,-0.8203 1.95,-0.539 3.66,-1.3633 5.1,-2.4765 1.47,-1.1133 2.63,-2.543 3.5,-4.3008 0.86,-1.7578 1.29,-3.8125 1.29,-6.1875 0,-3.3594 -0.86,-6.2696 -2.59,-8.7461 -1.73,-2.4688 -4.3,-4.0469 -7.7,-4.7383 l 0,-0.1484 c 1.72,-0.25 3.15,-0.7032 4.28,-1.3672 1.15,-0.668 2.07,-1.5235 2.79,-2.5586 0.72,-1.0391 1.24,-2.2344 1.55,-3.5977 0.32,-1.3593 0.54,-2.8281 0.63,-4.4062 0.05,-0.8867 0.1,-1.9766 0.15,-3.2656 0.05,-1.2852 0.15,-2.5782 0.29,-3.8868 0.15,-1.3125 0.39,-2.5468 0.71,-3.707 0.33,-1.1562 0.76,-2.0586 1.3,-2.707 l -5.55,0 c -0.3,0.5 -0.54,1.1015 -0.71,1.8203 -0.17,0.7187 -0.3,1.4531 -0.38,2.2265 -0.07,0.7618 -0.13,1.5118 -0.18,2.25 -0.04,0.7461 -0.1,1.3946 -0.15,1.9297 -0.1,1.875 -0.26,3.7461 -0.49,5.6016 -0.22,1.8555 -0.68,3.5 -1.39,4.9609 -0.73,1.4532 -1.76,2.6289 -3.13,3.5235 -1.35,0.8906 -3.21,1.2812 -5.59,1.1875 l -19.11,0 0,-23.5 -5.04,0 0,52.914 24.23,0"
|
|
||||||
id="path3118"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2208.34,81.2695 0,-4.2929 -31.49,0 0,-19.1211 29.49,0 0,-4.3008 -29.49,0 0,-20.8945 31.87,0 0,-4.3047 -36.91,0 0,52.914 36.53,0"
|
|
||||||
id="path3120"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2221.6,38.9609 c 0.9,-1.8281 2.13,-3.289 3.66,-4.375 1.58,-1.0898 3.4,-1.8671 5.53,-2.3359 2.12,-0.4727 4.41,-0.7031 6.82,-0.7031 1.38,0 2.9,0.1914 4.53,0.5976 1.62,0.3907 3.13,1.0196 4.55,1.8828 1.41,0.8711 2.58,1.9727 3.52,3.336 0.94,1.3515 1.4,3.0039 1.4,4.9258 0,1.4843 -0.32,2.7695 -0.99,3.8593 -0.66,1.086 -1.55,1.9961 -2.59,2.7383 -1.06,0.7422 -2.24,1.3438 -3.53,1.8164 -1.28,0.4688 -2.54,0.8555 -3.78,1.1524 l -11.77,2.8789 c -1.55,0.4062 -3.03,0.8906 -4.5,1.4922 -1.45,0.5898 -2.73,1.375 -3.82,2.3672 -1.08,0.9843 -1.95,2.2031 -2.62,3.6289 -0.66,1.4336 -1,3.1875 -1,5.2617 0,1.289 0.24,2.7929 0.74,4.5234 0.5,1.7266 1.42,3.3594 2.78,4.8906 1.36,1.5274 3.23,2.8243 5.59,3.8907 2.38,1.0625 5.41,1.5898 9.12,1.5898 2.61,0 5.11,-0.3398 7.48,-1.0351 2.37,-0.6915 4.46,-1.7305 6.24,-3.1133 1.77,-1.3789 3.19,-3.0977 4.24,-5.1446 1.08,-2.0546 1.6,-4.4453 1.6,-7.1601 l -5.03,0 c -0.1,2.0351 -0.55,3.7969 -1.38,5.3047 -0.81,1.5039 -1.87,2.7617 -3.18,3.7773 -1.31,1.0117 -2.82,1.7852 -4.53,2.3008 -1.71,0.5195 -3.48,0.7773 -5.37,0.7773 -1.73,0 -3.4,-0.1914 -5.01,-0.5586 -1.6,-0.371 -3,-0.9609 -4.21,-1.7812 -1.21,-0.8164 -2.19,-1.8906 -2.94,-3.2227 -0.74,-1.332 -1.1,-2.9882 -1.1,-4.9648 0,-1.2305 0.21,-2.3086 0.63,-3.2227 0.43,-0.914 0.99,-1.6953 1.73,-2.332 0.75,-0.6484 1.62,-1.1601 2.56,-1.5547 0.97,-0.4023 1.99,-0.7226 3.08,-0.9687 l 12.9,-3.1875 c 1.87,-0.4883 3.64,-1.0938 5.3,-1.8164 1.65,-0.711 3.11,-1.6055 4.37,-2.6602 1.26,-1.0625 2.24,-2.3633 2.97,-3.8945 0.71,-1.5313 1.07,-3.3867 1.07,-5.5586 0,-0.5899 -0.07,-1.3828 -0.2,-2.3672 -0.11,-0.9922 -0.41,-2.0313 -0.87,-3.1523 -0.48,-1.1133 -1.15,-2.2344 -2.01,-3.3711 -0.86,-1.1368 -2.05,-2.1602 -3.55,-3.0782 -1.5,-0.9062 -3.37,-1.6562 -5.6,-2.2226 -2.22,-0.5586 -4.89,-0.8516 -8.01,-0.8516 -3.11,0 -5.99,0.3594 -8.67,1.0781 -2.66,0.7188 -4.94,1.8125 -6.8,3.2969 -1.89,1.4844 -3.33,3.3789 -4.36,5.707 -0.99,2.3204 -1.43,5.1055 -1.29,8.375 l 5.04,0 c -0.05,-2.7148 0.38,-4.9921 1.26,-6.8164"
|
|
||||||
id="path3122"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2270.24,46.3281 c 0.79,-2.789 1.96,-5.2812 3.57,-7.4804 1.6,-2.1993 3.67,-3.9688 6.18,-5.2969 2.52,-1.3399 5.54,-2.0039 9.04,-2.0039 3.51,0 6.52,0.664 9.02,2.0039 2.49,1.3281 4.54,3.0976 6.15,5.2969 1.6,2.1992 2.77,4.6914 3.55,7.4804 0.77,2.793 1.15,5.6211 1.15,8.4844 0,2.918 -0.38,5.7578 -1.15,8.5273 -0.78,2.7618 -1.95,5.2461 -3.55,7.4454 -1.61,2.2031 -3.66,3.9648 -6.15,5.3007 -2.5,1.3321 -5.51,2 -9.02,2 -3.5,0 -6.52,-0.6679 -9.04,-2 -2.51,-1.3359 -4.58,-3.0976 -6.18,-5.3007 -1.61,-2.1993 -2.78,-4.6836 -3.57,-7.4454 -0.75,-2.7695 -1.13,-5.6093 -1.13,-8.5273 0,-2.8633 0.38,-5.6914 1.13,-8.4844 z m -4.62,18.9336 c 1.04,3.3125 2.59,6.2383 4.66,8.7813 2.09,2.5429 4.68,4.5742 7.83,6.0781 3.14,1.5078 6.78,2.2578 10.92,2.2578 4.15,0 7.8,-0.75 10.9,-2.2578 3.11,-1.5039 5.7,-3.5352 7.79,-6.0781 2.07,-2.543 3.63,-5.4688 4.66,-8.7813 1.04,-3.3047 1.56,-6.789 1.56,-10.4492 0,-3.6602 -0.52,-7.1406 -1.56,-10.4414 -1.03,-3.3164 -2.59,-6.2305 -4.66,-8.7461 -2.09,-2.5195 -4.68,-4.5312 -7.79,-6.0391 -3.1,-1.5039 -6.75,-2.2656 -10.9,-2.2656 -4.14,0 -7.78,0.7617 -10.92,2.2656 -3.15,1.5079 -5.74,3.5196 -7.83,6.0391 -2.07,2.5156 -3.62,5.4297 -4.66,8.7461 -1.04,3.3008 -1.56,6.7812 -1.56,10.4414 0,3.6602 0.52,7.1445 1.56,10.4492"
|
|
||||||
id="path3124"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2328.53,81.2695 0,-32.7539 c 0,-3.0625 0.35,-5.664 1.03,-7.8242 0.69,-2.1406 1.71,-3.8984 3.05,-5.2578 1.33,-1.3555 2.97,-2.3477 4.88,-2.9648 1.93,-0.6172 4.11,-0.9219 6.52,-0.9219 2.47,0 4.67,0.3047 6.61,0.9219 1.93,0.6171 3.55,1.6093 4.88,2.9648 1.34,1.3594 2.35,3.1172 3.04,5.2578 0.69,2.1602 1.04,4.7617 1.04,7.8242 l 0,32.7539 5.04,0 0,-33.8672 c 0,-2.7148 -0.38,-5.2968 -1.14,-7.7382 -0.77,-2.4493 -1.99,-4.5899 -3.65,-6.418 -1.66,-1.8242 -3.76,-3.2695 -6.36,-4.332 -2.6,-1.0586 -5.74,-1.5938 -9.46,-1.5938 -3.65,0 -6.77,0.5352 -9.37,1.5938 -2.59,1.0625 -4.71,2.5078 -6.37,4.332 -1.66,1.8281 -2.87,3.9687 -3.63,6.418 -0.77,2.4414 -1.13,5.0234 -1.13,7.7382 l 0,33.8672 5.02,0"
|
|
||||||
id="path3126"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2400.87,56.1484 c 1.51,0 2.99,0.2383 4.36,0.7071 1.39,0.4687 2.59,1.1484 3.63,2.0351 1.03,0.8907 1.86,1.9688 2.49,3.2227 0.62,1.2617 0.92,2.7109 0.92,4.332 0,3.2656 -0.94,5.836 -2.82,7.7031 -1.86,1.8829 -4.73,2.8282 -8.58,2.8282 l -18.83,0 0,-20.8282 18.83,0 z m 0.36,25.1211 c 2.18,0 4.23,-0.2695 6.2,-0.8203 1.94,-0.539 3.64,-1.3633 5.11,-2.4765 1.45,-1.1133 2.61,-2.543 3.47,-4.3008 0.88,-1.7578 1.29,-3.8125 1.29,-6.1875 0,-3.3594 -0.85,-6.2696 -2.58,-8.7461 -1.73,-2.4688 -4.29,-4.0469 -7.71,-4.7383 l 0,-0.1484 c 1.73,-0.25 3.17,-0.7032 4.31,-1.3672 1.11,-0.668 2.05,-1.5235 2.77,-2.5586 0.71,-1.0391 1.23,-2.2344 1.55,-3.5977 0.32,-1.3593 0.52,-2.8281 0.63,-4.4062 0.05,-0.8867 0.11,-1.9766 0.16,-3.2656 0.04,-1.2852 0.15,-2.5782 0.29,-3.8868 0.14,-1.3125 0.38,-2.5468 0.7,-3.707 0.31,-1.1562 0.75,-2.0586 1.3,-2.707 l -5.56,0 c -0.29,0.5 -0.53,1.1015 -0.71,1.8203 -0.16,0.7187 -0.29,1.4531 -0.36,2.2265 -0.09,0.7618 -0.14,1.5118 -0.19,2.25 -0.05,0.7461 -0.1,1.3946 -0.15,1.9297 -0.09,1.875 -0.27,3.7461 -0.47,5.6016 -0.23,1.8555 -0.69,3.5 -1.42,4.9609 -0.71,1.4532 -1.75,2.6289 -3.1,3.5235 -1.37,0.8906 -3.23,1.2812 -5.6,1.1875 l -19.12,0 0,-23.5 -5.04,0 0,52.914 24.23,0"
|
|
||||||
id="path3128"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2465.16,70.7109 c -1.02,1.6094 -2.27,2.9493 -3.71,4.0391 -1.47,1.0859 -3.08,1.9141 -4.82,2.4844 -1.75,0.5625 -3.59,0.8515 -5.53,0.8515 -3.5,0 -6.51,-0.6679 -9.03,-2 -2.52,-1.3359 -4.6,-3.0976 -6.18,-5.3007 -1.62,-2.1993 -2.8,-4.6836 -3.58,-7.4454 -0.76,-2.7695 -1.14,-5.6093 -1.14,-8.5273 0,-2.8633 0.38,-5.6914 1.14,-8.4844 0.78,-2.789 1.96,-5.2812 3.58,-7.4804 1.58,-2.1993 3.66,-3.9688 6.18,-5.2969 2.52,-1.3399 5.53,-2.0039 9.03,-2.0039 2.47,0 4.7,0.4453 6.66,1.332 2,0.8906 3.7,2.1016 5.13,3.6289 1.44,1.5274 2.6,3.3281 3.48,5.3711 0.9,2.0508 1.46,4.2695 1.71,6.6367 l 5.04,0 c -0.35,-3.2578 -1.13,-6.1953 -2.3,-8.8203 -1.19,-2.6172 -2.72,-4.8359 -4.59,-6.668 -1.88,-1.8281 -4.09,-3.2304 -6.63,-4.2226 -2.56,-0.9844 -5.37,-1.4844 -8.5,-1.4844 -4.15,0 -7.79,0.7617 -10.93,2.2656 -3.13,1.5079 -5.74,3.5196 -7.83,6.0391 -2.05,2.5156 -3.62,5.4297 -4.65,8.7461 -1.04,3.3008 -1.56,6.7812 -1.56,10.4414 0,3.6602 0.52,7.1445 1.56,10.4492 1.03,3.3125 2.6,6.2383 4.65,8.7813 2.09,2.5429 4.7,4.5742 7.83,6.0781 3.14,1.5078 6.78,2.2578 10.93,2.2578 2.52,0 4.97,-0.3711 7.38,-1.1094 2.39,-0.7382 4.57,-1.8398 6.52,-3.2968 1.95,-1.461 3.57,-3.25 4.89,-5.3711 1.31,-2.1289 2.14,-4.5703 2.48,-7.3399 l -5.04,0 c -0.45,2.0274 -1.17,3.8399 -2.17,5.4492"
|
|
||||||
id="path3130"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 2519.59,81.2695 0,-4.2929 -31.5,0 0,-19.1211 29.5,0 0,-4.3008 -29.5,0 0,-20.8945 31.86,0 0,-4.3047 -36.9,0 0,52.914 36.54,0"
|
|
||||||
id="path3132"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 109.109,130.879 c -2.171,6.246 -5.242,11.781 -9.2145,16.601 -3.9765,4.825 -8.8007,8.7 -14.4765,11.637 -5.6758,2.938 -12.1133,4.395 -19.2969,4.395 -7.375,0 -13.9023,-1.457 -19.5781,-4.395 -5.6797,-2.937 -10.5039,-6.812 -14.4766,-11.637 -3.9726,-4.82 -7.1406,-10.41 -9.5078,-16.75 -2.3633,-6.332 -3.9258,-12.816 -4.6758,-19.433 l 94.7732,0 c -0.179,6.812 -1.371,13.348 -3.547,19.582 z M 20.5703,76.2539 c 1.8008,-6.9141 4.6875,-13.1055 8.6563,-18.5937 3.9765,-5.4883 8.9922,-10.0235 15.0429,-13.6133 6.0547,-3.6016 13.336,-5.3985 21.8516,-5.3985 13.0586,0 23.2734,3.4102 30.6484,10.2188 7.3755,6.8008 12.4885,15.8867 15.3205,27.2344 l 17.883,0 C 126.184,59.457 119.234,46.5898 109.109,37.5195 98.9922,28.4258 84.6602,23.8906 66.1211,23.8906 c -11.5352,0 -21.5234,2.043 -29.9336,6.1133 C 27.7578,34.0664 20.9023,39.6445 15.6094,46.7422 10.3125,53.8281 6.39063,62.0586 3.83203,71.4336 1.28125,80.7891 0,90.6719 0,101.086 c 0,9.641 1.28125,19.098 3.83203,28.371 2.5586,9.27 6.48047,17.551 11.77737,24.828 5.2929,7.285 12.1484,13.153 20.5781,17.606 8.4102,4.437 18.3984,6.664 29.9336,6.664 11.7266,0 21.7539,-2.375 30.0859,-7.102 8.32,-4.719 15.078,-10.922 20.285,-18.578 5.196,-7.66 8.938,-16.461 11.203,-26.395 2.278,-9.937 3.219,-20 2.84,-30.2222 l -112.6522,0 c 0,-6.4336 0.8867,-13.1055 2.6875,-20.0039"
|
|
||||||
id="path3134"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 157.859,174.297 0,-25.258 0.571,0 c 3.41,8.895 9.457,16.039 18.164,21.426 8.695,5.398 18.254,8.09 28.66,8.09 10.219,0 18.777,-1.325 25.68,-3.977 6.91,-2.648 12.441,-6.379 16.601,-11.203 4.16,-4.824 7.098,-10.738 8.797,-17.734 1.699,-7.008 2.555,-14.864 2.555,-23.555 l 0,-94.2188 -17.875,0 0,91.3708 c 0,6.246 -0.567,12.059 -1.703,17.461 -1.141,5.387 -3.121,10.067 -5.957,14.047 -2.844,3.969 -6.676,7.09 -11.5,9.359 -4.821,2.274 -10.829,3.407 -18.02,3.407 -7.191,0 -13.578,-1.278 -19.152,-3.828 -5.578,-2.555 -10.309,-6.055 -14.192,-10.5 -3.879,-4.442 -6.91,-9.743 -9.082,-15.895 -2.172,-6.156 -3.355,-12.82 -3.547,-20.004 l 0,-85.4178 -17.871,0 0,146.4298 17.871,0"
|
|
||||||
id="path3136"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 274.938,174.297 45.976,-128.5509 0.566,0 45.407,128.5509 18.449,0 -54.77,-146.4298 -19.019,0 -56.465,146.4298 19.856,0"
|
|
||||||
id="path3138"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 409.707,174.297 0,-146.4298 -17.875,0 0,146.4298 17.875,0 z m 0,56.187 0,-28.664 -17.875,0 0,28.664 17.875,0"
|
|
||||||
id="path3140"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 487.02,104.863 c 3.683,0 7.222,0.27 10.632,0.809 3.407,0.547 6.403,1.601 8.993,3.172 2.589,1.566 4.668,3.785 6.238,6.648 1.558,2.852 2.347,6.613 2.347,11.235 0,4.636 -0.789,8.39 -2.347,11.25 -1.57,2.859 -3.649,5.074 -6.238,6.64 -2.59,1.571 -5.586,2.629 -8.993,3.172 -3.41,0.547 -6.949,0.813 -10.632,0.813 l -24.934,0 0,-43.739 24.934,0 z m 8.793,68.68 c 9.128,0 16.898,-1.32 23.304,-3.988 6.406,-2.66 11.613,-6.16 15.633,-10.524 4.023,-4.359 6.961,-9.34 8.797,-14.922 1.84,-5.589 2.758,-11.379 2.758,-17.382 0,-5.852 -0.918,-11.614 -2.758,-17.27 -1.836,-5.652 -4.774,-10.664 -8.797,-15.0273 -4.02,-4.3633 -9.227,-7.8672 -15.633,-10.5234 -6.406,-2.6602 -14.176,-3.9844 -23.304,-3.9844 l -33.727,0 0,-52.336 -32.102,0 0,145.9571 65.829,0"
|
|
||||||
id="path3142"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 614.273,76.7539 c -1.835,-0.6211 -3.812,-1.1289 -5.929,-1.5351 -2.114,-0.4102 -4.324,-0.75 -6.641,-1.0196 -2.316,-0.2773 -4.637,-0.6211 -6.953,-1.0273 -2.176,-0.4102 -4.328,-0.9571 -6.437,-1.6328 -2.114,-0.6836 -3.958,-1.6016 -5.52,-2.7618 -1.566,-1.1562 -2.832,-2.625 -3.777,-4.3945 -0.957,-1.7773 -1.438,-4.0234 -1.438,-6.7461 0,-2.5937 0.481,-4.7695 1.438,-6.5429 0.945,-1.7696 2.246,-3.168 3.879,-4.1915 1.636,-1.0234 3.543,-1.7382 5.726,-2.1484 2.176,-0.4101 4.426,-0.6094 6.746,-0.6094 5.723,0 10.145,0.9532 13.285,2.8672 3.133,1.9024 5.45,4.1875 6.953,6.8438 1.497,2.6562 2.418,5.3476 2.758,8.0742 0.336,2.7226 0.516,4.9101 0.516,6.543 l 0,10.8398 c -1.234,-1.1055 -2.766,-1.9492 -4.606,-2.5586 z m -57.339,40.9841 c 3,4.496 6.812,8.106 11.449,10.832 4.637,2.723 9.844,4.672 15.637,5.828 5.789,1.157 11.617,1.735 17.48,1.735 5.316,0 10.691,-0.375 16.145,-1.125 5.457,-0.75 10.425,-2.211 14.921,-4.395 4.504,-2.175 8.18,-5.207 11.043,-9.093 2.86,-3.883 4.297,-9.032 4.297,-15.434 l 0,-54.9922 c 0,-4.7774 0.27,-9.336 0.817,-13.6954 0.539,-4.3632 1.496,-7.6328 2.859,-9.8125 l -29.437,0 c -0.543,1.6329 -0.989,3.3008 -1.329,5.0118 -0.343,1.6992 -0.582,3.4414 -0.718,5.2109 -4.633,-4.7734 -10.082,-8.1133 -16.348,-10.0156 -6.273,-1.9063 -12.676,-2.8672 -19.219,-2.8672 -5.043,0 -9.746,0.6172 -14.105,1.8398 -4.367,1.2266 -8.18,3.1367 -11.449,5.7305 -3.27,2.5859 -5.825,5.8594 -7.668,9.8125 -1.84,3.9492 -2.758,8.6523 -2.758,14.1016 0,5.9961 1.058,10.9375 3.168,14.8242 2.109,3.8789 4.836,6.9726 8.179,9.2969 3.34,2.3164 7.157,4.0585 11.446,5.2148 4.297,1.1562 8.617,2.0742 12.98,2.7539 4.364,0.6836 8.656,1.2266 12.879,1.6367 4.227,0.4102 7.973,1.0235 11.25,1.8438 3.266,0.8125 5.856,2.0117 7.762,3.582 1.91,1.5664 2.793,3.8477 2.664,6.8435 0,3.137 -0.516,5.617 -1.535,7.461 -1.028,1.844 -2.395,3.266 -4.09,4.293 -1.707,1.02 -3.68,1.699 -5.93,2.039 -2.25,0.344 -4.672,0.516 -7.258,0.516 -5.718,0 -10.222,-1.223 -13.488,-3.68 -3.277,-2.453 -5.183,-6.543 -5.726,-12.265 l -29.032,0 c 0.41,6.816 2.118,12.46 5.114,16.968"
|
|
||||||
id="path3144"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 720.172,133.277 0,-19.422 -21.254,0 0,-52.3355 c 0,-4.9023 0.812,-8.1718 2.449,-9.8047 1.637,-1.6406 4.903,-2.4609 9.817,-2.4609 1.632,0 3.195,0.0703 4.699,0.2031 1.496,0.1328 2.926,0.3438 4.289,0.6172 l 0,-22.4883 c -2.453,-0.414 -5.176,-0.6836 -8.176,-0.8203 -2.996,-0.1289 -5.926,-0.1992 -8.789,-0.1992 -4.5,0 -8.754,0.3047 -12.773,0.918 -4.024,0.6094 -7.563,1.8086 -10.629,3.5781 -3.071,1.7695 -5.489,4.293 -7.254,7.5586 -1.781,3.2773 -2.664,7.5703 -2.664,12.8828 l 0,62.3511 -17.578,0 0,19.422 17.578,0 0,31.684 29.031,0 0,-31.684 21.254,0"
|
|
||||||
id="path3146"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 755.918,173.543 0,-54.984 0.613,0 c 3.684,6.125 8.387,10.586 14.11,13.379 5.722,2.796 11.312,4.195 16.761,4.195 7.77,0 14.137,-1.059 19.114,-3.164 4.972,-2.114 8.894,-5.043 11.754,-8.793 2.863,-3.75 4.871,-8.317 6.031,-13.699 1.152,-5.383 1.734,-11.3481 1.734,-17.8832 l 0,-65.0079 -29.027,0 0,59.6954 c 0,8.7148 -1.363,15.2227 -4.086,19.5157 -2.731,4.293 -7.567,6.433 -14.516,6.433 -7.902,0 -13.633,-2.343 -17.172,-7.039 -3.543,-4.703 -5.316,-12.441 -5.316,-23.2144 l 0,-55.3907 -29.023,0 0,145.9571 29.023,0"
|
|
||||||
id="path3148"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /><path
|
|
||||||
d="m 863.082,0 21.875,0 0,190.547 -21.875,0 0,-190.547 z"
|
|
||||||
id="path3150"
|
|
||||||
style="fill:#090c0d;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></svg>
|
|
||||||
|
Before Width: | Height: | Size: 41 KiB |
9
static/images/logo-mission.svg
Normal file
|
After Width: | Height: | Size: 22 KiB |
3
static/images/logo-name.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 104 26" role="img" fill="currentColor">
|
||||||
|
<path id="ep-logo-name" d="M13.638 12.451a6.613 6.613 0 0 0-1.152-2.075 5.687 5.687 0 0 0-1.81-1.455c-.708-.369-1.513-.55-2.411-.55-.922 0-1.739.181-2.447.55a5.702 5.702 0 0 0-1.81 1.455 7.21 7.21 0 0 0-1.188 2.092 10.28 10.28 0 0 0-.586 2.43h11.848a8.013 8.013 0 0 0-.444-2.447zM2.571 19.277a6.885 6.885 0 0 0 1.082 2.324 6.187 6.187 0 0 0 1.88 1.702c.757.452 1.667.676 2.732.676 1.633 0 2.91-.427 3.83-1.277.923-.852 1.563-1.987 1.917-3.405h2.234c-.474 2.08-1.342 3.689-2.608 4.824-1.264 1.135-3.056 1.702-5.373 1.702-1.442 0-2.69-.254-3.742-.765-1.053-.507-1.91-1.203-2.572-2.092C1.29 22.082.8 21.052.48 19.88A13.991 13.991 0 0 1 0 16.174c0-1.206.16-2.388.479-3.547a9.56 9.56 0 0 1 1.472-3.103c.662-.91 1.519-1.643 2.572-2.2 1.051-.554 2.3-.833 3.742-.833 1.466 0 2.72.296 3.76.887A7.487 7.487 0 0 1 14.562 9.7c.65.959 1.118 2.058 1.401 3.3.284 1.243.402 2.5.354 3.777H2.234c0 .806.113 1.638.337 2.5M19.732 7.024v3.156h.07c.428-1.113 1.184-2.004 2.271-2.678a6.654 6.654 0 0 1 3.584-1.01c1.277 0 2.346.163 3.21.495.862.332 1.555.799 2.075 1.402.52.603.887 1.342 1.1 2.216.212.877.32 1.858.32 2.945v11.777h-2.235v-11.42c0-.782-.071-1.51-.214-2.184-.142-.673-.39-1.26-.745-1.757a3.61 3.61 0 0 0-1.436-1.17c-.603-.283-1.354-.425-2.253-.425-.898 0-1.697.16-2.395.479a5.221 5.221 0 0 0-1.772 1.31 6.034 6.034 0 0 0-1.136 1.988 8.128 8.128 0 0 0-.444 2.5v10.679h-2.234V7.024h2.234M34.367 7.024l5.747 16.067h.071L45.86 7.024h2.307l-6.846 18.303h-2.378L31.885 7.024h2.482M51.214 7.024v18.303h-2.235V7.024h2.235zm0-7.024V3.58h-2.235V0h2.235M61.037 15.703c.46 0 .902-.034 1.33-.103.424-.068.799-.2 1.122-.395.325-.195.584-.474.78-.833.196-.356.294-.825.294-1.404 0-.578-.098-1.047-.294-1.406a2.162 2.162 0 0 0-.78-.83 3.104 3.104 0 0 0-1.123-.395 8.39 8.39 0 0 0-1.329-.103H57.92v5.469h3.117zm1.099-8.587c1.14 0 2.112.166 2.913.498.801.335 1.452.772 1.953 1.316.503.545.871 1.167 1.1 1.866a6.89 6.89 0 0 1 .346 2.172c0 .733-.115 1.453-.346 2.159a5.043 5.043 0 0 1-1.1 1.88c-.501.544-1.152.984-1.953 1.316-.8.332-1.772.498-2.913.498H57.92v6.54h-4.013V7.116h8.229M76.944 19.216a5.26 5.26 0 0 1-.742.19c-.264.052-.54.096-.83.13-.29.034-.579.076-.87.127-.27.051-.54.12-.804.205-.263.085-.494.2-.69.344-.195.144-.354.33-.472.55-.12.222-.18.502-.18.844 0 .323.06.596.18.818.118.22.28.396.485.523.205.129.443.217.716.268.272.051.553.076.844.076.715 0 1.267-.117 1.66-.357.392-.239.68-.525.869-.857.187-.332.303-.668.344-1.008a6.93 6.93 0 0 0 .065-.818v-1.355a1.615 1.615 0 0 1-.575.32zm-7.168-5.124a4.345 4.345 0 0 1 1.43-1.353 6.257 6.257 0 0 1 1.956-.73 11.148 11.148 0 0 1 2.185-.215c.664 0 1.336.047 2.018.14a6.193 6.193 0 0 1 1.866.549 3.69 3.69 0 0 1 1.38 1.137c.356.486.537 1.128.537 1.93v6.874c0 .596.033 1.167.102 1.712.066.544.186.954.357 1.225h-3.68a5.23 5.23 0 0 1-.256-1.277 4.735 4.735 0 0 1-2.043 1.253 8.261 8.261 0 0 1-2.402.356c-.63 0-1.219-.076-1.763-.23a4.016 4.016 0 0 1-1.432-.715 3.34 3.34 0 0 1-.958-1.228c-.23-.493-.344-1.081-.344-1.762 0-.75.131-1.368.395-1.853a3.324 3.324 0 0 1 1.023-1.163 4.648 4.648 0 0 1 1.43-.651 15.515 15.515 0 0 1 1.623-.345 27.623 27.623 0 0 1 1.61-.202c.527-.052.996-.13 1.406-.232.408-.1.732-.252.97-.447.239-.195.349-.48.333-.857 0-.39-.065-.7-.192-.933a1.406 1.406 0 0 0-.511-.534 2.014 2.014 0 0 0-.741-.257 6.208 6.208 0 0 0-.907-.063c-.715 0-1.278.151-1.686.459-.41.308-.648.818-.716 1.533h-3.63c.052-.852.265-1.557.64-2.121M90.181 12.15v2.427h-2.657v6.543c0 .613.101 1.02.306 1.226.205.205.613.308 1.227.308.204 0 .399-.01.587-.027.188-.015.366-.042.537-.076v2.81a8.619 8.619 0 0 1-1.023.103c-.373.017-.74.024-1.098.024a10.41 10.41 0 0 1-1.597-.115 3.728 3.728 0 0 1-1.328-.446 2.356 2.356 0 0 1-.907-.945c-.222-.41-.333-.945-.333-1.61v-7.795h-2.198v-2.426h2.198V8.19h3.629v3.96h2.657M94.703 7.116v6.873h.075c.462-.764 1.05-1.323 1.764-1.672.716-.35 1.415-.523 2.096-.523.97 0 1.767.132 2.388.396.622.263 1.113.63 1.47 1.098.358.47.609 1.04.754 1.712.144.674.217 1.418.217 2.236v8.125h-3.629v-7.46c0-1.09-.17-1.905-.511-2.44-.34-.537-.945-.805-1.814-.805-.988 0-1.704.293-2.146.88-.443.587-.664 1.556-.664 2.901v6.924h-3.628V7.116h3.628" class="logo-main"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.1 KiB |
3
static/images/logo-square.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg fill="currentColor" id="ep-logo-square" role="img" viewBox="0 0 65 65" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M26.538 25.283c-.532-1.519-1.274-2.861-2.24-4.037a11.163 11.163 0 0 0-3.522-2.828c-1.381-.712-2.948-1.07-4.697-1.07-1.791 0-3.379.358-4.76 1.07a11.11 11.11 0 0 0-3.522 2.828c-.966 1.176-1.737 2.533-2.308 4.07a19.839 19.839 0 0 0-1.139 4.728h23.047a15.559 15.559 0 0 0-.86-4.76zM5 38.57c.44 1.685 1.143 3.189 2.11 4.527.966 1.333 2.187 2.436 3.656 3.31 1.475.875 3.243 1.308 5.313 1.308 3.178 0 5.665-.83 7.456-2.485 1.793-1.65 3.037-3.867 3.726-6.626h4.35c-.922 4.054-2.613 7.179-5.073 9.39-2.46 2.208-5.947 3.315-10.46 3.315-2.802 0-5.233-.502-7.274-1.489-2.056-.986-3.721-2.348-5.01-4.072-1.284-1.724-2.241-3.725-2.861-6.005C.313 37.465 0 35.058 0 32.529c0-2.343.313-4.649.933-6.9.62-2.254 1.577-4.267 2.861-6.04 1.289-1.772 2.954-3.197 5.01-4.281 2.041-1.08 4.472-1.616 7.275-1.616 2.856 0 5.293.571 7.32 1.724 2.026 1.147 3.666 2.66 4.931 4.521 1.265 1.86 2.177 3.999 2.725 6.416a27.9 27.9 0 0 1 .692 7.348H4.35c0 1.567.215 3.188.65 4.868M49.301 31.456c.914 0 1.793-.07 2.638-.202.845-.136 1.586-.4 2.23-.78.641-.391 1.159-.942 1.548-1.656.387-.702.582-1.64.582-2.782 0-1.148-.195-2.08-.582-2.79-.39-.707-.907-1.26-1.547-1.65-.645-.386-1.386-.65-2.231-.78a16.554 16.554 0 0 0-2.638-.206h-6.176v10.846h6.176zm2.184-17.032c2.26 0 4.189.331 5.776.995 1.592.66 2.88 1.524 3.877 2.608a10.007 10.007 0 0 1 2.177 3.696c.46 1.393.684 2.828.684 4.313 0 1.455-.224 2.88-.684 4.28a9.955 9.955 0 0 1-2.177 3.727c-.997 1.079-2.285 1.953-3.877 2.607-1.587.664-3.516.992-5.776.992h-8.36v12.974h-7.964V14.424h16.324" class="logo-main"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
BIN
static/images/uoa-logo-small.png
Executable file
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 91 KiB |
488
static/images/uzh-logo.svg
Normal file
@ -0,0 +1,488 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
|
||||||
|
<svg version="1.1" baseProfile="tiny" id="Universität_Zürich"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="-0.499 -0.501 142.73 49.19" xml:space="preserve">
|
||||||
|
<path d="M6.818,32.721C6.296,32.944,6.2,32.986,6.093,33.04c-0.113,0.058-0.156,0.108-0.133,0.231
|
||||||
|
c0.005,0.029,0.026,0.091,0.047,0.139c0.017,0.038,0.019,0.062-0.006,0.071c-0.023,0.011-0.041-0.01-0.062-0.062
|
||||||
|
c-0.078-0.182-0.161-0.401-0.205-0.506c-0.035-0.082-0.138-0.295-0.191-0.418c-0.021-0.052-0.024-0.079-0.001-0.089
|
||||||
|
c0.024-0.011,0.04,0.007,0.056,0.042c0.016,0.037,0.027,0.057,0.053,0.095c0.057,0.086,0.127,0.088,0.25,0.043
|
||||||
|
c0.113-0.04,0.209-0.081,0.731-0.305l0.481-0.206c0.499-0.215,0.666-0.404,0.729-0.631c0.062-0.21,0.008-0.373-0.043-0.49
|
||||||
|
c-0.063-0.151-0.191-0.315-0.389-0.395c-0.27-0.108-0.584,0.014-0.938,0.166l-0.431,0.184c-0.521,0.225-0.619,0.266-0.726,0.319
|
||||||
|
c-0.114,0.058-0.157,0.107-0.132,0.23c0.005,0.031,0.025,0.091,0.042,0.129c0.016,0.037,0.018,0.062-0.006,0.071
|
||||||
|
c-0.024,0.011-0.041-0.011-0.062-0.06C5.083,31.425,5.001,31.204,5,31.201c-0.018-0.042-0.121-0.254-0.178-0.387
|
||||||
|
c-0.021-0.048-0.024-0.075,0-0.085c0.024-0.012,0.04,0.007,0.057,0.048c0.017,0.038,0.029,0.058,0.054,0.096
|
||||||
|
c0.057,0.085,0.127,0.088,0.25,0.043c0.112-0.04,0.209-0.082,0.73-0.306l0.368-0.157c0.382-0.164,0.803-0.3,1.175-0.117
|
||||||
|
c0.314,0.154,0.458,0.387,0.554,0.608c0.078,0.183,0.21,0.517,0.091,0.865c-0.083,0.242-0.281,0.481-0.78,0.695L6.818,32.721z
|
||||||
|
M6.676,28.899c0.283-0.069,0.368-0.139,0.378-0.217c0.008-0.066-0.004-0.138-0.017-0.195c-0.009-0.04-0.007-0.063,0.017-0.068
|
||||||
|
c0.028-0.006,0.043,0.025,0.055,0.076c0.052,0.237,0.073,0.386,0.088,0.455c0.007,0.033,0.056,0.202,0.098,0.393
|
||||||
|
c0.011,0.048,0.015,0.081-0.019,0.089c-0.022,0.005-0.034-0.017-0.042-0.053c-0.01-0.048-0.028-0.111-0.054-0.16
|
||||||
|
c-0.051-0.089-0.159-0.079-0.479-0.015l-2.169,0.442c-0.073,0.016-0.127,0.016-0.135-0.021c-0.009-0.04,0.031-0.083,0.083-0.16
|
||||||
|
c0.038-0.054,0.511-0.739,0.924-1.39c0.194-0.303,0.612-0.911,0.657-0.986l-0.004-0.018l-1.633,0.396
|
||||||
|
c-0.222,0.053-0.283,0.102-0.301,0.196c-0.01,0.061,0.009,0.146,0.021,0.198c0.01,0.044,0.002,0.061-0.021,0.064
|
||||||
|
c-0.028,0.008-0.042-0.032-0.054-0.088C4.028,27.651,4,27.474,3.984,27.397c-0.009-0.041-0.05-0.178-0.09-0.356
|
||||||
|
c-0.011-0.048-0.016-0.085,0.015-0.091c0.022-0.005,0.038,0.015,0.047,0.059c0.008,0.036,0.015,0.065,0.035,0.106
|
||||||
|
c0.051,0.097,0.135,0.108,0.34,0.067l2.313-0.467c0.08-0.018,0.115-0.01,0.124,0.022c0.009,0.041-0.021,0.094-0.054,0.143
|
||||||
|
c-0.168,0.277-0.544,0.852-0.837,1.312c-0.308,0.484-0.675,0.99-0.729,1.071l0.002,0.011L6.676,28.899z M4.871,25.556
|
||||||
|
c-0.566,0.035-0.672,0.042-0.791,0.058c-0.126,0.016-0.188,0.057-0.201,0.14C3.87,25.796,3.87,25.844,3.873,25.89
|
||||||
|
c0.002,0.036-0.004,0.06-0.034,0.062c-0.021,0.002-0.031-0.027-0.035-0.087c-0.01-0.142-0.014-0.378-0.021-0.486
|
||||||
|
c-0.006-0.093-0.031-0.312-0.04-0.455c-0.003-0.048,0.003-0.079,0.025-0.081c0.029-0.002,0.039,0.021,0.041,0.059
|
||||||
|
c0.002,0.037,0.008,0.066,0.018,0.111c0.025,0.1,0.09,0.126,0.222,0.123c0.12,0,0.225-0.006,0.792-0.042l0.657-0.042
|
||||||
|
c0.362-0.021,0.657-0.041,0.816-0.065c0.1-0.019,0.166-0.048,0.173-0.161c0.004-0.053,0.006-0.135,0.003-0.191
|
||||||
|
c-0.002-0.042,0.007-0.061,0.026-0.062c0.025-0.001,0.039,0.028,0.042,0.069c0.016,0.246,0.02,0.48,0.025,0.583
|
||||||
|
c0.005,0.086,0.031,0.319,0.041,0.47c0.003,0.048-0.006,0.075-0.033,0.076c-0.019,0.002-0.03-0.014-0.033-0.059
|
||||||
|
c-0.003-0.056-0.015-0.1-0.023-0.133c-0.02-0.074-0.084-0.093-0.193-0.097c-0.157-0.009-0.452,0.01-0.814,0.032L4.871,25.556z
|
||||||
|
M4.071,23.877c-0.21,0.073-0.256,0.134-0.302,0.267c-0.02,0.055-0.022,0.114-0.024,0.145c-0.002,0.034-0.014,0.044-0.037,0.043
|
||||||
|
c-0.029-0.002-0.031-0.043-0.026-0.099c0.013-0.198,0.038-0.41,0.045-0.541c0.006-0.093,0.006-0.273,0.019-0.46
|
||||||
|
c0.003-0.045,0.013-0.085,0.039-0.084c0.026,0.002,0.032,0.024,0.03,0.059c-0.003,0.061-0.003,0.116,0.017,0.147
|
||||||
|
c0.018,0.026,0.042,0.041,0.076,0.042c0.049,0.003,0.155-0.024,0.293-0.067l1.736-0.534l0.001-0.015
|
||||||
|
c-0.4-0.188-1.571-0.749-1.812-0.854c-0.047-0.021-0.102-0.041-0.136-0.042c-0.03-0.002-0.061,0.012-0.074,0.044
|
||||||
|
c-0.018,0.045-0.024,0.101-0.027,0.148c-0.003,0.034-0.009,0.063-0.034,0.062c-0.03-0.002-0.035-0.036-0.031-0.106
|
||||||
|
c0.012-0.188,0.033-0.343,0.036-0.391c0.004-0.063,0.004-0.24,0.011-0.353c0.003-0.048,0.013-0.078,0.039-0.076
|
||||||
|
c0.026,0.001,0.032,0.024,0.029,0.062C3.935,21.311,3.93,21.389,3.97,21.46C4,21.51,4.06,21.571,4.293,21.687
|
||||||
|
c0.342,0.168,0.537,0.281,0.983,0.513c0.53,0.274,0.926,0.476,1.106,0.569c0.21,0.11,0.27,0.137,0.266,0.188
|
||||||
|
c-0.003,0.048-0.058,0.067-0.236,0.127L4.071,23.877z M5.128,20.567c-0.556-0.12-0.657-0.143-0.776-0.16
|
||||||
|
c-0.126-0.019-0.191-0.002-0.242,0.113c-0.014,0.026-0.031,0.089-0.042,0.14c-0.009,0.041-0.021,0.062-0.046,0.055
|
||||||
|
c-0.026-0.006-0.027-0.032-0.017-0.087c0.021-0.099,0.047-0.204,0.067-0.295c0.024-0.095,0.045-0.178,0.057-0.229
|
||||||
|
c0.025-0.117,0.183-0.846,0.193-0.916c0.007-0.071,0.013-0.131,0.012-0.162c0-0.02-0.006-0.043-0.002-0.062
|
||||||
|
c0.004-0.018,0.02-0.019,0.038-0.015c0.025,0.005,0.065,0.033,0.231,0.08c0.036,0.012,0.194,0.054,0.236,0.07
|
||||||
|
c0.019,0.008,0.038,0.02,0.032,0.045c-0.005,0.024-0.024,0.028-0.058,0.021C4.787,19.16,4.724,19.15,4.676,19.16
|
||||||
|
c-0.07,0.011-0.122,0.039-0.185,0.216c-0.021,0.062-0.11,0.443-0.126,0.518c-0.004,0.019,0.005,0.027,0.031,0.032l0.925,0.199
|
||||||
|
c0.025,0.005,0.041,0.005,0.045-0.017c0.018-0.081,0.108-0.501,0.119-0.587c0.011-0.089,0.012-0.146-0.018-0.188
|
||||||
|
c-0.023-0.032-0.038-0.051-0.034-0.068c0.003-0.016,0.013-0.024,0.034-0.021c0.022,0.005,0.078,0.032,0.262,0.087
|
||||||
|
c0.072,0.02,0.216,0.062,0.242,0.067C6,19.405,6.04,19.414,6.033,19.447c-0.005,0.026-0.021,0.03-0.04,0.026
|
||||||
|
c-0.037-0.005-0.084-0.015-0.135-0.014c-0.077,0.002-0.144,0.042-0.188,0.174c-0.021,0.068-0.104,0.43-0.123,0.518
|
||||||
|
c-0.004,0.018,0.011,0.024,0.032,0.03l0.289,0.062c0.125,0.027,0.46,0.104,0.567,0.122c0.254,0.047,0.32,0,0.401-0.373
|
||||||
|
c0.021-0.095,0.054-0.249,0.03-0.353c-0.022-0.104-0.091-0.165-0.235-0.224C6.594,19.4,6.581,19.39,6.587,19.364
|
||||||
|
c0.008-0.029,0.036-0.023,0.072-0.015c0.084,0.018,0.327,0.101,0.396,0.135c0.089,0.046,0.083,0.079,0.052,0.218
|
||||||
|
c-0.06,0.274-0.109,0.474-0.146,0.63c-0.041,0.156-0.068,0.27-0.093,0.378c-0.009,0.04-0.026,0.121-0.041,0.209
|
||||||
|
C6.808,21.003,6.796,21.1,6.78,21.173c-0.01,0.049-0.026,0.071-0.052,0.065c-0.019-0.004-0.026-0.021-0.018-0.065
|
||||||
|
c0.013-0.055,0.015-0.1,0.015-0.135c0.001-0.076-0.075-0.112-0.179-0.148c-0.149-0.052-0.438-0.113-0.774-0.187L5.128,20.567z
|
||||||
|
M5.822,17.875c-0.53-0.205-0.628-0.243-0.743-0.278c-0.121-0.039-0.188-0.032-0.257,0.072c-0.018,0.025-0.044,0.083-0.063,0.132
|
||||||
|
c-0.015,0.038-0.029,0.058-0.054,0.048c-0.023-0.01-0.021-0.037-0.002-0.09c0.072-0.185,0.167-0.399,0.195-0.474
|
||||||
|
c0.046-0.118,0.138-0.388,0.18-0.496c0.085-0.22,0.196-0.446,0.398-0.584c0.104-0.072,0.336-0.143,0.569-0.052
|
||||||
|
c0.259,0.1,0.454,0.299,0.604,0.763c0.511-0.16,0.915-0.28,1.21-0.401c0.278-0.117,0.357-0.251,0.389-0.3
|
||||||
|
c0.021-0.035,0.038-0.065,0.048-0.094c0.011-0.028,0.026-0.038,0.044-0.031c0.028,0.012,0.025,0.038,0.01,0.08l-0.128,0.332
|
||||||
|
c-0.075,0.195-0.126,0.276-0.21,0.349c-0.139,0.118-0.354,0.188-0.698,0.279c-0.246,0.065-0.545,0.135-0.615,0.159
|
||||||
|
c-0.027,0.009-0.039,0.029-0.048,0.053l-0.125,0.302c-0.007,0.018-0.004,0.03,0.017,0.039l0.049,0.019
|
||||||
|
c0.325,0.125,0.601,0.232,0.754,0.271C7.45,18,7.535,18.009,7.59,17.91c0.027-0.05,0.064-0.124,0.08-0.166
|
||||||
|
c0.012-0.028,0.027-0.038,0.044-0.031c0.024,0.011,0.025,0.038,0.009,0.083c-0.079,0.202-0.188,0.457-0.209,0.51
|
||||||
|
c-0.025,0.065-0.101,0.289-0.154,0.43C7.341,18.779,7.321,18.8,7.297,18.79c-0.018-0.007-0.021-0.023-0.006-0.065
|
||||||
|
c0.021-0.054,0.029-0.098,0.035-0.132c0.013-0.074-0.057-0.123-0.153-0.176c-0.14-0.074-0.415-0.181-0.735-0.305L5.822,17.875z
|
||||||
|
M6.257,17.57c0.038,0.015,0.056,0.013,0.075-0.007c0.053-0.063,0.104-0.164,0.138-0.251c0.054-0.141,0.058-0.19,0.036-0.271
|
||||||
|
c-0.035-0.134-0.157-0.298-0.443-0.408c-0.495-0.191-0.766,0.081-0.846,0.287c-0.033,0.087-0.055,0.151-0.058,0.19
|
||||||
|
c-0.002,0.027,0.009,0.04,0.037,0.05L6.257,17.57z M8.459,16.014c-0.053,0.038-0.074,0.04-0.146-0.001
|
||||||
|
c-0.18-0.103-0.367-0.227-0.417-0.259c-0.047-0.03-0.077-0.061-0.062-0.087c0.018-0.028,0.048-0.016,0.074-0.001
|
||||||
|
c0.042,0.024,0.118,0.05,0.183,0.064c0.281,0.064,0.479-0.077,0.594-0.278c0.166-0.293,0.049-0.549-0.123-0.646
|
||||||
|
C8.4,14.716,8.223,14.68,7.858,14.83l-0.202,0.083c-0.483,0.199-0.781,0.193-1.044,0.044c-0.357-0.204-0.445-0.647-0.188-1.101
|
||||||
|
c0.12-0.212,0.23-0.33,0.302-0.401c0.022-0.024,0.042-0.036,0.064-0.022c0.042,0.023,0.129,0.091,0.383,0.233
|
||||||
|
c0.072,0.041,0.093,0.065,0.078,0.091c-0.013,0.023-0.038,0.021-0.077,0c-0.028-0.017-0.139-0.058-0.263-0.038
|
||||||
|
c-0.089,0.015-0.241,0.054-0.361,0.265C6.413,14.224,6.47,14.45,6.665,14.56c0.15,0.085,0.307,0.074,0.664-0.079l0.12-0.052
|
||||||
|
c0.521-0.227,0.823-0.238,1.133-0.062c0.188,0.107,0.372,0.306,0.393,0.627c0.012,0.222-0.062,0.421-0.16,0.593
|
||||||
|
C8.706,15.776,8.6,15.909,8.459,16.014z M8.373,12.925c-0.459-0.335-0.544-0.396-0.645-0.462c-0.107-0.067-0.182-0.075-0.244-0.021
|
||||||
|
c-0.034,0.026-0.065,0.063-0.091,0.1c-0.022,0.03-0.042,0.044-0.066,0.026c-0.018-0.013-0.006-0.042,0.029-0.09
|
||||||
|
c0.084-0.115,0.231-0.299,0.296-0.387c0.055-0.075,0.176-0.26,0.26-0.375c0.029-0.039,0.052-0.059,0.07-0.046
|
||||||
|
c0.023,0.019,0.017,0.041-0.005,0.071c-0.022,0.03-0.037,0.057-0.058,0.097c-0.044,0.094-0.011,0.154,0.092,0.237
|
||||||
|
c0.092,0.077,0.177,0.139,0.636,0.474l0.532,0.389c0.293,0.214,0.531,0.388,0.671,0.471c0.088,0.05,0.157,0.069,0.235-0.013
|
||||||
|
c0.037-0.038,0.093-0.101,0.125-0.146c0.024-0.033,0.044-0.042,0.061-0.031c0.021,0.017,0.012,0.047-0.013,0.08
|
||||||
|
c-0.146,0.199-0.294,0.384-0.354,0.466c-0.051,0.068-0.18,0.267-0.269,0.387c-0.029,0.04-0.054,0.054-0.074,0.039
|
||||||
|
c-0.016-0.011-0.017-0.03,0.011-0.066c0.033-0.045,0.053-0.086,0.067-0.118c0.031-0.068-0.007-0.125-0.087-0.197
|
||||||
|
c-0.116-0.108-0.354-0.282-0.648-0.496L8.373,12.925z M9.295,10.406l-0.372,0.415c-0.144,0.163-0.19,0.241-0.17,0.338
|
||||||
|
c0.016,0.065,0.035,0.11,0.052,0.136c0.017,0.026,0.02,0.044,0.004,0.062c-0.019,0.019-0.037,0.012-0.066-0.018
|
||||||
|
c-0.044-0.041-0.242-0.326-0.259-0.353c-0.028-0.042-0.036-0.065-0.021-0.081c0.021-0.022,0.073-0.023,0.144-0.086
|
||||||
|
c0.083-0.071,0.186-0.169,0.271-0.259l1.018-1.076c0.083-0.087,0.131-0.154,0.164-0.2c0.029-0.049,0.045-0.076,0.056-0.086
|
||||||
|
c0.018-0.019,0.037-0.006,0.078,0.032c0.057,0.054,0.237,0.238,0.308,0.306c0.024,0.028,0.036,0.049,0.021,0.065
|
||||||
|
c-0.021,0.021-0.039,0.014-0.083-0.021l-0.032-0.024c-0.076-0.062-0.221-0.061-0.456,0.177l-0.332,0.335l1.115,1.053
|
||||||
|
c0.25,0.236,0.465,0.439,0.595,0.536c0.083,0.062,0.159,0.104,0.247,0.032c0.042-0.033,0.104-0.087,0.142-0.128
|
||||||
|
c0.028-0.03,0.05-0.036,0.062-0.023c0.02,0.019,0.007,0.047-0.021,0.077c-0.169,0.18-0.339,0.343-0.41,0.419
|
||||||
|
c-0.06,0.062-0.214,0.242-0.315,0.351c-0.033,0.035-0.06,0.047-0.079,0.028c-0.014-0.013-0.012-0.031,0.02-0.063
|
||||||
|
c0.038-0.041,0.063-0.078,0.081-0.108c0.04-0.065-0.004-0.138-0.074-0.22c-0.103-0.122-0.316-0.324-0.566-0.562L9.295,10.406z
|
||||||
|
M12.134,9.947c-0.015,0.012-0.016,0.021-0.008,0.044l0.176,0.544c0.029,0.096,0.07,0.178,0.099,0.213
|
||||||
|
c0.042,0.053,0.099,0.069,0.188-0.003l0.044-0.035c0.035-0.027,0.049-0.028,0.062-0.012c0.019,0.023,0.006,0.043-0.026,0.069
|
||||||
|
c-0.094,0.074-0.227,0.166-0.316,0.237c-0.032,0.026-0.187,0.163-0.338,0.284c-0.038,0.03-0.061,0.039-0.079,0.016
|
||||||
|
c-0.015-0.019-0.007-0.033,0.017-0.052c0.026-0.021,0.065-0.057,0.086-0.078c0.121-0.125,0.097-0.269,0.039-0.461l-0.73-2.421
|
||||||
|
c-0.032-0.112-0.041-0.159-0.012-0.182c0.026-0.021,0.065-0.009,0.147,0.035c0.199,0.104,1.618,0.924,2.159,1.22
|
||||||
|
c0.32,0.174,0.438,0.148,0.512,0.113c0.051-0.026,0.097-0.059,0.132-0.086c0.023-0.02,0.041-0.027,0.057-0.008
|
||||||
|
c0.02,0.023-0.003,0.051-0.11,0.138c-0.105,0.084-0.319,0.254-0.558,0.435c-0.055,0.039-0.09,0.067-0.105,0.047
|
||||||
|
c-0.014-0.018-0.007-0.032,0.02-0.059c0.017-0.022,0.016-0.065-0.026-0.088l-0.729-0.434c-0.017-0.01-0.031-0.009-0.045,0.003
|
||||||
|
L12.134,9.947z M12.614,9.325c0.014-0.012,0.01-0.022,0-0.029l-0.839-0.513c-0.012-0.009-0.027-0.021-0.036-0.015
|
||||||
|
c-0.009,0.007-0.003,0.025,0.003,0.041l0.305,0.934c0.008,0.014,0.018,0.021,0.028,0.011L12.614,9.325z M14.557,9.301
|
||||||
|
c-0.064,0.009-0.084-0.002-0.126-0.072c-0.104-0.178-0.206-0.378-0.233-0.432c-0.025-0.05-0.037-0.091-0.011-0.105
|
||||||
|
c0.028-0.018,0.049,0.01,0.063,0.036c0.024,0.042,0.078,0.102,0.126,0.146c0.212,0.196,0.453,0.17,0.652,0.052
|
||||||
|
c0.29-0.172,0.315-0.451,0.214-0.623c-0.093-0.156-0.229-0.276-0.62-0.327l-0.217-0.028c-0.518-0.067-0.773-0.22-0.928-0.48
|
||||||
|
c-0.21-0.354-0.064-0.782,0.383-1.048c0.209-0.124,0.363-0.172,0.46-0.199c0.033-0.011,0.055-0.011,0.068,0.013
|
||||||
|
c0.024,0.042,0.066,0.143,0.216,0.394c0.042,0.071,0.047,0.104,0.021,0.118c-0.021,0.013-0.043,0-0.065-0.039
|
||||||
|
c-0.018-0.029-0.093-0.119-0.209-0.163c-0.084-0.032-0.235-0.074-0.444,0.05c-0.238,0.142-0.301,0.365-0.187,0.559
|
||||||
|
c0.088,0.147,0.229,0.217,0.614,0.261l0.13,0.014c0.562,0.062,0.833,0.202,1.015,0.508c0.109,0.187,0.171,0.45,0.028,0.738
|
||||||
|
c-0.1,0.198-0.263,0.333-0.433,0.436C14.89,9.217,14.731,9.28,14.557,9.301z M34.089,6.584L33.6,6.314
|
||||||
|
c-0.191-0.104-0.278-0.133-0.368-0.09c-0.062,0.028-0.101,0.059-0.121,0.081c-0.022,0.021-0.039,0.028-0.06,0.018
|
||||||
|
c-0.021-0.013-0.02-0.033,0.002-0.069c0.029-0.051,0.264-0.309,0.285-0.332c0.034-0.036,0.056-0.05,0.075-0.038
|
||||||
|
c0.026,0.016,0.039,0.066,0.116,0.12c0.088,0.064,0.207,0.144,0.312,0.205l1.278,0.75c0.104,0.062,0.18,0.093,0.232,0.115
|
||||||
|
c0.054,0.019,0.084,0.027,0.097,0.035c0.022,0.014,0.015,0.035-0.014,0.083c-0.04,0.067-0.181,0.285-0.229,0.369
|
||||||
|
c-0.021,0.03-0.04,0.046-0.06,0.035c-0.025-0.016-0.022-0.035,0.003-0.086l0.018-0.036c0.042-0.089,0.008-0.229-0.274-0.404
|
||||||
|
l-0.401-0.25l-0.776,1.323c-0.174,0.297-0.323,0.552-0.39,0.699c-0.043,0.097-0.064,0.179,0.024,0.248
|
||||||
|
c0.042,0.033,0.108,0.081,0.156,0.109c0.036,0.021,0.047,0.04,0.037,0.056c-0.013,0.022-0.044,0.018-0.08-0.004
|
||||||
|
C33.25,9.129,33.053,9,32.962,8.947c-0.073-0.043-0.282-0.153-0.412-0.229c-0.042-0.023-0.059-0.048-0.046-0.069
|
||||||
|
c0.01-0.017,0.028-0.019,0.067,0.004c0.048,0.029,0.091,0.045,0.124,0.055c0.072,0.025,0.133-0.034,0.197-0.122
|
||||||
|
c0.096-0.126,0.245-0.381,0.42-0.678L34.089,6.584z M35.774,8.711c0.371-0.431,0.438-0.511,0.511-0.605
|
||||||
|
c0.077-0.102,0.093-0.166,0.017-0.267c-0.018-0.024-0.062-0.069-0.104-0.104c-0.031-0.027-0.043-0.047-0.026-0.067
|
||||||
|
c0.018-0.02,0.042-0.009,0.084,0.028c0.15,0.129,0.322,0.291,0.407,0.364c0.068,0.058,0.254,0.204,0.356,0.291
|
||||||
|
c0.042,0.037,0.058,0.059,0.04,0.079c-0.018,0.02-0.039,0.011-0.067-0.014c-0.031-0.026-0.051-0.039-0.09-0.062
|
||||||
|
c-0.089-0.053-0.153-0.022-0.244,0.071c-0.084,0.087-0.152,0.166-0.521,0.598l-0.34,0.396c-0.353,0.412-0.419,0.655-0.378,0.889
|
||||||
|
c0.038,0.214,0.158,0.338,0.255,0.421c0.125,0.106,0.312,0.198,0.523,0.183c0.29-0.021,0.518-0.271,0.769-0.562l0.306-0.354
|
||||||
|
c0.37-0.432,0.438-0.511,0.511-0.605c0.077-0.103,0.093-0.167,0.017-0.268c-0.018-0.024-0.062-0.068-0.095-0.097
|
||||||
|
C37.673,9,37.661,8.979,37.678,8.96c0.017-0.02,0.042-0.009,0.08,0.025c0.146,0.124,0.316,0.286,0.319,0.289
|
||||||
|
c0.034,0.028,0.22,0.174,0.331,0.269c0.04,0.034,0.055,0.058,0.038,0.077c-0.017,0.021-0.039,0.011-0.073-0.018
|
||||||
|
c-0.031-0.027-0.05-0.039-0.089-0.062c-0.089-0.052-0.153-0.022-0.244,0.071c-0.083,0.086-0.151,0.166-0.521,0.597l-0.262,0.303
|
||||||
|
c-0.27,0.315-0.589,0.623-1.002,0.623c-0.35,0-0.581-0.144-0.766-0.302c-0.15-0.129-0.416-0.372-0.462-0.737
|
||||||
|
c-0.033-0.254,0.04-0.557,0.393-0.969L35.774,8.711z M38.61,11.381c0.443-0.355,0.523-0.422,0.613-0.503
|
||||||
|
c0.094-0.085,0.122-0.146,0.064-0.259c-0.013-0.028-0.05-0.08-0.083-0.121c-0.025-0.032-0.034-0.054-0.014-0.071
|
||||||
|
c0.021-0.016,0.043,0,0.078,0.043c0.125,0.154,0.263,0.346,0.312,0.406c0.079,0.1,0.268,0.313,0.339,0.404
|
||||||
|
c0.148,0.184,0.288,0.393,0.308,0.637c0.01,0.126-0.045,0.362-0.24,0.521c-0.216,0.173-0.486,0.242-0.962,0.141
|
||||||
|
c-0.117,0.522-0.215,0.932-0.257,1.249c-0.038,0.299,0.038,0.436,0.063,0.485c0.021,0.037,0.038,0.064,0.058,0.089
|
||||||
|
c0.019,0.022,0.02,0.042,0.005,0.054c-0.023,0.02-0.045,0.003-0.074-0.032l-0.223-0.275c-0.132-0.163-0.176-0.248-0.195-0.356
|
||||||
|
c-0.034-0.179,0.014-0.399,0.106-0.744c0.066-0.246,0.156-0.539,0.171-0.611c0.006-0.029-0.007-0.05-0.022-0.069l-0.198-0.258
|
||||||
|
c-0.012-0.016-0.023-0.02-0.042-0.005l-0.041,0.032c-0.271,0.219-0.501,0.403-0.611,0.517c-0.077,0.077-0.127,0.146-0.068,0.243
|
||||||
|
c0.029,0.048,0.075,0.117,0.103,0.151c0.02,0.023,0.021,0.042,0.006,0.055c-0.021,0.016-0.046,0.003-0.076-0.035
|
||||||
|
c-0.137-0.169-0.301-0.393-0.336-0.437c-0.044-0.055-0.201-0.23-0.294-0.348c-0.031-0.038-0.038-0.065-0.019-0.082
|
||||||
|
c0.016-0.012,0.033-0.007,0.062,0.028c0.034,0.043,0.068,0.073,0.096,0.096c0.059,0.049,0.135,0.012,0.229-0.044
|
||||||
|
c0.135-0.084,0.364-0.271,0.633-0.485L38.61,11.381z M38.656,11.91c-0.032,0.026-0.039,0.041-0.031,0.069
|
||||||
|
c0.029,0.078,0.09,0.172,0.149,0.245c0.094,0.116,0.136,0.145,0.216,0.167c0.134,0.035,0.336,0.013,0.575-0.181
|
||||||
|
c0.414-0.333,0.312-0.703,0.174-0.875c-0.059-0.072-0.104-0.123-0.136-0.145c-0.022-0.017-0.038-0.012-0.062,0.006L38.656,11.91z
|
||||||
|
M40.591,14.113c0.49-0.289,0.58-0.342,0.68-0.409c0.104-0.071,0.142-0.136,0.116-0.216c-0.012-0.041-0.033-0.084-0.056-0.123
|
||||||
|
c-0.02-0.032-0.023-0.056,0.001-0.071c0.021-0.011,0.041,0.012,0.072,0.062c0.072,0.123,0.182,0.331,0.237,0.424
|
||||||
|
c0.047,0.081,0.169,0.265,0.241,0.387c0.024,0.042,0.033,0.072,0.015,0.083c-0.025,0.016-0.043,0-0.062-0.033
|
||||||
|
c-0.019-0.032-0.038-0.056-0.065-0.091c-0.067-0.078-0.139-0.07-0.254-0.011c-0.107,0.054-0.197,0.108-0.688,0.396l-0.566,0.334
|
||||||
|
c-0.312,0.185-0.567,0.335-0.698,0.43c-0.081,0.061-0.126,0.118-0.082,0.222c0.021,0.049,0.056,0.123,0.084,0.172
|
||||||
|
c0.021,0.035,0.021,0.058,0.004,0.066c-0.022,0.014-0.047-0.007-0.068-0.042c-0.125-0.212-0.234-0.421-0.287-0.508
|
||||||
|
c-0.043-0.074-0.173-0.271-0.249-0.4c-0.024-0.042-0.027-0.07-0.006-0.083c0.017-0.009,0.033-0.002,0.057,0.036
|
||||||
|
c0.028,0.049,0.058,0.083,0.082,0.109c0.051,0.057,0.116,0.043,0.216-0.002c0.145-0.063,0.398-0.214,0.712-0.397L40.591,14.113z
|
||||||
|
M40.314,16.493c0.157-0.461,0.507-0.711,0.842-0.85c0.235-0.098,0.672-0.193,1.114,0.013c0.331,0.154,0.604,0.425,0.817,0.94
|
||||||
|
c0.089,0.214,0.128,0.348,0.174,0.515c0.036,0.139,0.052,0.262,0.084,0.37c0.012,0.039,0.001,0.06-0.021,0.068
|
||||||
|
c-0.028,0.012-0.073,0.019-0.197,0.062c-0.116,0.041-0.306,0.123-0.378,0.144c-0.053,0.019-0.084,0.022-0.097-0.008
|
||||||
|
c-0.011-0.028,0.014-0.046,0.062-0.065c0.105-0.048,0.208-0.144,0.263-0.267c0.073-0.164,0.056-0.472-0.076-0.79
|
||||||
|
c-0.125-0.3-0.282-0.466-0.483-0.561c-0.335-0.156-0.69-0.086-1.025,0.053c-0.822,0.34-0.972,1.134-0.78,1.597
|
||||||
|
c0.127,0.309,0.239,0.48,0.455,0.554c0.09,0.03,0.209,0.034,0.275,0.022c0.061-0.012,0.076-0.011,0.089,0.017
|
||||||
|
c0.01,0.023-0.012,0.042-0.039,0.053c-0.041,0.017-0.359,0.1-0.491,0.114c-0.066,0.007-0.089,0-0.137-0.05
|
||||||
|
c-0.113-0.114-0.246-0.367-0.338-0.589C40.232,17.361,40.171,16.92,40.314,16.493z M42.775,19.295
|
||||||
|
c0.555-0.125,0.657-0.146,0.771-0.181c0.123-0.035,0.175-0.077,0.174-0.204c0-0.031-0.01-0.094-0.021-0.145
|
||||||
|
c-0.009-0.04-0.007-0.064,0.019-0.069c0.026-0.006,0.039,0.018,0.052,0.073c0.021,0.099,0.042,0.205,0.062,0.296
|
||||||
|
c0.019,0.096,0.033,0.181,0.044,0.23c0.026,0.117,0.189,0.844,0.208,0.912c0.023,0.068,0.043,0.125,0.058,0.152
|
||||||
|
c0.008,0.018,0.023,0.037,0.027,0.056s-0.01,0.025-0.027,0.029c-0.025,0.005-0.073-0.003-0.244,0.023
|
||||||
|
c-0.038,0.005-0.2,0.033-0.245,0.036c-0.02,0-0.042-0.002-0.048-0.026c-0.006-0.025,0.011-0.037,0.043-0.044
|
||||||
|
c0.025-0.005,0.087-0.023,0.126-0.052c0.06-0.041,0.096-0.087,0.077-0.273c-0.006-0.063-0.085-0.448-0.103-0.521
|
||||||
|
c-0.004-0.018-0.017-0.022-0.042-0.017l-0.923,0.208c-0.026,0.006-0.04,0.013-0.035,0.034c0.019,0.081,0.112,0.5,0.14,0.583
|
||||||
|
c0.026,0.086,0.05,0.138,0.094,0.163c0.035,0.019,0.056,0.028,0.061,0.047c0.003,0.015-0.001,0.026-0.022,0.032
|
||||||
|
c-0.022,0.005-0.083,0.003-0.273,0.03c-0.074,0.014-0.223,0.035-0.248,0.041c-0.028,0.006-0.068,0.017-0.077-0.018
|
||||||
|
c-0.006-0.025,0.008-0.036,0.025-0.04c0.036-0.012,0.083-0.022,0.128-0.044c0.069-0.035,0.112-0.099,0.096-0.236
|
||||||
|
c-0.008-0.071-0.086-0.434-0.104-0.521c-0.004-0.019-0.021-0.02-0.042-0.015l-0.288,0.065c-0.124,0.028-0.461,0.1-0.566,0.127
|
||||||
|
c-0.25,0.062-0.292,0.134-0.208,0.507c0.021,0.095,0.057,0.248,0.121,0.333c0.065,0.085,0.152,0.112,0.308,0.104
|
||||||
|
c0.042-0.001,0.058,0.002,0.063,0.027c0.006,0.029-0.022,0.036-0.06,0.044c-0.084,0.02-0.338,0.045-0.416,0.043
|
||||||
|
c-0.102-0.004-0.108-0.037-0.14-0.176c-0.062-0.272-0.099-0.476-0.131-0.634c-0.027-0.158-0.05-0.272-0.074-0.382
|
||||||
|
c-0.009-0.04-0.026-0.121-0.05-0.207c-0.019-0.084-0.047-0.177-0.063-0.25c-0.012-0.047-0.006-0.075,0.02-0.081
|
||||||
|
c0.019-0.004,0.033,0.008,0.042,0.052c0.012,0.055,0.029,0.097,0.044,0.128c0.031,0.069,0.115,0.07,0.226,0.062
|
||||||
|
c0.156-0.017,0.445-0.081,0.78-0.156L42.775,19.295z M42.087,22.487c-0.292,0.018-0.387,0.07-0.41,0.146
|
||||||
|
c-0.021,0.064-0.021,0.137-0.02,0.195c0.001,0.041-0.005,0.064-0.027,0.064c-0.029,0.001-0.039-0.032-0.041-0.084
|
||||||
|
c-0.009-0.243-0.003-0.394-0.005-0.465c-0.001-0.033-0.019-0.209-0.024-0.402c-0.002-0.048,0.001-0.083,0.033-0.083
|
||||||
|
c0.022-0.001,0.031,0.021,0.032,0.059c0.002,0.049,0.008,0.116,0.024,0.167c0.034,0.097,0.143,0.107,0.468,0.101l2.214-0.044
|
||||||
|
c0.075-0.003,0.128,0.007,0.129,0.044c0.001,0.041-0.046,0.075-0.11,0.143c-0.048,0.046-0.637,0.636-1.159,1.201
|
||||||
|
c-0.245,0.263-0.767,0.787-0.823,0.852v0.02l1.677-0.098c0.229-0.012,0.298-0.048,0.332-0.139c0.021-0.057,0.018-0.146,0.016-0.199
|
||||||
|
c-0.001-0.045,0.009-0.061,0.031-0.061c0.03-0.001,0.035,0.04,0.037,0.095c0.007,0.194,0.002,0.375,0.005,0.453
|
||||||
|
c0.001,0.041,0.019,0.183,0.024,0.366c0.001,0.049,0,0.086-0.031,0.087c-0.021,0.001-0.034-0.021-0.036-0.066
|
||||||
|
c-0.001-0.038-0.002-0.066-0.015-0.111c-0.034-0.104-0.113-0.132-0.323-0.127l-2.359,0.042c-0.082,0.003-0.116-0.011-0.118-0.044
|
||||||
|
c-0.001-0.041,0.038-0.088,0.078-0.13c0.216-0.243,0.688-0.738,1.06-1.142c0.39-0.421,0.842-0.853,0.911-0.923v-0.011L42.087,22.487
|
||||||
|
z M41.585,25.938c0.035-0.057,0.056-0.064,0.137-0.054c0.203,0.03,0.424,0.076,0.481,0.09c0.055,0.012,0.094,0.027,0.09,0.058
|
||||||
|
c-0.004,0.034-0.038,0.032-0.067,0.028c-0.049-0.008-0.128-0.003-0.194,0.006c-0.286,0.042-0.417,0.246-0.45,0.476
|
||||||
|
c-0.048,0.333,0.154,0.528,0.352,0.558c0.182,0.025,0.359-0.006,0.645-0.277l0.158-0.151c0.377-0.36,0.656-0.465,0.956-0.422
|
||||||
|
c0.407,0.06,0.649,0.441,0.577,0.956c-0.035,0.24-0.095,0.392-0.135,0.483c-0.012,0.031-0.025,0.049-0.052,0.045
|
||||||
|
c-0.048-0.007-0.152-0.037-0.441-0.078c-0.082-0.012-0.109-0.027-0.105-0.057c0.004-0.026,0.027-0.034,0.072-0.027
|
||||||
|
c0.033,0.004,0.149,0.002,0.258-0.062c0.078-0.046,0.205-0.137,0.239-0.378c0.04-0.272-0.097-0.463-0.318-0.495
|
||||||
|
c-0.17-0.023-0.312,0.042-0.589,0.316l-0.093,0.093c-0.401,0.398-0.68,0.521-1.031,0.472c-0.215-0.03-0.458-0.148-0.594-0.44
|
||||||
|
c-0.092-0.202-0.097-0.414-0.067-0.61C41.442,26.249,41.492,26.087,41.585,25.938z M42.705,29.112
|
||||||
|
c0.547,0.154,0.648,0.183,0.766,0.208c0.125,0.027,0.195,0.009,0.235-0.065c0.022-0.036,0.039-0.082,0.051-0.125
|
||||||
|
c0.011-0.036,0.023-0.056,0.053-0.048c0.021,0.007,0.021,0.037,0.004,0.095c-0.039,0.138-0.113,0.36-0.144,0.466
|
||||||
|
c-0.024,0.09-0.073,0.305-0.112,0.44c-0.014,0.047-0.028,0.074-0.051,0.068c-0.028-0.009-0.029-0.032-0.02-0.068
|
||||||
|
s0.015-0.064,0.02-0.11c0.01-0.103-0.044-0.147-0.168-0.19c-0.112-0.04-0.213-0.068-0.76-0.223l-0.633-0.181
|
||||||
|
c-0.349-0.099-0.633-0.179-0.792-0.208c-0.1-0.017-0.172-0.01-0.217,0.095c-0.021,0.049-0.051,0.126-0.066,0.18
|
||||||
|
c-0.011,0.04-0.026,0.055-0.045,0.05c-0.025-0.007-0.028-0.039-0.017-0.079c0.066-0.236,0.142-0.461,0.169-0.559
|
||||||
|
c0.022-0.082,0.077-0.312,0.118-0.456c0.013-0.047,0.03-0.068,0.056-0.062c0.018,0.005,0.025,0.022,0.013,0.066
|
||||||
|
c-0.016,0.053-0.021,0.099-0.021,0.133c-0.006,0.076,0.049,0.115,0.149,0.155c0.146,0.061,0.431,0.141,0.779,0.239L42.705,29.112z
|
||||||
|
M40.502,30.431c0.048-0.046,0.069-0.048,0.146-0.016c0.188,0.081,0.389,0.186,0.441,0.211c0.051,0.026,0.083,0.054,0.072,0.08
|
||||||
|
c-0.013,0.031-0.046,0.021-0.073,0.009c-0.044-0.019-0.123-0.035-0.188-0.044c-0.287-0.033-0.467,0.128-0.56,0.342
|
||||||
|
c-0.134,0.309,0.011,0.55,0.192,0.629c0.168,0.071,0.348,0.09,0.694-0.101l0.191-0.104c0.458-0.25,0.755-0.277,1.033-0.156
|
||||||
|
c0.377,0.163,0.512,0.596,0.306,1.072c-0.097,0.224-0.192,0.353-0.256,0.432c-0.02,0.028-0.038,0.041-0.062,0.03
|
||||||
|
c-0.044-0.021-0.139-0.076-0.406-0.192c-0.075-0.032-0.099-0.055-0.086-0.082c0.01-0.022,0.035-0.024,0.077-0.007
|
||||||
|
c0.031,0.013,0.145,0.042,0.265,0.009c0.088-0.022,0.233-0.079,0.33-0.302c0.11-0.254,0.029-0.473-0.177-0.562
|
||||||
|
c-0.158-0.068-0.312-0.041-0.651,0.149l-0.113,0.064c-0.492,0.28-0.792,0.325-1.119,0.185c-0.199-0.086-0.403-0.264-0.458-0.58
|
||||||
|
c-0.036-0.22,0.017-0.425,0.095-0.606C40.282,30.694,40.373,30.55,40.502,30.431z M13.791,41.773c-0.024,0-0.056-0.002-0.114-0.02
|
||||||
|
c-0.053-0.015-0.07-0.058-0.09-0.186l-0.189-1.25c-0.009-0.048-0.034-0.077-0.064-0.079c-0.029,0.001-0.052,0.024-0.069,0.06
|
||||||
|
l-0.548,1.112l-0.546-1.098c-0.026-0.057-0.05-0.074-0.08-0.074c-0.029,0.001-0.052,0.029-0.057,0.066l-0.207,1.321
|
||||||
|
c-0.009,0.067-0.032,0.141-0.071,0.142c-0.032,0.004-0.046,0.004-0.062,0.004c-0.025,0-0.049,0.012-0.05,0.037
|
||||||
|
c0,0.032,0.033,0.04,0.055,0.04c0.068,0,0.168-0.008,0.208-0.008c0.037,0,0.132,0.008,0.221,0.008c0.029,0,0.065-0.005,0.067-0.04
|
||||||
|
c-0.003-0.027-0.026-0.036-0.05-0.037c-0.018,0-0.035-0.002-0.07-0.009c-0.035-0.009-0.05-0.017-0.051-0.044
|
||||||
|
c0-0.031,0.002-0.058,0.007-0.093l0.094-0.746c0.07,0.145,0.175,0.359,0.19,0.395c0.024,0.06,0.19,0.367,0.241,0.461
|
||||||
|
c0.034,0.061,0.054,0.105,0.099,0.111c0.04-0.004,0.051-0.031,0.099-0.124l0.432-0.866l0.109,0.832
|
||||||
|
c0.002,0.018,0.003,0.032,0.003,0.043c0,0.023-0.003,0.022-0.002,0.024c-0.015,0.006-0.033,0.015-0.035,0.037
|
||||||
|
c0.003,0.029,0.029,0.039,0.078,0.041c0.084,0.005,0.382,0.015,0.436,0.015c0.031-0.001,0.066-0.003,0.071-0.04
|
||||||
|
C13.839,41.781,13.812,41.773,13.791,41.773z M15.5,40.521c-0.234-0.237-0.593-0.235-0.854-0.235c-0.126,0-0.277,0.004-0.341,0.004
|
||||||
|
c-0.06,0-0.193-0.004-0.303-0.004c-0.028,0-0.062,0.002-0.064,0.035c0.001,0.029,0.029,0.039,0.053,0.039
|
||||||
|
c0.03,0,0.066,0.002,0.079,0.006c0.063,0.021,0.071,0.028,0.078,0.095c0.003,0.063,0.003,0.12,0.003,0.429v0.355
|
||||||
|
c0,0.188,0,0.346-0.01,0.43c-0.009,0.061-0.019,0.086-0.05,0.094c-0.018,0.004-0.04,0.006-0.069,0.006
|
||||||
|
c-0.031,0-0.05,0.02-0.05,0.039c0.001,0.028,0.029,0.038,0.058,0.038c0.043,0,0.096-0.002,0.146-0.005
|
||||||
|
c0.051,0,0.097-0.003,0.119-0.003c0.052,0,0.127,0.006,0.21,0.013c0.083,0.005,0.175,0.012,0.251,0.012
|
||||||
|
c0.391,0,0.616-0.145,0.715-0.243c0.121-0.119,0.233-0.315,0.233-0.576C15.703,40.802,15.607,40.629,15.5,40.521z M15.368,41.105
|
||||||
|
c0,0.207-0.042,0.382-0.172,0.488c-0.123,0.103-0.258,0.135-0.446,0.135c-0.162,0.001-0.24-0.044-0.26-0.073
|
||||||
|
c-0.011-0.012-0.02-0.086-0.021-0.134c-0.003-0.04-0.006-0.195-0.006-0.409v-0.255c0-0.159,0-0.326,0.003-0.396
|
||||||
|
c0.003-0.021,0-0.018,0.016-0.024c0.009-0.007,0.082-0.015,0.123-0.014c0.163,0,0.386,0.021,0.574,0.188
|
||||||
|
C15.268,40.69,15.368,40.853,15.368,41.105z M17.351,41.434c-0.028-0.001-0.041,0.025-0.042,0.055
|
||||||
|
c-0.006,0.033-0.034,0.09-0.068,0.127c-0.078,0.087-0.173,0.102-0.358,0.102c-0.272-0.001-0.635-0.222-0.636-0.691
|
||||||
|
c0-0.196,0.038-0.386,0.188-0.514c0.091-0.077,0.203-0.11,0.384-0.11c0.189,0,0.327,0.05,0.393,0.114
|
||||||
|
c0.049,0.049,0.074,0.116,0.076,0.177c0,0.023,0.004,0.058,0.039,0.06c0.036-0.003,0.043-0.038,0.045-0.065
|
||||||
|
c0.002-0.041,0.002-0.153,0.007-0.22c0.004-0.07,0.01-0.094,0.01-0.112c0.002-0.021-0.02-0.04-0.047-0.04
|
||||||
|
c-0.061-0.008-0.129-0.022-0.208-0.034c-0.096-0.012-0.176-0.021-0.308-0.021c-0.313,0-0.52,0.083-0.675,0.22
|
||||||
|
c-0.205,0.184-0.251,0.426-0.251,0.566c0,0.198,0.056,0.435,0.268,0.61c0.195,0.164,0.442,0.224,0.73,0.224
|
||||||
|
c0.137,0,0.296-0.012,0.385-0.047c0.037-0.013,0.057-0.033,0.065-0.069c0.021-0.072,0.045-0.245,0.045-0.273
|
||||||
|
C17.391,41.465,17.382,41.437,17.351,41.434z M19.029,41.434c-0.028-0.001-0.041,0.025-0.043,0.055
|
||||||
|
c-0.005,0.033-0.034,0.09-0.067,0.127c-0.079,0.087-0.173,0.102-0.358,0.102c-0.273-0.001-0.636-0.222-0.637-0.691
|
||||||
|
c0-0.196,0.038-0.386,0.188-0.514c0.092-0.077,0.203-0.11,0.384-0.11c0.19,0,0.327,0.05,0.394,0.114
|
||||||
|
c0.049,0.049,0.072,0.116,0.075,0.177c0,0.023,0.006,0.058,0.039,0.06c0.037-0.003,0.043-0.038,0.045-0.065
|
||||||
|
c0.002-0.041,0.002-0.153,0.008-0.22c0.004-0.07,0.009-0.094,0.01-0.112c0.001-0.021-0.021-0.04-0.047-0.04
|
||||||
|
c-0.062-0.008-0.129-0.022-0.208-0.034c-0.097-0.012-0.177-0.021-0.308-0.021c-0.314,0-0.521,0.083-0.676,0.22
|
||||||
|
c-0.205,0.184-0.251,0.426-0.251,0.566c0,0.198,0.056,0.435,0.269,0.61c0.194,0.164,0.441,0.224,0.729,0.224
|
||||||
|
c0.137,0,0.297-0.012,0.385-0.047c0.037-0.013,0.058-0.033,0.064-0.069c0.021-0.072,0.045-0.245,0.046-0.273
|
||||||
|
C19.069,41.465,19.06,41.437,19.029,41.434z M20.707,41.434c-0.027-0.001-0.041,0.025-0.043,0.055
|
||||||
|
c-0.006,0.033-0.034,0.09-0.066,0.127c-0.079,0.087-0.174,0.102-0.359,0.102c-0.272-0.001-0.635-0.222-0.635-0.691
|
||||||
|
c0-0.196,0.037-0.386,0.187-0.514c0.092-0.077,0.203-0.11,0.385-0.11c0.189,0,0.327,0.05,0.394,0.114
|
||||||
|
c0.049,0.049,0.074,0.116,0.076,0.177c0,0.023,0.005,0.058,0.039,0.06c0.037-0.003,0.043-0.038,0.045-0.065
|
||||||
|
c0.002-0.041,0.002-0.153,0.007-0.22c0.005-0.07,0.009-0.094,0.009-0.112c0.002-0.021-0.019-0.04-0.046-0.04
|
||||||
|
c-0.061-0.008-0.129-0.022-0.209-0.034c-0.095-0.012-0.175-0.021-0.307-0.021c-0.314,0-0.521,0.083-0.677,0.22
|
||||||
|
c-0.205,0.184-0.251,0.426-0.251,0.566c0,0.198,0.057,0.435,0.269,0.61c0.194,0.164,0.441,0.224,0.729,0.224
|
||||||
|
c0.138,0,0.297-0.012,0.386-0.047c0.036-0.013,0.057-0.033,0.064-0.069c0.022-0.072,0.045-0.245,0.046-0.273
|
||||||
|
C20.747,41.465,20.738,41.437,20.707,41.434z M28.803,41.773c-0.019,0-0.051-0.002-0.076-0.011
|
||||||
|
c-0.043-0.015-0.072-0.032-0.106-0.075c-0.049-0.061-0.379-0.581-0.459-0.703l0.34-0.465c0.064-0.089,0.104-0.141,0.142-0.148
|
||||||
|
c0.027-0.007,0.053-0.011,0.071-0.011c0.025,0,0.05-0.014,0.051-0.039c-0.002-0.031-0.032-0.036-0.056-0.036
|
||||||
|
c-0.08,0-0.166,0.005-0.205,0.005c-0.04,0-0.138-0.005-0.22-0.005c-0.029,0-0.06,0.005-0.062,0.036
|
||||||
|
c0.001,0.028,0.025,0.039,0.043,0.039c0.017,0,0.044,0,0.062,0.006c0.019,0.004,0.024,0.015,0.024,0.018
|
||||||
|
c0,0.013-0.006,0.039-0.022,0.064c-0.032,0.053-0.195,0.293-0.268,0.399c-0.079-0.132-0.161-0.266-0.248-0.418
|
||||||
|
c-0.011-0.02-0.021-0.047-0.021-0.052c0-0.002,0.002-0.009,0.017-0.013s0.036-0.006,0.046-0.006c0.021,0,0.049-0.01,0.05-0.039
|
||||||
|
c-0.002-0.031-0.033-0.036-0.06-0.036c-0.079,0-0.208,0.005-0.236,0.005c-0.101,0-0.269-0.005-0.319-0.005
|
||||||
|
c-0.024,0.001-0.055,0.001-0.06,0.034c0,0.021,0.016,0.041,0.038,0.041c0.019,0,0.051,0.004,0.083,0.014
|
||||||
|
c0.068,0.022,0.106,0.062,0.16,0.142l0.361,0.564l-0.401,0.544c-0.072,0.099-0.102,0.125-0.158,0.142
|
||||||
|
c-0.028,0.007-0.06,0.009-0.072,0.009c-0.024,0.001-0.045,0.018-0.045,0.041s0.024,0.036,0.048,0.036h0.036
|
||||||
|
c0.034,0,0.137-0.008,0.176-0.008c0.052,0,0.189,0.008,0.203,0.008h0.038c0.027,0,0.058-0.004,0.06-0.036
|
||||||
|
c-0.002-0.025-0.021-0.039-0.043-0.041c-0.015,0-0.03-0.002-0.045-0.002c-0.013,0-0.022-0.01-0.022-0.018c0-0.001,0-0.003,0-0.003
|
||||||
|
c0-0.015,0.01-0.042,0.028-0.07l0.293-0.453c0.093,0.149,0.201,0.332,0.316,0.52c0.004,0.007,0.005,0.012,0.005,0.014
|
||||||
|
c0,0.005-0.002,0.005-0.002,0.005c-0.021,0.005-0.041,0.021-0.041,0.043c0.006,0.036,0.038,0.034,0.09,0.038
|
||||||
|
c0.172,0.005,0.339,0.005,0.39,0.005h0.062c0.024,0,0.055-0.008,0.059-0.038C28.846,41.788,28.824,41.773,28.803,41.773z
|
||||||
|
M30.581,41.773c-0.018,0-0.05-0.002-0.076-0.011c-0.043-0.015-0.071-0.032-0.105-0.075c-0.049-0.061-0.379-0.581-0.46-0.703
|
||||||
|
l0.341-0.465c0.064-0.089,0.104-0.141,0.141-0.148c0.028-0.007,0.054-0.011,0.072-0.011c0.025,0,0.05-0.014,0.05-0.039
|
||||||
|
c-0.001-0.031-0.031-0.036-0.055-0.036c-0.079,0-0.165,0.005-0.205,0.005s-0.138-0.005-0.219-0.005
|
||||||
|
c-0.029,0-0.062,0.005-0.062,0.036c0.001,0.028,0.026,0.039,0.043,0.039c0.018,0,0.044,0,0.062,0.006
|
||||||
|
c0.019,0.004,0.024,0.015,0.023,0.018c0,0.013-0.006,0.039-0.021,0.064c-0.032,0.053-0.195,0.293-0.269,0.399
|
||||||
|
c-0.078-0.133-0.16-0.266-0.247-0.418c-0.012-0.02-0.021-0.047-0.02-0.052c0-0.002,0.001-0.008,0.016-0.013
|
||||||
|
c0.016-0.004,0.036-0.006,0.047-0.006c0.021,0,0.049-0.01,0.05-0.039c-0.002-0.031-0.033-0.036-0.061-0.036
|
||||||
|
c-0.079,0-0.208,0.005-0.234,0.005c-0.101,0-0.27-0.005-0.319-0.005c-0.025,0.001-0.055,0.001-0.06,0.034
|
||||||
|
c0,0.021,0.017,0.041,0.037,0.041s0.053,0.004,0.083,0.014c0.069,0.022,0.107,0.062,0.16,0.142l0.362,0.564l-0.402,0.544
|
||||||
|
c-0.071,0.099-0.101,0.125-0.157,0.142c-0.029,0.007-0.06,0.009-0.071,0.009c-0.025,0.001-0.045,0.018-0.046,0.041
|
||||||
|
c0,0.023,0.023,0.036,0.048,0.036h0.036c0.035,0,0.137-0.008,0.176-0.008c0.052,0,0.189,0.008,0.203,0.008h0.038
|
||||||
|
c0.026,0,0.058-0.004,0.06-0.036c-0.002-0.025-0.021-0.039-0.043-0.041c-0.015,0-0.031-0.002-0.045-0.002
|
||||||
|
c-0.013,0-0.022-0.008-0.023-0.018c0-0.001,0-0.003,0-0.003c0-0.015,0.01-0.042,0.028-0.07l0.292-0.453
|
||||||
|
c0.092,0.149,0.201,0.332,0.317,0.52c0.004,0.007,0.005,0.012,0.005,0.014c0,0.004-0.002,0.005-0.002,0.005
|
||||||
|
c-0.021,0.005-0.041,0.021-0.041,0.043c0.006,0.036,0.038,0.034,0.09,0.038c0.171,0.005,0.338,0.005,0.389,0.005h0.062
|
||||||
|
c0.024,0,0.055-0.008,0.058-0.038C30.624,41.788,30.603,41.773,30.581,41.773z M32.359,41.773c-0.019,0-0.05-0.002-0.076-0.011
|
||||||
|
c-0.043-0.015-0.072-0.032-0.106-0.075c-0.049-0.061-0.379-0.581-0.459-0.703l0.341-0.465c0.063-0.089,0.104-0.141,0.141-0.148
|
||||||
|
c0.028-0.007,0.053-0.011,0.072-0.011c0.024,0,0.049-0.014,0.05-0.039c-0.002-0.031-0.032-0.036-0.055-0.036
|
||||||
|
c-0.079,0-0.166,0.005-0.205,0.005c-0.04,0-0.139-0.005-0.22-0.005c-0.028,0-0.061,0.005-0.062,0.036
|
||||||
|
c0.001,0.028,0.025,0.039,0.043,0.039c0.016,0,0.044,0,0.061,0.006c0.02,0.004,0.025,0.015,0.024,0.018
|
||||||
|
c0,0.013-0.006,0.039-0.021,0.064c-0.032,0.053-0.195,0.293-0.269,0.399c-0.079-0.132-0.161-0.266-0.248-0.418
|
||||||
|
c-0.011-0.02-0.02-0.047-0.02-0.052c0-0.002,0.002-0.009,0.016-0.013c0.015-0.004,0.036-0.006,0.046-0.006
|
||||||
|
c0.021,0,0.049-0.01,0.05-0.039c-0.002-0.031-0.032-0.036-0.06-0.036c-0.079,0-0.208,0.005-0.236,0.005
|
||||||
|
c-0.099,0-0.268-0.005-0.317-0.005c-0.026,0.001-0.057,0.001-0.061,0.034c0,0.021,0.018,0.041,0.038,0.041
|
||||||
|
c0.02,0,0.052,0.004,0.083,0.014c0.069,0.022,0.107,0.062,0.159,0.142l0.363,0.564l-0.402,0.544
|
||||||
|
c-0.072,0.099-0.101,0.125-0.157,0.142c-0.029,0.007-0.059,0.009-0.072,0.009c-0.023,0.001-0.045,0.018-0.045,0.041
|
||||||
|
s0.024,0.036,0.047,0.036h0.036c0.035,0,0.138-0.008,0.177-0.008c0.052,0,0.188,0.008,0.201,0.008h0.038
|
||||||
|
c0.027,0,0.059-0.004,0.061-0.036c-0.002-0.025-0.021-0.039-0.043-0.041c-0.017,0-0.032-0.002-0.045-0.002
|
||||||
|
c-0.014,0-0.023-0.008-0.024-0.018v-0.003c0-0.015,0.01-0.042,0.028-0.07l0.293-0.453c0.092,0.149,0.201,0.332,0.315,0.52
|
||||||
|
c0.004,0.007,0.006,0.012,0.006,0.014c0,0.004-0.003,0.005-0.003,0.005c-0.021,0.005-0.041,0.021-0.041,0.043
|
||||||
|
c0.007,0.036,0.038,0.033,0.091,0.038c0.172,0.005,0.339,0.005,0.389,0.005h0.062c0.025,0,0.056-0.008,0.059-0.038
|
||||||
|
C32.401,41.788,32.38,41.773,32.359,41.773z M33.453,41.773c-0.03,0-0.078-0.002-0.104-0.007c-0.057-0.012-0.061-0.026-0.069-0.08
|
||||||
|
c-0.009-0.084-0.009-0.246-0.009-0.44v-0.356c0-0.309,0-0.364,0.004-0.429c0.007-0.069,0.015-0.083,0.063-0.094
|
||||||
|
c0.024-0.005,0.039-0.007,0.06-0.007s0.051-0.012,0.051-0.041c-0.005-0.033-0.035-0.033-0.061-0.034
|
||||||
|
c-0.081,0-0.218,0.005-0.27,0.005c-0.059,0-0.202-0.005-0.281-0.005c-0.031,0.001-0.062,0-0.066,0.034
|
||||||
|
c0,0.029,0.028,0.041,0.051,0.041c0.025,0,0.05,0.002,0.071,0.009c0.04,0.015,0.053,0.025,0.06,0.092
|
||||||
|
c0.002,0.063,0.002,0.12,0.002,0.429v0.356c0,0.194,0,0.356-0.01,0.438c-0.009,0.06-0.015,0.073-0.049,0.083
|
||||||
|
c-0.018,0.004-0.04,0.006-0.07,0.006c-0.031,0-0.051,0.02-0.051,0.039c0.001,0.029,0.031,0.038,0.058,0.038
|
||||||
|
c0.084,0,0.228-0.008,0.273-0.008c0.056,0,0.2,0.008,0.338,0.008c0.025,0,0.055-0.008,0.058-0.038
|
||||||
|
C33.504,41.791,33.482,41.773,33.453,41.773z M34.724,41.773c-0.03,0-0.078-0.002-0.104-0.007c-0.056-0.012-0.06-0.026-0.069-0.08
|
||||||
|
c-0.01-0.084-0.01-0.246-0.01-0.44v-0.356c0-0.309,0-0.364,0.005-0.429c0.008-0.069,0.015-0.083,0.064-0.094
|
||||||
|
c0.023-0.005,0.039-0.007,0.059-0.007c0.021,0,0.051-0.012,0.051-0.041c-0.006-0.033-0.034-0.033-0.061-0.034
|
||||||
|
c-0.082,0-0.218,0.005-0.27,0.005c-0.06,0-0.202-0.005-0.281-0.005c-0.032,0.001-0.062,0-0.067,0.034
|
||||||
|
c0,0.029,0.029,0.041,0.05,0.041c0.025,0,0.051,0.002,0.071,0.009c0.04,0.015,0.052,0.025,0.06,0.092
|
||||||
|
c0.003,0.063,0.003,0.12,0.003,0.429v0.356c0,0.194,0,0.356-0.011,0.438c-0.009,0.06-0.015,0.073-0.049,0.083
|
||||||
|
c-0.018,0.004-0.04,0.006-0.069,0.006c-0.031,0-0.051,0.02-0.051,0.039c0.001,0.029,0.03,0.038,0.058,0.038
|
||||||
|
c0.084,0,0.227-0.008,0.273-0.008c0.057,0,0.2,0.008,0.338,0.008c0.025,0,0.056-0.008,0.059-0.038
|
||||||
|
C34.774,41.791,34.753,41.773,34.724,41.773z M35.995,41.773c-0.03,0-0.077-0.002-0.104-0.007c-0.057-0.012-0.061-0.026-0.069-0.08
|
||||||
|
c-0.01-0.084-0.01-0.246-0.01-0.44v-0.356c0-0.309,0-0.364,0.005-0.429c0.007-0.069,0.014-0.083,0.063-0.094
|
||||||
|
c0.024-0.005,0.039-0.007,0.06-0.007s0.05-0.012,0.05-0.041c-0.005-0.033-0.035-0.033-0.06-0.034c-0.081,0-0.218,0.005-0.27,0.005
|
||||||
|
c-0.059,0-0.202-0.005-0.281-0.005c-0.031,0.001-0.062,0-0.066,0.034c0,0.029,0.028,0.041,0.05,0.041
|
||||||
|
c0.025,0,0.05,0.002,0.071,0.009c0.041,0.015,0.053,0.025,0.06,0.092c0.002,0.063,0.002,0.12,0.002,0.429v0.356
|
||||||
|
c0,0.194,0,0.356-0.009,0.438c-0.009,0.06-0.015,0.073-0.049,0.083c-0.019,0.004-0.04,0.006-0.07,0.006
|
||||||
|
c-0.031,0-0.05,0.02-0.05,0.039c0.001,0.029,0.031,0.038,0.058,0.038c0.084,0,0.228-0.008,0.274-0.008
|
||||||
|
c0.056,0,0.2,0.008,0.338,0.008c0.024,0,0.055-0.008,0.057-0.038C36.045,41.79,36.024,41.773,35.995,41.773z M23.406,31.974v-1.188
|
||||||
|
c0-0.222-0.18-0.402-0.402-0.402c-0.222,0-0.402,0.182-0.402,0.402v1.188H23.406z M25.583,31.974v-1.188
|
||||||
|
c0-0.222-0.18-0.402-0.401-0.402c-0.224,0-0.403,0.182-0.403,0.402v1.188H25.583z M24.092,8.076c-0.232,0-0.422,0.189-0.422,0.422
|
||||||
|
c0,0.233,0.189,0.422,0.422,0.422c0.233,0,0.423-0.188,0.423-0.422C24.514,8.265,24.325,8.076,24.092,8.076z M23.879,19.853h0.426
|
||||||
|
v-0.915h-0.426V19.853L23.879,19.853z M19.84,42.941c-0.232,0-0.422,0.188-0.422,0.422s0.189,0.422,0.422,0.422
|
||||||
|
c0.233,0,0.423-0.188,0.423-0.422S20.073,42.941,19.84,42.941z M19.584,19.869v-1.345c-0.003-0.315-0.158-0.533-0.39-0.635
|
||||||
|
c-0.231,0.102-0.386,0.319-0.389,0.636v1.344H19.584z M19.584,15.548V14.68c-0.003-0.315-0.158-0.534-0.39-0.637
|
||||||
|
c-0.231,0.104-0.386,0.321-0.389,0.637v0.867H19.584z M19.402,24.539v-1.127c0-0.116-0.093-0.209-0.209-0.209
|
||||||
|
s-0.209,0.093-0.209,0.209v1.127H19.402z M19.402,27.931v-1.126c0-0.116-0.093-0.211-0.209-0.211s-0.209,0.095-0.209,0.211v1.126
|
||||||
|
H19.402z M19.525,31.721v-1c0-0.188-0.151-0.339-0.338-0.339c-0.188,0-0.338,0.151-0.338,0.339v1H19.525z M19.194,3.409
|
||||||
|
c-0.233,0-0.422,0.189-0.422,0.422c0,0.233,0.188,0.422,0.422,0.422c0.232,0,0.422-0.188,0.422-0.422
|
||||||
|
C19.616,3.598,19.427,3.409,19.194,3.409z M29.375,19.869v-1.345c-0.002-0.315-0.158-0.533-0.389-0.635
|
||||||
|
c-0.231,0.102-0.387,0.319-0.389,0.636v1.344H29.375z M29.375,15.548V14.68c-0.002-0.315-0.158-0.534-0.389-0.637
|
||||||
|
c-0.231,0.104-0.387,0.321-0.389,0.637v0.867H29.375z M29.194,24.539v-1.127c0-0.116-0.094-0.209-0.209-0.209
|
||||||
|
s-0.209,0.093-0.209,0.209v1.127H29.194z M29.194,27.931v-1.126c0-0.116-0.094-0.211-0.209-0.211s-0.209,0.095-0.209,0.211v1.126
|
||||||
|
H29.194z M29.317,31.721v-1c0-0.188-0.151-0.339-0.338-0.339c-0.188,0-0.338,0.151-0.338,0.339v1H29.317z M28.985,3.409
|
||||||
|
c-0.233,0-0.422,0.189-0.422,0.422c0,0.233,0.188,0.422,0.422,0.422c0.232,0,0.422-0.188,0.422-0.422
|
||||||
|
C29.408,3.598,29.219,3.409,28.985,3.409z M60.109,21.36c-3.838,0-4.703-2.09-4.703-4.415V8.998h2.342v7.803
|
||||||
|
c0,1.532,0.505,2.613,2.523,2.613c1.802,0,2.559-0.757,2.559-2.829V8.998h2.325v7.442C65.155,19.774,63.316,21.36,60.109,21.36z
|
||||||
|
M73.155,21.162v-5.729c0-0.938-0.253-1.496-1.1-1.496c-1.172,0-2.091,1.334-2.091,2.901v4.325h-2.307v-8.956h2.181
|
||||||
|
c0,0.415-0.035,1.117-0.126,1.586l0.019,0.019c0.541-1.063,1.586-1.803,3.046-1.803c2.018,0,2.666,1.298,2.666,2.865v6.289
|
||||||
|
L73.155,21.162L73.155,21.162z M79.102,11.052c-0.793,0-1.424-0.631-1.424-1.405c0-0.757,0.631-1.389,1.424-1.389
|
||||||
|
s1.44,0.613,1.44,1.389C80.543,10.422,79.895,11.052,79.102,11.052z M77.948,21.162v-8.956h2.307v8.956H77.948z M87.211,21.162
|
||||||
|
h-2.343l-3.314-8.956h2.521l1.424,4.036c0.216,0.613,0.434,1.334,0.596,1.982h0.035c0.145-0.612,0.324-1.298,0.54-1.91l1.441-4.108
|
||||||
|
h2.451L87.211,21.162z M98.797,17.054h-5.551c-0.018,1.676,0.812,2.485,2.469,2.485c0.884,0,1.839-0.198,2.613-0.559l0.216,1.784
|
||||||
|
c-0.955,0.378-2.09,0.576-3.207,0.576c-2.848,0-4.433-1.423-4.433-4.576c0-2.739,1.514-4.758,4.198-4.758
|
||||||
|
c2.611,0,3.767,1.784,3.767,4C98.869,16.314,98.851,16.675,98.797,17.054z M95.03,13.702c-0.955,0-1.622,0.703-1.748,1.784h3.298
|
||||||
|
C96.616,14.368,96.004,13.702,95.03,13.702z M105.59,14.278c-1.657-0.343-2.485,0.739-2.485,3.226v3.658h-2.308v-8.956h2.181
|
||||||
|
c0,0.45-0.055,1.171-0.162,1.802h0.036c0.433-1.135,1.298-2.126,2.848-2L105.59,14.278z M108.743,21.342
|
||||||
|
c-0.647,0-1.298-0.071-1.874-0.161l0.055-1.893c0.559,0.145,1.242,0.271,1.929,0.271c0.883,0,1.459-0.361,1.459-0.956
|
||||||
|
c0-1.585-3.621-0.686-3.621-3.73c0-1.567,1.278-2.865,3.802-2.865c0.522,0,1.1,0.072,1.64,0.162l-0.07,1.82
|
||||||
|
c-0.505-0.146-1.101-0.234-1.658-0.234c-0.901,0-1.333,0.36-1.333,0.919c0,1.46,3.676,0.812,3.676,3.713
|
||||||
|
C112.744,20.153,111.194,21.342,108.743,21.342z M115.861,11.052c-0.793,0-1.424-0.631-1.424-1.405c0-0.757,0.631-1.389,1.424-1.389
|
||||||
|
s1.44,0.613,1.44,1.389C117.302,10.422,116.654,11.052,115.861,11.052z M114.708,21.162v-8.956h2.308v8.956H114.708z
|
||||||
|
M122.851,21.342c-1.982,0-2.613-0.721-2.613-2.811V13.99h-1.531v-1.784h1.531V9.449l2.307-0.613v3.37h2.182v1.784h-2.182v3.928
|
||||||
|
c0,1.153,0.271,1.479,1.063,1.479c0.378,0,0.793-0.055,1.117-0.145v1.856C124.147,21.252,123.481,21.342,122.851,21.342z
|
||||||
|
M131.731,21.162c0-0.521,0.019-1.045,0.091-1.514l-0.019-0.019c-0.434,1.01-1.531,1.712-2.865,1.712c-1.621,0-2.56-0.919-2.56-2.36
|
||||||
|
c0-2.145,2.126-3.279,5.172-3.279v-0.487c0-0.937-0.45-1.423-1.747-1.423c-0.812,0-1.894,0.271-2.649,0.703l-0.198-1.928
|
||||||
|
c0.901-0.324,2.056-0.56,3.208-0.56c2.884,0,3.694,1.172,3.694,3.118v3.73c0,0.721,0.018,1.567,0.054,2.307L131.731,21.162
|
||||||
|
L131.731,21.162z M128.561,10.729c-0.687,0-1.243-0.56-1.243-1.244c0-0.703,0.558-1.244,1.243-1.244
|
||||||
|
c0.685,0,1.243,0.541,1.243,1.244C129.804,10.169,129.245,10.729,128.561,10.729z M131.552,17.198c-2.433,0-2.974,0.703-2.974,1.423
|
||||||
|
c0,0.577,0.396,0.955,1.063,0.955c1.135,0,1.909-1.081,1.909-2.162L131.552,17.198L131.552,17.198z M132.2,10.729
|
||||||
|
c-0.685,0-1.243-0.56-1.243-1.244c0-0.703,0.56-1.244,1.243-1.244s1.244,0.541,1.244,1.244
|
||||||
|
C133.444,10.169,132.885,10.729,132.2,10.729z M139.55,21.342c-1.981,0-2.612-0.721-2.612-2.811V13.99h-1.531v-1.784h1.531V9.449
|
||||||
|
l2.307-0.613v3.37h2.181v1.784h-2.181v3.928c0,1.153,0.271,1.479,1.063,1.479c0.379,0,0.793-0.055,1.116-0.145v1.856
|
||||||
|
C140.847,21.252,140.181,21.342,139.55,21.342z M54.955,40.202V38.4l4.379-7.137c0.252-0.414,0.504-0.774,0.793-1.153
|
||||||
|
c-0.433,0.019-1.009,0.036-2.217,0.036h-2.811v-2.108h7.856v1.874l-4.631,7.316c-0.18,0.288-0.342,0.559-0.558,0.848
|
||||||
|
c0.306-0.036,1.135-0.036,2.631-0.036h2.631v2.162H54.955z M70.484,40.202c0-0.414,0.018-1.117,0.107-1.586l-0.018-0.018
|
||||||
|
c-0.541,1.062-1.567,1.802-3.045,1.802c-2.02,0-2.667-1.298-2.667-2.865v-6.289h2.289v5.73c0,0.937,0.252,1.496,1.117,1.496
|
||||||
|
c1.171,0,2.071-1.334,2.071-2.901v-4.325h2.308v8.956H70.484z M66.826,29.769c-0.685,0-1.243-0.56-1.243-1.244
|
||||||
|
c0-0.702,0.56-1.243,1.243-1.243c0.685,0,1.244,0.541,1.244,1.243C68.069,29.21,67.511,29.769,66.826,29.769z M70.466,29.769
|
||||||
|
c-0.685,0-1.243-0.56-1.243-1.244c0-0.702,0.559-1.243,1.243-1.243c0.686,0,1.243,0.541,1.243,1.243
|
||||||
|
C71.709,29.21,71.151,29.769,70.466,29.769z M79.926,33.318c-1.656-0.343-2.485,0.739-2.485,3.226v3.658h-2.308v-8.956h2.182
|
||||||
|
c0,0.45-0.055,1.171-0.162,1.802h0.036c0.432-1.135,1.297-2.126,2.847-2L79.926,33.318z M82.854,30.093
|
||||||
|
c-0.793,0-1.424-0.631-1.424-1.405c0-0.756,0.631-1.388,1.424-1.388s1.44,0.612,1.44,1.388
|
||||||
|
C84.295,29.462,83.646,30.093,82.854,30.093z M81.7,40.202v-8.956h2.307v8.956H81.7z M89.729,40.364
|
||||||
|
c-2.486,0-4.036-1.297-4.036-4.343c0-2.793,1.46-4.938,4.632-4.938c0.612,0,1.261,0.09,1.838,0.252l-0.233,2.001
|
||||||
|
c-0.486-0.181-1.046-0.325-1.622-0.325c-1.46,0-2.198,1.081-2.198,2.775c0,1.531,0.595,2.577,2.126,2.577
|
||||||
|
c0.612,0,1.279-0.127,1.767-0.379l0.181,1.965C91.567,40.185,90.684,40.364,89.729,40.364z M99.478,40.202v-5.729
|
||||||
|
c0-0.938-0.252-1.496-1.1-1.496c-1.172,0-2.091,1.334-2.091,2.9v4.325h-2.307V27.047h2.307v3.839c0,0.541-0.036,1.298-0.162,1.82
|
||||||
|
l0.036,0.019c0.522-1.01,1.55-1.677,2.938-1.677c2.018,0,2.667,1.299,2.667,2.865v6.289H99.478z M105.334,31.716
|
||||||
|
c-1.461,0-1.813-0.788-1.813-1.706v-2.972h1.061v2.91c0,0.537,0.17,0.877,0.822,0.877c0.599,0,0.83-0.252,0.83-0.938v-2.85h1.047
|
||||||
|
v2.788C107.279,31.118,106.552,31.716,105.334,31.716z M108.163,31.628v-0.83l1.477-2.468c0.073-0.122,0.155-0.238,0.243-0.354
|
||||||
|
c-0.12,0.007-0.277,0.014-0.721,0.014h-0.951v-0.952h2.972v0.863l-1.558,2.502c-0.055,0.089-0.107,0.164-0.177,0.259
|
||||||
|
c0.089-0.014,0.347-0.014,0.891-0.014h0.87v0.979L108.163,31.628L108.163,31.628z M114.922,31.628v-1.911h-1.68v1.911h-1.061v-4.59
|
||||||
|
h1.061V28.8h1.68v-1.762h1.062v4.59H114.922z M0,24.091C0,10.786,10.786,0,24.091,0l0,0c13.306,0,24.092,10.786,24.092,24.091l0,0
|
||||||
|
c0,13.306-10.786,24.092-24.092,24.092l0,0C10.786,48.182,0,37.396,0,24.091L0,24.091z M7.477,7.477
|
||||||
|
C3.225,11.73,0.595,17.602,0.595,24.091l0,0c0,6.489,2.629,12.361,6.882,16.614l0,0c4.253,4.252,10.125,6.881,16.613,6.881l0,0
|
||||||
|
c6.489,0,12.361-2.629,16.614-6.881l0,0c4.252-4.253,6.882-10.125,6.882-16.614l0,0c0-6.488-2.629-12.36-6.882-16.613l0,0
|
||||||
|
C36.452,3.224,30.58,0.594,24.091,0.594l0,0C17.602,0.594,11.73,3.224,7.477,7.477L7.477,7.477z M24.456,39.232h0.194v-0.34h-0.462
|
||||||
|
v0.753h0.269L24.456,39.232z M24.091,1.568c-12.436,0-22.516,10.081-22.516,22.516c0,12.437,10.081,22.518,22.516,22.518
|
||||||
|
c12.436,0,22.516-10.081,22.517-22.518C46.606,11.649,36.526,1.568,24.091,1.568z M21.598,43.19h-1.021v0.34h1.021v2.53
|
||||||
|
c-5.112-0.573-9.696-2.889-13.146-6.338c-0.495-0.495-0.967-1.015-1.414-1.555c0.091-0.549,0.565-0.967,1.141-0.967
|
||||||
|
c0.639,0,1.155,0.518,1.155,1.156v1.11h1.468v-0.007l0,0v-1.104c0-0.64,0.519-1.156,1.156-1.156c0.639,0,1.157,0.518,1.157,1.156
|
||||||
|
v1.11h1.468v-0.007l0,0v-1.104c0-0.64,0.519-1.156,1.156-1.156s1.157,0.518,1.157,1.156v1.11h1.468v-0.007l0,0v-1.104
|
||||||
|
c0-0.64,0.518-1.156,1.157-1.156c0.639,0,1.155,0.518,1.155,1.156v1.11h0.922V43.19z M25.794,46.135
|
||||||
|
c-0.562,0.044-1.13,0.065-1.703,0.065c-0.571,0-1.14-0.021-1.7-0.063l-0.418-2.606h0.481c-0.12-0.286-0.329-0.786-0.409-0.989
|
||||||
|
c-0.13-0.326-0.032-0.542,0.185-0.626c0.211-0.082,0.449,0.034,0.523,0.312l0.211,0.792h0.309v0.511l0,0v0.102h-0.729v0.341h1.066
|
||||||
|
l0.001-0.441h1.293l-0.001-0.511h0.31l0.213-0.792c0.075-0.278,0.315-0.396,0.528-0.312c0.218,0.084,0.315,0.3,0.186,0.626
|
||||||
|
c-0.035,0.089-0.093,0.235-0.154,0.396l-0.288,0.695H24.92v0.341h1.005l0.184-0.441h0.104L25.794,46.135z M23.391,38.684h1.4
|
||||||
|
c0.055,0.129,0.188,0.454,0.271,0.643c0.057,0.131,0.13,0.271,0.041,0.416c-0.106,0.171-0.245,0.146-0.342,0.139
|
||||||
|
c-0.006-0.001-0.012,0-0.018-0.001c-0.098,0.269-0.352,0.459-0.653,0.459c-0.301,0-0.555-0.19-0.652-0.459
|
||||||
|
c-0.005,0.001-0.013,0-0.018,0.001c-0.098,0.009-0.235,0.032-0.342-0.139c-0.089-0.145-0.016-0.285,0.041-0.416
|
||||||
|
C23.204,39.138,23.337,38.812,23.391,38.684z M23.18,37.23l0.447,0.641l0.458-0.869l0.458,0.869l0.448-0.641l-0.178,1.111h-1.456
|
||||||
|
L23.18,37.23z M23.715,40.376c0.105,0.293,0.385,0.504,0.715,0.504c0.356,0,0.654-0.247,0.736-0.58
|
||||||
|
c0.222,0.012,0.442,0.075,0.661,0.261c0.211,0.177,0.293,0.48,0.323,0.632h-4.116c0.029-0.15,0.112-0.455,0.323-0.632
|
||||||
|
C22.808,40.181,23.268,40.305,23.715,40.376z M25.414,41.532c-0.155,0.586-0.688,1.019-1.322,1.019
|
||||||
|
c-0.634,0-1.167-0.433-1.321-1.019H25.414z M39.729,39.723c-3.45,3.449-8.033,5.764-13.145,6.337v-2.53h0.935
|
||||||
|
c1.731,0,2.983-0.146,2.983-0.146s-1.289-0.194-2.983-0.194h-0.935v-3.721h1.117v-0.007l0,0v-1.104c0-0.64,0.519-1.156,1.157-1.156
|
||||||
|
s1.157,0.519,1.157,1.156v1.11h1.467v-0.007l0,0v-1.104c0-0.64,0.518-1.156,1.156-1.156c0.638,0,1.155,0.519,1.155,1.156v1.11h1.469
|
||||||
|
v-0.007l0,0v-1.104c0-0.64,0.518-1.156,1.156-1.156c0.64,0,1.156,0.519,1.156,1.156v1.11h1.468v-0.007l0,0v-1.104
|
||||||
|
c0-0.64,0.519-1.156,1.157-1.156c0.506,0,0.937,0.326,1.092,0.78C40.803,38.589,40.281,39.171,39.729,39.723z M41.541,37.673
|
||||||
|
c-0.257-0.541-0.808-0.916-1.445-0.916c-0.885,0-1.602,0.718-1.602,1.603v0.517h-0.579v-0.517c0-0.885-0.717-1.603-1.601-1.603
|
||||||
|
s-1.602,0.718-1.602,1.603v0.517h-0.58v-0.517c0-0.885-0.717-1.603-1.601-1.603s-1.601,0.718-1.601,1.603v0.517h-0.58v-0.517
|
||||||
|
c0-0.885-0.718-1.603-1.602-1.603s-1.601,0.718-1.601,1.603v0.517h-0.598c-0.182-1.198-1.213-2.118-2.462-2.118
|
||||||
|
s-2.279,0.92-2.462,2.118h-0.614v-0.517c0-0.885-0.718-1.603-1.602-1.603s-1.601,0.718-1.601,1.603v0.517h-0.58v-0.517
|
||||||
|
c0-0.885-0.716-1.603-1.602-1.603c-0.884,0-1.601,0.718-1.601,1.603v0.517h-0.58v-0.517c0-0.885-0.717-1.603-1.601-1.603
|
||||||
|
c-0.885,0-1.602,0.718-1.602,1.603v0.517H9.672v-0.517c0-0.885-0.717-1.603-1.601-1.603c-0.634,0-1.181,0.369-1.44,0.903
|
||||||
|
c-0.39-0.501-0.758-1.02-1.104-1.554h37.129C42.306,36.645,41.935,37.168,41.541,37.673z M43.027,35.515H5.155
|
||||||
|
c-0.11-0.183-0.217-0.366-0.322-0.553h38.517C43.243,35.148,43.137,35.333,43.027,35.515z M20.275,7.089v0.187
|
||||||
|
C20.27,7.313,20.26,7.368,20.241,7.42c-0.032,0.085-0.111,0.221-0.217,0.386c-0.04,0.064-0.11,0.174-0.188,0.33
|
||||||
|
C19.735,7.982,19.65,7.88,19.59,7.817c-0.066-0.07-0.154-0.16-0.228-0.246c-0.157-0.187-0.166-0.298-0.166-0.298l0,0
|
||||||
|
c0,0-0.005,0.11-0.163,0.297c-0.073,0.085-0.161,0.175-0.228,0.246c-0.062,0.063-0.147,0.167-0.25,0.325
|
||||||
|
c-0.08-0.161-0.151-0.272-0.192-0.341c-0.105-0.165-0.185-0.3-0.217-0.385c-0.03-0.081-0.041-0.174-0.042-0.184V7.089H20.275z
|
||||||
|
M18.109,6.749c0.017-0.277,0.092-0.805,0.362-1.164c0.204-0.278,0.407-0.443,0.557-0.54C19.096,5,19.151,4.973,19.19,4.954
|
||||||
|
c0.04,0.02,0.095,0.046,0.164,0.091c0.147,0.097,0.352,0.262,0.557,0.54c0.271,0.359,0.345,0.887,0.362,1.164H18.109z M20.354,7.988
|
||||||
|
c0.062,0.085,0.125,0.209,0.194,0.359c0.096,0.233,0.121,0.462,0.124,0.63v2.492h-0.642c0-0.548,0-1.756,0-2.491
|
||||||
|
c0.002-0.171,0.033-0.409,0.124-0.632C20.234,8.17,20.296,8.07,20.354,7.988z M19.682,8.994l-0.001,2.476h-0.974
|
||||||
|
c0-0.689-0.001-2.477-0.001-2.478c0.008-0.162,0.021-0.386,0.138-0.617c0.122-0.242,0.354-0.386,0.354-0.386h0.001
|
||||||
|
c0,0,0.219,0.144,0.342,0.386C19.664,8.618,19.675,8.828,19.682,8.994z M18.245,8.343c0.091,0.224,0.106,0.465,0.109,0.636
|
||||||
|
l0.003,2.491h-0.634V8.975c0.003-0.168,0.021-0.396,0.116-0.631c0.07-0.149,0.138-0.273,0.195-0.358
|
||||||
|
C18.106,8.091,18.175,8.193,18.245,8.343z M21.164,11.877v0.807h-3.941v-0.807H21.164z M21.164,13.022v3.141H20.21V14.75
|
||||||
|
c0.001-0.469-0.173-0.866-0.459-1.138c-0.153-0.147-0.338-0.258-0.542-0.328c-0.013-0.004-0.012-0.005-0.012-0.005
|
||||||
|
s-0.002,0-0.015,0.005c-0.204,0.07-0.39,0.181-0.543,0.328c-0.286,0.271-0.459,0.669-0.458,1.138v1.414h-0.958v-3.141L21.164,13.022
|
||||||
|
L21.164,13.022z M19.87,14.75v1.414h-1.35V14.75c0.005-0.546,0.272-0.925,0.675-1.103C19.596,13.824,19.865,14.203,19.87,14.75z
|
||||||
|
M21.164,16.503v3.995h-0.876v-1.995c0-0.468-0.176-0.875-0.47-1.155c-0.157-0.15-0.344-0.263-0.55-0.333
|
||||||
|
c-0.011-0.005-0.074-0.024-0.074-0.024s-0.062,0.02-0.067,0.022c-0.207,0.07-0.396,0.185-0.555,0.335
|
||||||
|
c-0.294,0.279-0.471,0.688-0.47,1.154v1.995h-0.88v-3.995L21.164,16.503L21.164,16.503z M19.948,18.506v1.992h-1.507v-1.995
|
||||||
|
c0-0.384,0.141-0.694,0.364-0.909c0.11-0.105,0.241-0.185,0.389-0.241h0.001c0.147,0.058,0.276,0.136,0.387,0.24
|
||||||
|
c0.226,0.215,0.364,0.525,0.365,0.91L19.948,18.506z M21.164,20.838v4.755h-3.941v-4.755H21.164z M21.164,25.933v3.103h-3.941
|
||||||
|
v-3.103H21.164z M21.164,29.375v5.247h-3.941v-5.247H21.164z M24.634,16.538v1.416l-0.542-0.542l-0.541,0.541v-1.415H24.634z
|
||||||
|
M23.566,16.13l0.396-1.694l0.163-2.835l0.098,2.833l0.396,1.696H23.566z M24.092,17.988l2.511,2.51h-5.021L24.092,17.988z
|
||||||
|
M26.603,20.838v1.921h-5.037v-1.921H26.603z M26.603,23.354v2.238h-1.575v-0.561c0-0.516-0.419-0.938-0.938-0.938
|
||||||
|
c-0.517,0-0.937,0.421-0.937,0.938v0.561h-1.589v-2.238H26.603z M23.155,25.933v1.998h1.873v-1.998h1.575v3.103h-5.037v-3.103
|
||||||
|
H23.155z M26.603,29.375v5.247h-5.037v-5.247H26.603z M30.067,7.089v0.187c-0.005,0.038-0.017,0.093-0.035,0.145
|
||||||
|
C30,7.505,29.921,7.64,29.815,7.805c-0.04,0.064-0.11,0.174-0.188,0.33c-0.101-0.153-0.186-0.256-0.246-0.318
|
||||||
|
c-0.065-0.07-0.154-0.16-0.228-0.246c-0.158-0.187-0.166-0.298-0.166-0.298l0,0c0,0-0.005,0.11-0.163,0.297
|
||||||
|
c-0.073,0.085-0.161,0.175-0.228,0.246c-0.062,0.063-0.147,0.167-0.25,0.325c-0.08-0.161-0.151-0.272-0.192-0.341
|
||||||
|
c-0.105-0.165-0.185-0.3-0.217-0.385c-0.031-0.082-0.041-0.177-0.042-0.185V7.089H30.067z M27.901,6.749
|
||||||
|
c0.017-0.277,0.092-0.805,0.362-1.164c0.204-0.278,0.407-0.443,0.557-0.54C28.888,5,28.942,4.973,28.982,4.954
|
||||||
|
c0.04,0.02,0.095,0.046,0.163,0.091c0.147,0.097,0.352,0.262,0.557,0.54c0.271,0.359,0.345,0.887,0.362,1.164H27.901z M30.146,7.988
|
||||||
|
c0.061,0.085,0.125,0.209,0.193,0.359c0.096,0.233,0.121,0.462,0.124,0.63v2.492h-0.642c0-0.548,0-1.756,0-2.491
|
||||||
|
c0.003-0.171,0.033-0.409,0.125-0.632C30.025,8.17,30.088,8.07,30.146,7.988z M29.473,8.994l-0.001,2.476H28.5
|
||||||
|
c0-0.689-0.001-2.477-0.001-2.478c0.008-0.162,0.021-0.386,0.138-0.617c0.122-0.242,0.354-0.386,0.354-0.386h0.001
|
||||||
|
c0,0,0.219,0.144,0.342,0.386C29.455,8.618,29.466,8.828,29.473,8.994z M28.036,8.343c0.091,0.224,0.106,0.465,0.109,0.636
|
||||||
|
l0.003,2.491h-0.635V8.975c0.004-0.168,0.021-0.396,0.116-0.631c0.07-0.149,0.138-0.273,0.194-0.358
|
||||||
|
C27.898,8.091,27.966,8.193,28.036,8.343z M30.956,11.877v0.807h-3.941v-0.807H30.956z M30.956,13.022v3.141h-0.954V14.75
|
||||||
|
c0-0.469-0.173-0.866-0.459-1.138c-0.153-0.147-0.339-0.258-0.543-0.328c-0.013-0.004-0.012-0.005-0.012-0.005s-0.002,0-0.015,0.005
|
||||||
|
c-0.204,0.07-0.39,0.181-0.543,0.328c-0.286,0.271-0.459,0.669-0.459,1.138v1.414h-0.958v-3.141L30.956,13.022L30.956,13.022z
|
||||||
|
M29.662,14.75v1.414h-1.351V14.75c0.005-0.546,0.272-0.925,0.675-1.103C29.388,13.824,29.657,14.203,29.662,14.75z M30.956,16.503
|
||||||
|
v3.995H30.08v-1.995c0-0.468-0.176-0.875-0.47-1.155c-0.157-0.15-0.344-0.263-0.55-0.333c-0.01-0.005-0.074-0.024-0.074-0.024
|
||||||
|
s-0.062,0.02-0.068,0.022c-0.207,0.07-0.396,0.185-0.555,0.335c-0.294,0.279-0.47,0.688-0.47,1.154v1.995h-0.88v-3.995
|
||||||
|
L30.956,16.503L30.956,16.503z M29.74,18.506v1.992h-1.506v-1.995c0-0.384,0.141-0.694,0.364-0.909
|
||||||
|
c0.11-0.105,0.241-0.185,0.388-0.241h0.001c0.147,0.058,0.277,0.136,0.388,0.24c0.225,0.215,0.364,0.525,0.365,0.91V18.506z
|
||||||
|
M30.956,20.838v4.755h-3.941v-4.755H30.956z M30.956,25.933v3.103h-3.941v-3.103H30.956z M30.956,29.375v5.247h-3.941v-5.247
|
||||||
|
H30.956z M31.562,34.622V11.469h-0.497V8.917c-0.005-0.317-0.051-0.519-0.191-0.844c-0.036-0.082-0.087-0.172-0.145-0.262V6.889
|
||||||
|
c0,0-0.001-0.725-0.3-1.27c-0.325-0.595-0.956-0.92-1.264-1.049c-0.07-0.033-0.117-0.048-0.126-0.05l-0.051-0.019l-0.063,0.019
|
||||||
|
c-0.03,0.009-0.529,0.167-1.004,0.812c-0.43,0.593-0.444,1.354-0.448,1.563c0,0.034,0.001,0.054,0.001,0.057v0.851
|
||||||
|
c-0.058,0.084-0.138,0.211-0.226,0.398c-0.132,0.324-0.141,0.624-0.146,0.804v2.465h-0.5v8.452l-1.368-1.367v-2.413l-0.464-1.558
|
||||||
|
l-0.68-5.341l0,0l-0.501,5.117l-0.466,1.782v2.234l-1.354,1.355v-8.265h-0.497V8.917c-0.005-0.317-0.051-0.519-0.192-0.844
|
||||||
|
c-0.035-0.082-0.087-0.172-0.144-0.262V6.889c0,0-0.001-0.725-0.3-1.27c-0.326-0.595-0.957-0.92-1.264-1.049
|
||||||
|
c-0.07-0.033-0.117-0.048-0.126-0.05l-0.051-0.019l-0.063,0.019c-0.031,0.009-0.529,0.167-1.005,0.812
|
||||||
|
c-0.43,0.593-0.444,1.354-0.448,1.563c0,0.034,0,0.054,0,0.057v0.851c-0.058,0.084-0.138,0.211-0.226,0.398
|
||||||
|
c-0.131,0.324-0.141,0.624-0.145,0.804v2.465h-0.5v23.151H4.646c-1.702-3.133-2.672-6.721-2.672-10.538
|
||||||
|
c0-6.106,2.475-11.635,6.477-15.639c4.003-4.002,9.531-6.479,15.639-6.479c6.108,0,11.637,2.476,15.64,6.479
|
||||||
|
c4.002,4.003,6.478,9.531,6.478,15.639c0,3.817-0.97,7.405-2.672,10.538L31.562,34.622L31.562,34.622z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 53 KiB |
170
static/js/discourse-api.js
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/**
|
||||||
|
* Discourse API Integration for enviPath Community
|
||||||
|
* Handles fetching topics from the Discourse forum API
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DiscourseAPI {
|
||||||
|
constructor() {
|
||||||
|
this.baseUrl = 'https://community.envipath.org';
|
||||||
|
this.categoryId = 10; // Announcements category
|
||||||
|
this.limit = 3; // Number of topics to fetch
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch topics from Discourse API
|
||||||
|
* @param {number} limit - Number of topics to fetch
|
||||||
|
* @returns {Promise<Array>} Array of topic objects
|
||||||
|
*/
|
||||||
|
async fetchTopics(limit = this.limit) {
|
||||||
|
try {
|
||||||
|
const url = `${this.baseUrl}/c/announcements/${this.categoryId}.json`;
|
||||||
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
return this.processTopics(data.topic_list.topics, limit);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching Discourse topics:', error);
|
||||||
|
return this.getFallbackTopics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process raw Discourse topics into standardized format
|
||||||
|
* @param {Array} topics - Raw topics from Discourse API
|
||||||
|
* @param {number} limit - Number of topics to return
|
||||||
|
* @returns {Array} Processed topics
|
||||||
|
*/
|
||||||
|
processTopics(topics, limit) {
|
||||||
|
return topics
|
||||||
|
.slice(0, limit)
|
||||||
|
.map(topic => ({
|
||||||
|
id: topic.id,
|
||||||
|
title: topic.title,
|
||||||
|
excerpt: this.extractExcerpt(topic.excerpt),
|
||||||
|
url: `${this.baseUrl}/t/${topic.slug}/${topic.id}`,
|
||||||
|
replies: topic.reply_count,
|
||||||
|
views: topic.views,
|
||||||
|
created_at: topic.created_at,
|
||||||
|
category: 'Announcements',
|
||||||
|
category_id: this.categoryId,
|
||||||
|
author: topic.last_poster_username,
|
||||||
|
author_avatar: this.getAvatarUrl(topic.last_poster_username)
|
||||||
|
}))
|
||||||
|
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); // Latest first
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract excerpt from topic content
|
||||||
|
* @param {string} excerpt - Raw excerpt from Discourse
|
||||||
|
* @returns {string} Cleaned excerpt
|
||||||
|
*/
|
||||||
|
extractExcerpt(excerpt) {
|
||||||
|
if (!excerpt) return 'Click to read more';
|
||||||
|
|
||||||
|
// Remove HTML tags and clean up; collapse whitespace; do not add manual ellipsis
|
||||||
|
return excerpt
|
||||||
|
.replace(/<[^>]*>/g, '') // Remove HTML tags
|
||||||
|
.replace(/ /g, ' ') // Replace with spaces
|
||||||
|
.replace(/&/g, '&') // Replace & with &
|
||||||
|
.replace(/</g, '<') // Replace < with <
|
||||||
|
.replace(/>/g, '>') // Replace > with >
|
||||||
|
.replace(/\s+/g, ' ') // Collapse all whitespace/newlines
|
||||||
|
.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get avatar URL for user
|
||||||
|
* @param {string} username - Username
|
||||||
|
* @returns {string} Avatar URL
|
||||||
|
*/
|
||||||
|
getAvatarUrl(username) {
|
||||||
|
if (!username) return `${this.baseUrl}/letter_avatar_proxy/v4/letter/u/1.png`;
|
||||||
|
return `${this.baseUrl}/user_avatar/${this.baseUrl.replace('https://', '')}/${username}/40/1_1.png`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get fallback topics when API fails
|
||||||
|
* @returns {Array} Fallback topics
|
||||||
|
*/
|
||||||
|
getFallbackTopics() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 110,
|
||||||
|
title: "enviPath Beta Update: Major Improvements to Prediction, Analysis & Collaboration!",
|
||||||
|
excerpt: "We're excited to announce major updates to the enviPath beta platform! This release includes significant improvements to our prediction algorithms, enhanced analysis tools, and new collaboration features that will make environmental biotransformation research more accessible and efficient.",
|
||||||
|
url: "https://community.envipath.org/t/envipath-beta-update-major-improvements-to-prediction-analysis-collaboration/110",
|
||||||
|
replies: 0,
|
||||||
|
views: 16,
|
||||||
|
created_at: "2025-09-23T00:00:00Z",
|
||||||
|
category: "Announcements",
|
||||||
|
category_id: 10,
|
||||||
|
author: "wicker",
|
||||||
|
author_avatar: "https://community.envipath.org/user_avatar/community.envipath.org/wicker/40/1_1.png"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date for display
|
||||||
|
* @param {string} dateString - ISO date string
|
||||||
|
* @returns {string} Formatted date
|
||||||
|
*/
|
||||||
|
formatDate(dateString) {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load topics and call render function
|
||||||
|
* @param {string} containerId - ID of container element
|
||||||
|
* @param {Function} renderCallback - Function to render topics
|
||||||
|
*/
|
||||||
|
async loadTopics(containerId = 'community-news-container', renderCallback = null) {
|
||||||
|
const container = document.getElementById(containerId);
|
||||||
|
if (!container) {
|
||||||
|
console.error(`Container with ID '${containerId}' not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide loading spinner
|
||||||
|
const loading = document.getElementById('loading');
|
||||||
|
if (loading) {
|
||||||
|
loading.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const topics = await this.fetchTopics();
|
||||||
|
|
||||||
|
if (renderCallback && typeof renderCallback === 'function') {
|
||||||
|
renderCallback(topics);
|
||||||
|
} else {
|
||||||
|
// Default rendering - just log topics
|
||||||
|
console.log('Topics loaded:', topics);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading topics:', error);
|
||||||
|
container.innerHTML = '<p class="text-neutral">No updates found. Head over to the <a href="https://community.envipath.org" target="_blank" class="link link-primary">community</a> to see the latest discussions.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export for use in other scripts
|
||||||
|
window.DiscourseAPI = DiscourseAPI;
|
||||||
|
|
||||||
|
// Auto-initialize if container exists
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
if (document.getElementById('community-news-container')) {
|
||||||
|
const discourseAPI = new DiscourseAPI();
|
||||||
|
discourseAPI.loadTopics('community-news-container', function(topics) {
|
||||||
|
// This will be handled by the template's render function
|
||||||
|
if (window.renderDiscourseTopics) {
|
||||||
|
window.renderDiscourseTopics(topics);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -646,8 +646,8 @@ function handleAssessmentResponse(depict_url, data) {
|
|||||||
var reactivityCentersImgSrc = null;
|
var reactivityCentersImgSrc = null;
|
||||||
|
|
||||||
if (data['assessment']['node'] !== undefined) {
|
if (data['assessment']['node'] !== undefined) {
|
||||||
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>";
|
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "&highlight=true'>";
|
||||||
reactivityCentersImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>"
|
reactivityCentersImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "&highlightReactivity=true'>"
|
||||||
} else {
|
} else {
|
||||||
functionalGroupsImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">";
|
functionalGroupsImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">";
|
||||||
reactivityCentersImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">"
|
reactivityCentersImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">"
|
||||||
@ -751,7 +751,7 @@ function handleAssessmentResponse(depict_url, data) {
|
|||||||
var predProb = "<a class='list-group-item'>Predicted probability: " + transObj['probability'].toFixed(2) + "</a>";
|
var predProb = "<a class='list-group-item'>Predicted probability: " + transObj['probability'].toFixed(2) + "</a>";
|
||||||
var timesTriggered = "<a class='list-group-item'>This rule has triggered " + transObj['times_triggered'] + " times in the training set</a>";
|
var timesTriggered = "<a class='list-group-item'>This rule has triggered " + transObj['times_triggered'] + " times in the training set</a>";
|
||||||
var reliability = "<a class='list-group-item'>Reliability: " + transObj['reliability'].toFixed(2) + " (" + (transObj['reliability'] > data['ad_params']['reliability_threshold'] ? ">" : "<") + " Reliability Threshold of " + data['ad_params']['reliability_threshold'] + ") </a>";
|
var reliability = "<a class='list-group-item'>Reliability: " + transObj['reliability'].toFixed(2) + " (" + (transObj['reliability'] > data['ad_params']['reliability_threshold'] ? ">" : "<") + " Reliability Threshold of " + data['ad_params']['reliability_threshold'] + ") </a>";
|
||||||
var localCompatibility = "<a class='list-group-item'>Local Compatibility: " + transObj['local_compatibility'].toFixed(2) + " (" + (transObj['local_compatibility'] > data['ad_params']['local_compatibilty_threshold'] ? ">" : "<") + " Local Compatibility Threshold of " + data['ad_params']['local_compatibilty_threshold'] + ")</a>";
|
var localCompatibility = "<a class='list-group-item'>Local Compatibility: " + transObj['local_compatibility'].toFixed(2) + " (" + (transObj['local_compatibility'] > data['ad_params']['local_compatibility_threshold'] ? ">" : "<") + " Local Compatibility Threshold of " + data['ad_params']['local_compatibility_threshold'] + ")</a>";
|
||||||
|
|
||||||
var transImg = "<img width='100%' src='" + transObj['rule']['url'] + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "'>";
|
var transImg = "<img width='100%' src='" + transObj['rule']['url'] + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "'>";
|
||||||
|
|
||||||
|
|||||||
@ -444,6 +444,13 @@ function serializeSVG(svgElement) {
|
|||||||
line.setAttribute("fill", style.fill);
|
line.setAttribute("fill", style.fill);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
svgElement.querySelectorAll("line.link_no_arrow").forEach(line => {
|
||||||
|
const style = getComputedStyle(line);
|
||||||
|
line.setAttribute("stroke", style.stroke);
|
||||||
|
line.setAttribute("stroke-width", style.strokeWidth);
|
||||||
|
line.setAttribute("fill", style.fill);
|
||||||
|
});
|
||||||
|
|
||||||
const serializer = new XMLSerializer();
|
const serializer = new XMLSerializer();
|
||||||
let svgString = serializer.serializeToString(svgElement);
|
let svgString = serializer.serializeToString(svgElement);
|
||||||
|
|
||||||
@ -455,7 +462,26 @@ function serializeSVG(svgElement) {
|
|||||||
return svgString;
|
return svgString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shrinkSVG(svgSelector) {
|
||||||
|
|
||||||
|
const svg = d3.select(svgSelector);
|
||||||
|
const node = svg.node();
|
||||||
|
|
||||||
|
// Compute bounding box of everything inside the SVG
|
||||||
|
const bbox = node.getBBox();
|
||||||
|
|
||||||
|
const padding = 10;
|
||||||
|
svg.attr("viewBox",
|
||||||
|
`${bbox.x - padding} ${bbox.y - padding} ${bbox.width + 2 * padding} ${bbox.height + 2 * padding}`
|
||||||
|
)
|
||||||
|
.attr("width", bbox.width + 2 * padding)
|
||||||
|
.attr("height", bbox.height + 2 * padding);
|
||||||
|
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
function downloadSVG(svgElement, filename = 'chart.svg') {
|
function downloadSVG(svgElement, filename = 'chart.svg') {
|
||||||
|
shrinkSVG("#" + svgElement.id);
|
||||||
const svgString = serializeSVG(svgElement);
|
const svgString = serializeSVG(svgElement);
|
||||||
const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
|
const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{% if meta.can_edit %}
|
{% if meta.can_edit %}
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#predict_modal">
|
<a href="{{ meta.server_url }}/predict">
|
||||||
<span class="glyphicon glyphicon-plus"></span> New Pathway</a>
|
<span class="glyphicon glyphicon-plus"></span> New Pathway</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -3,6 +3,10 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_compound_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_compound_modal">
|
||||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Compound</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#add_structure_modal">
|
<a role="button" data-toggle="modal" data-target="#add_structure_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
|
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
|
||||||
@ -11,6 +15,10 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#generic_set_external_reference_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||||
|
|||||||
@ -3,10 +3,18 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_compound_structure_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_compound_structure_modal">
|
||||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#generic_set_external_reference_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
{% if meta.can_edit %}
|
{% if meta.can_edit %}
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
|||||||
@ -3,6 +3,10 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_node_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_node_modal">
|
||||||
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
|||||||
@ -22,6 +22,10 @@
|
|||||||
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway as Image</a>
|
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway as Image</a>
|
||||||
</li>
|
</li>
|
||||||
{% if meta.can_edit %}
|
{% if meta.can_edit %}
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#identify_missing_rules_modal">
|
||||||
|
<i class="glyphicon glyphicon-question-sign"></i> Identify Missing Rules</a>
|
||||||
|
</li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#edit_pathway_modal">
|
<a class="button" data-toggle="modal" data-target="#edit_pathway_modal">
|
||||||
@ -31,6 +35,10 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
{# <li>#}
|
{# <li>#}
|
||||||
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
||||||
{# <i class="glyphicon glyphicon-plus"></i> Calculate Compound Properties</a>#}
|
{# <i class="glyphicon glyphicon-plus"></i> Calculate Compound Properties</a>#}
|
||||||
|
|||||||
@ -3,10 +3,18 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_reaction_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_reaction_modal">
|
||||||
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#generic_set_external_reference_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set External Reference</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||||
|
|||||||
@ -3,6 +3,10 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
||||||
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
|||||||
70
templates/collections/joblog.html
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{% extends "framework.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="panel-group" id="reviewListAccordion">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||||
|
Jobs
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
Job Logs Desc
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="job-accordion-link" data-toggle="collapse" data-parent="#job-accordion" href="#jobs">
|
||||||
|
Jobs
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="jobs"
|
||||||
|
class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item" id="job-content">
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
||||||
|
<th scope="col">ID</th>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<th scope="col">Queued</th>
|
||||||
|
<th scope="col">Done</th>
|
||||||
|
<th scope="col">Result</th>
|
||||||
|
</tr>
|
||||||
|
<tbody>
|
||||||
|
{% for job in jobs %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ job.task_id }}</td>
|
||||||
|
<td>{{ job.job_name }}</td>
|
||||||
|
<td>{{ job.status }}</td>
|
||||||
|
<td>{{ job.created }}</td>
|
||||||
|
<td>{{ job.done_at }}</td>
|
||||||
|
{% if job.task_result and job.task_result|is_url == True %}
|
||||||
|
<td><a href="{{ job.task_result }}">Result</a></td>
|
||||||
|
{% elif job.task_result %}
|
||||||
|
<td>{{ job.task_result|slice:"40" }}...</td>
|
||||||
|
{% else %}
|
||||||
|
<td>Empty</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||||
|
<ul class='list-group'>
|
||||||
|
{% for obj in objects %}
|
||||||
|
{% if object_type == 'user' %}
|
||||||
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
@ -192,7 +192,7 @@
|
|||||||
<div class="panel-body list-group-item" id="ReviewedContent">
|
<div class="panel-body list-group-item" id="ReviewedContent">
|
||||||
{% if object_type == 'package' %}
|
{% if object_type == 'package' %}
|
||||||
{% for obj in reviewed_objects %}
|
{% for obj in reviewed_objects %}
|
||||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}
|
||||||
<span class="glyphicon glyphicon-star" aria-hidden="true"
|
<span class="glyphicon glyphicon-star" aria-hidden="true"
|
||||||
style="float:right" data-toggle="tooltip"
|
style="float:right" data-toggle="tooltip"
|
||||||
data-placement="top" title="" data-original-title="Reviewed">
|
data-placement="top" title="" data-original-title="Reviewed">
|
||||||
@ -201,7 +201,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for obj in reviewed_objects|slice:":50" %}
|
{% for obj in reviewed_objects|slice:":50" %}
|
||||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}{# <i>({{ obj.package.name }})</i> #}
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}{# <i>({{ obj.package.name }})</i> #}
|
||||||
<span class="glyphicon glyphicon-star" aria-hidden="true"
|
<span class="glyphicon glyphicon-star" aria-hidden="true"
|
||||||
style="float:right" data-toggle="tooltip"
|
style="float:right" data-toggle="tooltip"
|
||||||
data-placement="top" title="" data-original-title="Reviewed">
|
data-placement="top" title="" data-original-title="Reviewed">
|
||||||
@ -221,11 +221,11 @@
|
|||||||
<div class="panel-body list-group-item" id="UnreviewedContent">
|
<div class="panel-body list-group-item" id="UnreviewedContent">
|
||||||
{% if object_type == 'package' %}
|
{% if object_type == 'package' %}
|
||||||
{% for obj in unreviewed_objects %}
|
{% for obj in unreviewed_objects %}
|
||||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for obj in unreviewed_objects|slice:":50" %}
|
{% for obj in unreviewed_objects|slice:":50" %}
|
||||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@ -236,9 +236,9 @@
|
|||||||
<ul class='list-group'>
|
<ul class='list-group'>
|
||||||
{% for obj in objects %}
|
{% for obj in objects %}
|
||||||
{% if object_type == 'user' %}
|
{% if object_type == 'user' %}
|
||||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username }}</a>
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username|safe }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
55
templates/compare.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{% extends "framework.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="text" class="form-control" id="smiles" name="smiles" placeholder="SMILES"
|
||||||
|
value="{{ smiles }}"/>
|
||||||
|
<input type="text" class="form-control" id="smiles" name="smirks" placeholder="SMIRKS"
|
||||||
|
value="{{ smirks }}"/>
|
||||||
|
<button type="submit" class="btn btn-primary">Test</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% if result %}
|
||||||
|
{{ smiles }}<p></p>
|
||||||
|
<img width='400' src='{% url 'depict' %}?smiles={{ smiles|urlencode }}'><br>
|
||||||
|
<p></p>
|
||||||
|
{% if rule %}
|
||||||
|
{{ smirks }}
|
||||||
|
<p></p>
|
||||||
|
{{ rule.reactants_smarts }}
|
||||||
|
<p></p>
|
||||||
|
{{ rule.products_smarts }}
|
||||||
|
<p></p>
|
||||||
|
<div>
|
||||||
|
{{ rule.as_svg|safe }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<h2>Diff</h2>
|
||||||
|
{% if diff %}
|
||||||
|
{% for d in diff %}
|
||||||
|
{{ d }}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{{ "No diff" }}
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2>Ambit</h2>
|
||||||
|
{% for p in ambit_res %}
|
||||||
|
{{ p }}<br>
|
||||||
|
<img width='400' src='{% url 'depict' %}?smiles={{ p|urlencode }}'><br>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2>RDKit</h2>
|
||||||
|
{% for p in rdkit_res %}
|
||||||
|
{{ p }}<br>
|
||||||
|
<img width='400' src='{% url 'depict' %}?smiles={{ p|urlencode }}'><br>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock content %}
|
||||||
@ -6,8 +6,7 @@
|
|||||||
<h4 class="alert-heading">{{ error_message }}</h4>
|
<h4 class="alert-heading">{{ error_message }}</h4>
|
||||||
<hr>
|
<hr>
|
||||||
<p class="mb-0">
|
<p class="mb-0">
|
||||||
{{ error_detail }}<br>
|
{{ error_detail }}
|
||||||
The error was logged and will be investigated.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -1,77 +1,106 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html data-theme="envipath">
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<head>
|
<head>
|
||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
<style>
|
<meta name="csrf-token" content="{{ csrf_token }}" />
|
||||||
html, body {
|
{# Favicon #}
|
||||||
height: 100%; /* ensure body fills viewport */
|
<link
|
||||||
overflow-x: hidden; /* prevent horizontal scroll */
|
rel="shortcut icon"
|
||||||
}
|
type="image/png"
|
||||||
</style>
|
href="{% static 'images/favicon.ico' %}"
|
||||||
{# TODO use bundles from bootstrap 3.3.7 #}
|
/>
|
||||||
|
|
||||||
|
{# Tailwind CSS disabled for legacy Bootstrap framework #}
|
||||||
|
{# Pages using this framework will be migrated to framework_modern.html incrementally #}
|
||||||
|
{# <link href="{% static 'css/output.css' %}" rel="stylesheet" type="text/css"/> #}
|
||||||
|
|
||||||
|
{# Legacy Bootstrap 3.3.7 - scoped to .legacy-bootstrap #}
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||||
|
/>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>
|
||||||
<link href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
<link
|
||||||
<link rel="stylesheet"
|
href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/css/bootstrap-select.min.css">
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/css/bootstrap-select.min.css"
|
||||||
|
/>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/js/bootstrap-select.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.7.3/js/bootstrap-select.min.js"></script>
|
||||||
<script src="https://community.envipath.org/javascripts/embed-topics.js"></script>
|
<script src="https://community.envipath.org/javascripts/embed-topics.js"></script>
|
||||||
<!-- CDN END -->
|
<!-- CDN END -->
|
||||||
<meta name="csrf-token" content="{{ csrf_token }}">
|
|
||||||
<script>
|
|
||||||
const csrftoken = document.querySelector('[name=csrf-token]').content;
|
|
||||||
|
|
||||||
// Setup CSRF header for all jQuery AJAX requests
|
{# Bootstrap compatibility styles #}
|
||||||
$.ajaxSetup({
|
<style>
|
||||||
beforeSend: function(xhr, settings) {
|
/* Ensure proper viewport behavior */
|
||||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
|
html,
|
||||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
body {
|
||||||
}
|
height: 100%; /* ensure body fills viewport */
|
||||||
}
|
overflow-x: hidden; /* prevent horizontal scroll */
|
||||||
});
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const csrftoken = document.querySelector("[name=csrf-token]").content;
|
||||||
|
|
||||||
|
// Setup CSRF header for all jQuery AJAX requests
|
||||||
|
$.ajaxSetup({
|
||||||
|
beforeSend: function (xhr, settings) {
|
||||||
|
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{# Favicon #}
|
|
||||||
<link rel="shortcut icon" type="image/png" href="{% static 'images/favicon.ico' %}"/>
|
|
||||||
<!-- {# C3 CSS #}-->
|
<!-- {# C3 CSS #}-->
|
||||||
<!-- <link id="css-c3" href="{% static 'css/c3.css' %}" rel="stylesheet" type="text/css"/>-->
|
<!-- <link id="css-c3" href="{% static 'css/c3.css' %}" rel="stylesheet" type="text/css"/>-->
|
||||||
<!-- {# EP CSS #}-->
|
<!-- {# EP CSS #}-->
|
||||||
<!-- <link id="css-pps_white_general" href="{% static 'css/epp.css' %}" rel="stylesheet" type="text/css"/>-->
|
<!-- <link id="css-pps_white_general" href="{% static 'css/epp.css' %}" rel="stylesheet" type="text/css"/>-->
|
||||||
|
|
||||||
|
|
||||||
{# General EP JS #}
|
{# General EP JS #}
|
||||||
<script src="{% static 'js/pps.js' %}"></script>
|
<script src="{% static 'js/pps.js' %}"></script>
|
||||||
{# Modal Steps for Stepwise Modal Wizards #}
|
{# Modal Steps for Stepwise Modal Wizards #}
|
||||||
<script src="{% static 'js/jquery-bootstrap-modal-steps.js' %}"></script>
|
<script src="{% static 'js/jquery-bootstrap-modal-steps.js' %}"></script>
|
||||||
|
|
||||||
{% if not debug %}
|
{% if not debug %}
|
||||||
<!-- Matomo -->
|
<!-- Matomo -->
|
||||||
<script>
|
<script>
|
||||||
var _paq = window._paq = window._paq || [];
|
var _paq = (window._paq = window._paq || []);
|
||||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
_paq.push(['trackPageView']);
|
_paq.push(["trackPageView"]);
|
||||||
_paq.push(['enableLinkTracking']);
|
_paq.push(["enableLinkTracking"]);
|
||||||
(function () {
|
(function () {
|
||||||
var u = "//matomo.envipath.com/";
|
var u = "//matomo.envipath.com/";
|
||||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
_paq.push(["setTrackerUrl", u + "matomo.php"]);
|
||||||
_paq.push(['setSiteId', '10']);
|
_paq.push(["setSiteId", "{{ meta.site_id }}"]);
|
||||||
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
var d = document,
|
||||||
g.async = true;
|
g = d.createElement("script"),
|
||||||
g.src = u + 'matomo.js';
|
s = d.getElementsByTagName("script")[0];
|
||||||
s.parentNode.insertBefore(g, s);
|
g.async = true;
|
||||||
})();
|
g.src = u + "matomo.js";
|
||||||
</script>
|
s.parentNode.insertBefore(g, s);
|
||||||
<!-- End Matomo Code -->
|
})();
|
||||||
|
</script>
|
||||||
|
<!-- End Matomo Code -->
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</head>
|
||||||
</head>
|
<body>
|
||||||
<body>
|
<!-- Legacy Bootstrap navbar - isolated from Tailwind -->
|
||||||
<nav class="navbar navbar-default navbar-inverse" style="border-radius:0px;" role="navigation">
|
<div class="legacy-bootstrap">
|
||||||
<div class="container-fluid">
|
<nav
|
||||||
<!-- Brand and toggle get grouped for better mobile display -->
|
class="navbar navbar-default navbar-inverse"
|
||||||
<div class="navbar-header navbar-header-framework">
|
style="border-radius:0px;"
|
||||||
|
role="navigation"
|
||||||
|
>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!-- Brand and toggle get grouped for better mobile display -->
|
||||||
|
<div class="navbar-header navbar-header-framework">
|
||||||
<!-- <button type="button" class="navbar-toggle navbar-toggle-framework" data-toggle="collapse"-->
|
<!-- <button type="button" class="navbar-toggle navbar-toggle-framework" data-toggle="collapse"-->
|
||||||
<!-- data-target="#navbarCollapse">-->
|
<!-- data-target="#navbarCollapse">-->
|
||||||
<!-- <span class="sr-only">Toggle navigation</span>-->
|
<!-- <span class="sr-only">Toggle navigation</span>-->
|
||||||
@ -79,196 +108,315 @@
|
|||||||
<!-- <span class="icon-bar"></span>-->
|
<!-- <span class="icon-bar"></span>-->
|
||||||
<!-- <span class="icon-bar"></span>-->
|
<!-- <span class="icon-bar"></span>-->
|
||||||
<!-- </button>-->
|
<!-- </button>-->
|
||||||
<a id="pictureLink" href="{{ meta.server_url }}" class="navbar-brand">
|
<a
|
||||||
<img id="image-logo-short-white.svg" src='{% static "/images/logo-short-white.svg" %}' width="100"
|
id="pictureLink"
|
||||||
alt="enviPath">
|
href="{{ meta.server_url }}"
|
||||||
|
class="navbar-brand"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
id="image-logo-short-white.svg"
|
||||||
|
src="{% static "/images/logo-short-white.svg" %}"
|
||||||
|
width="100"
|
||||||
|
alt="enviPath"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse collapse-framework navbar-collapse-framework" id="navbarCollapse">
|
<div
|
||||||
|
class="collapse navbar-collapse collapse-framework navbar-collapse-framework"
|
||||||
|
id="navbarCollapse"
|
||||||
|
>
|
||||||
<ul class="nav navbar-nav navbar-nav-framework">
|
<ul class="nav navbar-nav navbar-nav-framework">
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/predict"> Predict Pathway </a>
|
||||||
|
</li>
|
||||||
|
{# <li class="dropdown">#}
|
||||||
|
{# <a data-toggle="dropdown" class="dropdown-toggle" href="#">Predict Pathway<b class="caret"></b></a>#}
|
||||||
|
{# <ul role="menu" class="dropdown-menu">#}
|
||||||
|
{# <li>#}
|
||||||
|
{# <a class="button" data-toggle="modal" data-target="#predict_modal">#}
|
||||||
|
{# <i class=" glyphicon glyphicon-tag"></i> Predict Pathway#}
|
||||||
|
{# </a>#}
|
||||||
|
{# </li>#}
|
||||||
|
{# <li>#}
|
||||||
|
{# <a class="button" data-toggle="modal" data-target="#batch_predict_modal">#}
|
||||||
|
{# <i class=" glyphicon glyphicon-tags"></i> Batch Prediction#}
|
||||||
|
{# </a>#}
|
||||||
|
{# </li>#}
|
||||||
|
{# </ul>#}
|
||||||
|
{# </li>#}
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/package" id="packageLink"
|
||||||
|
>Package</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/search" id="searchLink"
|
||||||
|
>Search</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/model" id="modelLink"
|
||||||
|
>Modelling</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown">
|
||||||
|
<a data-toggle="dropdown" class="dropdown-toggle" href="#"
|
||||||
|
>Browse Data<b class="caret"></b
|
||||||
|
></a>
|
||||||
|
<ul role="menu" class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/pathway" id="pathwayLink"
|
||||||
|
>Pathway</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/rule" id="ruleLink">Rule</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/compound" id="compoundLink"
|
||||||
|
>Compound</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/reaction" id="reactionLink"
|
||||||
|
>Reaction</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="{{ meta.server_url }}/model"
|
||||||
|
id="relative-reasoningLink"
|
||||||
|
>Model</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/scenario" id="scenarioLink"
|
||||||
|
>Scenario</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{# <li><a href="{{ meta.server_url }}/setting" id="settingLink">Setting</a></li>#}
|
||||||
|
{# <li><a href="{{ meta.server_url }}/user" id="userLink">User</a></li>#}
|
||||||
|
{# <li><a href="{{ meta.server_url }}/group" id="groupLink">Group</a></li>#}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul
|
||||||
|
class="nav navbar-nav navbar-right navbar-nav-framework navbar-right-framework"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a href="https://community.envipath.org/" id="communityLink"
|
||||||
|
>Community</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown">
|
||||||
|
<a data-toggle="dropdown" class="dropdown-toggle" href="#"
|
||||||
|
>Info <b class="caret"></b
|
||||||
|
></a>
|
||||||
|
<ul role="menu" class="dropdown-menu">
|
||||||
|
<!--<li><a href="{{ meta.server_url }}/funding" id="fundingLink">Funding</a></li>-->
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://community.envipath.org/t/envipath-license/109"
|
||||||
|
id="licenceLink"
|
||||||
|
>Licences</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
href="https://wiki.envipath.org/"
|
||||||
|
id="wikiLink"
|
||||||
|
>Documentation Wiki</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
id="citeButton"
|
||||||
|
data-toggle="modal"
|
||||||
|
data-target="#citemodal"
|
||||||
|
>How to cite enviPath</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li><a>Version: {{ meta.version }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% if meta.user.username == 'anonymous' %}
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#predict_modal">
|
<a
|
||||||
Predict Pathway
|
href="{% url 'login' %}"
|
||||||
</a>
|
id="loginButton"
|
||||||
|
style="margin-right:10px"
|
||||||
|
>Login</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
{# <li class="dropdown">#}
|
{% else %}
|
||||||
{# <a data-toggle="dropdown" class="dropdown-toggle" href="#">Predict Pathway<b class="caret"></b></a>#}
|
|
||||||
{# <ul role="menu" class="dropdown-menu">#}
|
|
||||||
{# <li>#}
|
|
||||||
{# <a class="button" data-toggle="modal" data-target="#predict_modal">#}
|
|
||||||
{# <i class=" glyphicon glyphicon-tag"></i> Predict Pathway#}
|
|
||||||
{# </a>#}
|
|
||||||
{# </li>#}
|
|
||||||
{# <li>#}
|
|
||||||
{# <a class="button" data-toggle="modal" data-target="#batch_predict_modal">#}
|
|
||||||
{# <i class=" glyphicon glyphicon-tags"></i> Batch Prediction#}
|
|
||||||
{# </a>#}
|
|
||||||
{# </li>#}
|
|
||||||
{# </ul>#}
|
|
||||||
{# </li>#}
|
|
||||||
<li><a href="{{ meta.server_url }}/package" id="packageLink">Package</a></li>
|
|
||||||
<li><a href="{{ meta.server_url }}/search" id="searchLink">Search</a></li>
|
|
||||||
<li><a href="{{ meta.server_url }}/model" id="modelLink">Modelling</a></li>
|
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">Browse Data<b class="caret"></b></a>
|
<a
|
||||||
<ul role="menu" class="dropdown-menu">
|
data-toggle="dropdown"
|
||||||
<li><a href="{{ meta.server_url }}/pathway" id="pathwayLink">Pathway</a></li>
|
id="loggedInButton"
|
||||||
<li><a href="{{ meta.server_url }}/rule" id="ruleLink">Rule</a></li>
|
class="dropdown-toggle"
|
||||||
<li><a href="{{ meta.server_url }}/compound" id="compoundLink">Compound</a></li>
|
id="logedInButton"
|
||||||
<li><a href="{{ meta.server_url }}/reaction" id="reactionLink">Reaction</a></li>
|
href="#"
|
||||||
<li><a href="{{ meta.server_url }}/model" id="relative-reasoningLink">Model</a></li>
|
>
|
||||||
<li><a href="{{ meta.server_url }}/scenario" id="scenarioLink">Scenario</a></li>
|
<div id="username">
|
||||||
{# <li><a href="{{ meta.server_url }}/setting" id="settingLink">Setting</a></li>#}
|
{{ user.username }}<b class="caret"></b>
|
||||||
{# <li><a href="{{ meta.server_url }}/user" id="userLink">User</a></li>#}
|
</div>
|
||||||
{# <li><a href="{{ meta.server_url }}/group" id="groupLink">Group</a></li>#}
|
</a>
|
||||||
</ul>
|
<ul role="menu" class="dropdown-menu">
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right navbar-nav-framework navbar-right-framework">
|
|
||||||
<li><a href="https://community.envipath.org/" id="communityLink">Community</a></li>
|
|
||||||
<li class="dropdown">
|
|
||||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">Info <b class="caret"></b></a>
|
|
||||||
<ul role="menu" class="dropdown-menu">
|
|
||||||
<!--<li><a href="{{ meta.server_url }}/funding" id="fundingLink">Funding</a></li>-->
|
|
||||||
<li><a href="https://envipath.com/license/" id="licenceLink">Licences</a></li>
|
|
||||||
<li class="divider"></li>
|
|
||||||
<li><a target="_blank" href="https://wiki.envipath.org/" id="wikiLink">Documentation Wiki</a>
|
|
||||||
</li>
|
|
||||||
<li><a href="#" id="citeButton" data-toggle="modal" data-target="#citemodal">How to cite
|
|
||||||
enviPath</a></li>
|
|
||||||
<li class="divider"></li>
|
|
||||||
<li><a>Version: {{ meta.version }}</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% if meta.user.username == 'anonymous' %}
|
|
||||||
<li>
|
<li>
|
||||||
<a href="#signup" id="loginButton" data-toggle="modal" data-target="#signupmodal"
|
<a href="{{ meta.user.url }}" id="accountbutton"
|
||||||
style="margin-right:10px">Login</a>
|
>My Account</a
|
||||||
|
>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
<li class="divider"></li>
|
||||||
<li class="dropdown">
|
<form
|
||||||
<a data-toggle="dropdown" id="loggedInButton" class="dropdown-toggle" id="logedInButton"
|
class="navbar-form navbar-left navbar-left-framework"
|
||||||
href="#">
|
role="logout"
|
||||||
<div id="username">
|
action="{% url 'logout' %}"
|
||||||
{{ user.username }}<b class="caret"></b>
|
method="post"
|
||||||
</div>
|
>
|
||||||
</a>
|
{% csrf_token %}
|
||||||
<ul role="menu" class="dropdown-menu">
|
<div class="form-group">
|
||||||
<li>
|
<input type="hidden" name="logout" value="true" />
|
||||||
<a href="{{ meta.user.url }}" id="accountbutton">My Account</a>
|
</div>
|
||||||
</li>
|
<button type="submit" class="btn btn-default">
|
||||||
<li class="divider"></li>
|
Logout
|
||||||
<form class="navbar-form navbar-left navbar-left-framework" role="logout"
|
</button>
|
||||||
action="{% url 'logout' %}" method="post">
|
</form>
|
||||||
{% csrf_token %}
|
</ul>
|
||||||
<div class="form-group">
|
</li>
|
||||||
<input type="hidden" name="logout" value="true">
|
{% endif %}
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-default">Logout</button>
|
|
||||||
</form>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
<!-- End legacy Bootstrap navbar -->
|
||||||
<div id="docContent" class="content container">
|
|
||||||
{% if breadcrumbs %}
|
<div id="docContent" class="content container">
|
||||||
|
{% if breadcrumbs %}
|
||||||
<div id="bread">
|
<div id="bread">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
{% for elem in breadcrumbs %}
|
{% for elem in breadcrumbs %}
|
||||||
{% for name, url in elem.items %}
|
{% for name, url in elem.items %}
|
||||||
{% if forloop.parentloop.last %}
|
{% if forloop.parentloop.last %}
|
||||||
<li class="active">{{ name }}</li>
|
<li class="active">{{ name }}</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url }}">{{ name }}</a>
|
<a href="{{ url }}">{{ name }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if message %}
|
{% if message %}
|
||||||
<div id="message">
|
<div id="message">{{ message }}</div>
|
||||||
{{ message }}
|
{% endif %}
|
||||||
</div>
|
{% block content %}
|
||||||
{% endif %}
|
{% endblock content %}
|
||||||
{% block content %}
|
{% if meta.url_contains_package and meta.current_package.license %}
|
||||||
{% endblock content %}
|
|
||||||
{% if meta.url_contains_package and meta.current_package.license %}
|
|
||||||
<p></p>
|
<p></p>
|
||||||
<div class="panel-group" id="license_accordion">
|
<div class="panel-group" id="license_accordion">
|
||||||
<div class="panel panel-default list-group-item" style="background-color:#f5f5f5">
|
<div
|
||||||
<div class="panel-title">
|
class="panel panel-default list-group-item"
|
||||||
<a data-toggle="collapse" data-parent="#licence_accordion" href="#license">License</a>
|
style="background-color:#f5f5f5"
|
||||||
</div>
|
>
|
||||||
|
<div class="panel-title">
|
||||||
|
<a
|
||||||
|
data-toggle="collapse"
|
||||||
|
data-parent="#licence_accordion"
|
||||||
|
href="#license"
|
||||||
|
>License</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div id="license" class="panel-collapse collapse in">
|
</div>
|
||||||
<div class="panel-body list-group-item">
|
<div id="license" class="panel-collapse collapse in">
|
||||||
<a target="_blank" href="{{ meta.current_package.license.link }}">
|
<div class="panel-body list-group-item">
|
||||||
<img src="{{ meta.current_package.license.image_link }}">
|
<a target="_blank" href="{{ meta.current_package.license.link }}">
|
||||||
</a>
|
<img src="{{ meta.current_package.license.image_link }}" />
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- FOOTER -->
|
|
||||||
<div class="container text-center">
|
|
||||||
<hr/>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<ul class="nav nav-pills nav-justified">
|
|
||||||
<li><a href="http://eawag.ch" target="_blank">
|
|
||||||
<img id="image-ealogo"
|
|
||||||
height="60"
|
|
||||||
src='{% static "/images/ealogo.gif" %}'
|
|
||||||
alt="Eawag"/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="http://ml.auckland.ac.nz" target="_blank">
|
|
||||||
<img id="image-uoalogo"
|
|
||||||
height="60"
|
|
||||||
src='{% static "/images/uoa.png" %}'
|
|
||||||
alt="The Univserity of Auckland"/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="row">
|
<!-- FOOTER - Legacy Bootstrap -->
|
||||||
<div class="col-lg-12">
|
<div class="legacy-bootstrap">
|
||||||
<ul class="nav nav-pills nav-justified">
|
<div class="container text-center">
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<ul class="nav nav-pills nav-justified">
|
||||||
|
<li>
|
||||||
|
<a href="http://ml.auckland.ac.nz" target="_blank">
|
||||||
|
<img
|
||||||
|
id="image-uoalogo"
|
||||||
|
height="60"
|
||||||
|
src="{% static "/images/UoA-Logo-Primary-RGB-Small.png" %}"
|
||||||
|
alt="The Univserity of Auckland"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://eawag.ch" target="_blank">
|
||||||
|
<img
|
||||||
|
id="image-ealogo"
|
||||||
|
height="60"
|
||||||
|
src="{% static "/images/ealogo.gif" %}"
|
||||||
|
alt="Eawag"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://www.uzh.ch/" target="_blank">
|
||||||
|
<img
|
||||||
|
id="image-ufzlogo"
|
||||||
|
height="60"
|
||||||
|
src="{% static "/images/uzh-logo.svg" %}"
|
||||||
|
alt="University of Zurich"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<ul class="nav nav-pills nav-justified">
|
||||||
<!-- <li><a href="https://envipath.com/imprint/" target="_blank">Impressum/Imprint</a></li>-->
|
<!-- <li><a href="https://envipath.com/imprint/" target="_blank">Impressum/Imprint</a></li>-->
|
||||||
<li><a href="mailto:admin@envipath.org" target="_blank">Contact</a></li>
|
<li>
|
||||||
|
<a href="mailto:admin@envipath.org" target="_blank">Contact</a>
|
||||||
|
</li>
|
||||||
<!-- <li><a href="http://envipath.com" target="_blank"> enviPath UG (haftungsbeschränkt) & Co. KG ©-->
|
<!-- <li><a href="http://envipath.com" target="_blank"> enviPath UG (haftungsbeschränkt) & Co. KG ©-->
|
||||||
<!-- {{ YEAR }}</a></li>-->
|
<!-- {{ YEAR }}</a></li>-->
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!-- End legacy Bootstrap footer -->
|
||||||
<script>
|
|
||||||
$(function () {
|
<script>
|
||||||
|
$(function () {
|
||||||
// Hide actionsbutton if theres no action defined
|
// Hide actionsbutton if theres no action defined
|
||||||
if ($('#actionsButton ul').children().length > 0) {
|
if ($("#actionsButton ul").children().length > 0) {
|
||||||
$('#actionsButton').show();
|
$("#actionsButton").show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% block modals %}
|
{% block modals %}
|
||||||
{% include "modals/cite_modal.html" %}
|
{% include "modals/cite_modal.html" %}
|
||||||
{% include "modals/signup_modal.html" %}
|
{% include "modals/predict_modal.html" %}
|
||||||
{% include "modals/predict_modal.html" %}
|
{% include "modals/batch_predict_modal.html" %}
|
||||||
{% include "modals/batch_predict_modal.html" %}
|
{% endblock %}
|
||||||
{% endblock %}
|
</body>
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
223
templates/framework_modern.html
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html data-theme="envipath" lang="en">
|
||||||
|
{% load static %}
|
||||||
|
<head>
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token }}" />
|
||||||
|
|
||||||
|
{# Favicon #}
|
||||||
|
<link
|
||||||
|
rel="shortcut icon"
|
||||||
|
type="image/png"
|
||||||
|
href="{% static 'images/favicon.ico' %}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{# Tailwind CSS + DaisyUI Output #}
|
||||||
|
<link
|
||||||
|
href="{% static 'css/output.css' %}"
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{# jQuery - Keep for compatibility with existing JS #}
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
|
|
||||||
|
{# Font Awesome #}
|
||||||
|
<link
|
||||||
|
href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{# Discourse embed for community #}
|
||||||
|
<script src="https://community.envipath.org/javascripts/embed-topics.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const csrftoken = document.querySelector("[name=csrf-token]").content;
|
||||||
|
|
||||||
|
// Setup CSRF header for all jQuery AJAX requests
|
||||||
|
$.ajaxSetup({
|
||||||
|
beforeSend: function (xhr, settings) {
|
||||||
|
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{# General EP JS #}
|
||||||
|
<script src="{% static 'js/pps.js' %}"></script>
|
||||||
|
{# Modal Steps for Stepwise Modal Wizards #}
|
||||||
|
<script src="{% static 'js/jquery-bootstrap-modal-steps.js' %}"></script>
|
||||||
|
|
||||||
|
{% if not debug %}
|
||||||
|
<!-- Matomo -->
|
||||||
|
<script>
|
||||||
|
var _paq = (window._paq = window._paq || []);
|
||||||
|
_paq.push(["trackPageView"]);
|
||||||
|
_paq.push(["enableLinkTracking"]);
|
||||||
|
(function () {
|
||||||
|
var u = "//matomo.envipath.com/";
|
||||||
|
_paq.push(["setTrackerUrl", u + "matomo.php"]);
|
||||||
|
_paq.push(["setSiteId", "{{ meta.site_id }}"]);
|
||||||
|
var d = document,
|
||||||
|
g = d.createElement("script"),
|
||||||
|
s = d.getElementsByTagName("script")[0];
|
||||||
|
g.async = true;
|
||||||
|
g.src = u + "matomo.js";
|
||||||
|
s.parentNode.insertBefore(g, s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<!-- End Matomo Code -->
|
||||||
|
{% endif %}
|
||||||
|
</head>
|
||||||
|
<body class="bg-base-300 min-h-screen">
|
||||||
|
{% include "includes/navbar.html" %}
|
||||||
|
|
||||||
|
{# Main Content Area #}
|
||||||
|
<main class="w-full">
|
||||||
|
{% block main_content %}
|
||||||
|
{# Breadcrumbs - outside main content, optional #}
|
||||||
|
{% if breadcrumbs %}
|
||||||
|
<div id="bread" class="max-w-7xl mx-auto px-4 py-4">
|
||||||
|
<div class="breadcrumbs text-sm">
|
||||||
|
<ul>
|
||||||
|
{% for elem in breadcrumbs %}
|
||||||
|
{% for name, url in elem.items %}
|
||||||
|
{% if forloop.parentloop.last %}
|
||||||
|
<li>{{ name }}</li>
|
||||||
|
{% else %}
|
||||||
|
<li><a href="{{ url }}">{{ name }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Main content container - paper effect on medium+ screens #}
|
||||||
|
<div
|
||||||
|
id="docContent"
|
||||||
|
class="bg-base-100 mx-auto md:my-8 md:max-w-6xl md:rounded-lg md:shadow-xl"
|
||||||
|
>
|
||||||
|
{# Messages - inside paper #}
|
||||||
|
{% if message %}
|
||||||
|
<div id="message" class="alert alert-info m-4">{{ message }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Page content - no enforced styles #}
|
||||||
|
{% block content %}
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
{# License - inside paper if present #}
|
||||||
|
{% if meta.url_contains_package and meta.current_package.license %}
|
||||||
|
<div class="collapse collapse-arrow bg-base-200 m-8">
|
||||||
|
<input type="checkbox" checked />
|
||||||
|
<div class="collapse-title text-xl font-medium">License</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
href="{{ meta.current_package.license.link }}"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="{{ meta.current_package.license.image_link }}"
|
||||||
|
alt="License"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock main_content %}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{% include "includes/footer.html" %}
|
||||||
|
|
||||||
|
{# Floating Help Tab #}
|
||||||
|
{% if not public_mode %}
|
||||||
|
<div class="fixed right-0 top-1/2 -translate-y-1/2 z-50">
|
||||||
|
<a
|
||||||
|
href="https://community.envipath.org/"
|
||||||
|
target="_blank"
|
||||||
|
class="btn btn-secondary hover:btn-secondary-focus text-secondary-content flex items-center justify-center text-sm shadow-lg transition-all duration-300 hover:-translate-x-1 hover:scale-105"
|
||||||
|
title="Get Help from the Community"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="lucide lucide-message-circle-question-mark-icon lucide-message-circle-question-mark"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719"
|
||||||
|
/>
|
||||||
|
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
|
||||||
|
<path d="M12 17h.01" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block modals %}
|
||||||
|
{% include "modals/search_modal.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
// Hide actionsbutton if there's no action defined
|
||||||
|
if ($("#actionsButton ul").children().length > 0) {
|
||||||
|
$("#actionsButton").show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open search modal function
|
||||||
|
function openSearchModal() {
|
||||||
|
const searchModal = document.getElementById("search_modal");
|
||||||
|
if (searchModal) {
|
||||||
|
searchModal.showModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click handler for search badge
|
||||||
|
const searchTrigger = document.getElementById("search-trigger");
|
||||||
|
if (searchTrigger) {
|
||||||
|
searchTrigger.addEventListener("click", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
openSearchModal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global keyboard shortcut for search (Cmd+K on Mac, Ctrl+K on Windows/Linux)
|
||||||
|
document.addEventListener("keydown", function (event) {
|
||||||
|
// Check if user is typing in an input field
|
||||||
|
const activeElement = document.activeElement;
|
||||||
|
const isInputField =
|
||||||
|
activeElement &&
|
||||||
|
(activeElement.tagName === "INPUT" ||
|
||||||
|
activeElement.tagName === "TEXTAREA" ||
|
||||||
|
activeElement.contentEditable === "true");
|
||||||
|
|
||||||
|
if (isInputField) {
|
||||||
|
return; // Don't trigger shortcut when typing in input fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Cmd+K (Mac) or Ctrl+K (Windows/Linux)
|
||||||
|
const isMac = /Mac/.test(navigator.platform);
|
||||||
|
const isCorrectModifier = isMac ? event.metaKey : event.ctrlKey;
|
||||||
|
|
||||||
|
if (isCorrectModifier && event.key === "k") {
|
||||||
|
event.preventDefault();
|
||||||
|
openSearchModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
69
templates/includes/footer.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
{% load static %}
|
||||||
|
<div class="lg:max-w-5xl mt-10 mx-auto bg-base-300 text-base-content">
|
||||||
|
|
||||||
|
<footer class="footer sm:footer-horizontal p-10">
|
||||||
|
{% if not public_mode %}
|
||||||
|
<nav>
|
||||||
|
<h6 class="footer-title">Services</h6>
|
||||||
|
<a class="link link-hover" href="/">Predict</a>
|
||||||
|
<a class="link link-hover" href="/search">Search</a>
|
||||||
|
<a class="link link-hover" href="/package">Browse</a>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<a class="link link-hover" href="/model">Your Collections</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="https://wiki.envipath.org/" target="_blank" class="link link-hover">Documentation</a>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
<nav>
|
||||||
|
<h6 class="footer-title">Company</h6>
|
||||||
|
<a class="link link-hover" href="/about">About us</a>
|
||||||
|
<a class="link link-hover" href="/contact">Contact us</a>
|
||||||
|
<a class="link link-hover" href="/careers">Careers</a>
|
||||||
|
<a class="link link-hover" href="/legal">Legal</a>
|
||||||
|
</nav>
|
||||||
|
<nav>
|
||||||
|
<h6 class="footer-title">Legal</h6>
|
||||||
|
<a class="link link-hover" href="/terms">Terms of use</a>
|
||||||
|
<a class="link link-hover" href="/privacy">Privacy policy</a>
|
||||||
|
<a class="link link-hover" href="/cookie-policy">Cookie policy</a>
|
||||||
|
<a class="link link-hover" href="/cite">Cite enviPath</a>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
<footer class="footer border-neutral-300 border-t-2 px-10 py-4">
|
||||||
|
<div class="flex flex-row justify-between w-full items-start">
|
||||||
|
<aside class="grid-flow-col items-center">
|
||||||
|
<svg class="fill-neutral-content flex-shrink-0 h-14 m-2" viewbox="0 0 65 65" >
|
||||||
|
<use
|
||||||
|
href="{% static "/images/logo-square.svg" %}#ep-logo-square"
|
||||||
|
>
|
||||||
|
</use>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
enviPath Ltd.
|
||||||
|
<br />
|
||||||
|
Biodegredation prediction since 2015.
|
||||||
|
</p>
|
||||||
|
</aside>
|
||||||
|
<aside class="text-sm text-base-200 mt-2"><span class="text-xs tracking-tight">Version</span> <span class="text-base font-bold">{{ meta.version }}</span></aside>
|
||||||
|
</div>
|
||||||
|
<nav class="md:place-self-center md:justify-self-end">
|
||||||
|
<div class="grid grid-flow-col gap-4">
|
||||||
|
<a href="https://www.youtube.com/@envipath7231" target="_blank">
|
||||||
|
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 fill-current">
|
||||||
|
<title>YouTube</title>
|
||||||
|
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="https://community.envipath.org/" target="_blank">
|
||||||
|
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 fill-current">
|
||||||
|
<title>Discourse</title>
|
||||||
|
<path d="M12.103 0C18.666 0 24 5.485 24 11.997c0 6.51-5.33 11.99-11.9 11.99L0 24V11.79C0 5.28 5.532 0 12.103 0zm.116 4.563c-2.593-.003-4.996 1.352-6.337 3.57-1.33 2.208-1.387 4.957-.148 7.22L4.4 19.61l4.794-1.074c2.745 1.225 5.965.676 8.136-1.39 2.17-2.054 2.86-5.228 1.737-7.997-1.135-2.778-3.84-4.59-6.84-4.585h-.008z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.linkedin.com/company/envipath/" target="_blank">
|
||||||
|
<img src="{% static "/images/linkedin.png" %}" alt="LinkedIn" class="w-6 h-6">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
147
templates/includes/navbar.html
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
{% load static %}
|
||||||
|
{# Modern DaisyUI Navbar #}
|
||||||
|
<div class="navbar bg-neutral-50 text-neutral-950 shadow-lg x-50">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<a href="{{ meta.server_url }}" class="btn btn-ghost normal-case text-xl">
|
||||||
|
<svg class="h-8 fill-base-content" viewBox="0 0 104 26" role="img">
|
||||||
|
<use href="{% static "/images/logo-name.svg" %}#ep-logo-name" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if not public_mode %}
|
||||||
|
<div class="navbar-center hidden lg:flex">
|
||||||
|
<a
|
||||||
|
href="{{ meta.server_url }}/predict"
|
||||||
|
role="button"
|
||||||
|
class="btn btn-ghost"
|
||||||
|
id="predictLink"
|
||||||
|
>Predict</a
|
||||||
|
>
|
||||||
|
<!-- <li><a href="{{ meta.server_url }}/package" id="packageLink">Package</a></li> -->
|
||||||
|
<!--<li><a href="{{ meta.server_url }}/browse" id="browseLink">Browse</a></li>-->
|
||||||
|
<div class="dropdown dropdown-center">
|
||||||
|
<div tabindex="0" role="button" class="btn btn-ghost">Browse</div>
|
||||||
|
<ul
|
||||||
|
tabindex="-1"
|
||||||
|
class="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/pathway" id="pathwayLink">Pathway</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="{{ meta.server_url }}/rule" id="ruleLink">Rule</a></li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/compound" id="compoundLink"
|
||||||
|
>Compound</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/reaction" id="reactionLink"
|
||||||
|
>Reaction</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/model" id="relative-reasoningLink"
|
||||||
|
>Model</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ meta.server_url }}/scenario" id="scenarioLink"
|
||||||
|
>Scenario</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="navbar-end">
|
||||||
|
{% if not public_mode %}
|
||||||
|
<a id="search-trigger" role="button" class="cursor-pointer">
|
||||||
|
<div
|
||||||
|
class="flex items-center badge badge-dash space-x-1 bg-base-200 text-base-content/50 p-2 m-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="lucide lucide-search-icon lucide-search"
|
||||||
|
>
|
||||||
|
<path d="m21 21-4.34-4.34" />
|
||||||
|
<circle cx="11" cy="11" r="8" />
|
||||||
|
</svg>
|
||||||
|
<span id="search-shortcut">⌘K</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if meta.user.username == 'anonymous' or public_mode %}
|
||||||
|
<a href="{% url 'login' %}" id="loginButton" class="p-2">Login</a>
|
||||||
|
{% else %}
|
||||||
|
<div class="dropdown dropdown-end">
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
role="button"
|
||||||
|
class="btn btn-ghost m-1 btn-circle"
|
||||||
|
id="loggedInButton"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="lucide lucide-circle-user-icon lucide-circle-user"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="10" />
|
||||||
|
<circle cx="12" cy="10" r="3" />
|
||||||
|
<path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
tabindex="-1"
|
||||||
|
class="dropdown-content menu bg-base-100 rounded-box z-50 w-52 p-2 shadow-sm"
|
||||||
|
>
|
||||||
|
<li><a href="{{ meta.user.url }}" id="accountbutton">Settings</a></li>
|
||||||
|
<li>
|
||||||
|
<form
|
||||||
|
id="logoutForm"
|
||||||
|
action="{% url 'logout' %}"
|
||||||
|
method="post"
|
||||||
|
style="display: none;"
|
||||||
|
>
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="logout" value="true" />
|
||||||
|
</form>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
id="logoutButton"
|
||||||
|
onclick="event.preventDefault(); document.getElementById('logoutForm').submit();"
|
||||||
|
>Logout</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// OS-aware search shortcut display
|
||||||
|
(function () {
|
||||||
|
const isMac = /Mac/.test(navigator.platform);
|
||||||
|
const shortcutElement = document.getElementById("search-shortcut");
|
||||||
|
if (shortcutElement) {
|
||||||
|
shortcutElement.textContent = isMac ? "⌘K" : "Ctrl+K";
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
@ -1,185 +1,439 @@
|
|||||||
{% extends "framework.html" %}
|
{% extends "framework_modern.html" %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% block content %}
|
{% block main_content %}
|
||||||
<!-- TODO rename ids as well as remove pathways if modal is closed!-->
|
<!-- Hero Section with Logo and Search -->
|
||||||
<div class="modal fade" tabindex="-1" id="foundMatching" role="dialog" aria-labelledby="foundModal"
|
<section class="hero h-fit max-w-5xl w-full shadow-none mx-auto relative">
|
||||||
aria-hidden="true">
|
<div
|
||||||
<div class="modal-dialog">
|
class="hero min-h-[calc(100vh*0.4)] bg-gradient-to-br from-primary-800 to-primary-600"
|
||||||
<div class="modal-content">
|
style="background-image: url('{% static "/images/hero.png" %}'); background-size: cover; background-position: center;"
|
||||||
<div class="modal-header">
|
>
|
||||||
<button type="button" class="close" data-dismiss="modal">
|
<div class="hero-overlay"></div>
|
||||||
<span aria-hidden="true">×</span>
|
<!-- Predict Pathway text over the image -->
|
||||||
<span class="sr-only">Close</span>
|
<div class="absolute bottom-40 left-1/8 -translate-x-8 z-10">
|
||||||
</button>
|
<h2 class="text-3xl text-base-100 text-shadow-lg text-left">
|
||||||
<h4 class="modal-title" id="newPackMod">Found Pathway in Database</h4>
|
Predict Your Pathway
|
||||||
</div>
|
</h2>
|
||||||
<div class="modal-body">
|
</div>
|
||||||
<p>We found at least one pathway in the database with the given root
|
|
||||||
compound. Do you want to open any of the existing pathways or
|
|
||||||
predict a new one? To open an existing pathway, simply click
|
|
||||||
on the pathway, to predict a new one, click Predict. The predicted
|
|
||||||
pathway might differ from the ones in the database due to the
|
|
||||||
settings used in the prediction.</p>
|
|
||||||
<div id="foundPathways"></div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a id="modal-predict" class="btn btn-primary" href="#">Predict</a>
|
|
||||||
<button type="button" id="cancel-predict" class="btn btn-default" data-dismiss="modal">Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
</section>
|
||||||
<div class="col-xs-8">
|
|
||||||
<div class="jumbotron">
|
<div class="shadow-md max-w-5xl mx-auto bg-base-200">
|
||||||
<h1>
|
<!-- Predict Pathway Section -->
|
||||||
<img id="image-logo-long" class="img-responsive" alt="enviPath" width="1000ex"
|
<div
|
||||||
src='{% static "/images/logo-long.svg" %}'/>
|
class="flex-col lg:flex-row-reverse w-full mx-auto -mt-32 relative z-20 mb-10 "
|
||||||
</h1>
|
>
|
||||||
<p>enviPath is a database and prediction system for the microbial
|
<div
|
||||||
biotransformation of organic environmental contaminants. The
|
class="card bg-base-100 shrink-0 shadow-xl w-3/4 mx-auto transition-all duration-300 ease-in-out"
|
||||||
database provides the possibility to store and view experimentally
|
>
|
||||||
observed biotransformation pathways. The pathway prediction system
|
<div class="card-body">
|
||||||
provides different relative reasoning models to predict likely biotransformation
|
<!-- Input Mode Toggle - Fixed position outside fieldset -->
|
||||||
pathways and products. You can try it out below.
|
<div class="flex flex-row justify-start items-center h-fit ml-8 my-4">
|
||||||
</p>
|
<div class="flex items-center gap-2">
|
||||||
<p>
|
<!-- <span class="text-sm text-neutral-500">Input Mode:</span> -->
|
||||||
<a class="btn" style="background-color:#222222;color:#9d9d9d" role="button" target="_blank"
|
<label class="toggle text-base-content toggle-md">
|
||||||
href="https://wiki.envipath.org/index.php/Main_Page">Learn more >></a>
|
<input type="checkbox" />
|
||||||
</p>
|
<svg
|
||||||
|
aria-label="smiles mode"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
class="size-5"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="currentColor"
|
||||||
|
stroke="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M8 2.75A.75.75 0 0 1 8.75 2h7.5a.75.75 0 0 1 0 1.5h-3.215l-4.483 13h2.698a.75.75 0 0 1 0 1.5h-7.5a.75.75 0 0 1 0-1.5h3.215l4.483-13H8.75A.75.75 0 0 1 8 2.75Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
aria-label="draw mode"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
stroke="none"
|
||||||
|
class="size-5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="m2.695 14.762-1.262 3.155a.5.5 0 0 0 .65.65l3.155-1.262a4 4 0 0 0 1.343-.886L17.5 5.501a2.121 2.121 0 0 0-3-3L3.58 13.419a4 4 0 0 0-.885 1.343Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset
|
||||||
|
class="fieldset transition-all duration-300 ease-in-out overflow-hidden"
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
id="index-form"
|
||||||
|
action="{{ meta.current_package.url }}/pathway"
|
||||||
|
method="POST"
|
||||||
|
>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div
|
||||||
|
id="text-input-container"
|
||||||
|
class="transition-all duration-300 ease-in-out opacity-100 transform scale-100"
|
||||||
|
>
|
||||||
|
<div class="join w-full mx-auto">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="index-form-text-input"
|
||||||
|
placeholder="canonical SMILES string"
|
||||||
|
class="input grow input-md join-item"
|
||||||
|
/>
|
||||||
|
<button class="btn btn-neutral join-item">Predict!</button>
|
||||||
|
</div>
|
||||||
|
<div class="label relative w-full mt-1">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="example-link cursor-pointer hover:text-primary"
|
||||||
|
data-smiles="CN1C=NC2=C1C(=O)N(C(=O)N2C)C"
|
||||||
|
title="load example"
|
||||||
|
>Caffeine</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="example-link cursor-pointer hover:text-primary"
|
||||||
|
data-smiles="CC(C)CC1=CC=C(C=C1)C(C)C(=O)O"
|
||||||
|
title="load example"
|
||||||
|
>Ibuprofen</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<a class="absolute top-0 left-[calc(100%-5.4rem)]" href="#"
|
||||||
|
>Advanced</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="ketcher-container"
|
||||||
|
class="hidden w-full transition-all duration-300 ease-in-out opacity-0 transform scale-95"
|
||||||
|
>
|
||||||
|
<iframe
|
||||||
|
id="index-ketcher"
|
||||||
|
src="{% static '/js/ketcher2/ketcher.html' %}"
|
||||||
|
width="100%"
|
||||||
|
height="400"
|
||||||
|
class="rounded-lg"
|
||||||
|
></iframe>
|
||||||
|
<button
|
||||||
|
class="btn btn-lg bg-primary-950 text-primary-50 join-item w-full mt-2"
|
||||||
|
>
|
||||||
|
Predict!
|
||||||
|
</button>
|
||||||
|
<a class="label mx-auto w-full mt-1" href="#">Advanced</a>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
id="index-form-smiles"
|
||||||
|
name="smiles"
|
||||||
|
value="smiles"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
id="index-form-predict"
|
||||||
|
name="predict"
|
||||||
|
value="predict"
|
||||||
|
/>
|
||||||
|
<input type="hidden" id="current-action" value="predict" />
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div id="loading"></div>
|
</div>
|
||||||
<div class="col-xs-4">
|
|
||||||
<d-topics-list discourse-url="https://community.envipath.org" per-page="10" category="10"
|
|
||||||
template="complete"></d-topics-list>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<form id="index-form" action="{{ meta.current_package.url }}/pathway" method="POST">
|
<!-- Community News Section -->
|
||||||
{% csrf_token %}
|
<section class="py-16 bg-base-200 z-10 mx-8">
|
||||||
<div class="input-group" id="index-form-bar">
|
<div class="max-w-7xl mx-auto px-4">
|
||||||
<div class="input-group-btn">
|
<h2 class="h2 font-bold text-left mb-8">Community Updates</h2>
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
|
|
||||||
aria-expanded="false">
|
<div id="community-news-container" class="flex gap-4 justify-center">
|
||||||
<span class="caret"></span>
|
<!-- News cards will be populated here -->
|
||||||
</button>
|
<div id="loading" class="flex justify-center w-full">
|
||||||
<ul class="dropdown-menu" role="menu">
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
<li>
|
</div>
|
||||||
<iframe id="index-form-ketcher" src="{% static '/js/ketcher2/ketcher.html' %}" width="100%"
|
</div>
|
||||||
height="510"></iframe>
|
|
||||||
</li>
|
<div class="text-right mt-6">
|
||||||
</ul>
|
<a
|
||||||
</div>
|
href="https://community.envipath.org/c/announcements/10"
|
||||||
<input type="text" class="form-control" id='index-form-text-input'
|
target="_blank"
|
||||||
placeholder="Enter a SMILES to predict a Pathway or type something to search">
|
class="btn btn-ghost btn-sm"
|
||||||
<div class="input-group-btn">
|
>
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
|
Read More Announcements
|
||||||
aria-haspopup="true"
|
</a>
|
||||||
aria-expanded="false" id="action-button">Predict <span class="caret"></span></button>
|
</div>
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a id="dropdown-predict">Predict</a></li>
|
<!-- Discourse API integration -->
|
||||||
<li><a id="dropdown-search">Search</a></li>
|
<script src="{% static 'js/discourse-api.js' %}"></script>
|
||||||
</ul>
|
</div>
|
||||||
<button class="btn" style="background-color:#222222;color:#9d9d9d" type="button" id="run-button">Go!
|
</section>
|
||||||
</button>
|
|
||||||
</div>
|
<!-- Mission Statement Section -->
|
||||||
|
<section class="py-16 from-base-200 to-base-100 bg-gradient-to-b">
|
||||||
|
<div class="mx-auto px-8 md:px-12">
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
<div class="w-1/3">
|
||||||
|
<img
|
||||||
|
src="{% static "/images/ep-rule-artwork.png" %}"
|
||||||
|
alt="rule-based iterative tree greneration"
|
||||||
|
class="w-full h-full object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4 text-left w-2/3 mr-8">
|
||||||
|
<h2 class="h2 font-bold mb-8">About enviPath</h2>
|
||||||
|
<p class="">
|
||||||
|
enviPath is a database and prediction system for the microbial
|
||||||
|
biotransformation of organic environmental contaminants. The
|
||||||
|
database provides the possibility to store and view experimentally
|
||||||
|
observed biotransformation pathways.
|
||||||
|
</p>
|
||||||
|
<p class="">
|
||||||
|
The pathway prediction system provides different relative
|
||||||
|
reasoning models to predict likely biotransformation pathways and
|
||||||
|
products. Explore our tools and contribute to advancing
|
||||||
|
environmental biotransformation research.
|
||||||
|
</p>
|
||||||
|
<div class="flex flex-row gap-4 float-right">
|
||||||
|
<a href="/about" class="btn btn-ghost-neutral">Read More</a>
|
||||||
|
<a href="/about" class="btn btn-neutral">Publications</a>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" id="index-form-smiles" name="smiles" value="smiles">
|
</div>
|
||||||
<input type="hidden" id="index-form-predict" name="predict" value="predict">
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
<p></p>
|
|
||||||
<script language="javascript">
|
|
||||||
var currentPackage = "{{ meta.current_package.url }}";
|
|
||||||
|
|
||||||
function goButtonClicked() {
|
<!-- Partners Section -->
|
||||||
$(this).prop("disabled", true);
|
<section class="py-14 sm:py-12 bg-base-100">
|
||||||
|
<div class="mx-auto px-6 lg:px-8">
|
||||||
|
<div class="divider">
|
||||||
|
<h2 class="text-center text-lg/8 font-semibold">Backed by Science</h2>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx-auto mt-10 grid max-w-lg grid-cols-4 items-center gap-x-8 gap-y-10 sm:max-w-xl sm:grid-cols-6 sm:gap-x-10 lg:mx-0 lg:max-w-none lg:grid-cols-3"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="{% static "/images/uoa-logo-small.png" %}"
|
||||||
|
alt="The University of Auckland"
|
||||||
|
class=" max-h-20 w-full object-contain lg:col-span-1"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="{% static "/images/logo-eawag.svg" %}"
|
||||||
|
alt="Eawag"
|
||||||
|
class=" max-h-12 w-full object-contain lg:col-span-1"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="{% static "/images/uzh-logo.svg" %}"
|
||||||
|
alt="University of Zurich"
|
||||||
|
class="2 max-h-16 w-full object-contain lg:col-span-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
var action = $('#action-button').text().trim();
|
<script language="javascript">
|
||||||
|
var currentPackage = "{{ meta.current_package.url }}";
|
||||||
|
|
||||||
var textSmiles = $('#index-form-text-input').val().trim();
|
// Discourse API integration is now handled by discourse-api.js
|
||||||
|
|
||||||
if (textSmiles === '') {
|
// Function to render Discourse topics into cards
|
||||||
return;
|
function renderDiscourseTopics(topics) {
|
||||||
}
|
const container = document.getElementById("community-news-container");
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
var ketcherSmiles = getKetcher('index-form-ketcher').getSmiles().trim();
|
// Clear container
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
if (action !== 'Search' && ketcherSmiles !== '' && textSmiles !== ketcherSmiles) {
|
// Create cards for each topic
|
||||||
console.log("Ketcher and TextInput differ!");
|
topics.forEach((topic) => {
|
||||||
}
|
const card = createDiscourseCard(topic);
|
||||||
|
container.insertAdjacentHTML("beforeend", card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (action === 'Search') {
|
// Function to create HTML card for a topic
|
||||||
var par = {};
|
function createDiscourseCard(topic) {
|
||||||
par['search'] = textSmiles;
|
const date = new Date(topic.created_at).toLocaleDateString();
|
||||||
par['mode'] = 'text';
|
|
||||||
var queryString = $.param(par, true);
|
return `
|
||||||
window.location.href = "/search?" + queryString;
|
<div class="card bg-white shadow-xs hover:shadow-lg transition-shadow duration-300 h-64 w-75 flex-shrink-0">
|
||||||
} else {
|
<div class="card-body flex flex-col h-full">
|
||||||
$('#index-form-smiles').val(textSmiles);
|
<h3 class="card-title leading-tight font-normal tracking-tight h-12 mb-2 line-clamp-2 text-ellipsis wrap-break-word overflow-hidden">
|
||||||
$('#index-form').submit();
|
<a href="${topic.url}" target="_blank" class="hover:text-primary">
|
||||||
}
|
${topic.title}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<div class="text-sm line-clamp-4 break-words" >
|
||||||
|
${topic.excerpt}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-row items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="avatar tooltip tooltip-right" data-tip="${topic.author}">
|
||||||
|
<div class="w-8 rounded-full">
|
||||||
|
<img src="${topic.author_avatar}" alt="${topic.author}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="text-xs text-gray-500">${date}</span>
|
||||||
|
</div>
|
||||||
|
<a href="${topic.url}" target="_blank" class="btn btn-ghost text-neutral-500 rounded-full p-2">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M12 7v14"/>
|
||||||
|
<path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make render function globally available
|
||||||
|
window.renderDiscourseTopics = renderDiscourseTopics;
|
||||||
|
|
||||||
|
// Toggle functionality with smooth animations
|
||||||
|
function toggleInputMode() {
|
||||||
|
const toggle = $('input[type="checkbox"]');
|
||||||
|
const textContainer = $("#text-input-container");
|
||||||
|
const ketcherContainer = $("#ketcher-container");
|
||||||
|
const formCard = $(".card");
|
||||||
|
const fieldset = $(".fieldset");
|
||||||
|
|
||||||
|
if (toggle.is(":checked")) {
|
||||||
|
// Draw mode - show Ketcher, hide text input
|
||||||
|
textContainer.addClass("opacity-0 transform scale-95");
|
||||||
|
textContainer.removeClass("opacity-100 transform scale-100");
|
||||||
|
|
||||||
|
// Adjust fieldset padding for Ketcher mode - reduce padding and make more compact
|
||||||
|
fieldset.removeClass("p-8");
|
||||||
|
fieldset.addClass("p-4");
|
||||||
|
|
||||||
|
// Wait for fade out to complete, then hide and show new content
|
||||||
|
setTimeout(() => {
|
||||||
|
textContainer.addClass("hidden");
|
||||||
|
ketcherContainer.removeClass("hidden opacity-0 transform scale-95");
|
||||||
|
ketcherContainer.addClass("opacity-100 transform scale-100");
|
||||||
|
|
||||||
|
// Force re-evaluation of iframe size
|
||||||
|
const iframe = document.getElementById("index-ketcher");
|
||||||
|
if (iframe) {
|
||||||
|
iframe.style.height = "400px";
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
// SMILES mode - show text input, hide Ketcher
|
||||||
|
ketcherContainer.addClass("opacity-0 transform scale-95");
|
||||||
|
ketcherContainer.removeClass("opacity-100 transform scale-100");
|
||||||
|
|
||||||
|
// Restore fieldset padding for text input mode
|
||||||
|
fieldset.removeClass("p-4");
|
||||||
|
fieldset.addClass("p-8");
|
||||||
|
|
||||||
|
// Wait for fade out to complete, then hide and show new content
|
||||||
|
setTimeout(() => {
|
||||||
|
ketcherContainer.addClass("hidden");
|
||||||
|
textContainer.removeClass("hidden opacity-0 transform scale-95");
|
||||||
|
textContainer.addClass("opacity-100 transform scale-100");
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
// Transfer SMILES from Ketcher to text input if available
|
||||||
|
if (window.indexKetcher && window.indexKetcher.getSmiles) {
|
||||||
|
const smiles = window.indexKetcher.getSmiles();
|
||||||
|
if (smiles && smiles.trim() !== "") {
|
||||||
|
$("#index-form-text-input").val(smiles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function actionDropdownClicked() {
|
// Ketcher integration
|
||||||
var suffix = ' <span class="caret"></span>';
|
function indexKetcherToTextInput() {
|
||||||
var dropdownVal = $(this).text();
|
$("#index-form-smiles").val(this.ketcher.getSmiles());
|
||||||
|
}
|
||||||
|
|
||||||
if (dropdownVal === 'Search') {
|
$(function () {
|
||||||
$("#index-form").attr("action", '/search');
|
// Initialize fieldset with proper padding
|
||||||
$("#index-form").attr("method", 'GET');
|
$(".fieldset").addClass("p-8");
|
||||||
} else {
|
|
||||||
$("#index-form").attr("action", currentPackage + "/pathway");
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#action-button').html(dropdownVal + suffix);
|
// Toggle event listener
|
||||||
}
|
$('input[type="checkbox"]').on("change", toggleInputMode);
|
||||||
|
|
||||||
function ketcherToTextInput() {
|
// Ketcher iframe load handler
|
||||||
$('#index-form-text-input').val(this.ketcher.getSmiles());
|
$("#index-ketcher").on("load", function () {
|
||||||
}
|
const checkKetcherReady = () => {
|
||||||
|
const win = this.contentWindow;
|
||||||
$(function () {
|
if (win.ketcher && "editor" in win.ketcher) {
|
||||||
|
window.indexKetcher = win.ketcher;
|
||||||
$('#index-form').on("keydown", function (e) {
|
win.ketcher.editor.event.change.handlers.push({
|
||||||
if (e.key === "Enter") {
|
once: false,
|
||||||
e.preventDefault();
|
priority: 0,
|
||||||
goButtonClicked();
|
f: indexKetcherToTextInput,
|
||||||
}
|
ketcher: win.ketcher,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
setTimeout(checkKetcherReady, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkKetcherReady();
|
||||||
|
});
|
||||||
|
|
||||||
// Code that should be executed once DOM is ready goes here
|
// Handle example link clicks
|
||||||
$('#dropdown-predict').on('click', actionDropdownClicked);
|
$(".example-link").on("click", function (e) {
|
||||||
$('#dropdown-search').on('click', actionDropdownClicked);
|
e.preventDefault();
|
||||||
|
const smiles = $(this).data("smiles");
|
||||||
|
const title = $(this).attr("title");
|
||||||
|
|
||||||
$('#run-button').on('click', goButtonClicked);
|
// Check if we're in Ketcher mode or text input mode
|
||||||
|
if ($('input[type="checkbox"]').is(":checked")) {
|
||||||
|
// In Ketcher mode - set the SMILES in Ketcher
|
||||||
|
if (window.indexKetcher && window.indexKetcher.setMolecule) {
|
||||||
|
window.indexKetcher.setMolecule(smiles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// In text input mode - set the SMILES in the text input
|
||||||
|
$("#index-form-text-input").val(smiles);
|
||||||
|
}
|
||||||
|
|
||||||
// Update Ketcher Width
|
// Show a brief feedback
|
||||||
var fullWidth = $('#index-form-bar').width();
|
const originalText = $(this).text();
|
||||||
$('#index-form-ketcher').width(fullWidth);
|
$(this).text(`loaded!`);
|
||||||
|
setTimeout(() => {
|
||||||
|
$(this).text(originalText);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
// add a listener that gets triggered whenever the structure in ketcher has changed
|
// Handle form submission on Enter
|
||||||
$('#index-form-ketcher').on('load', function () {
|
$("#index-form").on("submit", function (e) {
|
||||||
const checkKetcherReady = () => {
|
e.preventDefault();
|
||||||
win = this.contentWindow
|
|
||||||
if (win.ketcher && 'editor' in win.ketcher) {
|
|
||||||
win.ketcher.editor.event.change.handlers.push({
|
|
||||||
once: false,
|
|
||||||
priority: 0,
|
|
||||||
f: ketcherToTextInput,
|
|
||||||
ketcher: win.ketcher
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setTimeout(checkKetcherReady, 100);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
checkKetcherReady();
|
var textSmiles = "";
|
||||||
});
|
|
||||||
|
|
||||||
});
|
// Check if we're in Ketcher mode and extract SMILES
|
||||||
</script>
|
if ($('input[type="checkbox"]').is(":checked") && window.indexKetcher) {
|
||||||
{% endblock content %}
|
textSmiles = window.indexKetcher.getSmiles().trim();
|
||||||
|
} else {
|
||||||
|
textSmiles = $("#index-form-text-input").val().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textSmiles === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#index-form-smiles").val(textSmiles);
|
||||||
|
$("#index-form").attr("action", currentPackage + "/pathway");
|
||||||
|
$("#index-form").attr("method", "POST");
|
||||||
|
this.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Discourse topics are now loaded automatically by discourse-api.js
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock main_content %}
|
||||||
|
|||||||
@ -26,12 +26,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
|
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
|
||||||
href="#{{ obj.id }}">{{ obj.name }}</a>
|
href="#{{ obj.id }}">{{ obj.name|safe }}</a>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
||||||
<div class="panel-body list-group-item">
|
<div class="panel-body list-group-item">
|
||||||
<a class="list-group-item" href="{{ obj.detail_url }}">{{ obj.name }} Migration Detail Page</a>
|
<a class="list-group-item" href="{{ obj.detail_url }}">{{ obj.name|safe }} Migration Detail Page</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -1,50 +1,45 @@
|
|||||||
{% extends "framework.html" %}
|
{% extends "framework.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="panel-group" id="migration-detail">
|
<div class="panel-group" id="migration-detail">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||||
Migration Status for {{ bt_rule_name }}
|
Migration Status for {{ bt_rule_name }}
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<p>A package contains pathways, rules, etc. and can reflect specific experimental
|
|
||||||
conditions. <a target="_blank" href="https://wiki.envipath.org/index.php/packages" role="button">Learn
|
|
||||||
more >></a></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% for obj in results %}
|
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
|
||||||
{% if obj.status %}
|
|
||||||
<span class="glyphicon glyphicon-ok" aria-hidden="true"
|
|
||||||
style="float:right" data-toggle="tooltip"
|
|
||||||
data-placement="top" title="" data-original-title="Reviewed">
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"
|
|
||||||
style="float:right" data-toggle="tooltip"
|
|
||||||
data-placement="top" title="" data-original-title="Reviewed">
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
<h4 class="panel-title">
|
|
||||||
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
|
|
||||||
href="#{{ obj.id }}">{{ obj.name }}</a>
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
|
||||||
<div class="panel-body list-group-item">
|
|
||||||
{% if obj.status %}
|
|
||||||
<p>Products generated by AMBIT: {{ obj.ambit_smiles }}</p>
|
|
||||||
<p>Products generated by RDKit: {{ obj.rdkit_smiles }}</p>
|
|
||||||
{% else %}
|
|
||||||
<pre>{{ obj.detail }}</pre>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>A package contains pathways, rules, etc. and can reflect specific experimental
|
||||||
|
conditions. <a target="_blank" href="https://wiki.envipath.org/index.php/packages" role="button">Learn
|
||||||
|
more >></a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for obj in results %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
{% if obj.status %}
|
||||||
|
<span class="glyphicon glyphicon-ok" aria-hidden="true"
|
||||||
|
style="float:right" data-toggle="tooltip"
|
||||||
|
data-placement="top" title="" data-original-title="Reviewed">
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"
|
||||||
|
style="float:right" data-toggle="tooltip"
|
||||||
|
data-placement="top" title="" data-original-title="Reviewed">
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="{{ obj.id }}-link" data-toggle="collapse" data-parent="#migration-detail"
|
||||||
|
href="#{{ obj.id }}">{{ obj.name|safe }}</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
<pre>{{ obj.detail }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -15,12 +15,12 @@
|
|||||||
enctype="multipart/form-data">
|
enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<p>
|
<p>
|
||||||
<label class="btn btn-primary" for="jsonFile">
|
<label class="btn btn-primary" for="legacyJsonFile">
|
||||||
<input id="jsonFile" name="file" type="file" style="display:none;"
|
<input id="legacyJsonFile" name="file" type="file" style="display:none;"
|
||||||
onchange="$('#upload-file-info').html(this.files[0].name)">
|
onchange="$('#upload-legacy-file-info').html(this.files[0].name)">
|
||||||
Choose JSON File
|
Choose JSON File
|
||||||
</label>
|
</label>
|
||||||
<span class="label label-info" id="upload-file-info"></span>
|
<span class="label label-info" id="upload-legacy-file-info"></span>
|
||||||
<input type="hidden" value="import-legacy-package-json" name="hidden" readonly="">
|
<input type="hidden" value="import-legacy-package-json" name="hidden" readonly="">
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
<div class="modal fade" tabindex="-1" id="new_model_modal" role="dialog" aria-labelledby="new_model_modal"
|
<div class="modal fade" tabindex="-1" id="new_model_modal" role="dialog" aria-labelledby="new_model_modal"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
@ -18,113 +19,117 @@
|
|||||||
prediction. You just need to set a name and the packages
|
prediction. You just need to set a name and the packages
|
||||||
you want the object to be based on. There are multiple types of models available.
|
you want the object to be based on. There are multiple types of models available.
|
||||||
For additional information have a look at our
|
For additional information have a look at our
|
||||||
<a target="_blank" href="https://wiki.envipath.org/index.php/relative-reasoning" role="button">wiki >></a>
|
<a target="_blank" href="https://wiki.envipath.org/index.php/relative-reasoning" role="button">wiki
|
||||||
|
>></a>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Name -->
|
||||||
<label for="model-name">Name</label>
|
<label for="model-name">Name</label>
|
||||||
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
<label for="model-description">Description</label>
|
<label for="model-description">Description</label>
|
||||||
<input id="model-description" name="model-description" class="form-control"
|
<input id="model-description" name="model-description" class="form-control"
|
||||||
placeholder="Description"/>
|
placeholder="Description"/>
|
||||||
|
|
||||||
|
<!-- Model Type -->
|
||||||
<label for="model-type">Model Type</label>
|
<label for="model-type">Model Type</label>
|
||||||
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
||||||
<option disabled selected>Select Model Type</option>
|
<option disabled selected>Select Model Type</option>
|
||||||
{% for k, v in model_types.items %}
|
{% for k, v in model_types.items %}
|
||||||
<option value="{{ v }}">{{ k }}</option>
|
<option value="{{ v }}">{{ k }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<!-- ML and Rule Based Based Form-->
|
|
||||||
<div id="package-based-relative-reasoning-specific-form">
|
<!-- Rule Packages -->
|
||||||
<!-- Rule Packages -->
|
<div id="rule-packages" class="ep-model-param mlrr rbrr">
|
||||||
<label for="package-based-relative-reasoning-rule-packages">Rule Packages</label>
|
<label for="model-rule-packages">Rule Packages</label>
|
||||||
<select id="package-based-relative-reasoning-rule-packages" name="package-based-relative-reasoning-rule-packages"
|
<select id="model-rule-packages" name="model-rule-packages" data-actions-box='true'
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
class="form-control" multiple data-width='100%'>
|
||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if obj.reviewed %}
|
{% if obj.reviewed %}
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<option disabled>Unreviewed Packages</option>
|
<option disabled>Unreviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if not obj.reviewed %}
|
{% if not obj.reviewed %}
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<!-- Data Packages -->
|
|
||||||
<label for="package-based-relative-reasoning-data-packages" >Data Packages</label>
|
|
||||||
<select id="package-based-relative-reasoning-data-packages" name="package-based-relative-reasoning-data-packages"
|
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
|
||||||
<option disabled>Reviewed Packages</option>
|
|
||||||
{% for obj in meta.readable_packages %}
|
|
||||||
{% if obj.reviewed %}
|
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<option disabled>Unreviewed Packages</option>
|
|
||||||
{% for obj in meta.readable_packages %}
|
|
||||||
{% if not obj.reviewed %}
|
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div id="ml-relative-reasoning-specific-form">
|
|
||||||
<!-- Fingerprinter -->
|
|
||||||
<label for="ml-relative-reasoning-fingerprinter">Fingerprinter</label>
|
|
||||||
<select id="ml-relative-reasoning-fingerprinter" name="ml-relative-reasoning-fingerprinter"
|
|
||||||
class="form-control">
|
|
||||||
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
|
||||||
</select>
|
|
||||||
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
|
||||||
<!-- Property Plugins go here -->
|
|
||||||
<label for="ml-relative-reasoning-additional-fingerprinter">Additional Fingerprinter /
|
|
||||||
Descriptors</label>
|
|
||||||
<select id="ml-relative-reasoning-additional-fingerprinter"
|
|
||||||
name="ml-relative-reasoning-additional-fingerprinter" class="form-control">
|
|
||||||
<option disabled selected>Select Additional Fingerprinter / Descriptor</option>
|
|
||||||
{% for k, v in additional_descriptors.items %}
|
|
||||||
<option value="{{ v }}">{{ k }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<label for="ml-relative-reasoning-threshold">Threshold</label>
|
|
||||||
<input type="number" min="0" max="1" step="0.05" value="0.5"
|
|
||||||
id="ml-relative-reasoning-threshold"
|
|
||||||
name="ml-relative-reasoning-threshold" class="form-control">
|
|
||||||
</div>
|
|
||||||
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
|
||||||
<!-- Build AD? -->
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="build-app-domain" name="build-app-domain">Also build an
|
|
||||||
Applicability Domain?
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="ad-params" style="display:none">
|
|
||||||
<!-- Num Neighbors -->
|
|
||||||
<label for="num-neighbors">Number of Neighbors</label>
|
|
||||||
<input id="num-neighbors" name="num-neighbors" type="number" class="form-control" value="5"
|
|
||||||
step="1" min="0" max="10">
|
|
||||||
<!-- Local Compatibility -->
|
|
||||||
<label for="local-compatibility-threshold">Local Compatibility Threshold</label>
|
|
||||||
<input id="local-compatibility-threshold" name="local-compatibility-threshold" type="number"
|
|
||||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
|
||||||
<!-- Reliability -->
|
|
||||||
<label for="reliability-threshold">Reliability Threshold</label>
|
|
||||||
<input id="reliability-threshold" name="reliability-threshold" type="number"
|
|
||||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<!-- EnviFormer-->
|
|
||||||
<div id="enviformer-specific-form">
|
<!-- Data Packages -->
|
||||||
<label for="enviformer-threshold">Threshold</label>
|
<div id="data-packages" class="ep-model-param mlrr rbrr enviformer">
|
||||||
<input type="number" min="0" max="1" step="0.05" value="0.5" id="enviformer-threshold"
|
<label for="model-data-packages">Data Packages</label>
|
||||||
name="enviformer-threshold" class="form-control">
|
<select id="model-data-packages" name="model-data-packages" data-actions-box='true'
|
||||||
|
class="form-control" multiple data-width='100%'>
|
||||||
|
<option disabled>Reviewed Packages</option>
|
||||||
|
{% for obj in meta.readable_packages %}
|
||||||
|
{% if obj.reviewed %}
|
||||||
|
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<option disabled>Unreviewed Packages</option>
|
||||||
|
{% for obj in meta.readable_packages %}
|
||||||
|
{% if not obj.reviewed %}
|
||||||
|
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fingerprinter -->
|
||||||
|
<div id="fingerprinter" class="ep-model-param mlrr">
|
||||||
|
<label for="model-fingerprinter">Fingerprinter</label>
|
||||||
|
<select id="model-fingerprinter" name="model-fingerprinter" data-actions-box='true'
|
||||||
|
class="form-control" multiple data-width='100%'>
|
||||||
|
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
||||||
|
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
||||||
|
<option disabled selected>Select Additional Fingerprinter / Descriptor</option>
|
||||||
|
{% for k, v in additional_descriptors.items %}
|
||||||
|
<option value="{{ v }}">{{ k }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Threshold -->
|
||||||
|
<div id="threshold" class="ep-model-param mlrr enviformer">
|
||||||
|
<label for="model-threshold">Threshold</label>
|
||||||
|
<input type="number" min="0" max="1" step="0.05" value="0.5" id="model-threshold"
|
||||||
|
name="model-threshold" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="appdomain" class="ep-model-param mlrr">
|
||||||
|
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
||||||
|
<!-- Build AD? -->
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="build-app-domain" name="build-app-domain">Also build an
|
||||||
|
Applicability Domain?
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="ad-params" style="display:none">
|
||||||
|
<!-- Num Neighbors -->
|
||||||
|
<label for="num-neighbors">Number of Neighbors</label>
|
||||||
|
<input id="num-neighbors" name="num-neighbors" type="number" class="form-control"
|
||||||
|
value="5"
|
||||||
|
step="1" min="0" max="10">
|
||||||
|
<!-- Local Compatibility -->
|
||||||
|
<label for="local-compatibility-threshold">Local Compatibility Threshold</label>
|
||||||
|
<input id="local-compatibility-threshold" name="local-compatibility-threshold"
|
||||||
|
type="number"
|
||||||
|
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||||
|
<!-- Reliability -->
|
||||||
|
<label for="reliability-threshold">Reliability Threshold</label>
|
||||||
|
<input id="reliability-threshold" name="reliability-threshold" type="number"
|
||||||
|
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -137,53 +142,47 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function () {
|
||||||
// Initially hide all "specific" forms
|
// Built in Model Types
|
||||||
$("div[id$='-specific-form']").each( function() {
|
var nativeModelTypes = [
|
||||||
$(this).hide();
|
"mlrr",
|
||||||
});
|
"rbrr",
|
||||||
|
"enviformer",
|
||||||
|
]
|
||||||
|
|
||||||
$('#model-type').selectpicker();
|
// Initially hide all "specific" forms
|
||||||
$("#ml-relative-reasoning-fingerprinter").selectpicker();
|
$(".ep-model-param").each(function () {
|
||||||
$("#package-based-relative-reasoning-rule-packages").selectpicker();
|
|
||||||
$("#package-based-relative-reasoning-data-packages").selectpicker();
|
|
||||||
$("#package-based-relative-reasoning-evaluation-packages").selectpicker();
|
|
||||||
if ($('#ml-relative-reasoning-additional-fingerprinter').length > 0) {
|
|
||||||
$("#ml-relative-reasoning-additional-fingerprinter").selectpicker();
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#build-app-domain").change(function () {
|
|
||||||
if ($(this).is(":checked")) {
|
|
||||||
$('#ad-params').show();
|
|
||||||
} else {
|
|
||||||
$('#ad-params').hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// On change hide all and show only selected
|
|
||||||
$("#model-type").change(function() {
|
|
||||||
$("div[id$='-specific-form']").each( function() {
|
|
||||||
$(this).hide();
|
$(this).hide();
|
||||||
});
|
});
|
||||||
val = $('option:selected', this).val();
|
|
||||||
|
|
||||||
if (val === 'ml-relative-reasoning' || val === 'rule-based-relative-reasoning') {
|
$('#model-type').selectpicker();
|
||||||
$("#package-based-relative-reasoning-specific-form").show();
|
$("#model-fingerprinter").selectpicker();
|
||||||
if (val === 'ml-relative-reasoning') {
|
$("#model-rule-packages").selectpicker();
|
||||||
$("#ml-relative-reasoning-specific-form").show();
|
$("#model-data-packages").selectpicker();
|
||||||
|
|
||||||
|
$("#build-app-domain").change(function () {
|
||||||
|
if ($(this).is(":checked")) {
|
||||||
|
$('#ad-params').show();
|
||||||
|
} else {
|
||||||
|
$('#ad-params').hide();
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
$("#" + val + "-specific-form").show();
|
|
||||||
}
|
// On change hide all and show only selected
|
||||||
|
$("#model-type").change(function () {
|
||||||
|
$('.ep-model-param').hide();
|
||||||
|
var modelType = $('#model-type').val();
|
||||||
|
if (nativeModelTypes.indexOf(modelType) !== -1) {
|
||||||
|
$('.' + modelType).show();
|
||||||
|
} else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#new_model_modal_form_submit').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#new_model_form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#new_model_modal_form_submit').on('click', function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$('#new_model_form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<div class="modal fade" tabindex="-1" id="new_pathway_modal" role="dialog" aria-labelledby="new_pathway_modal"
|
<div class="modal fade" tabindex="-1" id="new_pathway_modal" role="dialog" aria-labelledby="new_pathway_modal"
|
||||||
aria-hidden="true" style="overflow-y: auto;">
|
aria-hidden="true" style="overflow-y: auto;">
|
||||||
@ -111,7 +112,7 @@
|
|||||||
|
|
||||||
<select id="settingSelect" name="settingSelect" class="form-control">
|
<select id="settingSelect" name="settingSelect" class="form-control">
|
||||||
{% for setting in available_settings %}
|
{% for setting in available_settings %}
|
||||||
<option value="{{ setting.id }}">{{ setting.name }}</option>
|
<option value="{{ setting.id }}">{{ setting.name|safe }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<p></p>
|
<p></p>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<div id="new_prediction_setting_modal" class="modal" tabindex="-1">
|
<div id="new_prediction_setting_modal" class="modal" tabindex="-1">
|
||||||
@ -40,14 +41,14 @@
|
|||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if obj.reviewed %}
|
{% if obj.reviewed %}
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<option disabled>Unreviewed Packages</option>
|
<option disabled>Unreviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if not obj.reviewed %}
|
{% if not obj.reviewed %}
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
@ -57,7 +58,7 @@
|
|||||||
<select id="model-based-prediction-setting-model" name="model-based-prediction-setting-model" class="form-control" data-width='100%'>
|
<select id="model-based-prediction-setting-model" name="model-based-prediction-setting-model" class="form-control" data-width='100%'>
|
||||||
<option disabled selected>Select the model</option>
|
<option disabled selected>Select the model</option>
|
||||||
{% for m in models %}
|
{% for m in models %}
|
||||||
<option value="{{ m.url }}">{{ m.name }}</option>
|
<option value="{{ m.url }}">{{ m.name|safe }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<label for="model-based-prediction-setting-threshold">Threshold</label>
|
<label for="model-based-prediction-setting-threshold">Threshold</label>
|
||||||
|
|||||||
@ -29,11 +29,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
<input type="number" id="dateYear" name="scenario-date-year" class="form-control"
|
<input type="number" id="dateYear" name="scenario-date-year" class="form-control"
|
||||||
placeholder="YYYY">
|
placeholder="YYYY" max="{% now "Y" %}">
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<input type="number" id="dateMonth" name="scenario-date-month" min="1" max="12"
|
<input type="number" id="dateMonth" name="scenario-date-month" min="1" max="12"
|
||||||
class="form-control" placeholder="MM" align="">
|
class="form-control" placeholder="MM" >
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<input type="number" id="dateDay" name="scenario-date-day" min="1" max="31" class="form-control"
|
<input type="number" id="dateDay" name="scenario-date-day" min="1" max="31" class="form-control"
|
||||||
@ -88,8 +88,15 @@
|
|||||||
$('#new_scenario_form').submit();
|
$('#new_scenario_form').submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
var dateYear = document.getElementById("dateYear");
|
||||||
|
dateYear.addEventListener("change", () => {
|
||||||
|
console.log("Final value after editing:", dateYear.value);
|
||||||
|
if (dateYear.value.length < 4) {
|
||||||
|
dateYear.value = {% now "Y" %};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<div class="modal fade bs-modal-lg" id="add_pathway_edge_modal" tabindex="-1" aria-labelledby="add_pathway_edge_modal"
|
<div class="modal fade bs-modal-lg" id="add_pathway_edge_modal" tabindex="-1" aria-labelledby="add_pathway_edge_modal"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
@ -36,7 +37,7 @@
|
|||||||
<select id="add_pathway_edge_substrates" name="edge-substrates"
|
<select id="add_pathway_edge_substrates" name="edge-substrates"
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||||
{% for n in pathway.nodes %}
|
{% for n in pathway.nodes %}
|
||||||
<option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name }}</option>
|
<option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name|safe }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -47,7 +48,7 @@
|
|||||||
<select id="add_pathway_edge_products" name="edge-products"
|
<select id="add_pathway_edge_products" name="edge-products"
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||||
{% for n in pathway.nodes %}
|
{% for n in pathway.nodes %}
|
||||||
<option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name }}</option>
|
<option data-smiles="{{ n.default_node_label.smiles }}" value="{{ n.url }}">{{ n.default_node_label.name|safe }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<!-- Delete Edge -->
|
<!-- Delete Edge -->
|
||||||
<div id="delete_pathway_edge_modal" class="modal" tabindex="-1">
|
<div id="delete_pathway_edge_modal" class="modal" tabindex="-1">
|
||||||
@ -19,7 +20,7 @@
|
|||||||
data-actions-box='true' class="form-control" data-width='100%'>
|
data-actions-box='true' class="form-control" data-width='100%'>
|
||||||
<option value="" disabled selected>Select Reaction to delete</option>
|
<option value="" disabled selected>Select Reaction to delete</option>
|
||||||
{% for e in pathway.edges %}
|
{% for e in pathway.edges %}
|
||||||
<option value="{{ e.url }}">{{ e.edge_label.name }}</option>
|
<option value="{{ e.url }}">{{ e.edge_label.name|safe }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
||||||
|
|||||||