diff --git a/.gitignore b/.gitignore index 2f989b4e26ac8e8a501051a09660ffab81d7b5cc..57f16fb67c1b1589981416b323d7a9debc728665 100644 --- a/.gitignore +++ b/.gitignore @@ -1,144 +1,41 @@ -### Java template -# Compiled class file -*.class -target/* - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -### VisualStudioCode template -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +/build* +/workspace +setting.xml +release/ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +icy.log + +### IntelliJ IDEA ### .idea/ - - *.iml - *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format *.iws +*.iml +*.ipr -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Eclipse template -.metadata -bin/ -tmp/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.settings/ -.loadpath -.recommenders - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# PyDev specific (Python IDE for Eclipse) -*.pydevproject - -# CDT-specific (C/C++ Development Tooling) -.cproject - -# CDT- autotools -.autotools - -# Java annotation processor (APT) +### Eclipse ### +.apt_generated +.classpath .factorypath - -# PDT-specific (PHP Development Tools) -.buildpath - -# sbteclipse plugin -.target - -# Tern plugin -.tern-project - -# TeXlipse plugin -.texlipse - -# STS (Spring Tool Suite) -.springBeans - -# Code Recommenders -.recommenders/ - -# Annotation Processing -.apt_generated/ -.apt_generated_test/ - -# Scala IDE specific (Scala & Java development for Eclipse) -.cache-main -.scala_dependencies -.worksheet - -# Uncomment this line if you wish to ignore the project description file. -# Typically, this file would be tracked if it contains build/dependency configurations: -#.project - -/target/ .project -.classpath +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### **/.DS_Store +Icon? \ No newline at end of file diff --git a/pom.xml b/pom.xml index 56d2bed859423080909a20b02dff9a025a9999c7..82c90648fa3f329f4ca15075976b48e88653b4c5 100644 --- a/pom.xml +++ b/pom.xml @@ -8,14 +8,12 @@ <parent> <artifactId>pom-icy</artifactId> <groupId>org.bioimageanalysis.icy</groupId> - <version>2.2.0</version> + <version>3.0.0-a.1</version> </parent> <!-- Project Information --> <artifactId>icy-jep</artifactId> - <version>5.0.0</version> - - <packaging>jar</packaging> + <version>5.0.0-a.1</version> <name>JEP - Java Embedded Python for Icy</name> <description>Jep embeds CPython in Java through JNI. Fork to include the library in Icy.</description> @@ -69,17 +67,22 @@ </developer> </developers> - <!-- Project properties --> - <properties> - <artifact-to-extract>jep</artifact-to-extract> - </properties> - <!-- List of project's dependencies --> <dependencies> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>icy-kernel</artifactId> + </dependency> + + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>script-manager-core</artifactId> + </dependency> + <dependency> <groupId>black.ninia</groupId> <artifactId>jep</artifactId> - <version>4.1.1</version> + <version>4.2.0</version> </dependency> </dependencies> @@ -87,8 +90,7 @@ <repositories> <repository> <id>icy</id> - <name>Icy's Nexus</name> - <url>https://icy-nexus.pasteur.fr/repository/Icy/</url> + <url>https://nexus-icy.pasteur.cloud/repository/icy/</url> </repository> </repositories> </project> diff --git a/src/main/java/plugins/atournay/jep/JepPlugin.java b/src/main/java/plugins/atournay/jep/JepPlugin.java index afce2fce7eee66489a9cecba39a7b0ba68c3dac9..8409b07b781e7708c0d9fa94b691822ba69605bb 100644 --- a/src/main/java/plugins/atournay/jep/JepPlugin.java +++ b/src/main/java/plugins/atournay/jep/JepPlugin.java @@ -1,14 +1,41 @@ package plugins.atournay.jep; -import icy.plugin.abstract_.Plugin; -import icy.plugin.interface_.PluginDaemon; -import icy.plugin.interface_.PluginLibrary; +import org.bioimageanalysis.icy.extension.plugin.abstract_.Plugin; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginDescription; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.extension.plugin.interface_.PluginDaemon; +import org.bioimageanalysis.icy.extension.plugin.interface_.PluginLibrary; +import org.bioimageanalysis.icy.gui.frame.progress.ToolTipFrame; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import plugins.atournay.jep.prefs.JepPreferences; import plugins.atournay.jep.utils.JepUtils; -public class JepPlugin extends Plugin implements PluginLibrary, PluginDaemon { +/** + * @author Amandine TOURNAY + * @author Thomas MUSSET + */ +@IcyPluginName("Jep for Icy") +@IcyPluginDescription(shortDesc = "Jep library wrapper for Icy. This library embed an interpreter for Python 3.") +@IcyPluginIcon(path = "/plugins/atournay/jep/python-logo-only.svg") +public final class JepPlugin extends Plugin implements PluginLibrary, PluginDaemon { private static JepPlugin instance; + private void showInstallMessage() { + final String message = "<div style=\"font-weight: bold; font-size: 105%; margin-bottom: 8px;\">" + + "You've just install the Jep plugin" + + "</div>" + + "<div style=\"margin-bottom: 8px;\">" + + "To use this plugin, you have to <strong>configure your Python or Conda environment</strong> in a specific way.<br>" + + "You must install Jep library:<br>" + + "In Python:<br><tt>$ pip install jep</tt><br>" + + "In Conda:<br><tt>$ conda install conda-forge::jep</tt><br/>" + + "</div>" + + "<div style=\"margin-bottom: 8px;\">" + + "Jep library must be installed on each environment you want to use in Icy." + + "</div>"; + new ToolTipFrame(message, "jep.installation"); + } public JepPlugin() { } @@ -30,6 +57,7 @@ public class JepPlugin extends Plugin implements PluginLibrary, PluginDaemon { @Override public void run() { + ThreadUtil.invokeLater(this::showInstallMessage); } @Override diff --git a/src/main/java/plugins/atournay/jep/engine/JepEngine.java b/src/main/java/plugins/atournay/jep/engine/JepEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..7a9ec41351940904a477f9dcb79372b3d4990ccf --- /dev/null +++ b/src/main/java/plugins/atournay/jep/engine/JepEngine.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2010-2023. Institut Pasteur. + * + * This file is part of Icy. + * Icy is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Icy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Icy. If not, see <https://www.gnu.org/licenses/>. + */ + +package plugins.atournay.jep.engine; + +import jep.JepConfig; +import jep.SharedInterpreter; +import org.bioimageanalysis.icy.extension.plugin.PluginLoader; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginDescription; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import plugins.atournay.jep.exec.DefaultClassEnquirer; +import plugins.tmusset.script.core.AbstractEngine; +import plugins.tmusset.script.core.EngineException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +/** + * @author Thomas MUSSET + */ +@IcyPluginName("Script Manager - Jep") +@IcyPluginDescription(shortDesc = "Jep engine implementation for script manager.") +@IcyPluginIcon(path = "/plugins/atournay/jep/python-logo-only.svg") +public final class JepEngine extends AbstractEngine<SharedInterpreter> { + private static @Nullable AbstractEngine<SharedInterpreter> instance = null; + + public static @NotNull AbstractEngine<SharedInterpreter> getInstance() { + if (instance == null) + instance = new JepEngine(); + + return instance; + } + + private static final @NotNull JepConfig CONFIG = new JepConfig(); + + /** + * JepEngine constructor. + */ + @SuppressWarnings("UseOfSystemOutOrSystemErr") + public JepEngine() { + super("Jep", "Python 3", new String[]{"py"}); + CONFIG.setClassEnquirer(new DefaultClassEnquirer()); + CONFIG.setClassLoader(PluginLoader.getLoader()); + CONFIG.redirectStdout(System.out); + CONFIG.redirectStdErr(System.err); + SharedInterpreter.setConfig(CONFIG); + } + + /** + * {@inheritDoc} + * + * @param name {@inheritDoc} + * @return {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + protected @NotNull Interpreter<SharedInterpreter> createInterpreterInstance(final @NotNull String name) throws EngineException { + try { + return new JepInterpreter(new SharedInterpreter(), name); + } + catch (final Throwable t) { + throw new EngineException(this, t); + } + } + + public final class JepInterpreter extends AbstractInterpreter { + JepInterpreter(final @NotNull SharedInterpreter context, final @NotNull String name) { + super(JepEngine.getInstance(), context, name); + } + + /** + * {@inheritDoc} + */ + @Override + public void destroy() { + context.close(); + } + + /** + * {@inheritDoc} + * + * @param file {@inheritDoc} + * @param name {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + public void loadFile(@NotNull final File file, @NotNull final String name) throws EngineException { + context.runScript(file.getAbsolutePath()); + } + + /** + * {@inheritDoc} + * + * @param stream {@inheritDoc} + * @param name {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + public void loadFileAsStream(final @NotNull InputStream stream, final @NotNull String name) throws EngineException { + try (final InputStreamReader streamReader = new InputStreamReader(stream, StandardCharsets.UTF_8); final BufferedReader reader = new BufferedReader(streamReader)) { + final StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + //context.exec(line); + builder.append(line).append("\n\r"); + } + + context.exec(builder.toString()); + } + catch (final Throwable t) { + throw new EngineException(this, t); + } + } + + /** + * {@inheritDoc} + * + * @param script {@inheritDoc} + * @return {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + public @Nullable Object runScript(final @NotNull String script) throws EngineException { + try { + context.exec(script); + return null; + } + catch (final Throwable t) { + throw new EngineException(this, t); + } + } + + /** + * {@inheritDoc} + * + * @param name {@inheritDoc} + * @param value {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + public void putVariable(final @NotNull String name, final @NotNull Object value) throws EngineException { + try { + context.set(name, value); + } + catch (final Throwable t) { + throw new EngineException(this, t); + } + } + + /** + * {@inheritDoc} + * + * @param name {@inheritDoc} + * @return {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + public @Nullable Object getVariable(final @NotNull String name) throws EngineException { + try { + return context.getValue(name); + } + catch (final Throwable t) { + throw new EngineException(this, t); + } + } + + /** + * {@inheritDoc} + * + * @param name {@inheritDoc} + * @param args {@inheritDoc} + * @return {@inheritDoc} + * @throws EngineException {@inheritDoc} + */ + @Override + public @Nullable Object callFunction(final @NotNull String name, final @NotNull Object... args) throws EngineException { + try { + return context.invoke(name, args); + } + catch (final Throwable t) { + throw new EngineException(this, t); + } + } + } +} diff --git a/src/main/java/plugins/atournay/jep/exec/PythonExec.java b/src/main/java/plugins/atournay/jep/exec/PythonExec.java index c359815baf5364a797ec6695153de3043a0c17b1..c6567d5e799f880dc208e1179b9dab9b4226c533 100644 --- a/src/main/java/plugins/atournay/jep/exec/PythonExec.java +++ b/src/main/java/plugins/atournay/jep/exec/PythonExec.java @@ -1,9 +1,9 @@ package plugins.atournay.jep.exec; -import icy.system.IcyExceptionHandler; import jep.JepConfig; import jep.JepException; import jep.SubInterpreter; +import org.bioimageanalysis.icy.system.IcyExceptionHandler; import java.io.Closeable; diff --git a/src/main/java/plugins/atournay/jep/prefs/JepPreferences.java b/src/main/java/plugins/atournay/jep/prefs/JepPreferences.java index 6cae41188f8701eec03a0df484a87a6f7e06d990..5c7cc432f2182aaa01d102c8906da76414827a58 100644 --- a/src/main/java/plugins/atournay/jep/prefs/JepPreferences.java +++ b/src/main/java/plugins/atournay/jep/prefs/JepPreferences.java @@ -1,7 +1,7 @@ package plugins.atournay.jep.prefs; -import icy.preferences.PluginPreferences; -import icy.preferences.XMLPreferences; +import org.bioimageanalysis.icy.system.preferences.PluginPreferences; +import org.bioimageanalysis.icy.system.preferences.XMLPreferences; import plugins.atournay.jep.ui.Python3Preferences; /** diff --git a/src/main/java/plugins/atournay/jep/ui/JepPreferencesWindow.java b/src/main/java/plugins/atournay/jep/ui/JepPreferencesWindow.java index 8456cb713366b0c836123de3dd6cc622ec2a1801..113139abb626189b559fb0b2b4bdb7319f4d70c2 100644 --- a/src/main/java/plugins/atournay/jep/ui/JepPreferencesWindow.java +++ b/src/main/java/plugins/atournay/jep/ui/JepPreferencesWindow.java @@ -1,8 +1,8 @@ package plugins.atournay.jep.ui; -import icy.gui.component.IcyTextField; -import icy.gui.dialog.MessageDialog; -import icy.gui.frame.IcyFrame; +import org.bioimageanalysis.icy.gui.component.field.IcyTextField; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.gui.frame.IcyFrame; import plugins.atournay.jep.prefs.JepPreferences; import plugins.atournay.jep.utils.JepUtils; import plugins.atournay.jep.utils.PythonUtils; diff --git a/src/main/java/plugins/atournay/jep/ui/Python3Preferences.java b/src/main/java/plugins/atournay/jep/ui/Python3Preferences.java index 63379f662bc2161162f1aa3a8a45f6af79a108dd..41be2410dbbb297c838569adc64a9cf3bfa0432e 100644 --- a/src/main/java/plugins/atournay/jep/ui/Python3Preferences.java +++ b/src/main/java/plugins/atournay/jep/ui/Python3Preferences.java @@ -1,11 +1,17 @@ package plugins.atournay.jep.ui; -import icy.gui.frame.IcyFrameAdapter; -import icy.gui.frame.IcyFrameEvent; -import icy.plugin.abstract_.PluginActionable; -import icy.plugin.interface_.PluginBundled; +import org.bioimageanalysis.icy.extension.plugin.abstract_.PluginActionable; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginDescription; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.extension.plugin.interface_.PluginBundled; +import org.bioimageanalysis.icy.gui.frame.IcyFrameAdapter; +import org.bioimageanalysis.icy.gui.frame.IcyFrameEvent; import plugins.atournay.jep.JepPlugin; +@IcyPluginName("Python 3 preferences") +@IcyPluginDescription(shortDesc = "Jep configuration panel.") +@IcyPluginIcon(path = "/plugins/atournay/jep/python-logo-only.svg") public class Python3Preferences extends PluginActionable implements PluginBundled { @Override public void run() { diff --git a/src/main/java/plugins/atournay/jep/utils/PythonUtils.java b/src/main/java/plugins/atournay/jep/utils/PythonUtils.java index 398e589632a1baf66792286ae5d4634ae6f371f0..33b0976c8d91a6b9f111fdc333edf89055e0b162 100644 --- a/src/main/java/plugins/atournay/jep/utils/PythonUtils.java +++ b/src/main/java/plugins/atournay/jep/utils/PythonUtils.java @@ -1,9 +1,9 @@ package plugins.atournay.jep.utils; -import icy.gui.dialog.MessageDialog; -import icy.gui.frame.IcyFrame; -import icy.system.IcyExceptionHandler; -import icy.system.thread.ThreadUtil; +import org.bioimageanalysis.icy.gui.dialog.MessageDialog; +import org.bioimageanalysis.icy.gui.frame.IcyFrame; +import org.bioimageanalysis.icy.system.IcyExceptionHandler; +import org.bioimageanalysis.icy.system.thread.ThreadUtil; import plugins.atournay.jep.prefs.JepPreferences; import javax.swing.*; diff --git a/src/main/resources/plugins/atournay/jep/icon_32.png b/src/main/resources/plugins/atournay/jep/icon_32.png new file mode 100644 index 0000000000000000000000000000000000000000..2ab218b9642954ca66da330cb878971dbbe0805d Binary files /dev/null and b/src/main/resources/plugins/atournay/jep/icon_32.png differ diff --git a/src/main/resources/plugins/atournay/jep/python-logo-only.svg b/src/main/resources/plugins/atournay/jep/python-logo-only.svg new file mode 100644 index 0000000000000000000000000000000000000000..69b3e866191f6f395f9815c4c06d551d67f2185e --- /dev/null +++ b/src/main/resources/plugins/atournay/jep/python-logo-only.svg @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.0" + id="svg2" + width="83.371017pt" + height="101.00108pt" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient2795"> + <stop + style="stop-color:#b8b8b8;stop-opacity:0.49803922;" + offset="0" + id="stop2797"/> + <stop + style="stop-color:#7f7f7f;stop-opacity:0;" + offset="1" + id="stop2799"/> + </linearGradient> + <linearGradient + id="linearGradient2787"> + <stop + style="stop-color:#7f7f7f;stop-opacity:0.5;" + offset="0" + id="stop2789"/> + <stop + style="stop-color:#7f7f7f;stop-opacity:0;" + offset="1" + id="stop2791"/> + </linearGradient> + <linearGradient + id="linearGradient3676"> + <stop + style="stop-color:#b2b2b2;stop-opacity:0.5;" + offset="0" + id="stop3678"/> + <stop + style="stop-color:#b3b3b3;stop-opacity:0;" + offset="1" + id="stop3680"/> + </linearGradient> + <linearGradient + id="linearGradient3236"> + <stop + style="stop-color:#f4f4f4;stop-opacity:1" + offset="0" + id="stop3244"/> + <stop + style="stop-color:white;stop-opacity:1" + offset="1" + id="stop3240"/> + </linearGradient> + <linearGradient + id="linearGradient4671"> + <stop + style="stop-color:#ffd43b;stop-opacity:1;" + offset="0" + id="stop4673"/> + <stop + style="stop-color:#ffe873;stop-opacity:1" + offset="1" + id="stop4675"/> + </linearGradient> + <linearGradient + id="linearGradient4689"> + <stop + style="stop-color:#5a9fd4;stop-opacity:1;" + offset="0" + id="stop4691"/> + <stop + style="stop-color:#306998;stop-opacity:1;" + offset="1" + id="stop4693"/> + </linearGradient> + <linearGradient + x1="224.23996" + y1="144.75717" + x2="-65.308502" + y2="144.75717" + id="linearGradient2987" + xlink:href="#linearGradient4671" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(100.2702,99.61116)"/> + <linearGradient + x1="172.94208" + y1="77.475983" + x2="26.670298" + y2="76.313133" + id="linearGradient2990" + xlink:href="#linearGradient4689" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(100.2702,99.61116)"/> + <linearGradient + xlink:href="#linearGradient4689" + id="linearGradient2587" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(100.2702,99.61116)" + x1="172.94208" + y1="77.475983" + x2="26.670298" + y2="76.313133"/> + <linearGradient + xlink:href="#linearGradient4671" + id="linearGradient2589" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(100.2702,99.61116)" + x1="224.23996" + y1="144.75717" + x2="-65.308502" + y2="144.75717"/> + <linearGradient + xlink:href="#linearGradient4689" + id="linearGradient2248" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(100.2702,99.61116)" + x1="172.94208" + y1="77.475983" + x2="26.670298" + y2="76.313133"/> + <linearGradient + xlink:href="#linearGradient4671" + id="linearGradient2250" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(100.2702,99.61116)" + x1="224.23996" + y1="144.75717" + x2="-65.308502" + y2="144.75717"/> + <linearGradient + xlink:href="#linearGradient4671" + id="linearGradient2255" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.562541,0,0,0.567972,-11.5974,-7.60954)" + x1="224.23996" + y1="144.75717" + x2="-65.308502" + y2="144.75717"/> + <linearGradient + xlink:href="#linearGradient4689" + id="linearGradient2258" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.562541,0,0,0.567972,-11.5974,-7.60954)" + x1="172.94208" + y1="76.176224" + x2="26.670298" + y2="76.313133"/> + <radialGradient + xlink:href="#linearGradient2795" + id="radialGradient2801" + cx="61.518883" + cy="132.28575" + fx="61.518883" + fy="132.28575" + r="29.036913" + gradientTransform="matrix(1,0,0,0.177966,0,108.7434)" + gradientUnits="userSpaceOnUse"/> + <linearGradient + xlink:href="#linearGradient4671" + id="linearGradient1475" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.562541,0,0,0.567972,-14.99112,-11.702371)" + x1="150.96111" + y1="192.35176" + x2="112.03144" + y2="137.27299"/> + <linearGradient + xlink:href="#linearGradient4689" + id="linearGradient1478" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.562541,0,0,0.567972,-14.99112,-11.702371)" + x1="26.648937" + y1="20.603781" + x2="135.66525" + y2="114.39767"/> + <radialGradient + xlink:href="#linearGradient2795" + id="radialGradient1480" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.7490565e-8,-0.23994696,1.054668,3.7915457e-7,-83.7008,142.46201)" + cx="61.518883" + cy="132.28575" + fx="61.518883" + fy="132.28575" + r="29.036913"/> + </defs> + <path + style="fill:url(#linearGradient1478);fill-opacity:1" + d="M 54.918785,9.1927421e-4 C 50.335132,0.02221727 45.957846,0.41313697 42.106285,1.0946693 30.760069,3.0991731 28.700036,7.2947714 28.700035,15.032169 v 10.21875 h 26.8125 v 3.40625 h -26.8125 -10.0625 c -7.792459,0 -14.6157588,4.683717 -16.7499998,13.59375 -2.46181998,10.212966 -2.57101508,16.586023 0,27.25 1.9059283,7.937852 6.4575432,13.593748 14.2499998,13.59375 h 9.21875 v -12.25 c 0,-8.849902 7.657144,-16.656248 16.75,-16.65625 h 26.78125 c 7.454951,0 13.406253,-6.138164 13.40625,-13.625 v -25.53125 c 0,-7.2663386 -6.12998,-12.7247771 -13.40625,-13.9374997 C 64.281548,0.32794397 59.502438,-0.02037903 54.918785,9.1927421e-4 Z m -14.5,8.21875012579 c 2.769547,0 5.03125,2.2986456 5.03125,5.1249996 -2e-6,2.816336 -2.261703,5.09375 -5.03125,5.09375 -2.779476,-1e-6 -5.03125,-2.277415 -5.03125,-5.09375 -10e-7,-2.826353 2.251774,-5.1249996 5.03125,-5.1249996 z" + id="path1948"/> + <path + style="fill:url(#linearGradient1475);fill-opacity:1" + d="m 85.637535,28.657169 v 11.90625 c 0,9.230755 -7.825895,16.999999 -16.75,17 h -26.78125 c -7.335833,0 -13.406249,6.278483 -13.40625,13.625 v 25.531247 c 0,7.266344 6.318588,11.540324 13.40625,13.625004 8.487331,2.49561 16.626237,2.94663 26.78125,0 6.750155,-1.95439 13.406253,-5.88761 13.40625,-13.625004 V 86.500919 h -26.78125 v -3.40625 h 26.78125 13.406254 c 7.792461,0 10.696251,-5.435408 13.406241,-13.59375 2.79933,-8.398886 2.68022,-16.475776 0,-27.25 -1.92578,-7.757441 -5.60387,-13.59375 -13.406241,-13.59375 z m -15.0625,64.65625 c 2.779478,3e-6 5.03125,2.277417 5.03125,5.093747 -2e-6,2.826354 -2.251775,5.125004 -5.03125,5.125004 -2.76955,0 -5.03125,-2.29865 -5.03125,-5.125004 2e-6,-2.81633 2.261697,-5.093747 5.03125,-5.093747 z" + id="path1950"/> + <ellipse + style="opacity:0.44382;fill:url(#radialGradient1480);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:15.4174;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path1894" + cx="55.816761" + cy="127.70079" + rx="35.930977" + ry="6.9673119"/> +</svg>