1 Commits

Author SHA1 Message Date
1282b81d9d adjusted migration
Some checks failed
API CI / api-tests (pull_request) Failing after 17s
CI / test (pull_request) Failing after 23s
Initial bayer app

Show Pack Classification

Adjusted docker compose to bayer specifics

Adjusted Dockerfile for Bayer

Adding secret flags to group, add secret pools to packages

Adjusted View for Package creation

Prep configs, added Package Create Modal

wip

More on PES

wip

wip

Wip

minor

PW interactions

API PES

wip

Make Select Widget reflect required

make required generallay available

Update UI if pathway mode is set to build

Added ais

circle adjustments

Initial Zoom, fix AD Creation

wip

auth log, bb4g fix

missing import

Added viz hint if PES is part of reaction

Add Edge check for pes

flip boolean

...

pes

Added extra

...

In / Out Edges Viz, Submitting Button Text

...
2026-07-02 10:37:13 +02:00
22551 changed files with 2192635 additions and 3350 deletions

View File

@ -7,10 +7,10 @@ repos:
- id: trailing-whitespace
exclude: epiuclid/schemas/
- id: end-of-file-fixer
exclude: ^epiuclid/schemas/|^static/js/ketcher3/
exclude: epiuclid/schemas/
- id: check-yaml
- id: check-added-large-files
exclude: ^static/images/|^epiuclid/schemas/|^fixtures/|^static/js/ketcher3/
exclude: ^static/images/|^epiuclid/schemas/|^fixtures/
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.13.3

View File

@ -185,7 +185,7 @@ class PESStructure(CompoundStructure):
def create(
compound: Compound,
pes_link: str,
molfile: str,
mol_file: str,
smiles: str,
name: str = None,
description: str = None,
@ -204,7 +204,7 @@ class PESStructure(CompoundStructure):
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
cs.smiles = smiles
cs.molfile = molfile
cs.mol_file = mol_file
cs.pes_link = pes_link
cs.compound = compound

View File

@ -3,11 +3,7 @@
<div class="collapse-arrow bg-base-200 collapse">
<input type="checkbox" checked />
<div class="collapse-title text-xl font-medium">Link to PES</div>
<div class="collapse-content">
<p>
<a href="{{ compound_structure.pes_link }}" class="hover:bg-base-200">{{ compound_structure.pes_link }}</a>
</p>
</div>
<div class="collapse-content">{{ compound_structure.pes_link }}</div>
</div>
<!-- Image Representation -->

View File

@ -3,11 +3,7 @@
<div class="collapse-arrow bg-base-200 collapse">
<input type="checkbox" checked />
<div class="collapse-title text-xl font-medium">Link to PES</div>
<div class="collapse-content">
<p>
<a href="{{ compound.default_structure.pes_link }}" class="hover:bg-base-200">{{ compound.default_structure.pes_link }}</a>
</p>
</div>
<div class="collapse-content">{{ compound.default_structure.pes_link }}</div>
</div>
<!-- Image Representation -->

View File

@ -3,11 +3,7 @@
<div class="collapse-arrow bg-base-200 collapse">
<input type="checkbox" checked />
<div class="collapse-title text-xl font-medium">Link to PES</div>
<div class="collapse-content">
<p>
<a href="{{ node.default_node_label.pes_link }}" class="hover:bg-base-200">{{ node.default_node_label.pes_link }}</a>
</p>
</div>
<div class="collapse-content">{{ node.default_node_label.pes_link }}</div>
</div>
<!-- Image Representation -->

View File

@ -4,7 +4,6 @@
{% block action_modals %}
{% include "modals/objects/edit_package_modal.html" %}
{% include "modals/objects/view_package_permissions_modal.html" %}
{% include "modals/objects/edit_package_permissions_modal.html" %}
{% include "modals/objects/publish_package_modal.html" %}
{% include "modals/objects/set_license_modal.html" %}

View File

@ -1,23 +1,20 @@
import base64
import logging
import requests
from django.conf import settings as s
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed
from django.core.exceptions import BadRequest
from django.http import HttpResponse
from django.shortcuts import redirect
from bayer.models import PESCompound
from epdb.logic import PackageManager
from epdb.models import Pathway, Node
from epdb.views import _anonymous_or_real, error
from epdb.views import _anonymous_or_real
from utilities.decorators import package_permission_required
Package = s.GET_PACKAGE_MODEL()
logger = logging.getLogger(__name__)
@package_permission_required()
def create_pes(request, package_uuid):
current_user = _anonymous_or_real(request)
@ -26,11 +23,7 @@ def create_pes(request, package_uuid):
if request.method == "POST":
if current_package.classification_level == Package.Classification.INTERNAL:
return error(
request,
f'Creation of PESs for package {current_package.name} failed!',
"Creating PESs for internal packages is not allowed.",
)
raise BadRequest("Cannot create PESs for internal packages.")
compound_name = request.POST.get('compound-name')
compound_description = request.POST.get('compound-description')
@ -40,41 +33,27 @@ def create_pes(request, package_uuid):
try:
pes_data = fetch_pes(request, pes_link)
except ValueError as e:
return error(
request,
"Could not fetch PES",
f"Could not fetch PES data for {pes_link}"
)
return BadRequest(f"Could not fetch PES data for {pes_link}")
classification = pes_data.get("classificationLevel", "")
if "secret" == classification.lower():
if current_package.classification_level != Package.Classification.SECRET:
return error(
request,
"Classification Mismatch!",
"Cannot create secret PESs in non-secret packages."
)
return BadRequest("Cannot create PESs for non-secret packages.")
if not current_package.data_pool or not current_package.data_pool.secret:
logger.info(f"The current package does not have a secret data pool.")
return error(
request,
"The current package does not have a secret data pool.",
"Cannot create secret PESs in package without a secret data pool."
)
data_pools = pes_data.get("dataPools")
if data_pools:
if s.DATA_POOL_MAPPING[current_package.data_pool.name] not in data_pools:
return BadRequest(
f"PES data pool {s.DATA_POOL_MAPPING[current_package.data_pool.name]} not found in PES data")
pes = PESCompound.create(current_package, pes_data, compound_name, compound_description)
return redirect(pes.url)
else:
return error(
request,
"No PES link received",
"Please provide a PES link."
)
return BadRequest("Please provide a PES link.")
else:
return HttpResponseNotAllowed(["POST"])
pass
@package_permission_required()
@ -86,11 +65,7 @@ def create_pes_node(request, package_uuid, pathway_uuid):
if request.method == "POST":
if current_package.classification_level == Package.Classification.INTERNAL:
return error(
request,
f'Creation of PESs for package {current_package.name} failed!',
"Creating PESs for internal packages is not allowed.",
)
raise BadRequest("Cannot create PESs for internal packages.")
compound_name = request.POST.get('compound-name')
compound_description = request.POST.get('compound-description')
@ -100,37 +75,23 @@ def create_pes_node(request, package_uuid, pathway_uuid):
try:
pes_data = fetch_pes(request, pes_link)
except ValueError as e:
return error(
request,
"Could not fetch PES",
f"Could not fetch PES data for {pes_link}"
)
return BadRequest(f"Could not fetch PES data for {pes_link}")
classification = pes_data.get("classificationLevel", "")
if "secret" == classification.lower():
if current_package.classification_level != Package.Classification.SECRET:
return error(
request,
"Classification Mismatch!",
"Cannot create secret PESs in non-secret packages."
)
return BadRequest("Cannot create PESs for non-secret packages.")
if not current_package.data_pool or not current_package.data_pool.secret:
logger.info(f"The current package does not have a secret data pool.")
return error(
request,
"The current package does not have a secret data pool.",
"Cannot create secret PESs in package without a secret data pool."
)
data_pools = pes_data.get("dataPools")
if data_pools:
if s.DATA_POOL_MAPPING[current_package.data_pool.name] not in data_pools:
return BadRequest(
f"PES data pool {s.DATA_POOL_MAPPING[current_package.data_pool.name]} not found in PES data")
pes = PESCompound.create(current_package, pes_data, compound_name, compound_description)
node_qs = Node.objects.filter(
pathway=current_pathway,
default_node_label=pes.default_structure
)
node_qs = Node.objects.filter(pathway=current_pathway, default_node_label=pes.default_structure)
if node_qs.exists():
return redirect(current_pathway.url)
@ -148,13 +109,9 @@ def create_pes_node(request, package_uuid, pathway_uuid):
return redirect(current_pathway.url)
else:
return error(
request,
"No PES link received",
"Please provide a PES link."
)
return BadRequest("Please provide a PES link.")
else:
return HttpResponseNotAllowed(["POST"])
pass
def fetch_pes(request, pes_url) -> dict:

View File

@ -117,28 +117,25 @@ class APIPermissionTestBase(TestCase):
# Create test compounds in each package
cls.reviewed_compound = Compound.create(
cls.reviewed_package, "C", name="Reviewed Compound", description="Test compound"
cls.reviewed_package, "C", "Reviewed Compound", "Test compound"
)
cls.owned_compound = Compound.create(
cls.unreviewed_package_owned, "CC", name="Owned Compound", description="Test compound"
cls.unreviewed_package_owned, "CC", "Owned Compound", "Test compound"
)
cls.read_compound = Compound.create(
cls.unreviewed_package_read, "CCC", name="Read Compound", description="Test compound"
cls.unreviewed_package_read, "CCC", "Read Compound", "Test compound"
)
cls.write_compound = Compound.create(
cls.unreviewed_package_write, "CCCC", name="Write Compound", description="Test compound"
cls.unreviewed_package_write, "CCCC", "Write Compound", "Test compound"
)
cls.all_compound = Compound.create(
cls.unreviewed_package_all, "CCCCC", name="All Compound", description="Test compound"
cls.unreviewed_package_all, "CCCCC", "All Compound", "Test compound"
)
cls.no_access_compound = Compound.create(
cls.unreviewed_package_no_access,
"CCCCCC",
name="No Access Compound",
description="Test compound",
cls.unreviewed_package_no_access, "CCCCCC", "No Access Compound", "Test compound"
)
cls.group_compound = Compound.create(
cls.group_package, "CCCCCCC", name="Group Compound", description="Test compound"
cls.group_package, "CCCCCCC", "Group Compound", "Test compound"
)

View File

@ -294,8 +294,8 @@ class CompoundPaginationAPITest(BaseTestAPIGetPaginated, TestCase):
return Compound.create(
package,
smiles,
name=f"Reviewed Compound {idx:03d}",
description="Compound for pagination tests",
f"Reviewed Compound {idx:03d}",
"Compound for pagination tests",
)
@classmethod
@ -305,8 +305,8 @@ class CompoundPaginationAPITest(BaseTestAPIGetPaginated, TestCase):
return Compound.create(
package,
smiles,
name=f"Draft Compound {idx:03d}",
description="Compound for pagination tests",
f"Draft Compound {idx:03d}",
"Compound for pagination tests",
)

View File

@ -9,8 +9,8 @@ from envipy_additional_information import registry
from envipy_additional_information.groups import GroupEnum
from epapi.utils.schema_transformers import build_rjsf_output
from epapi.utils.validation_errors import handle_validation_error
from epdb.models import AdditionalInformation, Scenario, Node
from ..dal import get_scenario_for_read, get_scenario_for_write, get_package_for_write
from epdb.models import AdditionalInformation
from ..dal import get_scenario_for_read, get_scenario_for_write
logger = logging.getLogger(__name__)
@ -58,61 +58,6 @@ def list_scenario_info(request, scenario_uuid: UUID):
return result
@router.post("/information/{model_name}/")
def add_object_info(request, model_name: str, payload: Dict[str, Any] = Body(...)):
from epdb.views import EPDBURLParser
cls = registry.get_model(model_name.lower())
if not cls:
raise HttpError(404, f"Unknown model: {model_name}")
try:
instance = cls(**payload) # Pydantic validates
except ValidationError as e:
handle_validation_error(e)
if "attach_obj_url" in payload:
url_parser = EPDBURLParser(payload["attach_obj_url"])
if url_parser.contains_package_url():
package = get_package_for_write(request.user, url_parser.get_objects()[0].uuid)
attach_obj = url_parser.get_object()
if "scenario_uuid" in payload:
scenario = get_scenario_for_read(request.user, payload["scenario_uuid"])
else:
scenario = Scenario.create(
package,
name=f"Scenario {Scenario.objects.filter(package=package).count() + 1}",
description="no description",
scenario_date=None,
scenario_type=None,
additional_information=[],
)
if isinstance(attach_obj, Node):
ai = add_info_to_node(package, instance, scenario, attach_obj)
else:
raise HttpError(404, f"Bad request - Not implemented for {type(attach_obj)}!")
return {"status": "created", "uuid": ai.uuid}
raise HttpError(404, "Bad request!")
def add_info_to_node(package, add_inf, scenario, node):
ai = AdditionalInformation.create(
package,
add_inf,
scenario=scenario,
content_object=node,
)
node.pathway.scenarios.add(scenario)
return ai
@router.post("/scenario/{uuid:scenario_uuid}/information/{model_name}/")
def add_scenario_info(
request, scenario_uuid: UUID, model_name: str, payload: Dict[str, Any] = Body(...)

View File

@ -1,10 +1,2 @@
class InvalidSMILESException(Exception):
pass
class InvalidMolfileException(Exception):
pass
class PackageImportException(Exception):
pass

View File

@ -15,7 +15,6 @@ from ninja.security import HttpBearer
from utilities.chem import FormatConverter
from utilities.misc import PackageExporter
from .logic import (
EPDBURLParser,
GroupManager,
@ -634,14 +633,9 @@ class CompoundSchema(Schema):
reviewStatus: str = Field(False, alias="review_status")
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
structures: List["CompoundStructureSchema"] = []
pesLink: str | None = Field(None, alias="pes_link")
@staticmethod
def resolve_pes_link(obj: Compound):
return getattr(obj.default_structure, "pes_link", None)
@staticmethod
def resolve_review_status(obj: Compound):
def resolve_review_status(obj: CompoundStructure):
return "reviewed" if obj.package.reviewed else "unreviewed"
@staticmethod
@ -715,7 +709,6 @@ class CompoundStructureSchema(Schema):
reviewStatus: str = Field(None, alias="review_status")
scenarios: List["SimpleScenario"] = Field([], alias="scenarios")
smiles: str = Field(None, alias="smiles")
pesLink: str | None = Field(None, alias="pes_link")
@staticmethod
def resolve_review_status(obj: CompoundStructure):
@ -851,7 +844,6 @@ def get_package_compound_structure(request, package_uuid, compound_uuid, structu
class CreateCompound(Schema):
compoundSmiles: str
compoundMolFile: str | None = None
compoundName: str | None = None
compoundDescription: str | None = None
inchi: str | None = None
@ -881,21 +873,17 @@ def create_package_compound(
if "secret" == classification.lower():
if p.classification_level != Package.Classification.SECRET:
return 400, {"message": "Cannot create secret PESs in non-secret packages."}
if not p.data_pool or not p.data_pool.secret:
return 400, {"message": "Cannot create secret PESs in package without a secret data pool."}
return 400, {"Cannot create PESs for non-secret packages."}
data_pools = pes_data.get("dataPools")
if data_pools:
if s.DATA_POOL_MAPPING[p.data_pool.name] not in data_pools:
return 400, { "messsage": f"PES data pool {s.DATA_POOL_MAPPING[p.data_pool.name]} not found in PES data"}
c = PESCompound.create(p, pes_data, c.compoundName, c.compoundDescription)
else:
c = Compound.create(
p,
c.compoundSmiles,
molfile=c.compoundMolFile,
name=c.compoundName,
description=c.compoundDescription,
inchi=c.inchi
p, c.compoundSmiles, c.compoundName, c.compoundDescription, inchi=c.inchi
)
return redirect(c.url)
except ValueError as e:
@ -1704,10 +1692,9 @@ class PathwayNode(Schema):
image: str = Field(None, alias="image")
imageSize: int = Field(None, alias="image_size")
name: str = Field(None, alias="name")
proposed: List[Dict[str, Any]] = []
proposed: List[Dict[str, str]] = Field([], alias="proposed_intermediate")
smiles: str = Field(None, alias="smiles")
pseudo: bool = Field(False, alias="pseudo")
pesLink: str | None = Field(None, alias="pes_link")
@staticmethod
def resolve_atom_count(obj: Node):
@ -1720,10 +1707,24 @@ class PathwayNode(Schema):
# TODO
return []
@staticmethod
def resolve_engineered_intermediate(obj: Node):
# TODO
return False
@staticmethod
def resolve_image(obj: Node):
return f"{obj.default_node_label.url}?image=svg"
@staticmethod
def resolve_image_size(obj: Node):
return 400
@staticmethod
def resolve_proposed_intermediate(obj: Node):
# TODO
return []
class PathwaySchema(Schema):
aliases: List[str] = Field([], alias="aliases")
@ -1974,8 +1975,7 @@ def get_package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
class CreateNode(Schema):
nodeAsSmiles: str | None = None
nodeAsMolFile: str | None = None
nodeAsSmiles: str
nodeName: str | None = None
nodeReason: str | None = None
nodeDepth: str | None = None
@ -2006,10 +2006,14 @@ def add_pathway_node(request, package_uuid, pathway_uuid, n: Form[CreateNode]):
if "secret" == classification.lower():
if p.classification_level != Package.Classification.SECRET:
return 400, {"message": "Cannot create secret PESs in non-secret packages."}
return 400, "Cannot create PESs for non-secret packages."
if not p.data_pool or not p.data_pool.secret:
return 400, {"message": "Cannot create secret PESs in package without a secret data pool."}
data_pools = pes_data.get("dataPools")
if data_pools:
if s.DATA_POOL_MAPPING[p.data_pool.name] not in data_pools:
return 400, {
"messsage": f"PES data pool {s.DATA_POOL_MAPPING[p.data_pool.name]} not found in PES data"
}
c = PESCompound.create(p, pes_data, n.nodeName, n.nodeReason)
@ -2033,14 +2037,7 @@ def add_pathway_node(request, package_uuid, pathway_uuid, n: Form[CreateNode]):
else:
node_depth = -1
node = Node.create(
pw,
n.nodeAsSmiles,
node_depth,
molfile=n.nodeAsMolFile,
name=n.nodeName,
description=n.nodeReason,
)
node = Node.create(pw, n.nodeAsSmiles, node_depth, n.nodeName, n.nodeReason)
return redirect(node.url)
except ValueError:
@ -2395,26 +2392,3 @@ def get_setting(request, setting_uuid):
return 403, {
"message": f"Getting Setting with id {setting_uuid} failed due to insufficient rights!"
}
########
# Util #
########
class NonPersistent(Schema):
smiles: str
setting_url: str = Field(..., alias="settingUri")
@router.post("/util", response={200: Any, 403: Error})
def predict(request, np: Form[NonPersistent]):
try:
from epdb.logic import SPathway
setting = SettingManager.get_setting_by_url(request.user, np.setting_url)
spw = SPathway(prediction_setting=setting, root_nodes=[np.smiles])
spw.predict()
return spw.to_json()
except ValueError:
return 403, {
"message": f"Getting Setting with id {np.setting_url} failed due to insufficient rights!"
}

View File

@ -1078,8 +1078,10 @@ class PackageManager(object):
data: Dict[str, Any],
owner: User,
preserve_uuids=False,
add_import_timestamp=True,
trust_reviewed=False,
) -> Package:
importer = PackageImporter(data, preserve_uuids)
importer = PackageImporter(data, preserve_uuids, add_import_timestamp, trust_reviewed)
imported_package = importer.do_import()
up = UserPackagePermission()
@ -1896,12 +1898,6 @@ class SPathway(object):
"to": to_indices,
}
if edge.rule:
e["rule"] = edge.rule.simple_json()
if edge.probability:
e["probability"] = edge.probability
edges.append(e)
return {

View File

@ -31,10 +31,7 @@ from sklearn.model_selection import ShuffleSplit
from bridge.contracts import Property
from bridge.dto import RunResult, PropertyPrediction
from epdb.exceptions import (
InvalidMolfileException,
InvalidSMILESException,
)
from epdb.exceptions import InvalidSMILESException
from utilities.chem import FormatConverter, IndigoUtils, PredictionResult, ProductSet
from utilities.ml import (
ApplicabilityDomainPCA,
@ -797,13 +794,6 @@ class Compound(
external_identifiers = GenericRelation("ExternalIdentifier")
def get_structure_by_smiles(self, smiles: str) -> "CompoundStructure":
for struct in self.structures.all():
if struct.smiles == smiles:
return struct
raise ValueError(f"No structure with SMILES {smiles} found for {self.get_name()}")
@property
def structures(self) -> QuerySet:
return CompoundStructure.objects.filter(compound=self)
@ -872,24 +862,8 @@ class Compound(
@staticmethod
@transaction.atomic
def create(
package: "Package",
smiles: str,
molfile: str | None = None,
name: str | None = None,
description: str | None = None,
*args,
**kwargs,
package: "Package", smiles: str, name: str = None, description: str = None, *args, **kwargs
) -> "Compound":
# Molfile has precendence over SMILES
if molfile is not None and molfile.strip() != "":
mol = FormatConverter.from_molfile(molfile)
if mol is None:
raise InvalidMolfileException("Given molfile is invalid")
else:
# Overwrite SMILES from molfile
smiles = FormatConverter.to_smiles(mol)
if smiles is None or smiles.strip() == "":
raise InvalidSMILESException("SMILES is required")
@ -922,21 +896,19 @@ class Compound(
return found_compound
qs = CompoundStructure.objects.filter(smiles=standardized_smiles, compound__package=package)
if subclasses:
qs = qs.not_instance_of(*subclasses)
# Check if we can find the standardized one
if qs.exists():
# TODO should we add a structure?
found_structure = qs.first()
found_compound = found_structure.compound
# We've only found the standardized one, create the very structure
_ = found_compound.add_structure(
smiles, molfile=molfile, name=name, description=description
)
if name:
found_structure.add_alias(name)
found_compound.add_alias(name)
return found_compound
@ -968,12 +940,7 @@ class Compound(
)
cs = CompoundStructure.create(
c,
smiles,
molfile=molfile,
name=name,
description=description,
normalized_structure=is_standardized,
c, smiles, name=name, description=description, normalized_structure=is_standardized
)
c.default_structure = cs
@ -986,22 +953,11 @@ class Compound(
self,
smiles: str,
name: str = None,
molfile: str = None,
description: str = None,
default_structure: bool = False,
*args,
**kwargs,
) -> "CompoundStructure":
# Molfile has precendence over SMILES
if molfile is not None and molfile.strip() != "":
mol = FormatConverter.from_molfile(molfile)
if mol is None:
raise InvalidMolfileException("Given molfile is invalid")
else:
# Overwrite SMILES from molfile
smiles = FormatConverter.to_smiles(mol)
if smiles is None or smiles == "":
raise ValueError("SMILES is required")
@ -1021,28 +977,16 @@ class Compound(
)
if is_standardized:
CompoundStructure.objects.get(smiles=smiles, compound__package=self.package)
CompoundStructure.objects.get(smiles__in=smiles, compound__package=self.package)
# Check if we find a direct match for a given SMILES and/or its standardized SMILES
if CompoundStructure.objects.filter(smiles=smiles, compound__package=self.package).exists():
found_cs = CompoundStructure.objects.get(smiles=smiles, compound__package=self.package)
if found_cs.molfile is None and (molfile is not None and molfile.strip() != ""):
logger.info(
f"Setting molfile for found CompoundStructure(uuid={found_cs.uuid}) as it was empty"
)
found_cs.molfile = molfile
found_cs.save()
return found_cs
if CompoundStructure.objects.filter(
smiles__in=smiles, compound__package=self.package
).exists():
return CompoundStructure.objects.get(smiles__in=smiles, compound__package=self.package)
cs = CompoundStructure.create(
self,
smiles,
name=name,
molfile=molfile,
description=description,
normalized_structure=is_standardized,
self, smiles, name=name, description=description, normalized_structure=is_standardized
)
if default_structure:
@ -1223,24 +1167,8 @@ class CompoundStructure(
@staticmethod
@transaction.atomic
def create(
compound: Compound,
smiles: str,
molfile: str = None,
name: str = None,
description: str = None,
*args,
**kwargs,
compound: Compound, smiles: str, name: str = None, description: str = None, molfile: str = None, *args, **kwargs
):
# Molfile has precendence over SMILES
if molfile is not None and molfile.strip() != "":
mol = FormatConverter.from_molfile(molfile)
if mol is None:
raise InvalidMolfileException("Given molfile is invalid")
else:
# Overwrite SMILES from molfile
smiles = FormatConverter.to_smiles(mol)
# Clean for potential XSS
if name is not None:
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
@ -1251,13 +1179,6 @@ class CompoundStructure(
if name:
found_cs.add_alias(name)
if found_cs.molfile is None and (molfile is not None and molfile.strip() != ""):
logger.info(
f"Setting molfile for found CompoundStructure(uuid={found_cs.uuid}) as it was empty"
)
found_cs.molfile = molfile
found_cs.save()
return found_cs
if compound.pk is None:
@ -1268,15 +1189,14 @@ class CompoundStructure(
if name is not None:
cs.name = name
# We have a default here only set the value if it carries some payload
if description is not None and description.strip() != "":
if description is not None:
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
cs.compound = compound
cs.smiles = smiles
cs.compound = compound
# If molfile is not None, it hase to be a valid Molfile as we've survived the parsing check
if molfile is not None:
# Check if molfile is present and valid
if molfile is not None and FormatConverter.from_molfile(molfile) is not None:
cs.molfile = molfile
if "normalized_structure" in kwargs:
@ -1652,9 +1572,6 @@ class ParallelRule(Rule):
f"Simple rule {sr.uuid} does not belong to package {package.uuid}!"
)
if name is not None:
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
# Deduplication check
query = ParallelRule.objects.annotate(
srs_count=Count("simple_rules", filter=Q(simple_rules__in=simple_rules), distinct=True)
@ -1666,19 +1583,15 @@ class ParallelRule(Rule):
if existing_rule_qs.exists():
if existing_rule_qs.count() > 1:
logger.error(
f"Found more than one ParallelRule for given input! {existing_rule_qs}"
)
found_rule = existing_rule_qs.first()
if name:
found_rule.add_alias(name)
return found_rule
logger.error(f"Found more than one reaction for given input! {existing_rule_qs}")
return existing_rule_qs.first()
r = ParallelRule()
r.package = package
if name is not None:
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if name is None or name == "":
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
@ -1774,6 +1687,7 @@ class Reaction(
rules: Union[Rule | List[Rule]] = None,
multi_step: bool = False,
):
# Clean for potential XSS
if name is not None and name.strip() != "":
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
@ -1843,9 +1757,7 @@ class Reaction(
r = Reaction()
r.package = package
if name is None or name == "":
name = f"Reaction {Reaction.objects.filter(package=package).count() + 1}"
if r is not None:
r.name = name
if description is not None and description.strip() != "":
@ -2082,7 +1994,6 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
# add links start -> pseudo
new_link = {
"name": link["name"],
"plain_name": link["plain_name"],
"id": link["id"],
"url": link["url"],
"image": link["image"],
@ -2092,7 +2003,6 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
"source": node_url_to_idx[link["start_node_urls"][0]],
"target": pseudo_idx,
"app_domain": link.get("app_domain", None),
"to_pseudo": True,
}
adjusted_links.append(new_link)
@ -2100,7 +2010,6 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
for target in link["end_node_urls"]:
new_link = {
"name": link["name"],
"plain_name": link["plain_name"],
"id": link["id"],
"url": link["url"],
"image": link["image"],
@ -2111,7 +2020,6 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
"target": node_url_to_idx[target],
"app_domain": link.get("app_domain", None),
"multi_step": link["multi_step"],
"from_pseudo": True,
}
adjusted_links.append(new_link)
@ -2321,12 +2229,11 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
def add_node(
self,
smiles: str,
molfile: str | None = None,
name: str | None = None,
description: str | None = None,
depth: int = -1,
name: Optional[str] = None,
description: Optional[str] = None,
depth: Optional[int] = -1,
):
return Node.create(self, smiles, depth, molfile=molfile, name=name, description=description)
return Node.create(self, smiles, depth, name=name, description=description)
@transaction.atomic
def add_edge(
@ -2422,19 +2329,17 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
def _url(self):
return "{}/node/{}".format(self.pathway.url, self.uuid)
def get_name(self, include_suffix=True):
def get_name(self):
non_generic_name = True
if self.name is None or self.name == "no name":
if self.name == "no name":
non_generic_name = False
if non_generic_name:
return self.name
else:
if include_suffix:
return f"{self.default_node_label.name} (taken from underlying structure)"
else:
return self.default_node_label.name
return (
self.name
if non_generic_name
else f"{self.default_node_label.name} (taken from underlying structure)"
)
def d3_json(self):
app_domain_data = self.get_app_domain_assessment_data()
@ -2464,9 +2369,8 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
),
"image_type": "svg",
"name": self.get_name(),
"plain_name": self.get_name(include_suffix=False),
"smiles": self.default_node_label.smiles,
"scenarios": [{"name": s.get_name(), "url": s.url} for s in self.get_scenarios()],
"scenarios": [{"name": s.get_name(), "url": s.url} for s in self.scenarios.all()],
"app_domain": {
"inside_app_domain": app_domain_data["assessment"]["inside_app_domain"]
if app_domain_data
@ -2475,7 +2379,6 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
},
"predicted_properties": predicted_properties,
"is_engineered_intermediate": self.kv.get("is_engineered_intermediate", False),
"proposed": self.get_proposed_info(),
"timeseries": self.get_timeseries_data(),
**structure_data,
}
@ -2488,43 +2391,28 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
pathway: "Pathway",
smiles: str,
depth: int,
molfile: str | None = None,
name: str | None = None,
description: str | None = None,
name: Optional[str] = None,
description: Optional[str] = None,
):
# Molfile has precendence over SMILES
if molfile is not None and molfile.strip() != "":
mol = FormatConverter.from_molfile(molfile)
if mol is None:
raise InvalidMolfileException("Given molfile is invalid")
else:
# Overwrite SMILES from molfile
smiles = FormatConverter.to_smiles(mol)
stereo_removed = False
if pathway.predicted and FormatConverter.has_stereo(smiles):
smiles = FormatConverter.standardize(smiles, remove_stereo=True)
stereo_removed = True
c = Compound.create(
pathway.package, smiles, molfile=molfile, name=name, description=description
)
c = Compound.create(pathway.package, smiles, name=name, description=description)
structure = c.get_structure_by_smiles(smiles)
if Node.objects.filter(pathway=pathway, default_node_label=structure).exists():
return Node.objects.get(pathway=pathway, default_node_label=structure)
if Node.objects.filter(pathway=pathway, default_node_label=c.default_structure).exists():
return Node.objects.get(pathway=pathway, default_node_label=c.default_structure)
n = Node()
n.stereo_removed = stereo_removed
n.pathway = pathway
n.depth = depth
n.default_node_label = structure
n.default_node_label = c.default_structure
n.save()
n.node_labels.add(structure)
n.node_labels.add(c.default_structure)
n.save()
return n
@ -2572,37 +2460,6 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
return res
def get_proposed_info(self):
collected = defaultdict(dict)
for ai in self.additional_information.filter(
type__in=["ProposedIntermediate", "TransformationProductImportance", "Confidence"],
scenario__isnull=False,
):
collected[str(ai.scenario.uuid)]["scenarioId"] = ai.scenario.url
collected[str(ai.scenario.uuid)]["scenarioName"] = ai.scenario.name
if ai.type == "ProposedIntermediate":
collected[str(ai.scenario.uuid)]["proposed"] = True
if ai.type == "Confidence":
collected[str(ai.scenario.uuid)]["Confidence"] = ai.get().level
if ai.type == "TransformationProductImportance":
collected[str(ai.scenario.uuid)]["Transformation product importance"] = (
ai.get().importance.value
)
return list(collected.values())
def get_scenarios(self):
qs = self.scenarios.all()
qs |= Scenario.objects.filter(
id__in=self.additional_information.filter(scenario__isnull=False)
.values_list("scenario", flat=True)
.distinct()
)
return qs.distinct()
class Edge(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin):
pathway = models.ForeignKey(
@ -2624,7 +2481,6 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
def d3_json(self):
edge_json = {
"name": self.get_name(),
"plain_name": self.get_name(include_suffix=False),
"id": self.url,
"url": self.url,
"image": self.url + "?image=svg",
@ -2739,19 +2595,17 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
return res
def get_name(self, include_suffix=True):
def get_name(self):
non_generic_name = True
if self.name == "no name":
non_generic_name = False
if non_generic_name:
return self.name
else:
if include_suffix:
return f"{self.edge_label.name} (taken from underlying reaction)"
else:
return self.edge_label.name
return (
self.name
if non_generic_name
else f"{self.edge_label.name} (taken from underlying reaction)"
)
class EPModel(PolymorphicModel, EnviPathModel, AdditionalInformationMixin):

View File

@ -19,7 +19,7 @@ from sentry_sdk import capture_exception
from utilities.chem import FormatConverter, IndigoUtils
from utilities.decorators import package_permission_required
from .exceptions import InvalidMolfileException, InvalidSMILESException
from .exceptions import InvalidSMILESException
from .logic import (
EPDBURLParser,
@ -1415,18 +1415,12 @@ def package_compounds(request, package_uuid):
elif request.method == "POST":
compound_name = request.POST.get("compound-name")
compound_smiles = request.POST.get("compound-smiles")
compound_molfile = request.POST.get("compound-molfile")
compound_description = request.POST.get("compound-description")
try:
c = Compound.create(
current_package,
compound_smiles,
molfile=compound_molfile,
name=compound_name,
description=compound_description,
current_package, compound_smiles, compound_name, compound_description
)
except (InvalidSMILESException, InvalidMolfileException) as e:
except ValueError as e:
raise BadRequest(str(e))
return redirect(c.url)
@ -1552,15 +1546,11 @@ def package_compound_structures(request, package_uuid, compound_uuid):
elif request.method == "POST":
structure_name = request.POST.get("structure-name")
structure_smiles = request.POST.get("structure-smiles")
structure_molfile = request.POST.get("structure-molfile")
structure_description = request.POST.get("structure-description")
try:
cs = current_compound.add_structure(
structure_smiles,
molfile=structure_molfile,
name=structure_name,
description=structure_description,
structure_smiles, structure_name, structure_description
)
except ValueError:
return error(
@ -1948,9 +1938,9 @@ def package_reactions(request, package_uuid):
elif request.method == "POST":
reaction_name = request.POST.get("reaction-name")
reaction_description = request.POST.get("reaction-description")
reaction_smiles = request.POST.get("reaction-smiles")
educts = reaction_smiles.split(">>")[0].split(".")
products = reaction_smiles.split(">>")[1].split(".")
reactions_smirks = request.POST.get("reaction-smirks")
educts = reactions_smirks.split(">>")[0].split(".")
products = reactions_smirks.split(">>")[1].split(".")
r = Reaction.create(
current_package,
@ -2131,14 +2121,12 @@ def package_pathways(request, package_uuid):
else:
prediction_setting = current_user.prediction_settings()
is_predict_mode = pw_mode in {"predict", "incremental"}
pw = Pathway.create(
current_package,
stand_smiles if is_predict_mode else smiles,
stand_smiles,
name=name,
description=description,
predicted=is_predict_mode,
predicted=pw_mode in {"predict", "incremental"},
)
# set mode
@ -2379,13 +2367,10 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
node_name = request.POST.get("node-name")
node_description = request.POST.get("node-description")
node_smiles = request.POST.get("node-smiles")
node_molfile = request.POST.get("node-molfile")
node_smiles = request.POST.get("node-smiles").strip()
try:
current_pathway.add_node(
node_smiles, molfile=node_molfile, name=node_name, description=node_description
)
current_pathway.add_node(node_smiles, name=node_name, description=node_description)
except InvalidSMILESException:
return error(
request, "Node creation failed!", f"Given SMILES ({node_smiles}) is invalid"
@ -2497,26 +2482,7 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
return JsonResponse({"success": current_node.url})
new_node_name = request.POST.get("node-name")
new_node_description = request.POST.get("node-description")
if any([new_node_name, new_node_description]):
if new_node_name is not None and new_node_name.strip() != "":
new_node_name = nh3.clean(new_node_name.strip(), tags=s.ALLOWED_HTML_TAGS).strip()
current_node.name = new_node_name
if new_node_description is not None and new_node_description.strip() != "":
new_node_description = nh3.clean(
new_node_description.strip(), tags=s.ALLOWED_HTML_TAGS
).strip()
current_node.description = new_node_description
current_node.save()
return redirect(current_node.url)
return error(request, "Node update failed!", "No changes were made to the node")
return HttpResponseBadRequest()
else:
return HttpResponseNotAllowed(["GET", "POST"])

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -39,7 +39,3 @@ select.select[multiple] {
display: block;
white-space: normal;
}
p a {
@apply underline;
}

View File

@ -5,126 +5,6 @@
*/
document.addEventListener('alpine:init', () => {
const basePagination = (
items,
currentPage,
totalPages,
totalItems,
perPage,
isReviewed,
instanceId
) => ({
items,
currentPage,
totalPages,
totalItems,
perPage,
isReviewed,
instanceId,
get paginatedItems() {
return this.items;
},
get showingStart() {
if (this.totalItems === 0) return 0;
return (this.currentPage - 1) * this.perPage + 1;
},
get showingEnd() {
if (this.totalItems === 0) return 0;
return Math.min((this.currentPage - 1) * this.perPage + this.items.length, this.totalItems);
},
nextPage() {
if (this.currentPage < this.totalPages) {
this.fetchPage(this.currentPage + 1);
}
},
prevPage() {
if (this.currentPage > 1) {
this.fetchPage(this.currentPage - 1);
}
},
goToPage(page) {
if (page >= 1 && page <= this.totalPages) {
this.fetchPage(page);
}
},
get pageNumbers() {
const pages = [];
const total = this.totalPages;
const current = this.currentPage;
if (total === 0) {
return pages;
}
if (total <= 7) {
for (let i = 1; i <= total; i++) {
pages.push({ page: i, isEllipsis: false, key: `${this.instanceId}-page-${i}` });
}
} else {
pages.push({ page: 1, isEllipsis: false, key: `${this.instanceId}-page-1` });
let rangeStart;
let rangeEnd;
if (current <= 4) {
rangeStart = 2;
rangeEnd = 5;
} else if (current >= total - 3) {
rangeStart = total - 4;
rangeEnd = total - 1;
} else {
rangeStart = current - 1;
rangeEnd = current + 1;
}
if (rangeStart > 2) {
pages.push({ page: '...', isEllipsis: true, key: `${this.instanceId}-ellipsis-start` });
}
for (let i = rangeStart; i <= rangeEnd; i++) {
pages.push({ page: i, isEllipsis: false, key: `${this.instanceId}-page-${i}` });
}
if (rangeEnd < total - 1) {
pages.push({ page: '...', isEllipsis: true, key: `${this.instanceId}-ellipsis-end` });
}
pages.push({ page: total, isEllipsis: false, key: `${this.instanceId}-page-${total}` });
}
return pages;
}
});
Alpine.data('paginatedList',
(items, options = {}) => ({
...basePagination(items,1, 0, 0, options.perPage || 50, options.isReviewed || false, options.instanceId || Math.random().toString(36).substring(2, 9),),
init() {
this.fetchPage(1);
},
async fetchPage(page) {
this.totalItems = this.items.length;
this.totalPages = Math.ceil(this.items.length / this.perPage);
this.currentPage = page
const start = page * this.perPage - this.perPage;
const end = page * this.perPage;
return this.items.slice(start, end);
}
})
);
Alpine.data('remotePaginatedList', (options = {}) => ({
items: [],
currentPage: 1,

View File

@ -186,40 +186,6 @@ window.AdditionalInformationApi = {
return this._handleResponse(response, "createItem");
},
/**
* Create new additional information and attach it to an object.
* @param {string} modelName - Name/type of the additional information model
* @param {Object} data - Data for the new item
* @param {string} attachObjectUrl - UUID of the object this data should be attached to
* @param {string} scenarioUuid - UUID of the scenario
* @returns {Promise<{status: string, uuid: string}>}
*/
async createItemOnNonScenarioObject(modelName, data, attachObjectUrl, scenarioUuid) {
const sanitizedData = this.sanitizePayload(data);
this._log("createItemOnNonScenarioObject", { modelName, data: sanitizedData, attachObjectUrl, scenarioUuid });
sanitizedData.attach_obj_url = attachObjectUrl;
if (scenarioUuid) {
sanitizedData.scenario_uuid = scenarioUuid;
}
// Normalize model name to lowercase
const normalizedName = modelName.toLowerCase();
const response = await fetch(
`/api/v1/information/${normalizedName}/`,
{
method: "POST",
headers: this._buildHeaders(),
body: JSON.stringify(sanitizedData),
},
);
return this._handleResponse(response, "createItemOnNonScenarioObject");
},
/**
* Delete additional information from a scenario
* @param {string} scenarioUuid - UUID of the scenario

View File

@ -0,0 +1,57 @@
## Prerequisites
Stable [Node.js](https://nodejs.org) version
## Build instructions
npm install
npm start
For production build:
npm run build
You could also build only the style with command
npm run style
## Indigo Service
Ketcher uses Indigo Service for server operations.
You can use `--api-path` parameter to start with it:
npm start -- --api-path=<server-url>
For production build:
npm run build -- --api-path=<server-url>
You can find the instruction for service installation
[here](http://lifescience.opensource.epam.com/indigo/service/index.html).
## Tests instructions
You can start tests for input/output `.mol`-files and render.
npm test
Tests are started for all structures in `test/fixtures` directory.
To start the tests separately:
npm run test-io
npm run test-render
#### Parameters
You can use following parameters to start the tests:
- `--fixtures` - for the choice of a specific directory with molecules
- `--headless` - for start of the browser in headless mode
```
npm run test-render -- --fixtures=fixtures/super --headless
```
If you have added new structures for testing to the `test/fixtures` directory
you have to generate `svg` from them for correct render-test with:
npm run generate-svg

184
static/js/ketcher2/LICENSE Normal file
View File

@ -0,0 +1,184 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 EPAM Systems
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,5 @@
Ketcher version 1 was released under GNU Affero General Public License v3.0
Ketcher version 2 was re-licensed under Apache License, Version 2.
Current version is distributed by the terms of the Apache License, Version 2.
which is included in the file LICENSE, found at the root of the Ketcher source tree.

19
static/js/ketcher2/NOTICE Normal file
View File

@ -0,0 +1,19 @@
Ketcher
Copyright (C) 2017 EPAM Systems
This product includes software developed at EPAM Systems, Inc.
In addition, this product contains dependencies on files licensed under:
The FreeBSD Documentation License https://www.freebsd.org/copyright/freebsd-doc-license.html
The MIT License https://opensource.org/licenses/MIT
X11 License http://www.xfree86.org/3.3.6/COPYRIGHT2.html
Academic Free License https://opensource.org/licenses/AFL-3.0
Apache License, Version 1.0 http://www.apache.org/licenses/LICENSE-1.0
Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
The 2-Clause BSD License https://opensource.org/licenses/BSD-2-Clause
The 3-Clause BSD License https://opensource.org/licenses/BSD-3-Clause
ISC License (ISC) https://opensource.org/licenses/ISC
GNU Lesser General Public License version 2.1 https://opensource.org/licenses/LGPL-2.1
The Mozilla Public License https://opensource.org/licenses/MPL-1.0
Public Domain https://wiki.creativecommons.org/wiki/Public_domain
Unlicense http://unlicense.org/

View File

@ -0,0 +1,35 @@
# EPAM Ketcher projects
Copyright (c) 2017 EPAM Systems, Inc
Ketcher is an open-source web-based chemical structure editor incorporating high performance, good portability, light weight, and ability to easily integrate into a custom web-application. Ketcher is designed for chemists, laboratory scientists and technicians who draw structures and reactions.
## KEY FEATURES
* Fast 2D structure representation that satisfies common chemical drawing standards
* 3D structure visualization
* Draw and edit structures using major tools: Atom Tool, Bond Tool, and Template Tool
* Template library (including custom and user's templates)
* Add atom and bond basic properties and query features, add aliases and Generic groups
* Select, modify, and erase connected and unconnected atoms and bonds using Selection Tool, or using Shift key
* Simple Structure Clean up Tool (checks bonds length, angles and spatial arrangement of atoms) and Advanced Structure Clean up Tool (+ stereochemistry checking and structure layout)
* Aromatize/De-aromatize Tool
* Calculate CIP Descriptors Tool
* Structure Check Tool
* MW and Structure Parameters Calculate Tool
* Stereochemistry support during editing, loading, and saving chemical structures
* Storing history of actions, with the ability to rollback to previous state
* Ability to load and save structures and reactions in MDL Molfile or RXN file format, InChI String, ChemAxon Extended SMILES, ChemAxon Extended CML file formats
* Easy to use R-Group and S-Group tools (Generic, Multiple group, SRU polymer, peratom, Data S-Group)
* Reaction Tool (reaction generating, manual and automatic atom-to-atom mapping)
* Flip/Rotate Tool
* Zoom in/out, hotkeys, cut/copy/paste
* OCR - ability to recognize structures at pictures (image files) and reproduce them
* Copy and paste between different chemical editors
* Settings support (Rendering, Displaying, Debugging)
* Use of SVG to achieve best quality in-browser chemical structure rendering
* Languages: JavaScript with third-party libraries
## Build instructions
Please read [DEVNOTES.md](DEVNOTES.md) for details.
## License
Please read [LICENSE](LICENSE) and [NOTICE](NOTICE) for details.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,570 @@
**Ketcher** is a tool to draw molecular structures and chemical
reactions.
# Ketcher Overview
**Ketcher** is a tool to draw molecular structures and chemical
reactions. Ketcher operates in two modes, the Server mode with most
functions available and the client mode with limited functions
available.
**Ketcher** consists of the following elements:
![](main.png "Main window")
**Note** : Depending on the screen size, some tools on the _Tool
palette_ can be displayed in expanded or collapsed forms.
Using the _Tool palette_, you can
* draw and edit a molecule or reaction by clicking on and dragging
atoms, bonds, and other elements provided with the buttons on the
_Atoms_ toolbar and _Tool palette_;
* delete any element of the drawing (atom or bond) by clicking on it
with the Erase tool;
* delete the entire molecule or its fragment by a lasso,
rectangular, or fragment selection with the Erase tool;
* draw special structures (see the following sections);
* select the entire molecule or its fragment in one of the following
ways (click on the button to see the list of available options):
* in the expanded form
![](expanded.png "Expanded tool")
* in the collapsed form
![](collapsed.png "Collapsed tool")
To select one atom or bond, click Lasso or Rectangle Selection tool,
and then click the atom or bond.
To select the entire structure:
* Select the Fragment Selection tool and then click the object.
* Select the Lasso or Rectangle Selection tool, and then drag the
mouse to select the object.
* `Ctrl-click` with the Lasso or Rectangle Selection tool.
To select multiple atoms, bonds, structures, or other objects, do one
of the following:
* `Shift-click` with the Lasso or Rectangle Selection tool selects
some (connected or not) atoms/bonds.
* With the Lasso or Rectangle Selection tool click and drag the
mouse around the atoms, bonds, or structures that you want to
select.
**Note** : `Ctrl+Shift-click` with the Lasso or Rectangle Selection tool
selects several structures.
You can use the buttons of the _Main_ toolbar:
![](toolbar.png "Tolbar")
* **Clear Canvas** (1) button to start drawing a new molecule; this
command clears the drawing area;
* **Open…** (2) and **Save As…** (3) buttons to import a molecule
from a molecular file or save it to a supported molecular file
format;
* **Undo** / **Redo** (4), **Cut** (5), **Copy** (6), **Paste** (7),
**Zoom In** / **Out** (8), and **Scaling** (9) buttons to perform
the corresponding actions;
* **Layout** button (10) to change the position of the structure to
work with it with the most convenience;
* **Clean Up** button (11) to improve the appearance of the
structure by assigning them uniform bond lengths and angles.
* **Aromatize** / **Dearomatize** buttons (12) to mark aromatic
structures (to convert a structure to the Aromatic or Kekule
presentation);
* **Calculate CIP** button (13) to determine R/S and E/Z
configurations;
* **Check Structure** button (14) to check the following properties
of the structure:
![](check.png "Structure Ckeck")
* **Calculated Values** button (15) to display some properties of
the structure:
![](analyse.png "Calculated Values")
* **Recognize Molecule** button (16) to recognize a structure in the
image file and load it to the canvas;
* **3D Viewer** button (17) to open the structure in the
three-dimensional Viewer;
* **Settings** button (18) to make some settings for molecular
files:
![](settings.png "Settings")
* **Help** button (19) to view Help;
* **About** button (20) to display version and copyright information
of the program.
**Note** : **Layout,** **Clean Up,** **Aromatize** / **Dearomatize,**
**Calculate CIP,** **Check Structure,** **Calculated Values,**
**Recognize Molecule** and **3D View** buttons are active only in the
Server mode.
# 3D Viewer
The structure appears in a modal window after clicking on the **3D
Viewer** button:
![](miew.png "3D Viewer")
You can perform the following actions:
* Rotate the structure holding the left mouse button;
* Zoom In/Out the structure;
Ketcher Settings allow to change the appearance of the structure and background coloring.
"Lines" drawing method, "Bright" atom name coloring
method and "Light" background coloring are default.
# Drawing Atoms
To draw/edit atoms you can:
* select an atom in the Atoms toolbar and click inside the drawing
area;
* if the desired atom is absent in the toolbar, click on
the ![](periodic-table.png) button to invoke the Periodic Table and
click on the desired atom (available options: _Single_ selection
of a single atom, _List_ choose an atom from the list of selected
options (To allow one atom from a list of atoms of your choice at
that position), _Not List_ - exclude any atom on your list at that
position).
![](periodic-dialog.png "Periodic Table")
* add an atom to the existing molecule by selecting an atom in the
_Atoms_ toolbar, clicking on an atom in the molecule, and dragging
the cursor; the atom will be added with a single bond; vacant
valences will be filled with the corresponding number of hydrogen
atoms;
* change an atom by selecting an atom in the _Atoms_ toolbar and
clicking on the atom to be changed; in the case a wrong valence thus
appears the atom will be underlined in red;
* change an atom by clicking on an existing atom with the
_Selection_ tool and waiting for a couple of seconds for the text
box to appear; type another atom symbol in the text box:
![](inline-edit.png "Change Atom")
* change the charge of an atom by selecting the Charge Plus or
Charge Minus tool and clicking consecutively on an atom to
increase/decrease its charge
![](charge.png "Ions")
* change an atom or its properties by double-clicking on the atom to
invoke the Atom Properties dialog (the dialog also provides atom
query features):
![](atom-dialog.png "Atom Properties")
* click on the Periodic Table button, open the Extended table and
select a corresponding Generic group or Special Node:
![](periodic-dialog-ext.png "Generic Groups")
# Drawing Bonds
To draw/edit bonds you can:
* Click an arrow on the Bond tool ![](bond.png) in the Tools palette
to open the drop-down list with the following bond types:
![](bonds.png)
For the full screen format, the Bond tool from the Tools palette
splits into three: _Single Bond,__Single Up Bond,_ and _Any
Bond_,which include the corresponding bond types:
![](bond-types.png)
* select a bond type from the drop down list and click inside the
drawing area; a bond of the selected type will be drawn;
* click on an atom in the molecule; a bond of the selected type will
be added to the atom at the angle of 120 degrees;
* add a bond to the existing molecule by clicking on an atom in the
molecule and dragging the cursor; in this case you can set the angle
manually;
* change the bond type by clicking on it;
* use the Chain Tool ![](chain.png) to draw consecutive single
bonds;
* change a bond or its properties by double-clicking on the bond to
invoke the Bond Properties dialog:
![](bond-dialog.png "Bond Properties")
* clicking on a drawn stereo bond changes its direction.
* clicking with the Single Bond tool or Chain tool switches the bond type
cyclically: Single-Double-Triple-Single.
# Drawing R-Groups
Use the _R-Group_ toolbox ![](rgroup.png) to draw R-groups in Markush
structures:
![](rgroup-types.png)
Selecting the _R-Group_ _Label_ Tool and clicking on an atom in the
structure invokes the dialog to select the R-Group label for a current
atom position in the structure:
![](rgroup-dialog.png)
Selecting the R-Group label and clicking **OK** converts the structure
into a Markush structure with the selected R-Group label:
![](rgroup-example1.png)
**Note** : You can choose several R-Group labels simultaneously:
![](rgroup-example2.png)
Particular chemical fragments that may be substituted for a given
R-Group form a set of R-Group members. R-Group members can be any
structural fragment, including functional groups and single atoms or
atom lists.
To create a set of R-Group members:
1. Draw a structure to become an R-Group member.
2. Select the structure using the _R-Group Fragment Tool_ to invoke
the R-Group dialog; in this dialog select the label of the
R-Group to assign the fragment to.
3. Click on **OK** to convert the structure into an R-Group member.
An R-Group attachment point is the atom in an R-Group member fragment
that attaches the fragment to the initial Markush structure.
Selecting the _Attachment Point Tool_ and clicking on an atom in the
R-Group fragment converts this atom into an attachment point. If the
R-Group contains more than one attachment point, you can specify one
of them as primary and the other as secondary. You can select between
either the primary or secondary attachment point using the dialog that
appears after clicking on the atom:
![](attpoints-dialog.png)
If there are two attachment points on an R-Group member, there must be
two corresponding attachments (bonds) to the R-Group atom that has the
same R-Group label. Clicking on **OK** in the above dialog creates the
attachment point.
Schematically, the entire process of the R-Group member creation can
be presented as:
![](rgroup-example3.png)
![](rgroup-example4.png)
# R-Group Logic
**Ketcher** enables one to add logic when using R-Groups. To access
the R-Group logic:
1. Create an R-Group member fragment as described above.
2. Move the cursor over the entire fragment for the green frame to
appear, then click inside the fragment. The following dialog
appears:
![](rlogic-dialog.png)
3. Specify **Occurrence** to define how many of an R-Group
occurs. If an R-Group atom appears several times in the initial
structure, you will specify **Occurrence**"&gt;n", n
being the number of occurrences; if it appears once, you see
"R1 > 0".
4. Specify H at **unoccupied** R-Group sites ( **RestH** ): check or
clear the checkbox.
5. Specify the logical **Condition**. Use the R-Group condition **If
R(i) Then** to specify whether the presence of an R-Group is
dependent on the presence of another R-Group.
# Marking S-Groups
To mark S-Groups, use the _S-Group tool_ ![](sgroup.png) and the
following dialog that appears after selecting a fragment with this
tool:
![](sgroup-dialog.png "S-Group Dialog")
Available S-Group types:
_Generic_
Generic is a pair of brackets without any labels.
_Multiple group_
A Multiple group indicates a number of replications of a fragment or a part of a
structure in contracted form.
_SRU Polymer_
The Structural Repeating Unit (SRU) brackets enclose the structural
repeating of a polymer. You have three available patterns:
head-to-tail (the default), head-to-head, and either/unknown.
_Superatom_
An abbreviated structure (abbreviation) is all or part of a structure
(molecule or reaction component) that has been abbreviated to a text
label. Structures that you abbreviate keep their chemical
significance, but their underlying structure is hidden. The current
version can&#39;t display contracted structures but correctly
saves/reads them into/from files.
# Data S-Groups
The _Data S-Groups Tool_ ![](sdata.png) is a separate tool for
comfortable use with the accustomed set of descriptors (like Attached
Data in **Marvin** Editor).
You can attach data to an atom, a fragment, a single bond, or a
group. The defined set of _Names_ and _Values_ is introduced for each
type of selected elements:
![](sdata-dialog.png)
* Select the appropriate S-Group Field Name.
* Select or type the appropriate Field Value.
* Labels can be specified as Absolute, Relative or Attached.
# Changing Structure Display
Use the _Flip/Rotate_ tool ![](transform.png) to change the structure
display:
![](transform-types.png)
For the full screen format, the _Flip/Rotate_ tool is split into
separate buttons:
![](rotate.png)
_Rotate Tool_
This tool allows rotating objects.
* If some objects are selected, the tool rotates the selected objects.
* If no objects are selected, or all objects are selected, the tool rotates the whole canvas
* The default rotation step is 15 degrees.
* Press and hold the Ctrl key for more gradual continuous rotation with 1 degree rotation step
Select any bond on the structure and click Alt+H to rotate the structure so that the selected bond is placed horizontally.
Select any bond on the structure and click Alt+V to rotate the structure so that the selected bond is placed vertically.
_Flip Tool_
This tool flips the objects horizontally or vertically.
* If some objects are selected, the Horizontal Flip tool (or Alt+H) flips the selected objects horizontally
* If no objects are selected, or all objects are selected, the Horizontal Flip tool (or Alt+H) flips each structure horizontally
* If some objects are selected, the Vertical Flip tool (or Alt+V) flips the selected objects vertically
* If no objects are selected, or all objects are selected, the Vertical Flip tool (or Alt+V) flips each structure vertically
# Drawing Reactions
To draw/edit reactions you can
* draw reagents and products as described above;
* use options of the _Reaction Arrow Tool_ ![](reaction.png) to draw an
arrow and pluses in the reaction equation and map same atoms in
reagents and products.
![](reaction-types.png)
**Note** : Reaction Auto-Mapping Tool is available only in the Server
mode.
# Templates toolbar
You can add templates (rings or other predefined structures) to the
structure using the _Templates_ toolbar together with the _Custom
Templates_ button located at the bottom:
![](template.png)
To add a ring to the molecule, select a ring from the toolbar and
click inside the drawing area, or click on an atom or a bond in the
molecule.
Rules of using templates:
* Selecting a template and clicking on an atom in the existing
structure adds the template to the structure connected with a single
bond:
![](template-example1.png)
* Selecting a template and dragging the cursor from an atom in the
existing structure adds the template directly to this atom resulting
in the fused structure:
![](template-example2.png)
* Dragging the cursor from an atom in the existing structure results
in the single bond attachment if the cursor is dragged to more than
the bond length; otherwise the fused structure is drawn.
* Selecting a template and clicking on a bond in the existing
structure created a bond-to-bond fused structure:
![](template-example3.png)
* The bond in the initial structure is replaced with the bond in the
template.
* This procedure doesn&#39;t change the length of the bond in the
initial structure.
* Dragging the cursor relative to the initial bond applies the
template at the corresponding side of the bond.
**Note** : The added template will be fused by the default attachment
atom or bond preset in the program.
**Note** : User is able to define the attachment atom and bond by clicking
the Edit button for template structure.
The _Custom Templates_ button ![](template-lib.png)invokes the scrolling
list of templates available in the program; both built-in and created
by user:
![](template-dialog.png)
To create a user template:
* draw a structure.
* click the Save as button.
* click the Save to Templates button.
* enter a name and define the attachment atom and bond.
# Working with Files
Ketcher supports the following molecular formats that can be entered
either manually or from files:
* MDL Molfile or RXN file;
* Daylight SMILES (Server mode only);
* Daylight SMARTS (Server mode only);
* InChi string (Server mode only);
* CML file (Server mode only).
You can use the **Open…** and **Save As…** buttons of the _Main_
toolbar to import a molecule from a molecular file or save it to a
supported molecular file format. The _Open Structure_ dialog enables
one to either browse for a file (Server mode) or manually input, e.g.,
the Molfile ctable for the molecule to be imported:
![](open.png)
The _Save Structure_ dialog enables one to save the molecular file:
![](save.png)
**Note** : In the standalone version only mol/rxn are supported for
Open and mol/rxn/SMILES for Save.
# Hotkeys
You can use keyboard hotkeys (including Numeric keypad) for some
features/commands of the Editor. To display the hotkeys just place the
cursor over a toolbar button. If a hotkey is available for the button,
it will appear in brackets after the description of the button.
| Key | Action |
| --- | --- |
| `Esc` | Switching between the Lasso/Rectangle/Fragment Selection tools |
| `Del` | Delete the selected objects |
| `0` | Draw Any bond. |
| `1` | Single / Single Up / Single Down / Single Up/Down bond. Consecutive pressing switches between these types. |
| `2` | Double / Double Cis/Trans bond |
| `3` | Draw a triple bond. |
| `4` | Draw an aromatic bond. |
| `5` | Charge Plus/Charge Minus |
| `A` | Draw any atom |
| `H` | Draw a hydrogen |
| `C` | Draw a carbon |
| `N` | Draw a nitrogen |
| `O` | Draw an oxygen |
| `S` | Draw a sulfur |
| `F` | Draw a fluorine |
| `P` | Draw a phosphorus |
| `I` | Draw an iodine |
| `T` | Basic templates. Consecutive pressing switches between different templates |
| `Shift+t` | Open template library |
| `Alt+r` | Rotate tool |
| `Alt+v` | Flip vertically |
| `Alt+h` | Flip horizontally |
| `Ctrl+g` | S-Group tool / Data S-Group tool |
| `Ctrl+d` | Align and select all S-Group data
| `Ctrl+r` | Switching between the R-Group Label Tool/R-Group Fragment Tool/Attachment Point Tool |
| `Ctrl+Shift+r` | R-Group Fragment Tool |
| `Ctrl+Del` | Clear canvas |
| `Ctrl+o` | Open |
| `Ctrl+s` | Save As |
| `Ctrl+z` | Undo |
| `Ctrl+Shift+z` | Redo |
| `Ctrl+x` | Cut selected objects |
| `Ctrl+c` | Copy selected objects |
| `Ctrl+v` | Paste selected objects |
| `+` | Zoom In |
| `-` | Zoom Out |
| `Ctrl+l` | Layout |
| `Ctrl+Shift+l` | Clean Up |
| `Ctrl+p` | Calculate CIP |
| `?` | Help |
**Note** : Please, use `Ctrl+V` to paste the selected object in
Google Chrome and Mozilla Firefox browsers.
**Note 2** : Probably, you have forbidden access to the local storage.
If you are using IE10 or IE11 and didn't forbid access to local storage
intentionally, you can pay attention here: https://stackoverflow.com/a/20848924

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

View File

@ -0,0 +1,310 @@
/****************************************************************************
* Copyright 2017 EPAM Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
var gulp = require('gulp');
var gutil = require('gulp-util');
var plugins = require('gulp-load-plugins')();
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var budo = require('budo');
var istanbul = require('browserify-babel-istanbul');
var fs = require('fs');
var cp = require('child_process');
var del = require('del');
var minimist = require('minimist');
var MarkdownIt = require('markdown-it');
var pkg = require('./package.json');
var options = minimist(process.argv.slice(2), {
string: ['dist', 'api-path', 'build-number', 'build-date',
'miew-path'],
boolean: ['sgroup-data-special', 'no-generics', 'no-reactions',
'no-sgroup', 'no-rgroup', 'rgroup-label-only'],
default: {
'dist': 'dist',
'api-path': '',
'miew-path': '',
'build-number': '',
'build-date': new Date() // TODO: format me
}
});
var distrib = ['LICENSE', 'demo.html', 'library.sdf', 'library.svg'];
var bundleConfig = {
entries: 'script',
extensions: ['.js', '.jsx', '.es'],
debug: true,
standalone: pkg.name,
transform: [
['exposify', {
expose: {'raphael': 'Raphael' }
}],
['browserify-replace', {
replace: [
{ from: '__VERSION__', to: pkg.version },
{ from: '__API_PATH__', to: options['api-path'] },
{ from: '__BUILD_NUMBER__', to: options['build-number'] },
{ from: '__BUILD_DATE__', to: options['build-date'] },
{ from: '__MIEW_PATH__', to: options['miew-path'] },
]
}],
['babelify', {
presets: [
["env", {
"targets": {
"browsers": ["last 2 versions", "safari > 8", "chrome > 52"]
},
"useBuiltIns": true
}],
"react"],
plugins: ['lodash', 'transform-class-properties', 'transform-object-rest-spread']
}]
]
};
var iconfont = null;
gulp.task('script', ['patch-version'], function() {
bundleConfig.transform.push(
['loose-envify', {
NODE_ENV: 'production',
global: true
}]
);
return browserify(bundleConfig).bundle()
// Don't transform, see: http://git.io/vcJlV
.pipe(source(`${pkg.name}.js`)).pipe(buffer())
.pipe(plugins.sourcemaps.init({ loadMaps: true }))
.pipe(plugins.uglify({
compress: {
global_defs: {
DEBUG: false
},
dead_code: true
}}))
.pipe(plugins.header(fs.readFileSync('script/banner.js', 'utf8')))
.pipe(plugins.sourcemaps.write('./'))
.pipe(gulp.dest(options.dist));
});
gulp.task('test-render', function() {
return browserify({
entries: 'test/render/render-test.js',
debug: true,
transform: [
istanbul,
['exposify', {
expose: {
raphael: 'Raphael',
resemblejs: 'resemble'
}
}]
]
}).bundle()
.pipe(source('render-test.js'))
.pipe(plugins.header(fs.readFileSync('script/banner.js', 'utf8')))
.pipe(gulp.dest('./test/dist'));
});
gulp.task('style', ['font'], function () {
return gulp.src('style/index.less')
.pipe(plugins.sourcemaps.init())
.pipe(plugins.rename(pkg.name))
.pipe(plugins.less({
paths: ['node_modules/normalize.css'],
modifyVars: iconfont
}))
// don't use less plugins due http://git.io/vqVDy bug
.pipe(plugins.autoprefixer({ browsers: ['> 0.5%'] }))
.pipe(plugins.cleanCss({compatibility: 'ie8'}))
.pipe(plugins.sourcemaps.write('./'))
.pipe(gulp.dest(options.dist));
});
gulp.task('html', ['patch-version'], function () {
var hbs = plugins.hb()
.partials('template/menu/*.hbs')
.partials('template/dialog/*.hbs')
.data(Object.assign({ pkg: pkg }, options));
return gulp.src('template/index.hbs')
.pipe(hbs)
.pipe(plugins.rename('ketcher.html'))
.pipe(gulp.dest(options.dist));
});
gulp.task('doc', function () {
return gulp.src('doc/*.{png, jpg, gif}')
.pipe(gulp.dest(options.dist + '/doc'));
});
gulp.task('help', ['doc'], function () {
return gulp.src('doc/help.md')
.pipe(plugins.tap(markdownify()))
.pipe(gulp.dest(options.dist + '/doc'));
});
gulp.task('font', function (cb) {
return iconfont ? cb() : gulp.src(['icons/*.svg'])
.pipe(plugins.iconfont({
fontName: pkg.name,
formats: ['ttf', 'svg', 'eot', 'woff'],
timestamp: options['build-date'],
normalize: true
}))
.on('glyphs', function(glyphs) {
iconfont = glyphReduce(glyphs);
})
.pipe(gulp.dest(options.dist));
});
gulp.task('images', function () {
return gulp.src('images/*')
.pipe(gulp.dest(options.dist + '/images'));
});
gulp.task('copy', ['images'], function () {
return gulp.src(['raphael'].map(require.resolve)
.concat(distrib))
.pipe(gulp.dest(options.dist));
});
gulp.task('patch-version', function (cb) {
if (pkg.rev)
return cb();
cp.exec('git rev-list ' + pkg.version + '..HEAD --count', function (err, stdout, stderr) {
if (err && stderr.toString().search('path not in') > 0) {
cb(new Error('Could not fetch revision. ' +
'Please git tag the package version.'));
}
else if (!err && stdout > 0) {
pkg.rev = stdout.toString().trim();
pkg.version += ('+r' + pkg.rev);
}
cb();
});
});
gulp.task('lint', function () {
return gulp.src('script/**')
.pipe(plugins.eslint())
.pipe(plugins.eslint.format())
.pipe(plugins.eslint.failAfterError());
});
gulp.task('check-epam-email', function(cb) {
// TODO: should be pre-push and check remote origin
try {
var email = cp.execSync('git config user.email').toString().trim();
if (/@epam.com$/.test(email))
cb();
else {
cb(new Error('Email ' + email + ' is not from EPAM domain.'));
gutil.log('To check git project\'s settings run `git config --list`');
gutil.log('Could not continue. Bye!');
}
} catch(e) {};
});
gulp.task('check-deps-exact', function (cb) {
var semver = require('semver'); // TODO: output corrupted packages
var allValid = ['dependencies', 'devDependencies'].every(d => {
var dep = pkg[d];
return Object.keys(dep).every(name => {
var ver = dep[name];
return (semver.valid(ver) && semver.clean(ver));
});
});
if (!allValid) {
cb(new gutil.PluginError('check-deps-exact',
'All top level dependencies should be installed' +
'using `npm install --save-exact` command'));
} else
cb();
});
gulp.task('clean', function () {
return del.sync([options.dist + '/**', pkg.name + '-*.zip']);
});
gulp.task('archive', ['clean', 'assets', 'code'], function () {
var an = pkg.name + '-' + pkg.version;
return gulp.src(['**', '!*.map'], { cwd: options.dist })
.pipe(plugins.rename(function (path) {
path.dirname = an + '/' + path.dirname;
return path;
}))
.pipe(plugins.zip(an + '.zip'))
.pipe(gulp.dest('.'));
});
gulp.task('serve', ['clean', 'style', 'html', 'assets'], function(cb) {
var server = budo(`${bundleConfig.entries}:${pkg.name}.js`, {
dir: options.dist,
browserify: bundleConfig,
stream: process.stdout,
host: '0.0.0.0',
live: true,
watchGlob: `${options.dist}/*.{html,css}`,
staticOptions: {
index: `ketcher.html`
}
}).on('exit', cb);
gulp.watch('style/**.less', ['style']);
gulp.watch('template/**', ['html']);
gulp.watch('doc/**', ['help']);
gulp.watch(['gulpfile.js', 'package.json'], function() {
server.close();
cp.spawn('gulp', process.argv.slice(2), {
stdio: 'inherit'
});
process.exit(0);
});
return server;
});
function markdownify (options) {
var header = '<!DOCTYPE html>';
var footer = '';
var md = MarkdownIt(Object.assign({
html: true,
linkify: true,
typographer: true
}, options));
return function process (file) {
var data = md.render(file.contents.toString());
file.contents = new Buffer(header + data + footer);
file.path = gutil.replaceExtension(file.path, '.html');
};
}
function glyphReduce(glyphs) {
return glyphs.reduce(function (res, glyph) {
res['icon-' + glyph.name] = "'" + glyph.unicode[0] + "'";
return res;
}, {});
}
gulp.task('pre-commit', ['lint', 'check-epam-email',
'check-deps-exact']);
gulp.task('assets', ['copy', 'help']);
gulp.task('code', ['style', 'script', 'html']);
gulp.task('build', ['clean', 'code', 'assets']);

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generated by IcoMoon.io -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="1000"
height="1000"
viewBox="0 0 1000 1000"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="about.svg">
<metadata
id="metadata11">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs9" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="974"
id="namedview7"
showgrid="false"
inkscape:zoom="0.52678571"
inkscape:cx="708.89624"
inkscape:cy="375.86441"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<g
id="icomoon-ignore"
transform="translate(0,552)" />
<path
d="m 666.66667,812.5 0,-104.16667 c 0,-11.71875 -9.11459,-20.83333 -20.83334,-20.83333 l -62.5,0 0,-333.33333 c 0,-11.71875 -9.11458,-20.83334 -20.83333,-20.83334 l -208.33333,0 c -11.71875,0 -20.83334,9.11459 -20.83334,20.83334 l 0,104.16666 c 0,11.71875 9.11459,20.83334 20.83334,20.83334 l 62.5,0 0,208.33333 -62.5,0 c -11.71875,0 -20.83334,9.11458 -20.83334,20.83333 l 0,104.16667 c 0,11.71875 9.11459,20.83333 20.83334,20.83333 l 291.66666,0 c 11.71875,0 20.83334,-9.11458 20.83334,-20.83333 z m -83.33334,-583.33333 0,-104.16667 c 0,-11.71875 -9.11458,-20.83333 -20.83333,-20.83333 l -125,0 c -11.71875,0 -20.83333,9.11458 -20.83333,20.83333 l 0,104.16667 C 416.66667,240.88542 425.78125,250 437.5,250 l 125,0 c 11.71875,0 20.83333,-9.11458 20.83333,-20.83333 z M 1000,500 c 0,276.04167 -223.95833,500 -500,500 C 223.95833,1000 0,776.04167 0,500 0,223.95833 223.95833,0 500,0 c 276.04167,0 500,223.95833 500,500 z"
id="path5"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="0 0 750 750"><path d="M585.781 276.055l-8.73 15.797H559.59s-24.945 0-31.598 34.921l-7.066 34.922h47.808l-8.73 17.461H518.43l-24.942 122.23c-10.394 52.384-47.812 52.384-47.812 52.384h-54.047l7.07-17.461h17.043s26.61 0 33.676-34.922l24.945-122.23H435.7l8.73-17.462h33.676l7.067-34.922c10.394-52.382 47.808-52.382 47.808-52.382zm0 186.668l-33.676-46.149-12.054 7.485-12.059 7.898 34.508 52.8-57.79 55.708 19.958 19.957 54.047-51.969 37 56.125 12.058-7.898 12.055-7.485-41.574-60.699 57.371-55.293-9.977-9.976-9.976-10.395zm166.297-23.282c-.367 91.606-55.082 174.254-139.273 210.364a113.081 113.081 0 0 1-14.137 38.25c-19.602 35.312-55.742 58.308-96.035 61.113H110.172a118.487 118.487 0 0 1-93.543-60.7 124.736 124.736 0 0 1-4.574-115.16l180.851-356.706a41.618 41.618 0 0 0 5.82-17.461V80.238c-15.167-4.71-25.246-19.058-24.53-34.922C173.78 16.215 196.23.832 225.331.832h162.14a41.57 41.57 0 0 1 48.641 44.066c.91 17.106-11.008 32.23-27.855 35.34v118.489c0 6.234 5.406 12.054 8.316 17.46l7.899 12.473c71.336-30.547 153.21-23.472 218.25 18.856 65.039 42.332 104.66 114.328 105.613 191.925M87.723 644.816c4.988 7.899 13.304 21.204 22.863 21.204h369.18c-111.414-17.891-193.543-113.74-194.149-226.58a228.229 228.229 0 0 1 69.012-163.386l-12.473-22.453a127.586 127.586 0 0 1-17.875-54.875V83.98h-41.574v114.747a133.024 133.024 0 0 1-14.555 56.957L86.472 614.469a34.522 34.522 0 0 0 0 29.933m430.298-16.629c103.734-1.148 187.007-85.964 186.246-189.703-.762-103.738-85.27-187.328-189.012-186.949-103.738.379-187.64 84.578-187.645 188.32.684 104.54 85.868 188.79 190.41 188.332"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3017"
inkscape:version="0.48.4 r9939"
sodipodi:docname="arom.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3024"
showgrid="false"
inkscape:zoom="0.788"
inkscape:cx="451.14213"
inkscape:cy="500.63452"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3017" />
<metadata
id="metadata3028">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3026" />
<path
id="path3022"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 461.48649,555.69054 -18.12703,65.26757 -59.56757,0 77.6946,-254.13783 75.43513,0 78.77297,254.13783 -61.87838,0 -19.56486,-65.26757 z m 64.44594,-43.03243 -15.86757,-53.91892 C 505.5973,443.7446 501.02703,424.8473 497.27838,409.75001 l -0.77027,0 c -3.8,14.99459 -7.54865,34.3027 -11.70811,48.98918 l -15.04595,53.91892 z M 261.5,86.96875 C 182.01696,224.66603 102.49955,362.34349 23,500.03125 c 79.52601,137.6516 159.01303,275.32583 238.5,413 159,0 318,0 477,0 79.48707,-137.67411 158.97388,-275.34846 238.5,-413 -79.49951,-137.68778 -159.017,-275.3652 -238.5,-413.0625 -159,0 -318,0 -477,0 z m 14.84375,25.65625 c 149.10417,0 298.20833,0 447.3125,0 C 798.20833,241.75 872.76042,370.875 947.3125,500 872.76042,629.125 798.20833,758.25 723.65625,887.375 c -149.10417,0 -298.20833,0 -447.3125,0 C 201.79167,758.25 127.23958,629.125 52.6875,500 127.23958,370.875 201.79167,241.75 276.34375,112.625 z M 500,242 C 374.04836,239.29512 257.52291,342.03121 244.04439,467.20792 225.70876,589.90115 309.65836,716.56 429.41412,748.25904 546.18673,783.97655 681.70279,722.69748 732.56859,611.82988 787.72264,502.74797 750.317,358.42131 649.3252,289.64929 606.10754,258.72845 553.13905,241.83584 500,242 z m 0,25.65625 c 115.57457,-2.72299 222.02818,93.36956 231.17737,208.59286 14.12026,112.83847 -67.3644,226.90051 -178.63888,250.18431 C 444.05716,753.87 322.67939,690.15798 283.7264,585.26728 240.65276,481.8684 285.98523,352.23297 384.27419,298.42521 419.26475,278.23386 459.61245,267.57542 500,267.65625 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="bond_any.svg"
inkscape:version="0.48.4 r9939"
id="svg3079"
version="1.1"
viewBox="0 0 1000 1000"
height="1000px"
width="1000px">
<metadata
id="metadata3094">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3092" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3090"
showgrid="false"
inkscape:zoom="0.788"
inkscape:cx="405.21344"
inkscape:cy="500"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3079"
inkscape:snap-object-midpoints="true" />
<path
inkscape:connector-curvature="0"
d="m 807.5889,373.70454 -17.41667,-30.746 167.41111,-82.27937 17.41667,30.69765 z m -257.39723,123.32238 -17.41667,-30.746 174.48334,-84.4548 17.41667,30.746 z m -252.7,118.97153 -17.41667,-30.69765 167.41112,-82.37607 17.41666,30.79434 z M 42.416668,739.32083 25.000001,708.52649 199.48334,624.07169 216.9,654.81768 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3088" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3199"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_aromatic.svg">
<metadata
id="metadata3214">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3212" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3210"
showgrid="false"
inkscape:zoom="0.816"
inkscape:cx="500"
inkscape:cy="500.61275"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3199" />
<path
sodipodi:nodetypes="cccccccccccccccccscc"
inkscape:connector-curvature="0"
d="m 354.55846,455.58994 -16.98973,-32.66037 206.56763,-108.1644 16.93696,32.66037 z M 667.12719,292.3936 650.19023,259.73323 856.75785,151.56883 873.69481,184.2292 z M 41.936961,618.78627 24.999999,586.1259 231.56762,477.9615 l 16.93696,32.66037 z m 100.896279,229.6449 -16.89739,-32.60761 832.16677,-431.21981 16.89739,32.60761 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3208" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3263"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_crossed.svg">
<metadata
id="metadata3274">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3272" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3270"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3263" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
d="M 214.92692,956.46459 C 189.8034,944.24469 170.00797,930.87122 197.28383,907.30639 382.73782,619.38274 568.19182,331.45908 753.64582,43.535417 778.76894,55.755786 798.55569,69.131287 771.28239,92.693699 585.83056,380.61733 400.37874,668.54096 214.92692,956.46459 z M 39.649459,756.73262 C 23.919163,733.64652 13.307802,712.17807 48.705005,705.24876 352.58686,547.29687 656.46869,389.34499 960.35054,231.39309 976.08086,254.47918 986.69218,275.94762 951.295,282.87693 647.41315,440.82883 343.53131,598.78072 39.649459,756.73262 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3268" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3325"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_double.svg">
<metadata
id="metadata3336">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3334" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3332"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3325" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
d="M 41.850878,615.30151 25.000005,582.7935 855.18403,152.59836 872.0349,185.11295 z M 145.33039,847.40164 128.44654,814.90682 958.11615,383.66304 975,416.15125 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3330" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3397"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_doublearomatic.svg">
<metadata
id="metadata3420">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3418" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3416"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3397" />
<path
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
d="m 924.75556,388.79722 50.24444,0 0,50.61389 -50.24444,0 z m -110.04167,-238.81945 50.24444,0 0,50.66667 -50.24444,0 z m -458.79723,245.83889 50.24445,0 0,50.61389 -50.24445,0 z m 114.68612,238.71389 50.24444,0 0,50.66667 -50.24444,0 z m 147.51389,-30.34722 -17.25834,-33.30278 210.425,-110.09444 17.31112,33.25 z M 149.97777,850.02222 132.71944,816.71944 343.09166,706.57222 360.40278,739.875 z m 346.48612,-477.58611 -17.31111,-33.30278 210.425,-110.14722 17.25833,33.30278 z M 42.258329,613.57778 24.999996,580.275 235.425,470.12778 l 17.25833,33.30277 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3414" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3483"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_down.svg">
<metadata
id="metadata3508">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3506" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3504"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3483" />
<path
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
d="M 935.1657,651.47986 599.14704,136.37837 638.98135,110.39833 975,625.49322 z M 823.74444,681.96584 526.55071,226.22657 566.29265,200.20694 863.48638,655.84066 z M 712.32317,712.35286 453.8884,316.03517 493.66993,290.08812 752.11131,686.40581 z M 600.86234,742.6607 381.14693,405.67226 420.94165,379.65263 640.65706,716.5883 z M 489.50045,773.00814 308.47142,495.3951 348.26614,469.3227 529.2424,746.98851 z M 378.13857,803.35557 235.8487,585.01239 l 39.74194,-25.96685 142.2371,218.2904 z M 266.7635,833.61724 163.18638,674.76161 l 39.74855,-25.91407 103.5771,158.85563 z m -111.50703,30.43319 -64.864339,-99.4868 39.794719,-26.01962 64.86434,99.43402 z M 51.16478,889.60166 25.000011,849.44408 64.801335,823.51682 90.966087,863.6678 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3502" />
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3555"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_single.svg">
<metadata
id="metadata3564">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3562" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3560"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3555" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
d="M 43.960687,760.20465 25.000012,723.7281 956.03271,239.79536 l 18.96728,36.47653 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3558" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3619"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_singlearomatic.svg">
<metadata
id="metadata3636">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3634" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3632"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3619" />
<path
sodipodi:nodetypes="ccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
d="M 144.81672,842.64301 127.97985,810.1234 958.16973,380.25911 975,412.77214 z M 798.40091,157.357 l 49.27733,0 0,49.59389 -49.27733,0 z m -449.35232,240.68865 49.22458,0 0,49.59389 -49.22458,0 z m 137.64943,-22.89761 -16.93579,-32.55258 206.07845,-107.8931 16.88303,32.55259 z M 41.935778,611.35214 24.999991,578.7468 231.02568,470.8537 l 16.93579,32.60535 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3630" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3700"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_singledouble.svg">
<metadata
id="metadata3721">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3719" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3717"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3700" />
<path
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
d="m 407.50181,572.41513 -17.15373,-33.0935 209.11717,-109.4672 17.15373,33.04073 z M 765.83004,386.20479 748.67631,353.16406 957.84627,243.64409 975,276.7376 z M 42.100958,763.21739 25.000008,730.12389 234.11718,620.6567 251.27091,653.69742 z M 679.74471,691.11895 662.59098,658.02544 871.76093,548.55825 888.91466,581.59897 z M 326.06117,877.32929 308.90744,844.23578 518.02461,734.71581 535.17834,767.75654 z M 486.62009,265.2314 469.46636,232.1379 678.58353,122.67071 l 17.15373,33.04072 z m -358.38101,190.80227 -17.15374,-33.04073 209.11718,-109.51997 17.15373,33.04072 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3715" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3772"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_triple.svg">
<metadata
id="metadata3785">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3783" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3781"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3772" />
<path
sodipodi:nodetypes="ccccccccccccccc"
inkscape:connector-curvature="0"
d="M 226.3235,893.86915 211.12878,864.54149 959.81188,476.67372 975,505.99479 z m -95.68588,-183.37209 -15.24089,-29.30129 748.00383,-389.13399 15.2409,29.29469 z M 40.194716,523.32628 24.999992,494.00521 773.68311,106.13085 l 15.18812,29.32107 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3779" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3832"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_up.svg">
<metadata
id="metadata3841">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3839" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3837"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3832" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
d="M 24.999996,889.02501 661.975,110.975 975,595.84445 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3835" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3888"
inkscape:version="0.48.4 r9939"
sodipodi:docname="bond_updown.svg">
<metadata
id="metadata3897">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3895" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3893"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3888" />
<path
sodipodi:nodetypes="ccccccccccccccccccc"
inkscape:connector-curvature="0"
d="M 56.508328,883.35139 24.999995,866.04028 111.08055,708.55139 263.97777,765.12917 249.88611,513.5375 480.31389,685.85695 385.57777,318.52361 691.58333,602.78473 509.025,116.64861 975,587.84862 949.45556,613.12917 601.86111,261.73472 778.87778,732.9875 451.12778,428.45973 540.63889,775.89584 290.10277,588.53473 302.98055,817.90695 127.75833,753.09584 z"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3891" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg3944"
inkscape:version="0.48.4 r9939"
sodipodi:docname="chain.svg">
<metadata
id="metadata3953">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3951" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview3949"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="-36.016949"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg3944" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
d="m 337.18056,647.03889 -312.180562,-217.075 0,-77.00278 L 337.18056,565.12777 645.35,352.96111 975,565.12777 l 0,81.91112 -329.65,-217.075 z"
style="fill:#232323;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path3947" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg4889"
inkscape:version="0.48.4 r9939"
sodipodi:docname="charge_minus.svg">
<metadata
id="metadata4900">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4898" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview4896"
showgrid="false"
inkscape:zoom="0.5"
inkscape:cx="500"
inkscape:cy="500"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg4889" />
<path
id="path4894"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#232323;fill-opacity:1;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="m 620.54621,105.63025 c 0,43.64146 0,87.28291 0,130.92437 118.15127,0 236.30253,0 354.4538,0 0,-43.64146 0,-87.28291 0,-130.92437 -118.15127,0 -236.30253,0 -354.4538,0 z m 25.54622,25.54622 c 101.12045,0 202.24091,0 303.36136,0 0,26.61064 0,53.22129 0,79.83193 -101.12045,0 -202.24091,0 -303.36136,0 0,-26.61064 0,-53.22129 0,-79.83193 z M 315.58824,54.537816 C 217.79313,351.16839 121.28736,648.31607 24.999992,945.46219 c 46.302518,0 92.605048,0 138.907568,0 25.11444,-91.08472 55.76881,-180.85288 83.02521,-271.42857 91.54061,0 183.08124,0 274.62185,0 28.95815,90.55854 60.41705,180.46029 87.81513,271.42857 46.83473,0 93.66948,0 140.50421,0 C 654.06097,648.33488 558.18172,351.15654 460.88235,54.537816 c -48.43137,0 -96.86275,0 -145.29411,0 z m 17.56301,25.546219 c 36.7227,0 73.44539,0 110.16808,0 90.47619,279.943985 180.95238,559.887945 271.42857,839.831935 -28.73949,0 -57.47899,0 -86.21848,0 -29.46157,-90.40782 -57.41319,-181.35939 -87.81513,-271.42857 -103.78151,0 -207.56304,0 -311.34455,0 -29.51432,90.01363 -56.19751,181.02919 -84.62184,271.42857 -27.67507,0 -55.350149,0 -83.025214,0 C 152.19887,639.97198 242.67506,360.02802 333.15125,80.084035 z m 38.31933,73.445375 c -31.05302,145.82339 -82.74123,286.1567 -127.65132,428.07896 5.08436,10.53393 37.95757,1.60379 53.78908,4.61012 76.2454,0 152.4908,0 228.7362,0 -42.85341,-144.44483 -99.19133,-285.09212 -130.92438,-432.68908 -7.98319,0 -15.96639,0 -23.94958,0 z m 12.77311,54.28572 c 27.14928,120.23798 71.64827,235.46632 108.57143,352.85714 -71.84874,0 -143.69747,0 -215.54621,0 36.63565,-117.31388 81.094,-232.46281 106.97478,-352.85714 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg2"
inkscape:version="0.48.4 r9939"
sodipodi:docname="charge_plus.svg">
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs11" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview9"
showgrid="false"
inkscape:zoom="0.5"
inkscape:cx="423"
inkscape:cy="501"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path7"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#232323;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:25.67567444;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="m 731.65625,44.1875 c 0,37.364583 0,74.72917 0,112.09375 -37.38542,0 -74.77083,0 -112.15625,0 0,43.75 0,87.5 0,131.25 37.38542,0 74.77083,0 112.15625,0 0,37.36458 0,74.72917 0,112.09375 43.76042,0 87.52083,0 131.28125,0 0,-37.36458 0,-74.72917 0,-112.09375 37.35417,0 74.70833,0 112.0625,0 0,-43.75 0,-87.5 0,-131.25 -37.35417,0 -74.70833,0 -112.0625,0 0,-37.36458 0,-74.729167 0,-112.09375 -43.76042,0 -87.52083,0 -131.28125,0 z m 25.65625,25.65625 c 26.65625,0 53.3125,0 79.96875,0 0,37.375 0,74.75 0,112.125 37.34375,0 74.6875,0 112.03125,0 0,26.625 0,53.25 0,79.875 -37.34375,0 -74.6875,0 -112.03125,0 0,37.375 0,74.75 0,112.125 -26.65625,0 -53.3125,0 -79.96875,0 0,-37.375 0,-74.75 0,-112.125 -37.38542,0 -74.77083,0 -112.15625,0 0,-26.625 0,-53.25 0,-79.875 37.38542,0 74.77083,0 112.15625,0 0,-37.375 0,-74.75 0,-112.125 z m -446.40625,-8.0625 c -96.95367,297.99834 -193.82448,596.02372 -290.75,894.03125 46.291667,0 92.58333,0 138.875,0 28.26063,-91.03512 56.47566,-182.08442 84.71875,-273.125 91.51042,0 183.02083,0 274.53125,0 29.47956,91.04154 58.95593,182.08411 88.4375,273.125 47.05208,0 94.10417,0 141.15625,0 C 650.99701,657.80306 554.10775,359.79726 457.25,61.78125 c -48.78125,0 -97.5625,0 -146.34375,0 z m 18.65625,25.6875 c 36.34375,0 72.6875,0 109.03125,0 91.3125,280.89583 182.625,561.79167 273.9375,842.6875 -29.04167,0 -58.08333,0 -87.125,0 C 595.92659,839.10433 566.45093,748.05111 536.96875,657 c -104.04167,0 -208.08333,0 -312.125,0 -28.26124,91.04535 -56.47556,182.10529 -84.71875,273.15625 -28.20833,0 -56.416667,0 -84.625,0 C 146.85417,649.26042 238.20833,368.36458 329.5625,87.46875 z M 367.625,161 c -28.52254,141.51419 -79.7389,276.78333 -122.47528,414.30068 -8.88811,16.33685 -5.53664,23.75883 13.53081,19.76182 88.18982,0 176.37965,0 264.56947,0 C 473.04087,438.16621 426.80248,305.3818 391.71875,161 c -8.03125,0 -16.0625,0 -24.09375,0 z m 12.59375,60.875 c 29.76983,117.65318 71.46037,231.79826 107.71875,347.53125 -71.3125,0 -142.625,0 -213.9375,0 C 309.99584,453.75898 352.14073,339.82337 380.21875,221.875 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="0 0 750 750"><path d="M361.875 603.375L141.75 375h104.625l106.5 112.5 165.75-235.875L612 249zM375 0C167.895 0 0 167.895 0 375s167.895 375 375 375 375-167.895 375-375S582.105 0 375 0zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 271 B

View File

@ -0,0 +1,14 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 -5 70 35">
<defs>
<style>.cls-1{fill:#656565;}</style>
</defs>
<title>Chiral Btn</title>
<path class="cls-1" d="M0,25H69V0H0ZM68,1V24H1V1Z"/>
<path d="M21,18.14a3.85,3.85,0,0,0,2.71-.93,3.07,3.07,0,0,0,1-2.43v0H23.1a2.09,2.09,0,0,1-.53,1.54,2.09,2.09,0,0,1-1.55.53,1.94,1.94,0,0,1-1.64-.8,3.31,3.31,0,0,1-.6-2V12.07a3.33,3.33,0,0,1,.59-2,1.89,1.89,0,0,1,1.6-.8,2.18,2.18,0,0,1,1.59.53,2,2,0,0,1,.54,1.53h1.61v0a3,3,0,0,0-1-2.45A4,4,0,0,0,21,7.9a3.58,3.58,0,0,0-2.78,1.18,4.3,4.3,0,0,0-1.07,3V14a4.25,4.25,0,0,0,1.08,3A3.65,3.65,0,0,0,21,18.14Z"/>
<path d="M27.77,12.54a1.67,1.67,0,0,1,.64-.52,2.09,2.09,0,0,1,.92-.19,1.26,1.26,0,0,1,1,.39,1.91,1.91,0,0,1,.34,1.26V18h1.66V13.49a3.36,3.36,0,0,0-.66-2.29,2.33,2.33,0,0,0-1.84-.74,2.42,2.42,0,0,0-1.17.29,2.63,2.63,0,0,0-.9.81V7.34H26.11V18h1.66Z"/>
<rect x="34.16" y="7.34" width="1.66" height="1.46"/>
<rect x="34.16" y="10.6" width="1.66" height="7.4"/>
<path d="M39.32,12.86a1.35,1.35,0,0,1,.5-.58,1.49,1.49,0,0,1,.81-.21l.71,0,.2-1.55-.24-.06-.28,0a1.68,1.68,0,0,0-1,.32,2.38,2.38,0,0,0-.72.89l-.11-1.07H37.66V18h1.66Z"/>
<path d="M45.49,13.65a4.08,4.08,0,0,0-2.39.6,1.93,1.93,0,0,0-.85,1.67,2.16,2.16,0,0,0,.62,1.63,2.46,2.46,0,0,0,1.77.59,2.3,2.3,0,0,0,1.25-.35,2.85,2.85,0,0,0,.9-.87,4,4,0,0,0,.08.53q.06.27.15.55H48.7a4.59,4.59,0,0,1-.2-.82,6,6,0,0,1-.06-.88V13a2.31,2.31,0,0,0-.79-1.89,3.17,3.17,0,0,0-2.08-.66,3.32,3.32,0,0,0-2.16.68,1.83,1.83,0,0,0-.78,1.55v0h1.6a.86.86,0,0,1,.33-.7,1.39,1.39,0,0,1,.9-.27,1.35,1.35,0,0,1,1,.33,1.21,1.21,0,0,1,.34.91v.65Zm1.29,2.13a1.59,1.59,0,0,1-.67.72,2.07,2.07,0,0,1-1.12.31,1.15,1.15,0,0,1-.8-.25.86.86,0,0,1-.28-.67,1.09,1.09,0,0,1,.41-.84,1.67,1.67,0,0,1,1.13-.36h1.32Z"/>
<rect x="50.27" y="7.34" width="1.66" height="10.66"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 750 750.00002" height="1000" width="1000"><path d="M376.223 700.95L750 169.991 503.375 44.156l-128.2 650.504L246.974 44.156 0 169.992 373.777 700.95v4.895l2.098-3.145 2.094 3.145zM82.789 190.612l123.313-62.918 65.324 331.02zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 290 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="0 0 750 750"><path d="M750 625c.598 49.754-28.371 95.125-73.758 115.52-45.383 20.394-98.543 11.925-135.347-21.555-36.81-33.485-50.25-85.61-34.227-132.715L375 447.918 243.332 586.25c16.805 51.543-1.527 108.04-45.394 139.895-43.864 31.855-103.266 31.8-147.075-.13C7.055 694.083-11.18 637.552 5.72 586.04 22.613 534.527 70.789 499.777 125 500a125.019 125.019 0 0 1 64.582 18.75L333.332 375V242.5c-57.394-20.293-91.828-78.984-81.531-138.988C262.094 43.508 314.12-.352 375-.352s112.906 43.86 123.2 103.864c10.296 60.004-24.137 118.695-81.532 138.988V375l143.75 143.75c38.488-23.227 86.48-24 125.695-2.02C725.328 538.707 749.723 580.047 750 625zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 728 B

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg2"
inkscape:version="0.48.4 r9939"
sodipodi:docname="edit-copy.svg">
<metadata
id="metadata23">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs21" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview19"
showgrid="false"
inkscape:zoom="0.5"
inkscape:cx="509.29134"
inkscape:cy="504.35593"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path7"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#232323;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:25.67567444;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="m 233.625,137.25 c -15.75121,0 -27.46875,13.86495 -27.46875,29.0625 l 0,779.71875 C 206.15625,961.24737 217.87649,975 233.625,975 l 586.625,0 5.03125,0 3.6875,-3.40625 130.6875,-121.0625 4.125,-3.78125 0,-5.625 0,-674.8125 c 0,-15.29536 -11.72232,-29.0625 -27.46875,-29.0625 z m 0,25.6875 702.6875,0 c 0.27519,0 1.78125,0.69738 1.78125,3.375 l 0,669.21875 L 815.25,949.3125 l -581.625,0 c -0.37583,0 -1.8125,-0.72981 -1.8125,-3.28125 l 0,-779.71875 c 0,-2.77543 1.33667,-3.375 1.8125,-3.375 z m 124.77366,606.9652 472.74052,0 0,21.36216 -472.74052,0 z m 0,-113.53784 472.74052,0 0,21.41352 -472.74052,0 z m 0,-113.58918 472.74052,0 0,21.41351 -472.74052,0 z m 0,-113.53784 472.74052,0 0,21.41352 -472.74052,0 z m 0,-113.53783 472.74052,0 0,21.36216 -472.74052,0 z M 63.6875,25 C 47.882118,25 36.21875,38.927445 36.21875,54.125 l 0,779.59375 c 0,15.23108 11.611217,29.125 27.46875,29.125 l 142.46875,0 0,-25.65625 -142.46875,0 c -0.266791,0 -1.78125,-0.82957 -1.78125,-3.46875 l 0,-779.59375 c 0,-2.775417 1.359606,-3.4375 1.78125,-3.4375 l 702.6875,0 c 0.22033,0 1.8125,0.7599 1.8125,3.4375 l 0,83.125 25.65625,0 0,-83.125 C 793.84375,38.829628 782.17629,25 766.375,25 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssccccccssssssccsssscccccccccccccccccccccccccssssccssssssccsss" />
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg2"
inkscape:version="0.48.4 r9939"
sodipodi:docname="edit-cut.svg">
<metadata
id="metadata11">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs9" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview7"
showgrid="false"
inkscape:zoom="0.236"
inkscape:cx="116.52542"
inkscape:cy="502.11864"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path5"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#232323;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:25.67759323;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="m 188.59375,20.5625 c -41.9739,25.386468 -41.9363,82.30052 -39.58035,125.68133 7.16328,84.36486 69.36316,147.92745 116.48231,213.41185 43.80497,56.06746 89.43881,110.67704 135.59804,164.81307 -19.52083,23.96875 -39.04167,47.9375 -58.5625,71.90625 -73.59618,-17.17683 -141.83587,30.81882 -186.27934,85.05329 -46.46909,50.91774 -91.788688,124.35222 -60.508997,194.53235 32.385377,82.17639 135.850017,121.60056 215.949337,86.16651 76.85816,-32.00841 134.03287,-101.74018 165.26521,-177.36945 23.65403,-38.59641 -4.38972,-87.69494 -1.48831,-118.83988 15.14832,-23.22823 30.19455,-33.85669 45.33087,-4.26627 18.20114,27.33365 -24.52119,71.74861 -2.15455,108.89548 24.0083,74.26128 77.10818,139.98902 144.24637,179.71738 73.62266,45.36336 181.7133,26.59969 227.65484,-48.93183 C 931.68015,846.11349 914.43834,770.2591 874.3541,719.78746 828.07096,656.94488 763.67222,587.33082 678.25827,593.50017 654.13719,605.63693 645.74177,578.90898 631.92526,564.99767 620.91892,551.47762 609.91259,537.95756 598.90625,524.4375 680.00105,426.60618 766.08272,331.244 830.25675,221.02132 855.85493,165.70711 862.11803,96.69521 834.03092,41.149106 820.59144,12.889789 803.8261,23.054165 792.66856,43.446399 695.10196,163.2976 597.53535,283.1488 499.96875,403 396.17425,275.52314 292.40248,148.02776 188.59375,20.5625 z M 186.125,58.1875 C 290.73217,186.68311 395.39914,315.13012 499.96875,443.65625 604.57709,315.16158 709.19895,186.67792 813.8125,58.1875 c 28.59676,66.96359 6.73768,145.90514 -37.27079,201.11417 -64.80768,92.51367 -137.95159,178.8028 -211.01046,264.82333 27.3726,33.66473 54.79372,67.29 82.1875,100.9375 60.43539,-21.82579 122.88104,12.71794 162.38655,57.55394 42.65209,46.80434 95.46125,108.67093 73.69002,176.74145 C 858.71565,932.91864 767.81648,969.87468 697.62151,938.17427 625.88594,907.69842 572.44899,841.36538 545.09375,769.6875 532.60911,736.72152 539.0616,697.45432 565.625,673.28125 c -22.05023,-24.4384 -43.90363,-49.05402 -65.59375,-73.8125 -21.74523,24.70852 -43.48093,49.42827 -65.625,73.78125 35.38937,31.29995 31.08882,84.49057 10.00453,122.6644 -39.92551,76.23289 -109.9766,153.70798 -202.64033,153.42186 -77.32244,0.70053 -153.182172,-80.45752 -124.95187,-158.08019 24.72899,-61.99109 71.15024,-115.73319 126.4486,-152.74783 32.18032,-20.33536 72.89002,-25.51261 109.04532,-13.44569 27.34638,-33.67754 54.79964,-67.26824 82.15625,-100.9375 C 351.1499,424.4786 264.1063,326.64978 195.90625,215.6875 171.53797,168.26961 164.68558,107.842 186.125,58.1875 z m 489.5625,614.34375 c -47.41998,-4.12622 -79.36335,47.44784 -66.03426,90.39445 15.34441,62.16278 66.23701,115.74592 126.95195,135.42811 48.76378,15.21967 101.54806,-31.22597 90.88918,-81.99813 C 816.63649,743.99255 749.8688,676.79222 675.6875,672.53125 z m -351.40625,0.0313 c -76.43123,5.21861 -143.681,73.38336 -152.27409,148.8103 -8.15542,54.13166 53.29775,95.85591 101.43034,73.9397 59.46731,-25.67092 111.89425,-81.43618 118.93985,-147.77314 4.97977,-40.65385 -26.74113,-77.63886 -68.0961,-74.97686 z m -0.1875,25.65625 c 56.19247,-1.75863 48.73137,72.64041 22.64417,102.77799 -25.88443,35.89502 -63.16781,74.4713 -110.47975,74.28536 -48.46873,-8.66916 -45.66996,-71.25212 -21.33905,-102.78736 23.46541,-37.90747 63.09581,-71.54805 109.17463,-74.27599 z m 351.78125,0 c 65.12146,6.37585 123.10326,66.69779 126.60182,132.07325 -0.0395,47.12716 -62.08963,57.59628 -91.72994,28.273 -42.19759,-29.47593 -84.98785,-77.4615 -75.80747,-132.63037 4.23704,-18.25442 22.98865,-28.82381 40.93559,-27.71588 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000px"
height="1000px"
viewBox="0 0 1000 1000"
version="1.1"
id="svg2"
inkscape:version="0.48.4 r9939"
sodipodi:docname="dearom.svg">
<metadata
id="metadata19">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs17" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="985"
id="namedview15"
showgrid="false"
inkscape:zoom="0.5"
inkscape:cx="170"
inkscape:cy="501"
inkscape:window-x="-2"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path13"
style="fill:#232323;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 464.67027,555.69054 -18.12703,65.26757 -59.56757,0 77.6946,-254.13783 75.43513,0 78.77297,254.13783 -61.87838,0 -19.56486,-65.26757 z m 64.44594,-43.03243 -15.86757,-53.91892 c -4.46756,-14.99459 -9.03783,-33.89189 -12.78648,-48.98918 l -0.77027,0 c -3.8,14.99459 -7.54865,34.3027 -11.70811,48.98918 l -15.04595,53.91892 z m -168.89746,-321.75186 -0.3125,25.65625 260.9375,3.125 0.28125,-25.65625 -260.90625,-3.125 z m 400.6875,323.875 L 625.6875,744.25 l 22.125,13.03125 135.21875,-229.46875 -22.125,-13.03125 z m -553.28125,0 L 185.5,527.8125 320.71875,757.28125 342.84375,744.25 207.625,514.78125 z M 261.5,86.96875 C 182.01696,224.66603 102.49955,362.34349 23,500.03125 c 79.52601,137.6516 159.01303,275.32583 238.5,413 159,0 318,0 477,0 79.48707,-137.67411 158.97388,-275.34846 238.5,-413 -79.49951,-137.68778 -159.017,-275.3652 -238.5,-413.0625 -159,0 -318,0 -477,0 z m 14.84375,25.65625 c 149.10417,0 298.20833,0 447.3125,0 C 798.20833,241.75 872.76042,370.875 947.3125,500 872.76042,629.125 798.20833,758.25 723.65625,887.375 c -149.10417,0 -298.20833,0 -447.3125,0 C 201.79167,758.25 127.23958,629.125 52.6875,500 127.23958,370.875 201.79167,241.75 276.34375,112.625 z" />
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Some files were not shown because too many files have changed in this diff Show More