forked from enviPath/enviPy
Compare commits
44
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35c342a3e3 | ||
|
|
db9036ce72 | ||
|
|
1cccefa991 | ||
|
|
01a20e438d | ||
|
|
654707e6b5 | ||
|
|
c88b0ff3e7 | ||
|
|
4246460f91 | ||
|
|
e26d5a21e3 | ||
|
|
44b646e58a | ||
|
|
2194b097ae | ||
|
|
4524b8fdf3 | ||
|
|
98d62e1d1f | ||
|
|
13ed86a780 | ||
|
|
f1b4c5aadb | ||
|
|
37e0e18a28 | ||
|
|
de44c22606 | ||
|
|
a952c08469 | ||
|
|
551cfc7768 | ||
|
|
c663eaf7bd | ||
|
|
ec0fc8cdc1 | ||
|
|
8fda2577ee | ||
|
|
819a94aced | ||
|
|
61346c4097 | ||
|
|
43bce8a4e1 | ||
|
|
376fd65785 | ||
|
|
d5ebb23622 | ||
|
|
93dd811e39 | ||
|
|
9a4735246f | ||
|
|
1f863fdcd6 | ||
|
|
1effaeb342 | ||
|
|
386098b8a6 | ||
|
|
ef697ac5f5 | ||
|
|
8d955d685c | ||
|
|
17744294cc | ||
|
|
68a3f3b982 | ||
|
|
afeb56622c | ||
|
|
22f0bbe10b | ||
|
|
36879c266b | ||
|
|
c2c46fbfa7 | ||
|
|
d2f4fdc58a | ||
|
|
3f2b046bd6 | ||
|
|
7ad4112343 | ||
|
|
3f5bb76633 | ||
|
|
b757a07f91 |
@@ -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
|
||||
EMAIL_HOST_USER=
|
||||
EMAIL_HOST_PASSWORD=
|
||||
|
||||
# MATOMO
|
||||
MATOMO_SITE_ID
|
||||
@@ -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
|
||||
+5
-1
@@ -5,4 +5,8 @@ static/admin/
|
||||
static/django_extensions/
|
||||
.env
|
||||
debug.log
|
||||
scratches/
|
||||
scratches/
|
||||
|
||||
data/
|
||||
|
||||
.DS_Store
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# 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
|
||||
|
||||
- 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: django-check
|
||||
# name: Run Django Check
|
||||
# entry: uv run python manage.py check
|
||||
# language: system
|
||||
# pass_filenames: false
|
||||
# types: [python]
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.10
|
||||
3.12
|
||||
|
||||
@@ -1,2 +1,91 @@
|
||||
# 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) - A fast Python package installer and resolver.
|
||||
- **Docker and Docker Compose** - Required for running the PostgreSQL database.
|
||||
- Git
|
||||
|
||||
> **Note:** This application requires PostgreSQL, which uses `ArrayField`. Docker is the recommended 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:** If you have a different version of rdkit installed globally, the dependency installation may fail. If this happens, please uninstall the global version and run `uv sync` again.
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
The application will be available at `http://localhost:8000`.
|
||||
|
||||
#### 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 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
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
__all__ = ("celery_app",)
|
||||
|
||||
@@ -4,8 +4,6 @@ from ninja import NinjaAPI
|
||||
|
||||
api = NinjaAPI()
|
||||
|
||||
from ninja import NinjaAPI
|
||||
|
||||
api_v1 = NinjaAPI(title="API V1 Docs", urls_namespace="api-v1")
|
||||
api_legacy = NinjaAPI(title="Legacy API Docs", urls_namespace="api-legacy")
|
||||
|
||||
|
||||
+1
-1
@@ -11,6 +11,6 @@ import os
|
||||
|
||||
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()
|
||||
|
||||
+3
-3
@@ -4,15 +4,15 @@ from celery import Celery
|
||||
from celery.signals import setup_logging
|
||||
|
||||
# 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
|
||||
# the configuration object to child processes.
|
||||
# - namespace='CELERY' means all celery-related configuration keys
|
||||
# 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
|
||||
|
||||
+140
-144
@@ -9,6 +9,7 @@ https://docs.djangoproject.com/en/4.2/topics/settings/
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
@@ -20,34 +21,35 @@ from sklearn.tree import DecisionTreeClassifier
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
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
|
||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||
|
||||
# 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!
|
||||
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
|
||||
ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split(',')
|
||||
DEBUG = os.environ.get("DEBUG", "False") == "True"
|
||||
|
||||
ALLOWED_HOSTS = os.environ["ALLOWED_HOSTS"].split(",")
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
# 3rd party
|
||||
'django_extensions',
|
||||
'oauth2_provider',
|
||||
"django_extensions",
|
||||
"oauth2_provider",
|
||||
# Custom
|
||||
'epdb',
|
||||
'migration',
|
||||
'epauth',
|
||||
"epdb",
|
||||
"migration",
|
||||
]
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
@@ -55,42 +57,44 @@ AUTHENTICATION_BACKENDS = [
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'oauth2_provider.middleware.OAuth2TokenMiddleware',
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"oauth2_provider.middleware.OAuth2TokenMiddleware",
|
||||
]
|
||||
|
||||
OAUTH2_PROVIDER = {
|
||||
"PKCE_REQUIRED": False, # Accept PKCE requests but dont require them
|
||||
}
|
||||
|
||||
if os.environ.get('REGISTRATION_MANDATORY', False) == 'True':
|
||||
MIDDLEWARE.append('epdb.middleware.login_required_middleware.LoginRequiredMiddleware')
|
||||
if os.environ.get("REGISTRATION_MANDATORY", False) == "True":
|
||||
MIDDLEWARE.append("epdb.middleware.login_required_middleware.LoginRequiredMiddleware")
|
||||
|
||||
ROOT_URLCONF = 'envipath.urls'
|
||||
ROOT_URLCONF = "envipath.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': (os.path.join(BASE_DIR, 'templates'),),
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": (os.path.join(BASE_DIR, "templates"),),
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'envipath.wsgi.application'
|
||||
ALLOWED_HTML_TAGS = {'b', 'i', 'u', 'br', 'em', 'mark', 'p', 's', 'strong'}
|
||||
|
||||
WSGI_APPLICATION = "envipath.wsgi.application"
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||
@@ -98,11 +102,11 @@ WSGI_APPLICATION = 'envipath.wsgi.application'
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql",
|
||||
"USER": os.environ['POSTGRES_USER'],
|
||||
"NAME": os.environ['POSTGRES_DB'],
|
||||
"PASSWORD": os.environ['POSTGRES_PASSWORD'],
|
||||
"HOST": os.environ['POSTGRES_SERVICE_NAME'],
|
||||
"PORT": os.environ['POSTGRES_PORT']
|
||||
"USER": os.environ["POSTGRES_USER"],
|
||||
"NAME": os.environ["POSTGRES_DB"],
|
||||
"PASSWORD": os.environ["POSTGRES_PASSWORD"],
|
||||
"HOST": os.environ["POSTGRES_SERVICE_NAME"],
|
||||
"PORT": os.environ["POSTGRES_PORT"],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,96 +114,87 @@ DATABASES = {
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'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.UserAttributeSimilarityValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
|
||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
# 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_TZ = True
|
||||
|
||||
|
||||
|
||||
# Default primary key field type
|
||||
# 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:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
else:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
EMAIL_USE_TLS = True
|
||||
EMAIL_HOST = 'mail.gandi.net'
|
||||
EMAIL_HOST_USER = os.environ['EMAIL_HOST_USER']
|
||||
EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD']
|
||||
EMAIL_HOST = "mail.gandi.net"
|
||||
EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"]
|
||||
EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"]
|
||||
EMAIL_PORT = 587
|
||||
DEFAULT_FROM_EMAIL = os.environ["DEFAULT_FROM_EMAIL"]
|
||||
SERVER_EMAIL = os.environ["SERVER_EMAIL"]
|
||||
|
||||
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_MAX_AGE = 300
|
||||
# # TODO set to "home"
|
||||
# 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]
|
||||
|
||||
AMBIT_URL = 'http://localhost:9001'
|
||||
DEFAULT_VALUES = {
|
||||
'description': 'no description'
|
||||
}
|
||||
AMBIT_URL = "http://localhost:9001"
|
||||
DEFAULT_VALUES = {"description": "no description"}
|
||||
|
||||
EP_DATA_DIR = os.environ['EP_DATA_DIR']
|
||||
MODEL_DIR = os.path.join(EP_DATA_DIR, 'models')
|
||||
EP_DATA_DIR = os.environ["EP_DATA_DIR"]
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
os.mkdir(PLUGIN_DIR)
|
||||
|
||||
# Set this as our static root dir
|
||||
STATIC_ROOT = STATIC_DIR
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
# Where the sources are stored...
|
||||
STATICFILES_DIRS = (
|
||||
BASE_DIR / 'static',
|
||||
)
|
||||
STATICFILES_DIRS = (BASE_DIR / "static",)
|
||||
|
||||
FIXTURE_DIRS = (
|
||||
BASE_DIR / 'fixtures',
|
||||
)
|
||||
FIXTURE_DIRS = (BASE_DIR / "fixtures",)
|
||||
|
||||
# Logging
|
||||
LOGGING = {
|
||||
@@ -207,8 +202,8 @@ LOGGING = {
|
||||
"disable_existing_loggers": True,
|
||||
"formatters": {
|
||||
"simple": {
|
||||
'format': '[%(asctime)s] %(levelname)s %(module)s - %(message)s',
|
||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
||||
"format": "[%(asctime)s] %(levelname)s %(module)s - %(message)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
@@ -221,7 +216,7 @@ LOGGING = {
|
||||
"level": "DEBUG", # Or higher
|
||||
"class": "logging.FileHandler",
|
||||
"filename": os.path.join(LOG_DIR, "debug.log"),
|
||||
"formatter": "simple"
|
||||
"formatter": "simple",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
@@ -229,72 +224,66 @@ LOGGING = {
|
||||
"epdb": {
|
||||
"handlers": ["file"], # "console",
|
||||
"propagate": True,
|
||||
"level": os.environ.get('LOG_LEVEL', 'INFO')
|
||||
"level": os.environ.get("LOG_LEVEL", "INFO"),
|
||||
},
|
||||
# For everything under envipath/ loaded via getlogger(__name__)
|
||||
'envipath': {
|
||||
'handlers': ['file', 'console'],
|
||||
'propagate': True,
|
||||
'level': os.environ.get('LOG_LEVEL', 'INFO')
|
||||
"envipath": {
|
||||
"handlers": ["file", "console"],
|
||||
"propagate": True,
|
||||
"level": os.environ.get("LOG_LEVEL", "INFO"),
|
||||
},
|
||||
# For everything under utilities/ loaded via getlogger(__name__)
|
||||
'utilities': {
|
||||
'handlers': ['file', 'console'],
|
||||
'propagate': True,
|
||||
'level': os.environ.get('LOG_LEVEL', 'INFO')
|
||||
"utilities": {
|
||||
"handlers": ["file", "console"],
|
||||
"propagate": True,
|
||||
"level": os.environ.get("LOG_LEVEL", "INFO"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Flags
|
||||
ENVIFORMER_PRESENT = os.environ.get('ENVIFORMER_PRESENT', 'False') == 'True'
|
||||
if ENVIFORMER_PRESENT:
|
||||
print("Loading enviFormer")
|
||||
device = os.environ.get('ENVIFORMER_DEVICE', 'cpu')
|
||||
from enviformer import load
|
||||
ENVIFORMER_INSTANCE = load(device=device)
|
||||
print("loaded")
|
||||
|
||||
ENVIFORMER_PRESENT = os.environ.get("ENVIFORMER_PRESENT", "False") == "True"
|
||||
ENVIFORMER_DEVICE = os.environ.get("ENVIFORMER_DEVICE", "cpu")
|
||||
|
||||
# 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:
|
||||
CELERY_TASK_ALWAYS_EAGER = True
|
||||
|
||||
# Celery Configuration Options
|
||||
CELERY_TIMEZONE = "Europe/Berlin"
|
||||
# Celery Configuration
|
||||
CELERY_BROKER_URL = 'redis://localhost:6379/0' # Use Redis as message broker
|
||||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
|
||||
CELERY_ACCEPT_CONTENT = ['json']
|
||||
CELERY_TASK_SERIALIZER = 'json'
|
||||
CELERY_BROKER_URL = "redis://localhost:6379/0" # Use Redis as message broker
|
||||
CELERY_RESULT_BACKEND = "redis://localhost:6379/1"
|
||||
CELERY_ACCEPT_CONTENT = ["json"]
|
||||
CELERY_TASK_SERIALIZER = "json"
|
||||
|
||||
MODEL_BUILDING_ENABLED = os.environ.get('MODEL_BUILDING_ENABLED', 'False') == 'True'
|
||||
APPLICABILITY_DOMAIN_ENABLED = os.environ.get('APPLICABILITY_DOMAIN_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"
|
||||
DEFAULT_RF_MODEL_PARAMS = {
|
||||
'base_clf': RandomForestClassifier(
|
||||
"base_clf": RandomForestClassifier(
|
||||
n_estimators=100,
|
||||
max_features='log2',
|
||||
max_features="log2",
|
||||
random_state=42,
|
||||
criterion='entropy',
|
||||
criterion="entropy",
|
||||
ccp_alpha=0.0,
|
||||
max_depth=3,
|
||||
min_samples_leaf=1
|
||||
min_samples_leaf=1,
|
||||
),
|
||||
'num_chains': 10,
|
||||
"num_chains": 10,
|
||||
}
|
||||
|
||||
DEFAULT_MODEL_PARAMS = {
|
||||
'base_clf': DecisionTreeClassifier(
|
||||
criterion='entropy',
|
||||
"base_clf": DecisionTreeClassifier(
|
||||
criterion="entropy",
|
||||
max_depth=3,
|
||||
min_samples_split=5,
|
||||
# min_samples_leaf=5,
|
||||
max_features='sqrt',
|
||||
max_features="sqrt",
|
||||
# class_weight='balanced',
|
||||
random_state=42
|
||||
random_state=42,
|
||||
),
|
||||
'num_chains': 10,
|
||||
"num_chains": 10,
|
||||
}
|
||||
|
||||
DEFAULT_MAX_NUMBER_OF_NODES = 30
|
||||
@@ -302,9 +291,10 @@ DEFAULT_MAX_DEPTH = 5
|
||||
DEFAULT_MODEL_THRESHOLD = 0.25
|
||||
|
||||
# Loading Plugins
|
||||
PLUGINS_ENABLED = os.environ.get('PLUGINS_ENABLED', 'False') == 'True'
|
||||
PLUGINS_ENABLED = os.environ.get("PLUGINS_ENABLED", "False") == "True"
|
||||
if PLUGINS_ENABLED:
|
||||
from utilities.plugin import discover_plugins
|
||||
|
||||
CLASSIFIER_PLUGINS = discover_plugins(_cls=Classifier)
|
||||
PROPERTY_PLUGINS = discover_plugins(_cls=Property)
|
||||
DESCRIPTOR_PLUGINS = discover_plugins(_cls=Descriptor)
|
||||
@@ -313,56 +303,62 @@ else:
|
||||
PROPERTY_PLUGINS = {}
|
||||
DESCRIPTOR_PLUGINS = {}
|
||||
|
||||
SENTRY_ENABLED = os.environ.get('SENTRY_ENABLED', 'False') == 'True'
|
||||
SENTRY_ENABLED = os.environ.get("SENTRY_ENABLED", "False") == "True"
|
||||
if SENTRY_ENABLED:
|
||||
import sentry_sdk
|
||||
|
||||
def before_send(event, hint):
|
||||
# Check if was a handled exception by one of our loggers
|
||||
if event.get('logger'):
|
||||
for log_path in LOGGING.get('loggers').keys():
|
||||
if event['logger'].startswith(log_path):
|
||||
if event.get("logger"):
|
||||
for log_path in LOGGING.get("loggers").keys():
|
||||
if event["logger"].startswith(log_path):
|
||||
return None
|
||||
|
||||
return event
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn=os.environ.get('SENTRY_DSN'),
|
||||
dsn=os.environ.get("SENTRY_DSN"),
|
||||
# Add data like request headers and IP for users,
|
||||
# see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
|
||||
send_default_pii=True,
|
||||
environment=os.environ.get('SENTRY_ENVIRONMENT', 'development'),
|
||||
environment=os.environ.get("SENTRY_ENVIRONMENT", "development"),
|
||||
before_send=before_send,
|
||||
)
|
||||
|
||||
# compile into digestible flags
|
||||
FLAGS = {
|
||||
'MODEL_BUILDING': MODEL_BUILDING_ENABLED,
|
||||
'CELERY': FLAG_CELERY_PRESENT,
|
||||
'PLUGINS': PLUGINS_ENABLED,
|
||||
'SENTRY': SENTRY_ENABLED,
|
||||
'ENVIFORMER': ENVIFORMER_PRESENT,
|
||||
'APPLICABILITY_DOMAIN': APPLICABILITY_DOMAIN_ENABLED,
|
||||
"MODEL_BUILDING": MODEL_BUILDING_ENABLED,
|
||||
"CELERY": FLAG_CELERY_PRESENT,
|
||||
"PLUGINS": PLUGINS_ENABLED,
|
||||
"SENTRY": SENTRY_ENABLED,
|
||||
"ENVIFORMER": ENVIFORMER_PRESENT,
|
||||
"APPLICABILITY_DOMAIN": APPLICABILITY_DOMAIN_ENABLED,
|
||||
}
|
||||
|
||||
# path of the URL are checked via "startswith"
|
||||
# -> /password_reset/done is covered as well
|
||||
LOGIN_EXEMPT_URLS = [
|
||||
'/register',
|
||||
'/api/legacy/',
|
||||
'/o/token/',
|
||||
'/o/userinfo/',
|
||||
'/password_reset/',
|
||||
'/reset/',
|
||||
'/microsoft/',
|
||||
"/register",
|
||||
"/api/legacy/",
|
||||
"/o/token/",
|
||||
"/o/userinfo/",
|
||||
"/password_reset/",
|
||||
"/reset/",
|
||||
"/microsoft/",
|
||||
]
|
||||
|
||||
# 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:
|
||||
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']
|
||||
# Add app to installed apps
|
||||
INSTALLED_APPS.append("epauth")
|
||||
# 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_REDIRECT_URI = os.environ['MS_REDIRECT_URI']
|
||||
MS_ENTRA_SCOPES = os.environ.get('MS_SCOPES', '').split(',')
|
||||
MS_ENTRA_REDIRECT_URI = os.environ["MS_REDIRECT_URI"]
|
||||
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")
|
||||
|
||||
+5
-1
@@ -14,13 +14,14 @@ Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
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.urls import include, path
|
||||
|
||||
from .api import api_v1, api_legacy
|
||||
|
||||
urlpatterns = [
|
||||
path("", include("epauth.urls")),
|
||||
path("", include("epdb.urls")),
|
||||
path("", include("migration.urls")),
|
||||
path("admin/", admin.site.urls),
|
||||
@@ -28,3 +29,6 @@ urlpatterns = [
|
||||
path("api/legacy/", api_legacy.urls),
|
||||
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
||||
]
|
||||
|
||||
if s.MS_ENTRA_ENABLED:
|
||||
urlpatterns.append(path("", include("epauth.urls")))
|
||||
|
||||
+1
-1
@@ -11,6 +11,6 @@ import os
|
||||
|
||||
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()
|
||||
|
||||
+30
-3
@@ -7,6 +7,7 @@ from .models import (
|
||||
GroupPackagePermission,
|
||||
Package,
|
||||
MLRelativeReasoning,
|
||||
EnviFormer,
|
||||
Compound,
|
||||
CompoundStructure,
|
||||
SimpleAmbitRule,
|
||||
@@ -16,12 +17,15 @@ from .models import (
|
||||
Node,
|
||||
Edge,
|
||||
Scenario,
|
||||
Setting
|
||||
Setting,
|
||||
ExternalDatabase,
|
||||
ExternalIdentifier,
|
||||
JobLog,
|
||||
)
|
||||
|
||||
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
list_display = ["username", "email", "is_active"]
|
||||
|
||||
|
||||
class UserPackagePermissionAdmin(admin.ModelAdmin):
|
||||
@@ -36,17 +40,28 @@ class GroupPackagePermissionAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class JobLogAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class EPAdmin(admin.ModelAdmin):
|
||||
search_fields = ['name', 'description']
|
||||
search_fields = ["name", "description"]
|
||||
list_display = ["name", "url", "created"]
|
||||
ordering = ["-created"]
|
||||
|
||||
|
||||
class PackageAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class MLRelativeReasoningAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class EnviFormerAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class CompoundAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
@@ -87,12 +102,22 @@ class SettingAdmin(EPAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class ExternalDatabaseAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
class ExternalIdentifierAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
admin.site.register(UserPackagePermission, UserPackagePermissionAdmin)
|
||||
admin.site.register(Group, GroupAdmin)
|
||||
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
||||
admin.site.register(JobLog, JobLogAdmin)
|
||||
admin.site.register(Package, PackageAdmin)
|
||||
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
||||
admin.site.register(EnviFormer, EnviFormerAdmin)
|
||||
admin.site.register(Compound, CompoundAdmin)
|
||||
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
||||
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
||||
@@ -103,3 +128,5 @@ admin.site.register(Node, NodeAdmin)
|
||||
admin.site.register(Edge, EdgeAdmin)
|
||||
admin.site.register(Setting, SettingAdmin)
|
||||
admin.site.register(Scenario, ScenarioAdmin)
|
||||
admin.site.register(ExternalDatabase, ExternalDatabaseAdmin)
|
||||
admin.site.register(ExternalIdentifier, ExternalIdentifierAdmin)
|
||||
|
||||
+9
-4
@@ -21,7 +21,7 @@ class BearerTokenAuth(HttpBearer):
|
||||
def _anonymous_or_real(request):
|
||||
if request.user.is_authenticated and not request.user.is_anonymous:
|
||||
return request.user
|
||||
return get_user_model().objects.get(username='anonymous')
|
||||
return get_user_model().objects.get(username="anonymous")
|
||||
|
||||
|
||||
router = Router(auth=BearerTokenAuth())
|
||||
@@ -85,7 +85,9 @@ def get_package(request, package_uuid):
|
||||
try:
|
||||
return PackageManager.get_package_by_id(request.auth, package_id=package_uuid)
|
||||
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})
|
||||
@@ -97,7 +99,9 @@ def get_compounds(request):
|
||||
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
|
||||
def get_package_compounds(request, package_uuid):
|
||||
try:
|
||||
@@ -105,4 +109,5 @@ def get_package_compounds(request, package_uuid):
|
||||
return Compound.objects.filter(package=p)
|
||||
except ValueError:
|
||||
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
-2
@@ -2,8 +2,8 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class EPDBConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'epdb'
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "epdb"
|
||||
|
||||
def ready(self):
|
||||
import epdb.signals # noqa: F401
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from django import forms
|
||||
|
||||
|
||||
class EmailLoginForm(forms.Form):
|
||||
email = forms.EmailField()
|
||||
+722
-221
File diff suppressed because it is too large
Load Diff
+686
-405
File diff suppressed because it is too large
Load Diff
@@ -5,32 +5,49 @@ from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def create_users(self):
|
||||
|
||||
# Anonymous User
|
||||
if not User.objects.filter(email='anon@envipath.com').exists():
|
||||
anon = UserManager.create_user("anonymous", "anon@envipath.com", "SuperSafe",
|
||||
is_active=True, add_to_group=False, set_setting=False)
|
||||
if not User.objects.filter(email="anon@envipath.com").exists():
|
||||
anon = UserManager.create_user(
|
||||
"anonymous",
|
||||
"anon@envipath.com",
|
||||
"SuperSafe",
|
||||
is_active=True,
|
||||
add_to_group=False,
|
||||
set_setting=False,
|
||||
)
|
||||
else:
|
||||
anon = User.objects.get(email='anon@envipath.com')
|
||||
anon = User.objects.get(email="anon@envipath.com")
|
||||
|
||||
# Admin User
|
||||
if not User.objects.filter(email='admin@envipath.com').exists():
|
||||
admin = UserManager.create_user("admin", "admin@envipath.com", "SuperSafe",
|
||||
is_active=True, add_to_group=False, set_setting=False)
|
||||
if not User.objects.filter(email="admin@envipath.com").exists():
|
||||
admin = UserManager.create_user(
|
||||
"admin",
|
||||
"admin@envipath.com",
|
||||
"SuperSafe",
|
||||
is_active=True,
|
||||
add_to_group=False,
|
||||
set_setting=False,
|
||||
)
|
||||
admin.is_staff = True
|
||||
admin.is_superuser = True
|
||||
admin.save()
|
||||
else:
|
||||
admin = User.objects.get(email='admin@envipath.com')
|
||||
admin = User.objects.get(email="admin@envipath.com")
|
||||
|
||||
# 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.save()
|
||||
|
||||
@@ -43,14 +60,20 @@ class Command(BaseCommand):
|
||||
admin.default_group = g
|
||||
admin.save()
|
||||
|
||||
if not User.objects.filter(email='user0@envipath.com').exists():
|
||||
user0 = UserManager.create_user("user0", "user0@envipath.com", "SuperSafe",
|
||||
is_active=True, add_to_group=False, set_setting=False)
|
||||
if not User.objects.filter(email="user0@envipath.com").exists():
|
||||
user0 = UserManager.create_user(
|
||||
"user0",
|
||||
"user0@envipath.com",
|
||||
"SuperSafe",
|
||||
is_active=True,
|
||||
add_to_group=False,
|
||||
set_setting=False,
|
||||
)
|
||||
user0.is_staff = True
|
||||
user0.is_superuser = True
|
||||
user0.save()
|
||||
else:
|
||||
user0 = User.objects.get(email='user0@envipath.com')
|
||||
user0 = User.objects.get(email="user0@envipath.com")
|
||||
|
||||
g.user_member.add(user0)
|
||||
g.save()
|
||||
@@ -61,18 +84,20 @@ class Command(BaseCommand):
|
||||
return anon, admin, g, user0
|
||||
|
||||
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):
|
||||
s = SettingManager.create_setting(
|
||||
owner,
|
||||
name='Global Default Setting',
|
||||
description='Global Default Setting containing BBD Rules and Max 30 Nodes and Max Depth of 8',
|
||||
name="Global Default Setting",
|
||||
description="Global Default Setting containing BBD Rules and Max 30 Nodes and Max Depth of 8",
|
||||
max_nodes=30,
|
||||
max_depth=5,
|
||||
rule_packages=packages,
|
||||
model=None,
|
||||
model_threshold=None
|
||||
model_threshold=None,
|
||||
)
|
||||
|
||||
return s
|
||||
@@ -84,54 +109,51 @@ class Command(BaseCommand):
|
||||
"""
|
||||
databases = [
|
||||
{
|
||||
'name': 'PubChem Compound',
|
||||
'full_name': 'PubChem Compound Database',
|
||||
'description': 'Chemical database of small organic molecules',
|
||||
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
|
||||
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/compound/{id}'
|
||||
"name": "PubChem Compound",
|
||||
"full_name": "PubChem Compound Database",
|
||||
"description": "Chemical database of small organic molecules",
|
||||
"base_url": "https://pubchem.ncbi.nlm.nih.gov",
|
||||
"url_pattern": "https://pubchem.ncbi.nlm.nih.gov/compound/{id}",
|
||||
},
|
||||
{
|
||||
'name': 'PubChem Substance',
|
||||
'full_name': 'PubChem Substance Database',
|
||||
'description': 'Database of chemical substances',
|
||||
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
|
||||
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/substance/{id}'
|
||||
"name": "PubChem Substance",
|
||||
"full_name": "PubChem Substance Database",
|
||||
"description": "Database of chemical substances",
|
||||
"base_url": "https://pubchem.ncbi.nlm.nih.gov",
|
||||
"url_pattern": "https://pubchem.ncbi.nlm.nih.gov/substance/{id}",
|
||||
},
|
||||
{
|
||||
'name': 'ChEBI',
|
||||
'full_name': 'Chemical Entities of Biological Interest',
|
||||
'description': 'Dictionary of molecular entities',
|
||||
'base_url': 'https://www.ebi.ac.uk/chebi',
|
||||
'url_pattern': 'https://www.ebi.ac.uk/chebi/searchId.do?chebiId=CHEBI:{id}'
|
||||
"name": "ChEBI",
|
||||
"full_name": "Chemical Entities of Biological Interest",
|
||||
"description": "Dictionary of molecular entities",
|
||||
"base_url": "https://www.ebi.ac.uk/chebi",
|
||||
"url_pattern": "https://www.ebi.ac.uk/chebi/searchId.do?chebiId=CHEBI:{id}",
|
||||
},
|
||||
{
|
||||
'name': 'RHEA',
|
||||
'full_name': 'RHEA Reaction Database',
|
||||
'description': 'Comprehensive resource of biochemical reactions',
|
||||
'base_url': 'https://www.rhea-db.org',
|
||||
'url_pattern': 'https://www.rhea-db.org/rhea/{id}'
|
||||
"name": "RHEA",
|
||||
"full_name": "RHEA Reaction Database",
|
||||
"description": "Comprehensive resource of biochemical reactions",
|
||||
"base_url": "https://www.rhea-db.org",
|
||||
"url_pattern": "https://www.rhea-db.org/rhea/{id}",
|
||||
},
|
||||
{
|
||||
'name': 'KEGG Reaction',
|
||||
'full_name': 'KEGG Reaction Database',
|
||||
'description': 'Database of biochemical reactions',
|
||||
'base_url': 'https://www.genome.jp',
|
||||
'url_pattern': 'https://www.genome.jp/entry/reaction+{id}'
|
||||
"name": "KEGG Reaction",
|
||||
"full_name": "KEGG Reaction Database",
|
||||
"description": "Database of biochemical reactions",
|
||||
"base_url": "https://www.genome.jp",
|
||||
"url_pattern": "https://www.genome.jp/entry/{id}",
|
||||
},
|
||||
{
|
||||
'name': 'UniProt',
|
||||
'full_name': 'MetaCyc Metabolic Pathway Database',
|
||||
'description': 'UniProt is a freely accessible database of protein sequence and functional information',
|
||||
'base_url': 'https://www.uniprot.org',
|
||||
'url_pattern': 'https://www.uniprot.org/uniprotkb?query="{id}"'
|
||||
}
|
||||
"name": "UniProt",
|
||||
"full_name": "MetaCyc Metabolic Pathway Database",
|
||||
"description": "UniProt is a freely accessible database of protein sequence and functional information",
|
||||
"base_url": "https://www.uniprot.org",
|
||||
"url_pattern": 'https://www.uniprot.org/uniprotkb?query="{id}"',
|
||||
},
|
||||
]
|
||||
|
||||
for db_info in databases:
|
||||
ExternalDatabase.objects.get_or_create(
|
||||
name=db_info['name'],
|
||||
defaults=db_info
|
||||
)
|
||||
ExternalDatabase.objects.get_or_create(name=db_info["name"], defaults=db_info)
|
||||
|
||||
@transaction.atomic
|
||||
def handle(self, *args, **options):
|
||||
@@ -142,20 +164,24 @@ class Command(BaseCommand):
|
||||
|
||||
# Import Packages
|
||||
packages = [
|
||||
'EAWAG-BBD.json',
|
||||
'EAWAG-SOIL.json',
|
||||
'EAWAG-SLUDGE.json',
|
||||
'EAWAG-SEDIMENT.json',
|
||||
"EAWAG-BBD.json",
|
||||
"EAWAG-SOIL.json",
|
||||
"EAWAG-SLUDGE.json",
|
||||
"EAWAG-SEDIMENT.json",
|
||||
]
|
||||
|
||||
mapping = {}
|
||||
for p in packages:
|
||||
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)
|
||||
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.save()
|
||||
setting.make_global_default()
|
||||
@@ -171,26 +197,28 @@ class Command(BaseCommand):
|
||||
usp.save()
|
||||
|
||||
# Create Model Package
|
||||
pack = PackageManager.create_package(admin, "Public Prediction Models",
|
||||
"Package to make Prediction Models publicly available")
|
||||
pack = PackageManager.create_package(
|
||||
admin,
|
||||
"Public Prediction Models",
|
||||
"Package to make Prediction Models publicly available",
|
||||
)
|
||||
pack.reviewed = True
|
||||
pack.save()
|
||||
|
||||
# Create RR
|
||||
ml_model = MLRelativeReasoning.create(
|
||||
package=pack,
|
||||
rule_packages=[mapping['EAWAG-BBD']],
|
||||
data_packages=[mapping['EAWAG-BBD']],
|
||||
rule_packages=[mapping["EAWAG-BBD"]],
|
||||
data_packages=[mapping["EAWAG-BBD"]],
|
||||
eval_packages=[],
|
||||
threshold=0.5,
|
||||
name='ECC - BBD - T0.5',
|
||||
description='ML Relative Reasoning',
|
||||
name="ECC - BBD - T0.5",
|
||||
description="ML Relative Reasoning",
|
||||
)
|
||||
|
||||
ml_model.build_dataset()
|
||||
ml_model.build_model()
|
||||
# ml_model.evaluate_model()
|
||||
|
||||
# If available, create EnviFormerModel
|
||||
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)
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -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.db import transaction
|
||||
|
||||
from epdb.logic import PackageManager
|
||||
from epdb.models import *
|
||||
from epdb.models import User
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--data',
|
||||
"--data",
|
||||
type=str,
|
||||
help='Path of the Package to import.',
|
||||
help="Path of the Package to import.",
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--owner',
|
||||
"--owner",
|
||||
type=str,
|
||||
help='Username of the desired Owner.',
|
||||
help="Username of the desired Owner.",
|
||||
required=True,
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def handle(self, *args, **options):
|
||||
owner = User.objects.get(username=options['owner'])
|
||||
package_data = json.load(open(options['data']))
|
||||
owner = User.objects.get(username=options["owner"])
|
||||
package_data = json.load(open(options["data"]))
|
||||
PackageManager.import_legacy_package(package_data, owner)
|
||||
|
||||
@@ -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.core.management.base import BaseCommand
|
||||
|
||||
from django.db.models import F, Value
|
||||
from django.db.models.functions import Replace
|
||||
from django.db.models import F, Value, TextField, JSONField
|
||||
from django.db.models.functions import Replace, Cast
|
||||
|
||||
from epdb.models import EnviPathModel
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--old',
|
||||
"--old",
|
||||
type=str,
|
||||
help='Old Host, most likely https://envipath.org/',
|
||||
help="Old Host, most likely https://envipath.org/",
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--new',
|
||||
"--new",
|
||||
type=str,
|
||||
help='New Host, most likely http://localhost:8000/',
|
||||
help="New Host, most likely http://localhost:8000/",
|
||||
required=True,
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
MODELS = [
|
||||
'User',
|
||||
'Group',
|
||||
'Package',
|
||||
'Compound',
|
||||
'CompoundStructure',
|
||||
'Pathway',
|
||||
'Edge',
|
||||
'Node',
|
||||
'Reaction',
|
||||
'SimpleAmbitRule',
|
||||
'SimpleRDKitRule',
|
||||
'ParallelRule',
|
||||
'SequentialRule',
|
||||
'Scenario',
|
||||
'Setting',
|
||||
'MLRelativeReasoning',
|
||||
'RuleBasedRelativeReasoning',
|
||||
'EnviFormer',
|
||||
'ApplicabilityDomain',
|
||||
"User",
|
||||
"Group",
|
||||
"Package",
|
||||
"Compound",
|
||||
"CompoundStructure",
|
||||
"Pathway",
|
||||
"Edge",
|
||||
"Node",
|
||||
"Reaction",
|
||||
"SimpleAmbitRule",
|
||||
"SimpleRDKitRule",
|
||||
"ParallelRule",
|
||||
"SequentialRule",
|
||||
"Scenario",
|
||||
"Setting",
|
||||
"MLRelativeReasoning",
|
||||
"RuleBasedRelativeReasoning",
|
||||
"EnviFormer",
|
||||
"ApplicabilityDomain",
|
||||
"EnzymeLink",
|
||||
]
|
||||
for model in MODELS:
|
||||
obj_cls = apps.get_model("epdb", model)
|
||||
print(f"Localizing urls for {model}")
|
||||
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(),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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 urllib.parse import quote
|
||||
|
||||
|
||||
class LoginRequiredMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
self.exempt_urls = [
|
||||
reverse('login'),
|
||||
reverse('logout'),
|
||||
reverse('admin:login'),
|
||||
reverse('admin:index'),
|
||||
] + getattr(settings, 'LOGIN_EXEMPT_URLS', [])
|
||||
reverse("login"),
|
||||
reverse("logout"),
|
||||
reverse("admin:login"),
|
||||
reverse("admin:index"),
|
||||
] + getattr(settings, "LOGIN_EXEMPT_URLS", [])
|
||||
|
||||
def __call__(self, request):
|
||||
if not request.user.is_authenticated:
|
||||
path = request.path_info
|
||||
if not any(path.startswith(url) for url in self.exempt_urls):
|
||||
if request.method == 'GET':
|
||||
if request.get_full_path() and request.get_full_path() != '/':
|
||||
return redirect(f"{settings.LOGIN_URL}?next={quote(request.get_full_path())}")
|
||||
if request.method == "GET":
|
||||
if request.get_full_path() and request.get_full_path() != "/":
|
||||
return redirect(
|
||||
f"{settings.LOGIN_URL}?next={quote(request.get_full_path())}"
|
||||
)
|
||||
return redirect(settings.LOGIN_URL)
|
||||
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'),
|
||||
),
|
||||
]
|
||||
@@ -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,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -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,
|
||||
},
|
||||
),
|
||||
]
|
||||
+1604
-831
File diff suppressed because it is too large
Load Diff
+221
-23
@@ -1,58 +1,154 @@
|
||||
import csv
|
||||
import io
|
||||
import logging
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable, List, Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from celery import shared_task
|
||||
from epdb.models import Pathway, Node, Edge, EPModel, Setting
|
||||
from epdb.logic import SPathway
|
||||
from celery.utils.functional import LRUCache
|
||||
|
||||
from epdb.logic import SPathway
|
||||
from epdb.models import EPModel, JobLog, Node, Package, Pathway, Rule, Setting, User, Edge
|
||||
|
||||
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 = datetime.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):
|
||||
return a * b
|
||||
|
||||
|
||||
@shared_task(queue='predict')
|
||||
@shared_task(queue="predict")
|
||||
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)
|
||||
return res
|
||||
|
||||
|
||||
@shared_task(queue='background')
|
||||
@shared_task(queue="background")
|
||||
def send_registration_mail(user_pk: int):
|
||||
pass
|
||||
|
||||
|
||||
@shared_task(queue='model')
|
||||
def build_model(model_pk: int):
|
||||
@shared_task(bind=True, queue="model")
|
||||
def build_model(self, model_pk: int):
|
||||
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')
|
||||
def evaluate_model(model_pk: int):
|
||||
@shared_task(bind=True, queue="model")
|
||||
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.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):
|
||||
mod = EPModel.objects.get(id=model_pk)
|
||||
mod.retrain()
|
||||
|
||||
|
||||
@shared_task(queue='predict')
|
||||
def predict(pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_pk: Optional[int] = None) -> Pathway:
|
||||
@shared_task(bind=True, queue="predict")
|
||||
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)
|
||||
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()
|
||||
|
||||
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:
|
||||
# regular prediction
|
||||
if limit is not None:
|
||||
@@ -74,12 +170,114 @@ def predict(pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_
|
||||
else:
|
||||
raise ValueError("Neither limit nor node_pk given!")
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
pw.kv.update({'status': 'failed'})
|
||||
pw.kv.update({"status": "failed"})
|
||||
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
|
||||
|
||||
pw.kv.update(**{'status': 'completed'})
|
||||
pw.save()
|
||||
pw.kv.update(**{"status": "completed"})
|
||||
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 +0,0 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.filter
|
||||
def classname(obj):
|
||||
return obj.__class__.__name__
|
||||
@@ -0,0 +1,21 @@
|
||||
from django import template
|
||||
from pydantic import AnyHttpUrl, ValidationError
|
||||
from pydantic.type_adapter import TypeAdapter
|
||||
|
||||
register = template.Library()
|
||||
|
||||
url_adapter = TypeAdapter(AnyHttpUrl)
|
||||
|
||||
|
||||
@register.filter
|
||||
def classname(obj):
|
||||
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.
|
||||
+172
-75
@@ -1,99 +1,196 @@
|
||||
from django.urls import path, re_path
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.urls import path, re_path
|
||||
|
||||
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 = [
|
||||
# Home
|
||||
re_path(r'^$', v.index, name='index'),
|
||||
|
||||
re_path(r"^$", v.index, name="index"),
|
||||
# Login
|
||||
re_path(r'^login', v.login, name='login'),
|
||||
re_path(r'^logout', v.logout, name='logout'),
|
||||
re_path(r'^register', v.register, name='register'),
|
||||
|
||||
# Built In views
|
||||
path('password_reset/', auth_views.PasswordResetView.as_view(
|
||||
template_name='static/password_reset_form.html'
|
||||
), name='password_reset'),
|
||||
|
||||
path('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'
|
||||
), name='password_reset_confirm'),
|
||||
|
||||
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(
|
||||
template_name='static/password_reset_complete.html'
|
||||
), name='password_reset_complete'),
|
||||
|
||||
|
||||
re_path(r"^login", v.login, name="login"),
|
||||
re_path(r"^logout", v.logout, name="logout"),
|
||||
re_path(r"^register", v.register, name="register"),
|
||||
# Built-In views
|
||||
path(
|
||||
"password_reset/",
|
||||
auth_views.PasswordResetView.as_view(template_name="static/password_reset_form.html"),
|
||||
name="password_reset",
|
||||
),
|
||||
path(
|
||||
"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"
|
||||
),
|
||||
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
|
||||
re_path(r'^package$', v.packages, name='packages'),
|
||||
re_path(r'^compound$', v.compounds, name='compounds'),
|
||||
re_path(r'^rule$', v.rules, name='rules'),
|
||||
re_path(r'^reaction$', v.reactions, name='reactions'),
|
||||
re_path(r'^pathway$', v.pathways, name='pathways'),
|
||||
re_path(r'^scenario$', v.scenarios, name='scenarios'),
|
||||
re_path(r'^model$', v.models, name='model'),
|
||||
re_path(r'^user$', v.users, name='users'),
|
||||
re_path(r'^group$', v.groups, name='groups'),
|
||||
re_path(r'^search$', v.search, name='search'),
|
||||
|
||||
|
||||
re_path(r"^package$", v.packages, name="packages"),
|
||||
re_path(r"^compound$", v.compounds, name="compounds"),
|
||||
re_path(r"^rule$", v.rules, name="rules"),
|
||||
re_path(r"^reaction$", v.reactions, name="reactions"),
|
||||
re_path(r"^pathway$", v.pathways, name="pathways"),
|
||||
re_path(r"^scenario$", v.scenarios, name="scenarios"),
|
||||
re_path(r"^model$", v.models, name="model"),
|
||||
re_path(r"^user$", v.users, name="users"),
|
||||
re_path(r"^group$", v.groups, name="groups"),
|
||||
re_path(r"^search$", v.search, name="search"),
|
||||
# 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
|
||||
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
|
||||
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
|
||||
re_path(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'),
|
||||
re_path(
|
||||
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
|
||||
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(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'),
|
||||
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(
|
||||
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
|
||||
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(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'),
|
||||
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(
|
||||
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
|
||||
re_path(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'),
|
||||
re_path(
|
||||
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
|
||||
re_path(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'),
|
||||
re_path(
|
||||
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
|
||||
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(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'),
|
||||
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(
|
||||
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
|
||||
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(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'),
|
||||
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(
|
||||
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
|
||||
re_path(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'),
|
||||
re_path(
|
||||
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
|
||||
re_path(rf'^package/(?P<package_uuid>{UUID})/model$', v.package_models, name='package model list'),
|
||||
re_path(rf'^package/(?P<package_uuid>{UUID})/model/(?P<model_uuid>{UUID})$', v.package_model,name='package model detail'),
|
||||
|
||||
re_path(r'^setting$', v.settings, name='settings'),
|
||||
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'^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(
|
||||
rf"^package/(?P<package_uuid>{UUID})/model$", v.package_models, name="package model list"
|
||||
),
|
||||
re_path(
|
||||
rf"^package/(?P<package_uuid>{UUID})/model/(?P<model_uuid>{UUID})$",
|
||||
v.package_model,
|
||||
name="package model detail",
|
||||
),
|
||||
re_path(r"^setting$", v.settings, name="settings"),
|
||||
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"^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
|
||||
path("o/userinfo/", v.userinfo, name="oauth_userinfo"),
|
||||
]
|
||||
|
||||
+1573
-997
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -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})/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/compare$', v.compare, name='compare'),
|
||||
]
|
||||
|
||||
+189
-111
@@ -1,80 +1,123 @@
|
||||
import gzip
|
||||
import json
|
||||
import logging
|
||||
import os.path
|
||||
from datetime import datetime
|
||||
|
||||
from django.conf import settings as s
|
||||
from django.http import HttpResponseNotAllowed
|
||||
from django.shortcuts import render
|
||||
|
||||
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 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):
|
||||
if request.method == 'GET':
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
|
||||
if os.path.exists(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'))
|
||||
if (
|
||||
os.path.exists(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:
|
||||
data = json.load(gzip.open(s.BASE_DIR / 'fixtures' / 'ambit_rules.json.gz', 'rb'))
|
||||
|
||||
results = []
|
||||
BBD = Package.objects.get(
|
||||
url="http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1"
|
||||
)
|
||||
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
|
||||
error = 0
|
||||
total = 0
|
||||
|
||||
num_keys = len(data.keys())
|
||||
for i, bt_rule_name in enumerate(data.keys()):
|
||||
print(f"{i + 1}/{num_keys}")
|
||||
bt_rule = data[bt_rule_name]
|
||||
smirks = bt_rule['smirks']
|
||||
|
||||
all_prods = set()
|
||||
|
||||
for i, r in enumerate(RULES):
|
||||
logger.debug(f"\r{i + 1:03d}/{num_rules}")
|
||||
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']):
|
||||
|
||||
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:
|
||||
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
|
||||
res &= set(ambit_res) == set(rdkit_res)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
results.append(
|
||||
{
|
||||
'name': bt_rule_name,
|
||||
'id': bt_rule['id'].split('/')[-1],
|
||||
'url': bt_rule['id'],
|
||||
'status': res,
|
||||
'detail_url': s.SERVER_URL + '/migration/' + bt_rule['id'].replace('https://envipath.org/', '')
|
||||
"name": r.name,
|
||||
"detail_url": s.SERVER_URL
|
||||
+ "/migration/"
|
||||
+ r.url.replace("https://envipath.org/", "").replace(
|
||||
"http://localhost:8000/", ""
|
||||
),
|
||||
"id": str(r.uuid),
|
||||
"url": r.url,
|
||||
"status": res,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -84,95 +127,82 @@ def migration(request):
|
||||
error += 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 = {
|
||||
'results': results,
|
||||
'success': success,
|
||||
'error': error,
|
||||
'total': total
|
||||
"results": results,
|
||||
"success": success,
|
||||
"error": error,
|
||||
"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']:
|
||||
r['detail_url'] = r['detail_url'].replace('http://localhost:8000', s.SERVER_URL)
|
||||
for r in migration_status["results"]:
|
||||
r["detail_url"] = r["detail_url"].replace(
|
||||
"http://localhost:8000", s.SERVER_URL
|
||||
)
|
||||
|
||||
context.update(**migration_status)
|
||||
|
||||
return render(request, 'migration.html', context)
|
||||
return render(request, "migration.html", context)
|
||||
|
||||
|
||||
def migration_detail(request, package_uuid, rule_uuid):
|
||||
current_user = _anonymous_or_real(request)
|
||||
|
||||
if request.method == 'GET':
|
||||
if request.method == "GET":
|
||||
context = get_base_context(request)
|
||||
|
||||
p = PackageManager.get_package_by_id(current_user, package_uuid)
|
||||
rule = Rule.objects.get(package=p, uuid=rule_uuid)
|
||||
BBD = Package.objects.get(name="EAWAG-BBD")
|
||||
STRUCTURES = CompoundStructure.objects.filter(compound__package=BBD)
|
||||
rule = Rule.objects.get(package=BBD, uuid=rule_uuid)
|
||||
|
||||
bt_rule_name = rule.name
|
||||
|
||||
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 = []
|
||||
smirks = rule.smirks
|
||||
|
||||
res = True
|
||||
results = []
|
||||
|
||||
all_prods = set()
|
||||
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
||||
# if comp['smiles'] != 'CC1=C(C(=C(C=N1)CO)C=O)O':
|
||||
# continue
|
||||
|
||||
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 structure in STRUCTURES:
|
||||
ambit_smiles, ambit_errors, rdkit_smiles, rdkit_errors = run_both_engines(
|
||||
structure.smiles, smirks
|
||||
)
|
||||
|
||||
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)
|
||||
# FAILED (failures=18)
|
||||
|
||||
# TODO mode = "full ambit"
|
||||
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(ambit_smiles)
|
||||
# FAILED (failures=46)
|
||||
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(set(ambit_smiles))
|
||||
# FAILED (failures=34)
|
||||
|
||||
# TODO mode = "equality"
|
||||
partial_res = set(ambit_smiles) == set(rdkit_smiles)
|
||||
# FAILED (failures=69)
|
||||
# FAILED (failures=30)
|
||||
|
||||
#
|
||||
if len(ambit_smiles) or len(rdkit_smiles):
|
||||
temp = {
|
||||
'url': comp['id'],
|
||||
'id': comp['id'].split('/')[-1],
|
||||
'name': comp['name'],
|
||||
'initial_smiles': comp['smiles'],
|
||||
'ambit_smiles': sorted(list(ambit_smiles)),
|
||||
'rdkit_smiles': sorted(list(rdkit_smiles)),
|
||||
'status': set(ambit_smiles) == set(rdkit_smiles),
|
||||
"url": structure.url,
|
||||
"id": str(structure.uuid),
|
||||
"name": structure.name,
|
||||
"initial_smiles": structure.smiles,
|
||||
"ambit_smiles": sorted(list(ambit_smiles)),
|
||||
"rdkit_smiles": sorted(list(rdkit_smiles)),
|
||||
"status": set(ambit_smiles) == set(rdkit_smiles),
|
||||
}
|
||||
|
||||
if set(ambit_smiles) != set(rdkit_smiles):
|
||||
detail = f"""
|
||||
detail = f"""
|
||||
BT: {bt_rule_name}
|
||||
SMIRKS: {bt_rule['smirks']}
|
||||
Compound: {comp['smiles']}
|
||||
Compound URL: {comp['id']}
|
||||
SMIRKS: {smirks}
|
||||
Compound: {structure.smiles}
|
||||
Compound URL: {structure.url}
|
||||
Num ambit: {len(set(ambit_smiles))}
|
||||
Num rdkit: {len(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}
|
||||
"""
|
||||
|
||||
temp['detail'] = '\n'.join([x.strip() for x in detail.split('\n')])
|
||||
# print(detail.strip())
|
||||
temp["detail"] = "\n".join([x.strip() for x in detail.split("\n")])
|
||||
|
||||
results.append(temp)
|
||||
|
||||
res &= partial_res
|
||||
|
||||
results = sorted(results, key=lambda x: x['status'])
|
||||
context['results'] = results
|
||||
context['res'] = res
|
||||
context['bt_rule_name'] = bt_rule_name
|
||||
return render(request, 'migration_detail.html', context)
|
||||
results = sorted(results, key=lambda x: x["status"])
|
||||
context["results"] = results
|
||||
context["res"] = res
|
||||
context["bt_rule_name"] = bt_rule_name
|
||||
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"])
|
||||
|
||||
Generated
+4
@@ -0,0 +1,4 @@
|
||||
lockfileVersion: 6.0
|
||||
specifiers: {}
|
||||
dependencies: {}
|
||||
packages: {}
|
||||
+59
-4
@@ -3,7 +3,7 @@ name = "envipy"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"celery>=5.5.2",
|
||||
"django>=5.2.1",
|
||||
@@ -12,9 +12,9 @@ dependencies = [
|
||||
"django-ninja>=1.4.1",
|
||||
"django-oauth-toolkit>=3.0.1",
|
||||
"django-polymorphic>=4.1.0",
|
||||
"django-stubs>=5.2.4",
|
||||
"enviformer",
|
||||
"envipy-additional-information",
|
||||
"envipy-ambit>=0.1.0",
|
||||
"envipy-plugins",
|
||||
"epam-indigo>=1.30.1",
|
||||
"gunicorn>=23.0.0",
|
||||
@@ -27,12 +27,67 @@ dependencies = [
|
||||
"scikit-learn>=1.6.1",
|
||||
"sentry-sdk[django]>=2.32.0",
|
||||
"setuptools>=80.8.0",
|
||||
"nh3==0.3.2",
|
||||
"polars==1.35.1",
|
||||
]
|
||||
|
||||
[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-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]
|
||||
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 = { cmd = "python manage.py runserver", help = "Start the development server", deps = ["db-up"] }
|
||||
|
||||
# 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" }
|
||||
|
||||
# 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 = "python manage.py migrate", help = "Run database migrations" }
|
||||
bootstrap = { shell = """
|
||||
echo "Bootstrapping initial data..."
|
||||
echo "This will take a bit ⏱️. Get yourself some coffee..."
|
||||
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 = "python manage.py shell", help = "Open Django shell" }
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -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 |
+4
-4
@@ -646,8 +646,8 @@ function handleAssessmentResponse(depict_url, data) {
|
||||
var reactivityCentersImgSrc = null;
|
||||
|
||||
if (data['assessment']['node'] !== undefined) {
|
||||
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>";
|
||||
reactivityCentersImgSrc = "<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'] + "&highlightReactivity=true'>"
|
||||
} else {
|
||||
functionalGroupsImgSrc = "<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 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 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']) + "'>";
|
||||
|
||||
@@ -784,4 +784,4 @@ function handleAssessmentResponse(depict_url, data) {
|
||||
|
||||
$("#appDomainAssessmentResultTable").append(res);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,6 +444,13 @@ function serializeSVG(svgElement) {
|
||||
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();
|
||||
let svgString = serializer.serializeToString(svgElement);
|
||||
|
||||
@@ -455,7 +462,26 @@ function serializeSVG(svgElement) {
|
||||
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') {
|
||||
shrinkSVG("#" + svgElement.id);
|
||||
const svgString = serializeSVG(svgElement);
|
||||
const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<a role="button" data-toggle="modal" data-target="#edit_compound_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#add_structure_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
|
||||
@@ -11,6 +15,10 @@
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</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 %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
@@ -21,4 +29,4 @@
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -3,12 +3,20 @@
|
||||
<a role="button" data-toggle="modal" data-target="#edit_compound_structure_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</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>
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{% 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>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<a role="button" data-toggle="modal" data-target="#edit_node_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<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>
|
||||
</li>
|
||||
{% 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>
|
||||
<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">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
{# <li>#}
|
||||
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
||||
{# <i class="glyphicon glyphicon-plus"></i> Calculate Compound Properties</a>#}
|
||||
@@ -48,4 +56,4 @@
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Pathway</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -3,10 +3,18 @@
|
||||
<a role="button" data-toggle="modal" data-target="#edit_reaction_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
</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 %}
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#generic_copy_object_modal">
|
||||
@@ -17,4 +25,4 @@
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
||||
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||
@@ -17,4 +21,4 @@
|
||||
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||
<i class="glyphicon glyphicon-trash"></i> Delete Rule</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -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">
|
||||
{% if object_type == 'package' %}
|
||||
{% 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"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
@@ -201,7 +201,7 @@
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% 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"
|
||||
style="float:right" data-toggle="tooltip"
|
||||
data-placement="top" title="" data-original-title="Reviewed">
|
||||
@@ -221,11 +221,11 @@
|
||||
<div class="panel-body list-group-item" id="UnreviewedContent">
|
||||
{% if object_type == 'package' %}
|
||||
{% 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 %}
|
||||
{% else %}
|
||||
{% 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 %}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -236,9 +236,9 @@
|
||||
<ul class='list-group'>
|
||||
{% for obj in objects %}
|
||||
{% 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 %}
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name|safe }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
@@ -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>
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
{{ error_detail }}<br>
|
||||
The error was logged and will be investigated.
|
||||
{{ error_detail }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
+15
-13
@@ -56,7 +56,7 @@
|
||||
(function () {
|
||||
var u = "//matomo.envipath.com/";
|
||||
_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];
|
||||
g.async = true;
|
||||
g.src = u + 'matomo.js';
|
||||
@@ -89,7 +89,7 @@
|
||||
<div class="collapse navbar-collapse collapse-framework navbar-collapse-framework" id="navbarCollapse">
|
||||
<ul class="nav navbar-nav navbar-nav-framework">
|
||||
<li>
|
||||
<a class="button" data-toggle="modal" data-target="#predict_modal">
|
||||
<a href="#" data-toggle="modal" data-target="#predict_modal">
|
||||
Predict Pathway
|
||||
</a>
|
||||
</li>
|
||||
@@ -134,7 +134,7 @@
|
||||
<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><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>
|
||||
@@ -227,21 +227,23 @@
|
||||
<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" %}'
|
||||
<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>
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
var textSmiles = $('#index-form-text-input').val().trim();
|
||||
|
||||
if (textSmiles === '') {
|
||||
$(this).prop("disabled", false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
{% endif %}
|
||||
<h4 class="panel-title">
|
||||
<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>
|
||||
</div>
|
||||
<div id="{{ obj.id }}" class="panel-collapse collapse {% if not obj.status %}in{% endif %}">
|
||||
<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>
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,50 +1,45 @@
|
||||
{% extends "framework.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="panel-group" id="migration-detail">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
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 class="panel-group" id="migration-detail">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
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|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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label class="btn btn-primary" for="jsonFile">
|
||||
<input id="jsonFile" name="file" type="file" style="display:none;"
|
||||
onchange="$('#upload-file-info').html(this.files[0].name)">
|
||||
<label class="btn btn-primary" for="legacyJsonFile">
|
||||
<input id="legacyJsonFile" name="file" type="file" style="display:none;"
|
||||
onchange="$('#upload-legacy-file-info').html(this.files[0].name)">
|
||||
Choose JSON File
|
||||
</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="">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
<div class="modal fade" tabindex="-1" id="new_model_modal" role="dialog" aria-labelledby="new_model_modal"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
@@ -18,113 +19,117 @@
|
||||
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.
|
||||
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>
|
||||
<!-- Name -->
|
||||
<label for="model-name">Name</label>
|
||||
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
||||
|
||||
<!-- Description -->
|
||||
<label for="model-description">Description</label>
|
||||
<input id="model-description" name="model-description" class="form-control"
|
||||
placeholder="Description"/>
|
||||
|
||||
<!-- Model Type -->
|
||||
<label for="model-type">Model Type</label>
|
||||
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
||||
<option disabled selected>Select Model Type</option>
|
||||
{% for k, v in model_types.items %}
|
||||
<option value="{{ v }}">{{ k }}</option>
|
||||
<option value="{{ v }}">{{ k }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<!-- ML and Rule Based Based Form-->
|
||||
<div id="package-based-relative-reasoning-specific-form">
|
||||
<!-- Rule Packages -->
|
||||
<label for="package-based-relative-reasoning-rule-packages">Rule Packages</label>
|
||||
<select id="package-based-relative-reasoning-rule-packages" name="package-based-relative-reasoning-rule-packages"
|
||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||
|
||||
<!-- Rule Packages -->
|
||||
<div id="rule-packages" class="ep-model-param mlrr rbrr">
|
||||
<label for="model-rule-packages">Rule Packages</label>
|
||||
<select id="model-rule-packages" name="model-rule-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 %}
|
||||
{% 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 }}</option>
|
||||
{% endif %}
|
||||
{% if not obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</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>
|
||||
<!-- EnviFormer-->
|
||||
<div id="enviformer-specific-form">
|
||||
<label for="enviformer-threshold">Threshold</label>
|
||||
<input type="number" min="0" max="1" step="0.05" value="0.5" id="enviformer-threshold"
|
||||
name="enviformer-threshold" class="form-control">
|
||||
|
||||
<!-- Data Packages -->
|
||||
<div id="data-packages" class="ep-model-param mlrr rbrr enviformer">
|
||||
<label for="model-data-packages">Data Packages</label>
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
@@ -137,53 +142,47 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
// Initially hide all "specific" forms
|
||||
$("div[id$='-specific-form']").each( function() {
|
||||
$(this).hide();
|
||||
});
|
||||
$(function () {
|
||||
// Built in Model Types
|
||||
var nativeModelTypes = [
|
||||
"mlrr",
|
||||
"rbrr",
|
||||
"enviformer",
|
||||
]
|
||||
|
||||
$('#model-type').selectpicker();
|
||||
$("#ml-relative-reasoning-fingerprinter").selectpicker();
|
||||
$("#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() {
|
||||
// Initially hide all "specific" forms
|
||||
$(".ep-model-param").each(function () {
|
||||
$(this).hide();
|
||||
});
|
||||
val = $('option:selected', this).val();
|
||||
|
||||
if (val === 'ml-relative-reasoning' || val === 'rule-based-relative-reasoning') {
|
||||
$("#package-based-relative-reasoning-specific-form").show();
|
||||
if (val === 'ml-relative-reasoning') {
|
||||
$("#ml-relative-reasoning-specific-form").show();
|
||||
$('#model-type').selectpicker();
|
||||
$("#model-fingerprinter").selectpicker();
|
||||
$("#model-rule-packages").selectpicker();
|
||||
$("#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>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<div class="modal fade" tabindex="-1" id="new_pathway_modal" role="dialog" aria-labelledby="new_pathway_modal"
|
||||
aria-hidden="true" style="overflow-y: auto;">
|
||||
@@ -111,7 +112,7 @@
|
||||
|
||||
<select id="settingSelect" name="settingSelect" class="form-control">
|
||||
{% for setting in available_settings %}
|
||||
<option value="{{ setting.id }}">{{ setting.name }}</option>
|
||||
<option value="{{ setting.id }}">{{ setting.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p></p>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
|
||||
<div id="new_prediction_setting_modal" class="modal" tabindex="-1">
|
||||
@@ -40,14 +41,14 @@
|
||||
<option disabled>Reviewed Packages</option>
|
||||
{% for obj in meta.readable_packages %}
|
||||
{% if obj.reviewed %}
|
||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||
<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 }}</option>
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
@@ -57,7 +58,7 @@
|
||||
<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>
|
||||
{% for m in models %}
|
||||
<option value="{{ m.url }}">{{ m.name }}</option>
|
||||
<option value="{{ m.url }}">{{ m.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<label for="model-based-prediction-setting-threshold">Threshold</label>
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
<tr>
|
||||
<th>
|
||||
<input type="number" id="dateYear" name="scenario-date-year" class="form-control"
|
||||
placeholder="YYYY">
|
||||
placeholder="YYYY" max="{% now "Y" %}">
|
||||
</th>
|
||||
<th>
|
||||
<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>
|
||||
<input type="number" id="dateDay" name="scenario-date-day" min="1" max="31" class="form-control"
|
||||
@@ -88,8 +88,15 @@
|
||||
$('#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>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<div class="modal fade bs-modal-lg" id="add_pathway_edge_modal" tabindex="-1" aria-labelledby="add_pathway_edge_modal"
|
||||
aria-modal="true"
|
||||
@@ -36,7 +37,7 @@
|
||||
<select id="add_pathway_edge_substrates" name="edge-substrates"
|
||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||
{% 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 %}
|
||||
</select>
|
||||
</div>
|
||||
@@ -47,7 +48,7 @@
|
||||
<select id="add_pathway_edge_products" name="edge-products"
|
||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||
{% 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 %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Delete Edge -->
|
||||
<div id="delete_pathway_edge_modal" class="modal" tabindex="-1">
|
||||
@@ -19,7 +20,7 @@
|
||||
data-actions-box='true' class="form-control" data-width='100%'>
|
||||
<option value="" disabled selected>Select Reaction to delete</option>
|
||||
{% 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 %}
|
||||
</select>
|
||||
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{% load static %}
|
||||
|
||||
<!-- Delete Node -->
|
||||
<div id="delete_pathway_node_modal" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
@@ -19,7 +20,7 @@
|
||||
data-actions-box='true' class="form-control" data-width='100%'>
|
||||
<option value="" disabled selected>Select Compound to delete</option>
|
||||
{% for n in pathway.nodes %}
|
||||
<option value="{{ n.url }}">{{ n.default_node_label.name }}</option>
|
||||
<option value="{{ n.url }}">{{ n.default_node_label.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Compound -->
|
||||
<div id="edit_compound_modal" class="modal" tabindex="-1">
|
||||
@@ -15,12 +16,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="compound-name">Name</label>
|
||||
<input id="compound-name" class="form-control" name="compound-name" value="{{ compound.name}}">
|
||||
<input id="compound-name" class="form-control" name="compound-name" value="{{ compound.name|safe}}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="compound-description">Description</label>
|
||||
<input id="compound-description" type="text" class="form-control"
|
||||
value="{{ compound.description }}"
|
||||
value="{{ compound.description|safe }}"
|
||||
name="compound-description">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Compound -->
|
||||
<div id="edit_compound_structure_modal" class="modal" tabindex="-1">
|
||||
@@ -15,12 +16,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="compound-structure-name">Name</label>
|
||||
<input id="compound-structure-name" class="form-control" name="compound-structure-name" value="{{ structure.name }}">
|
||||
<input id="compound-structure-name" class="form-control" name="compound-structure-name" value="{{ compound_structure.name|safe }}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="compound-structure-description">Description</label>
|
||||
<input id="compound-structure-description" type="text" class="form-control"
|
||||
value="{{ structure.description }}" name="compound-structure-description">
|
||||
value="{{ compound_structure.description|safe }}" name="compound-structure-description">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Package Permission -->
|
||||
<div id="edit_group_member_modal" class="modal" tabindex="-1">
|
||||
@@ -39,7 +40,7 @@
|
||||
{% endfor %}
|
||||
<option disabled>Groups</option>
|
||||
{% for g in groups %}
|
||||
<option value="{{ g.url }}">{{ g.name }}</option>
|
||||
<option value="{{ g.url }}">{{ g.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="hidden" name="action" value="add">
|
||||
@@ -81,7 +82,7 @@
|
||||
accept-charset="UTF-8" action="" data-remote="true" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="col-xs-8">
|
||||
{{ g.name }}
|
||||
{{ g.name|safe }}
|
||||
<input type="hidden" name="member" value="{{ g.url }}"/>
|
||||
<input type="hidden" name="action" value="remove">
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Model -->
|
||||
<div id="edit_model_modal" class="modal" tabindex="-1">
|
||||
@@ -16,12 +17,12 @@
|
||||
<p>
|
||||
<label for="model-name">Name</label>
|
||||
<input id="model-name" type="text" class="form-control" name="model-name"
|
||||
value="{{ model.name }}">
|
||||
value="{{ model.name|safe }}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="model-description">Description</label>
|
||||
<input id="model-description" type="text" class="form-control" name="model-description"
|
||||
value="{{ model.description }}">
|
||||
value="{{ model.description|safe }}">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Node -->
|
||||
<div id="edit_node_modal" class="modal" tabindex="-1">
|
||||
@@ -15,12 +16,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="node-name">Name</label>
|
||||
<input id="node-name" class="form-control" name="node-name" value="{{ node.name}}">
|
||||
<input id="node-name" class="form-control" name="node-name" value="{{ node.name|safe}}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="node-description">Description</label>
|
||||
<input id="node-description" type="text" class="form-control"
|
||||
value="{{ node.description }}"
|
||||
value="{{ node.description|safe }}"
|
||||
name="node-description">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Package -->
|
||||
<div id="edit_package_modal" class="modal" tabindex="-1">
|
||||
@@ -15,12 +16,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="package-name">Name</label>
|
||||
<input id="package-name" class="form-control" name="package-name" value="{{ package.name}}">
|
||||
<input id="package-name" class="form-control" name="package-name" value="{{ package.name|safe}}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="package-description">Description</label>
|
||||
<input id="package-description" type="text" class="form-control"
|
||||
value="{{ package.description }}"
|
||||
value="{{ package.description|safe }}"
|
||||
name="package-description">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Package Permission -->
|
||||
<div id="edit_package_permissions_modal" class="modal" tabindex="-1">
|
||||
@@ -46,7 +47,7 @@
|
||||
{% endfor %}
|
||||
<option disabled>Groups</option>
|
||||
{% for g in groups %}
|
||||
<option value="{{ g.url }}">{{ g.name }}</option>
|
||||
<option value="{{ g.url }}">{{ g.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
@@ -100,7 +101,7 @@
|
||||
accept-charset="UTF-8" action="" data-remote="true" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="col-xs-4">
|
||||
{{ gp.group.name }}
|
||||
{{ gp.group.name|safe }}
|
||||
<input type="hidden" name="grantee" value="{{ gp.group.url }}"/>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Pathway -->
|
||||
<div id="edit_pathway_modal" class="modal" tabindex="-1">
|
||||
@@ -15,12 +16,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="pathway-name">Name</label>
|
||||
<input id="pathway-name" class="form-control" name="pathway-name" value="{{ pathway.name }}">
|
||||
<input id="pathway-name" class="form-control" name="pathway-name" value="{{ pathway.name|safe }}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="pathway-description">Description</label>
|
||||
<textarea id="pathway-description" type="text" class="form-control" name="pathway-description"
|
||||
rows="10">{{ pathway.description }}</textarea>
|
||||
rows="10">{{ pathway.description|safe }}</textarea>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<td colspan="2">
|
||||
<select id="model" name="model" class="form-control" data-width='100%'>
|
||||
{% for m in models %}
|
||||
<option value="{{ m.id }}" {% if user.prediction_settings.model.url == m.url %}selected{% endif %}>{{ m.name }}</option>
|
||||
<option value="{{ m.id }}" {% if user.prediction_settings.model.url == m.url %}selected{% endif %}>{{ m.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Reaction -->
|
||||
<div id="edit_reaction_modal" class="modal" tabindex="-1">
|
||||
@@ -14,12 +15,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="reaction-name">Name</label>
|
||||
<input id="reaction-name" class="form-control" name="reaction-name" value="{{ reaction.name }}">
|
||||
<input id="reaction-name" class="form-control" name="reaction-name" value="{{ reaction.name|safe }}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="reaction-description">Description</label>
|
||||
<input id="reaction-description" type="text" class="form-control"
|
||||
value="{{ reaction.description }}" name="reaction-description">
|
||||
value="{{ reaction.description|safe }}" name="reaction-description">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit Rule -->
|
||||
<div id="edit_rule_modal" class="modal" tabindex="-1">
|
||||
@@ -14,12 +15,12 @@
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<label for="rule-name">Name</label>
|
||||
<input id="rule-name" class="form-control" name="rule-name" value="{{ rule.name }}">
|
||||
<input id="rule-name" class="form-control" name="rule-name" value="{{ rule.name|safe }}">
|
||||
</p>
|
||||
<p>
|
||||
<label for="rule-description">Description</label>
|
||||
<input id="rule-description" type="text" class="form-control"
|
||||
value="{{ rule.description }}" name="rule-description">
|
||||
value="{{ rule.description|safe }}" name="rule-description">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Edit User -->
|
||||
<div id="edit_user_modal" class="modal" tabindex="-1">
|
||||
@@ -18,7 +19,7 @@
|
||||
<select id="default-package" name="default-package" class="form-control" data-width='100%'>
|
||||
<option disabled>Select a Package</option>
|
||||
{% for p in meta.writeable_packages %}
|
||||
<option value="{{ p.url }}" {% if p.id == meta.user.default_package.id %}selected{% endif %}>{{ p.name }}</option>
|
||||
<option value="{{ p.url }}" {% if p.id == meta.user.default_package.id %}selected{% endif %}>{{ p.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
@@ -27,7 +28,7 @@
|
||||
<select id="default-group" name="default-group" class="form-control" data-width='100%'>
|
||||
<option disabled>Select a Group</option>
|
||||
{% for g in meta.available_groups %}
|
||||
<option value="{{ g.url }}" {% if g.id == meta.user.default_group.id %}selected{% endif %}>{{ g.name }}</option>
|
||||
<option value="{{ g.url }}" {% if g.id == meta.user.default_group.id %}selected{% endif %}>{{ g.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
@@ -36,7 +37,7 @@
|
||||
<select id="default-prediction-setting" name="default-prediction-setting" class="form-control" data-width='100%'>
|
||||
<option disabled>Select a Setting</option>
|
||||
{% for s in meta.available_settings %}
|
||||
<option value="{{ s.url }}" {% if s.id == meta.user.default_setting.id %}selected{% endif %}>{{ s.name }}</option>
|
||||
<option value="{{ s.url }}" {% if s.id == meta.user.default_setting.id %}selected{% endif %}>{{ s.name|safe }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
<div class="modal fade" tabindex="-1" id="evaluate_model_modal" role="dialog" aria-labelledby="evaluate_model_modal"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
@@ -17,25 +18,34 @@
|
||||
For evaluation, you need to select the packages you want to use.
|
||||
While the model is evaluating, you can use the model for predictions.
|
||||
</div>
|
||||
<!-- Evaluation -->
|
||||
<label for="relative-reasoning-evaluation-packages">Evaluation Packages</label>
|
||||
<select id="relative-reasoning-evaluation-packages" name=relative-reasoning-evaluation-packages"
|
||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||
<!-- Evaluation Packages -->
|
||||
<label for="model-evaluation-packages">Evaluation Packages</label>
|
||||
<select id="model-evaluation-packages" name="model-evaluation-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>
|
||||
<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 }}</option>
|
||||
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="hidden" name="hidden" value="evaluate">
|
||||
|
||||
<!-- Eval Type -->
|
||||
<label for="model-evaluation-type">Evaluation Type</label>
|
||||
<select id="model-evaluation-type" name="model-evaluation-type" class="form-control">
|
||||
<option disabled selected>Select evaluation type</option>
|
||||
<option value="sg">Single Generation</option>
|
||||
<option value="mg">Multiple Generations</option>
|
||||
</select>
|
||||
|
||||
<input type="hidden" name="hidden" value="evaluate">
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -50,7 +60,7 @@
|
||||
|
||||
$(function () {
|
||||
|
||||
$("#relative-reasoning-evaluation-packages").selectpicker();
|
||||
$("#model-evaluation-packages").selectpicker();
|
||||
|
||||
$('#evaluate_model_form_submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Copy Object -->
|
||||
<div id="generic_copy_object_modal" class="modal" tabindex="-1">
|
||||
@@ -18,11 +19,13 @@
|
||||
data-width='100%'>
|
||||
<option disabled selected>Select Target Package</option>
|
||||
{% for p in meta.writeable_packages %}
|
||||
<option value="{{ p.url }}">{{ p.name }}</option>`
|
||||
<option value="{{ p.url }}">{{ p.name|safe }}</option>`
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="hidden" name="hidden" value="copy">
|
||||
</form>
|
||||
<div id="copy-object-error-message" class="alert alert-danger" role="alert" style="display: none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
@@ -38,6 +41,7 @@
|
||||
|
||||
$('#generic-copy-object-modal-form-submit').click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#copy-object-error-message').hide()
|
||||
|
||||
const packageUrl = $('#target-package').find(":selected").val();
|
||||
|
||||
@@ -49,12 +53,22 @@
|
||||
object_to_copy: '{{ current_object.url }}',
|
||||
}
|
||||
|
||||
$.post(packageUrl, formData, function (response) {
|
||||
if (response.success) {
|
||||
window.location.href = response.success;
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
data: formData,
|
||||
url: packageUrl,
|
||||
success: function (data, textStatus) {
|
||||
window.location.href = data.success;
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
if (jqXHR.responseJSON.error.indexOf('to the same package') > -1) {
|
||||
$('#copy-object-error-message').append('<p>The target Package is the same as the source Package. Please select another target!</p>');
|
||||
} else {
|
||||
$('#copy-object-error-message').append('<p>' + jqXHR.responseJSON.error + '</p>');
|
||||
}
|
||||
$('#copy-object-error-message').show();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
{% load static %}
|
||||
|
||||
<style>
|
||||
.alias-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 4px 6px;
|
||||
cursor: text;
|
||||
min-height: 38px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.alias {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
background-color: #5bc0de;
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
margin: 3px 3px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.alias .remove {
|
||||
margin-left: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.alias-input {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
border: none;
|
||||
outline: none;
|
||||
margin: 3px 3px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-control.alias-container {
|
||||
height: auto;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="modal fade bs-modal-lg" id="set_aliases_modal" tabindex="-1" aria-labelledby="set_aliases_modal"
|
||||
aria-modal="true" role="dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Set Aliases for {{ current_object.name|safe }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="set_aliases_modal_form" accept-charset="UTF-8" action="{{ current_object.url }}"
|
||||
data-remote="true" method="post">
|
||||
{% csrf_token %}
|
||||
<label for="alias-input">Aliases:</label>
|
||||
<div class="form-control alias-container" id="alias-box">
|
||||
{% for alias in current_object.aliases %}
|
||||
<span class="alias">{{ alias|escape }}<span class="remove">×</span></span>
|
||||
{% endfor %}
|
||||
<input type="text" id="alias-input" class="alias-input" placeholder="Add Alias...">
|
||||
</div>
|
||||
</form>
|
||||
<div id="add-alias-error-message" class="alert alert-danger" role="alert" style="display: none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary pull-left" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="set_aliases_modal_form_submit">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
function addAlias(aliasText) {
|
||||
aliasText = aliasText.trim();
|
||||
if (aliasText === '') return;
|
||||
|
||||
// Avoid duplicate aliass
|
||||
var exists = false;
|
||||
$('#alias-box .alias').each(function () {
|
||||
if ($(this).text().replace('×', '').trim().toLowerCase() === aliasText.toLowerCase()) {
|
||||
exists = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!exists) {
|
||||
var aliasHtml = '<span class="alias">' + $('<div>').text(aliasText).html() +
|
||||
'<span class="remove">×</span></span>';
|
||||
$(aliasHtml).insertBefore('#alias-input');
|
||||
}
|
||||
|
||||
$('#alias-input').val('');
|
||||
}
|
||||
|
||||
// Add alias when Enter is pressed
|
||||
$('#alias-input').on('keypress', function (e) {
|
||||
if (e.which === 13) {
|
||||
e.preventDefault();
|
||||
addAlias($(this).val());
|
||||
}
|
||||
});
|
||||
|
||||
// Add alias when input loses focus
|
||||
$('#alias-input').on('blur', function () {
|
||||
var val = $(this).val();
|
||||
if (val.trim() !== '') {
|
||||
addAlias(val);
|
||||
}
|
||||
});
|
||||
|
||||
// Remove alias when clicking ×
|
||||
$('#alias-box').on('click', '.remove', function () {
|
||||
$(this).closest('.alias').remove();
|
||||
});
|
||||
|
||||
// Focus input when clicking the container
|
||||
$('#alias-box').on('click', function () {
|
||||
$('#alias-input').focus();
|
||||
});
|
||||
|
||||
|
||||
$('#set_aliases_modal_form_submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let aliases = [];
|
||||
$('#alias-box .alias').each(function () {
|
||||
aliases.push($(this).text().replace('×', '').trim())
|
||||
});
|
||||
|
||||
if (aliases.length === 0) {
|
||||
// Set empty string for deletion of all aliases
|
||||
// If empty list is sent, its gets removed entirely from post data
|
||||
aliases = ['']
|
||||
}
|
||||
|
||||
formData = {
|
||||
'aliases': aliases
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
data: formData,
|
||||
url: '{{ current_object.url }}',
|
||||
traditional: true,
|
||||
success: function (data, textStatus) {
|
||||
window.location.href = data.success;
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
$('#add-alias-error-message').append('<p>Setting aliases failed!</p>');
|
||||
$('#add-alias-error-message').show(); }
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
{% load static %}
|
||||
<!-- Delete Object -->
|
||||
<div id="generic_set_external_reference_modal" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Add External References</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="generic-set-external-reference-modal-form" accept-charset="UTF-8"
|
||||
action="{{ current_object.url }}"
|
||||
data-remote="true" method="post">
|
||||
{% csrf_token %}
|
||||
<label for="database-select">Select the Database you want to attach an External Reference
|
||||
for</label>
|
||||
<select id="database-select" name="selected-database" data-actions-box='true' class="form-control"
|
||||
data-width='100%'>
|
||||
<option disabled selected>Select Database</option>
|
||||
{% for entity, databases in meta.external_databases.items %}
|
||||
{% if entity == object_type %}
|
||||
{% for db in databases %}
|
||||
<option id="db-select-{{ db.database.pk }}" data-input-placeholder="{{ db.placeholder }}"
|
||||
value="{{ db.database.id }}">{{ db.database.name|safe }}</option>`
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p></p>
|
||||
<div id="input-div" style="display: none">
|
||||
<label for="identifier" >The reference</label>
|
||||
<input type="text" id="identifier" name="identifier" class="form-control" placeholder="">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="generic-set-external-reference-modal-form-submit">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
$("#database-select").on("change", function () {
|
||||
let selected = $(this).val();
|
||||
$("#identifier").attr("placeholder", $('#db-select-' + selected).data('input-placeholder'));
|
||||
$("#input-div").show();
|
||||
});
|
||||
|
||||
$('#generic-set-external-reference-modal-form-submit').click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#generic-set-external-reference-modal-form').submit();
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{% load static %}
|
||||
<div class="modal fade bs-modal-lg" id="set_scenario_modal" tabindex="-1" aria-labelledby="set_scenario_modal"
|
||||
aria-modal="true" role="dialog">
|
||||
@@ -7,7 +8,7 @@
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">Set Scenarios for {{ current_object.name }}</h4>
|
||||
<h4 class="modal-title">Set Scenarios for {{ current_object.name|safe }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="loading_scenario_div" class="text-center"></div>
|
||||
@@ -18,6 +19,7 @@
|
||||
<select id="scenario-select" name="selected-scenarios" data-actions-box='true' class="form-control"
|
||||
multiple data-width='100%'>
|
||||
<option disabled>Select Scenarios</option>
|
||||
<option value="" hidden></option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
@@ -64,6 +66,9 @@
|
||||
|
||||
$('#set_scenario_modal_form_submit').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
if ($('#scenario-select').val().length == 0) {
|
||||
$('#scenario-select').val("")
|
||||
}
|
||||
$('#set_scenario_modal_form').submit();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{% load static %}
|
||||
<!-- Identify Missing Rules -->
|
||||
<div id="identify_missing_rules_modal" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Identify Missing Rules</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
By clicking on Download we'll search the Pathway for Reactions that are not backed by
|
||||
a Rule or which can be assembled by chaining two rules.
|
||||
<form id="identify-missing-rules-modal-form" accept-charset="UTF-8" action="{{ pathway.url }}"
|
||||
data-remote="true" method="GET">
|
||||
<label for="rule-package">Select the Rule Package</label>
|
||||
<select id="rule-package" name="rule-package" data-actions-box='true' class="form-control"
|
||||
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>
|
||||
<input type="hidden" name="identify-missing-rules" value="true"/>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="identify-missing-rules-modal-submit">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
$('#identify-missing-rules-modal-submit').click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#identify-missing-rules-modal-form').submit();
|
||||
$('#identify_missing_rules_modal').modal('hide');
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
<div class="modal fade"
|
||||
tabindex="-1"
|
||||
id="manage_api_token_modal"
|
||||
@@ -41,7 +42,7 @@
|
||||
<div class="input-group">
|
||||
<input type="hidden" name="hidden" value="delete">
|
||||
<input type="hidden" name="token-id" value="{{ t.pk }}">
|
||||
<input type="text" class="form-control" value="{{ t.name }}" disabled>
|
||||
<input type="text" class="form-control" value="{{ t.name|safe }}" disabled>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</span>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<option disabled>Select a Setting</option>
|
||||
{% for s in meta.available_settings %}
|
||||
<option value="{{ s.url }}"{% if s.id == meta.user.default_setting.id %}selected{% endif %}>
|
||||
{{ s.name }}{% if s.id == meta.user.default_setting.id %} <i>(User default)</i>{% endif %}
|
||||
{{ s.name|safe }}{% if s.id == meta.user.default_setting.id %} <i>(User default)</i>{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
@@ -2,17 +2,18 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% include "modals/objects/edit_rule_modal.html" %}
|
||||
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||
{% include "modals/objects/generic_copy_object_modal.html" %}
|
||||
{% include "modals/objects/generic_delete_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
{% block action_modals %}
|
||||
{% include "modals/objects/edit_rule_modal.html" %}
|
||||
{% include "modals/objects/generic_set_aliases_modal.html" %}
|
||||
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||
{% include "modals/objects/generic_copy_object_modal.html" %}
|
||||
{% include "modals/objects/generic_delete_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
<div class="panel-group" id="rule-detail">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||
{{ rule.name }}
|
||||
{{ rule.name|safe }}
|
||||
<div id="actionsButton"
|
||||
style="float: right;font-weight: normal;font-size: medium;position: relative; top: 50%; transform: translateY(-50%);z-index:100;display: none;"
|
||||
class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||
@@ -28,10 +29,27 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
{{ rule.description }}
|
||||
{{ rule.description|safe }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if rule.aliases %}
|
||||
<!-- Aliases -->
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
<a id="rule-aliases-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||
href="#rule-aliases">Aliases</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="rule-aliases" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item">
|
||||
{% for alias in rule.aliases %}
|
||||
<a class="list-group-item">{{ alias }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Reaction Patterns -->
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
@@ -42,7 +60,7 @@
|
||||
<div id="rule-reaction-patterns" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item">
|
||||
{% for r in rule.srs %}
|
||||
<a class="list-group-item" href="{{ r.url }}">{{ r.name }}</a>
|
||||
<a class="list-group-item" href="{{ r.url }}">{{ r.name|safe }}</a>
|
||||
<div align="center">
|
||||
<p>
|
||||
{{r.as_svg|safe}}
|
||||
@@ -63,25 +81,47 @@
|
||||
<div id="rule-scenario" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item">
|
||||
{% for s in rule.scenarios.all %}
|
||||
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||
<a class="list-group-item" href="{{ s.url }}">{{ s.name|safe }} <i>({{ s.package.name|safe }})</i></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- EC Numbers -->
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
<a id="rule-ec-numbers-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||
href="#rule-ec-numbers">EC Numbers</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="rule-ec-numbers" class="panel-collapse collapse">
|
||||
<div class="panel-body list-group-item">
|
||||
|
||||
{% if rule.enzymelinks %}
|
||||
<!-- EC Numbers -->
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
<a id="rule-ec-numbers-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||
href="#rule-ec-numbers">EC Numbers</a>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rule-ec-numbers" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item">
|
||||
{% for k, v in rule.get_grouped_enzymelinks.items %}
|
||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||
<h4 class="panel-title">
|
||||
<a id="{{ k|slugify }}_Link" data-toggle="collapse"
|
||||
data-parent="#{{ k|slugify }}_Accordion"
|
||||
href="#{{ k|slugify }}">
|
||||
{{ k }}
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="{{ k|slugify }}" class="panel-collapse collapse in">
|
||||
<div class="panel-body list-group-item">
|
||||
{% for enzyme in v %}
|
||||
<a class="list-group-item" href="{{ enzyme.url }}">
|
||||
{{ enzyme.ec_number }}
|
||||
<div style="position:absolute;bottom:10px;left:100px;">{{ enzyme.name }}</div>
|
||||
<div style="float:right;">{{ enzyme.linking_method }}</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user