Commit 85db0ad2 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch 'release-14.0.8-issues' into 'devel_14.0.x'

bug fixes for 14.0.8

See merge request !1046
parents a4409a4c 0e377ab0
Pipeline #20433 passed with stage
in 13 minutes and 21 seconds
...@@ -318,6 +318,8 @@ build_debian_package: ...@@ -318,6 +318,8 @@ build_debian_package:
dependencies: dependencies:
- build_war - build_war
artifacts: artifacts:
# you cannot enforce never here yet
expire_in: 1000 yrs
paths: paths:
- "debian/*.deb" - "debian/*.deb"
script: script:
...@@ -432,6 +434,8 @@ build_rpm: ...@@ -432,6 +434,8 @@ build_rpm:
tags: tags:
- privileged - privileged
artifacts: artifacts:
# you cannot enforce never here yet
expire_in: 1000 yrs
paths: paths:
- "rpm/rpmbuildtemp/RPMS/noarch/minerva-*.rpm" - "rpm/rpmbuildtemp/RPMS/noarch/minerva-*.rpm"
script: script:
......
minerva (14.0.8) stable; urgency=medium
* Bug fix: API didn't allow to upload pluins with local url (#1084,
regression 14.0.7)
* Bug fix: upload of data overlay with two entries having different uniprot
identifier but pointing to the same gene crashed (#1083)
* Bug fix: don't allow to remove plugin twice (#1081)
* Bug fix: upload of SBML file with very short reaction length could produce
a map that couldn't be exported to SBML anymore (#1078)
* Bug fix: import of structural state from SBGN-ML PD that cannot be
normalized to residue is changed into structural state without losing
information (#1062)
* Bug fix: import of stimulation modifiers from SBGN-ML crashed converter
(#1063)
* Bug fix: export to SBGN files created from newt source produced corrupted
disconnected reactions
* Bug fix: upload from zip file allowed empty overlay name (#1065)
* Bug fix: genome browser slider didn't work properly in Safari on
non-default Browser zoom level (#1048)
* Bug fix: project without background overlay but with some custom data
overlays crashed with an error (#1066)
* Bug fix: when session expires updating options in configuration panel threw
unhandled error (#1068)
-- Piotr Gawron <piotr.gawron@uni.lu> Tue, 28 Jan 2020 11:00:00 +0200
minerva (14.0.7) stable; urgency=high minerva (14.0.7) stable; urgency=high
* Bug fix: API allowed to provide malformed plugin url that could be used for * Bug fix: API allowed to provide malformed plugin url that could be used for
xss attack (#1073) xss attack (#1073)
......
...@@ -10,8 +10,8 @@ import org.apache.logging.log4j.LogManager; ...@@ -10,8 +10,8 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.sbgn.*; import org.sbgn.*;
import org.sbgn.bindings.*; import org.sbgn.bindings.*;
import org.sbgn.bindings.Map;
import org.sbgn.bindings.Arc.*; import org.sbgn.bindings.Arc.*;
import org.sbgn.bindings.Map;
import lcsb.mapviewer.common.comparator.DoubleComparator; import lcsb.mapviewer.common.comparator.DoubleComparator;
import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.InvalidArgumentException;
...@@ -192,7 +192,7 @@ public class SbgnmlXmlExporter { ...@@ -192,7 +192,7 @@ public class SbgnmlXmlExporter {
} }
} }
sourceTargetMap.put(newGlyph.getId(), newGlyph); sourceTargetMap.put(element.getElementId(), newGlyph);
return newGlyph; return newGlyph;
} }
...@@ -202,7 +202,13 @@ public class SbgnmlXmlExporter { ...@@ -202,7 +202,13 @@ public class SbgnmlXmlExporter {
glyph.setClazz(GlyphClazz.STATE_VARIABLE.getClazz()); glyph.setClazz(GlyphClazz.STATE_VARIABLE.getClazz());
Glyph.State state = new Glyph.State(); Glyph.State state = new Glyph.State();
if (structuralState.indexOf("@") >= 0) {
state.setValue(structuralState.substring(0, structuralState.indexOf("@")));
state.setVariable(structuralState.substring(structuralState.indexOf("@") + 1));
} else {
state.setValue(structuralState); state.setValue(structuralState);
}
glyph.setState(state); glyph.setState(state);
Bbox bbox = new Bbox(); Bbox bbox = new Bbox();
...@@ -838,6 +844,7 @@ public class SbgnmlXmlExporter { ...@@ -838,6 +844,7 @@ public class SbgnmlXmlExporter {
if (!node.getLine().getEndAtd().getArrowType().equals(ArrowType.NONE)) { if (!node.getLine().getEndAtd().getArrowType().equals(ArrowType.NONE)) {
arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction())); arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction()));
} else { } else {
boolean found = false;
for (NodeOperator operator : node.getReaction().getOperators()) { for (NodeOperator operator : node.getReaction().getOperators()) {
if (operator.getInputs().contains(node)) { if (operator.getInputs().contains(node)) {
if (!parsedOperators.contains(operator)) { if (!parsedOperators.contains(operator)) {
...@@ -845,7 +852,12 @@ public class SbgnmlXmlExporter { ...@@ -845,7 +852,12 @@ public class SbgnmlXmlExporter {
glyphList.add(newOperator); glyphList.add(newOperator);
} }
arc.setTarget(sourceTargetMap.get(operatorIds.get(operator).concat(".1"))); arc.setTarget(sourceTargetMap.get(operatorIds.get(operator).concat(".1")));
found = true;
}
} }
if (!found) {
throw new InvalidArgumentException(
new ElementUtils().getElementTag((Modifier) node) + "Problem with exportin modifier");
} }
} }
} else if (node instanceof NodeOperator) { } else if (node instanceof NodeOperator) {
......
package lcsb.mapviewer.converter.model.sbgnml; package lcsb.mapviewer.converter.model.sbgnml;
import java.awt.*; import java.awt.Color;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.sbgn.*; import org.sbgn.*;
import org.sbgn.bindings.*; import org.sbgn.bindings.*;
import org.sbgn.bindings.Arc.*; import org.sbgn.bindings.Arc.*;
import org.sbgn.bindings.Map;
import lcsb.mapviewer.common.comparator.DoubleComparator; import lcsb.mapviewer.common.comparator.DoubleComparator;
import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.InvalidArgumentException;
...@@ -390,8 +390,9 @@ public class SbgnmlXmlParser { ...@@ -390,8 +390,9 @@ public class SbgnmlXmlParser {
* arc to be parsed * arc to be parsed
* @param model * @param model
* model to be updated * model to be updated
* @throws InvalidInputDataExecption
*/ */
private void parseArc(Arc a, Model model) { private void parseArc(Arc a, Model model) throws InvalidInputDataExecption {
switch (ArcClazz.fromClazz(a.getClazz())) { switch (ArcClazz.fromClazz(a.getClazz())) {
case CONSUMPTION: case CONSUMPTION:
Port arcTargetPort = (Port) a.getTarget(); Port arcTargetPort = (Port) a.getTarget();
...@@ -422,6 +423,7 @@ public class SbgnmlXmlParser { ...@@ -422,6 +423,7 @@ public class SbgnmlXmlParser {
case MODULATION: case MODULATION:
case NECESSARY_STIMULATION: case NECESSARY_STIMULATION:
case STIMULATION: case STIMULATION:
if (a.getTarget() instanceof Glyph) {
Glyph targetGlyph = (Glyph) a.getTarget(); Glyph targetGlyph = (Glyph) a.getTarget();
if (GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.PHENOTYPE)) { if (GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.PHENOTYPE)) {
if (!(a.getSource() instanceof Glyph)) { if (!(a.getSource() instanceof Glyph)) {
...@@ -442,7 +444,8 @@ public class SbgnmlXmlParser { ...@@ -442,7 +444,8 @@ public class SbgnmlXmlParser {
try { try {
parsePhenotypeArc(a, model); parsePhenotypeArc(a, model);
} catch (InvalidArgumentException ex) { } catch (InvalidArgumentException ex) {
logger.warn("The arc " + a.getId() + " of class " + a.getClazz() + " is not a valid reduced notation arc."); logger
.warn("The arc " + a.getId() + " of class " + a.getClazz() + " is not a valid reduced notation arc.");
} }
break; break;
} }
...@@ -453,6 +456,25 @@ public class SbgnmlXmlParser { ...@@ -453,6 +456,25 @@ public class SbgnmlXmlParser {
break; break;
} }
} }
} else {
Port targetPort = (Port) a.getTarget();
boolean found = false;
for (Process p : processes) {
Set<String> ids = new HashSet<>();
ids.add(p.getCentralPoint().getId());
for (Port port : p.getCentralPoint().getPort()) {
ids.add(port.getId());
}
if (ids.contains(targetPort.getId())) {
p.addInfluenceArc(a);
found = true;
break;
}
}
if (!found) {
throw new InvalidInputDataExecption("Problem with processing arc: " + a.getId());
}
}
break; break;
default: default:
logger.warn("The arc " + a.getId() + " of class " + a.getClazz() logger.warn("The arc " + a.getId() + " of class " + a.getClazz()
...@@ -584,13 +606,35 @@ public class SbgnmlXmlParser { ...@@ -584,13 +606,35 @@ public class SbgnmlXmlParser {
for (Glyph child : children) { for (Glyph child : children) {
if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.STATE_VARIABLE)) { if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.STATE_VARIABLE)) {
if (child.getState() == null || child.getState().getVariable() != null) { if (child.getState() == null || child.getState().getVariable() != null) {
try { Residue residue = stateVariableToResidue(child);
parseStateVariable(child, newSpecies); if (residue != null) {
} catch (Exception ex) { if (newSpecies instanceof Protein) {
logger.warn(ex.getMessage()); ((Protein) newSpecies).addResidue(residue);
} else if (newSpecies instanceof Complex) {
String state = createStructuralState(child);
if (state != null) {
Complex complex = (Complex) newSpecies;
complex.setStructuralState(state);
}
} else {
logger.warn("Only macromolecule elements can have state variables.");
} }
} else { } else {
String structuralState = child.getState().getValue(); String state = createStructuralState(child);
if (state != null) {
if (newSpecies instanceof Protein) {
((Protein) newSpecies).setStructuralState(state);
} else if (newSpecies instanceof Complex) {
Complex complex = (Complex) newSpecies;
complex.setStructuralState(state);
} else {
logger.warn("Only macromolecule elements can have state.");
}
}
}
} else {
String structuralState = createStructuralState(child);
if (structuralState != null) {
if (newSpecies instanceof Protein) { if (newSpecies instanceof Protein) {
Protein protein = (Protein) newSpecies; Protein protein = (Protein) newSpecies;
protein.setStructuralState(structuralState); protein.setStructuralState(structuralState);
...@@ -601,6 +645,7 @@ public class SbgnmlXmlParser { ...@@ -601,6 +645,7 @@ public class SbgnmlXmlParser {
} }
} }
} }
}
parseSpecies(g, newSpecies, model); parseSpecies(g, newSpecies, model);
...@@ -608,6 +653,63 @@ public class SbgnmlXmlParser { ...@@ -608,6 +653,63 @@ public class SbgnmlXmlParser {
} }
/**
* Method used to parse state variable.
*
* @param glyph
* unit of information glyph from sbgn-ml file
* @throws Exception
* Exception is thrown if state variable is parsed for species other
* than Protein
*/
private Residue stateVariableToResidue(Glyph glyph) {
if (glyph.getState() != null && (glyph.getState().getVariable() == null
|| glyph.getState().getVariable().trim().isEmpty())) {
return null;
}
Residue mr = new Residue();
mr.setIdModificationResidue(glyph.getId());
if (glyph.getState() != null) {
// If State variable consists of value and variable
mr.setName(glyph.getState().getVariable());
for (ModificationState ms : ModificationState.values()) {
if (ms.getAbbreviation().equals(glyph.getState().getValue())) {
mr.setState(ms);
}
}
}
if (mr.getState() == null) {
return null;
}
// Compute the angle from coordinates and dimensions
double x = glyph.getBbox().getX() + glyph.getBbox().getW() / 2;
double y = glyph.getBbox().getY() + glyph.getBbox().getH() / 2;
mr.setPosition(new Point2D.Double(x, y));
return mr;
}
private String createStructuralState(Glyph glyph) {
if (glyph.getState() == null) {
return null;
}
String result = "";
if (glyph.getState().getValue() != null) {
result += glyph.getState().getValue();
}
if (glyph.getState().getVariable() != null && !glyph.getState().getVariable().isEmpty()) {
result += "@";
result += glyph.getState().getVariable();
}
return result;
}
/** /**
* {@link ModificationResidue} in element might have slightly off coordinates * {@link ModificationResidue} in element might have slightly off coordinates
* (due to different symbol shapes). For that we need to align them to match our * (due to different symbol shapes). For that we need to align them to match our
...@@ -751,45 +853,6 @@ public class SbgnmlXmlParser { ...@@ -751,45 +853,6 @@ public class SbgnmlXmlParser {
return rna; return rna;
} }
/**
* Method used to parse state variable.
*
* @param unitOfInformationGlyph
* unit of information glyph from sbgn-ml file
* @param species
* species that the unit of information considers
* @throws Exception
* Exception is thrown if state variable is parsed for species other
* than Protein
*/
private void parseStateVariable(Glyph unitOfInformationGlyph, Species species) {
if (!(species instanceof Protein)) {
throw new InvalidArgumentException("Only macromolecule elements can have state variables.");
}
Protein protein = (Protein) species;
Residue mr = new Residue();
mr.setSpecies(protein);
mr.setIdModificationResidue(unitOfInformationGlyph.getId());
if (unitOfInformationGlyph.getState() != null) {
// If State variable consists of value and variable
mr.setName(unitOfInformationGlyph.getState().getVariable());
for (ModificationState ms : ModificationState.values()) {
if (ms.getAbbreviation().equals(unitOfInformationGlyph.getState().getValue())) {
mr.setState(ms);
}
}
}
// Compute the angle from coordinates and dimensions
double x = unitOfInformationGlyph.getBbox().getX() + unitOfInformationGlyph.getBbox().getW() / 2;
double y = unitOfInformationGlyph.getBbox().getY() + unitOfInformationGlyph.getBbox().getH() / 2;
mr.setPosition(new Point2D.Double(x, y));
protein.addResidue(mr);
}
/** /**
* Method used for parsing units of information. * Method used for parsing units of information.
* *
...@@ -1144,6 +1207,7 @@ public class SbgnmlXmlParser { ...@@ -1144,6 +1207,7 @@ public class SbgnmlXmlParser {
throw new InvalidArgumentException( throw new InvalidArgumentException(
p.getCentralPoint().getId() + ": The process must have at least one outgoing arc."); p.getCentralPoint().getId() + ": The process must have at least one outgoing arc.");
} }
p.setProductsPort((Port) p.getProductArcs().get(0).getSource()); p.setProductsPort((Port) p.getProductArcs().get(0).getSource());
for (Arc productArc : p.getProductArcs()) { for (Arc productArc : p.getProductArcs()) {
if (!((Port) productArc.getSource()).equals(p.getProductsPort())) { if (!((Port) productArc.getSource()).equals(p.getProductsPort())) {
......
...@@ -3,6 +3,7 @@ package lcsb.mapviewer.converter.model.sbgnml; ...@@ -3,6 +3,7 @@ package lcsb.mapviewer.converter.model.sbgnml;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.io.InputStream;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -105,4 +106,45 @@ public class SbgnmlXmlParserTest2 extends SbgnmlTestFunctions { ...@@ -105,4 +106,45 @@ public class SbgnmlXmlParserTest2 extends SbgnmlTestFunctions {
assertEquals(p2.getLine().getBeginPoint(), outputOperator.getLine().getBeginPoint()); assertEquals(p2.getLine().getBeginPoint(), outputOperator.getLine().getBeginPoint());
} }
@Test
public void testImportExportStateWithVariable() throws Exception {
Converter converter = new SbgnmlXmlConverter();
Model model = converter.createModel(
new ConverterParams().filename("testFiles/sbgnmlParserTestFiles/sbgnmlFiles/state_with_variable.sbgn"));
String sbgn = converter.model2String(model);
assertTrue("State variable is missing", sbgn.contains("state variable"));
assertTrue("State variable doesn't contain variable", sbgn.contains("variable=\"g\""));
}
@Test
public void testStimulationModification() throws Exception {
Converter converter = new SbgnmlXmlConverter();
Model model = converter.createModel(
new ConverterParams().filename("testFiles/sbgnmlParserTestFiles/sbgnmlFiles/stimulation_modification.sbgn"));
for (Reaction r : model.getReactions()) {
assertEquals(1, r.getModifiers().size());
}
}
@Test
public void testExportStimulationModification() throws Exception {
Converter converter = new SbgnmlXmlConverter();
Model model = converter.createModel(
new ConverterParams().filename("testFiles/sbgnmlParserTestFiles/sbgnmlFiles/stimulation_modification.sbgn"));
InputStream is = converter.model2InputStream(model);
Model model2 = converter.createModel(new ConverterParams().inputStream(is));
for (Reaction r : model2.getReactions()) {
assertEquals(1, r.getModifiers().size());
}
}
} }
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<sbgn xmlns="http://sbgn.org/libsbgn/0.2">
<map language="process description">
<glyph id="nwtN_a529363c-d32c-4b03-bce7-1b79e6066b2d" class="complex">
<label text="complex"/>
<bbox x="1001.671875" y="148.375" w="63.25" h="33.25"/>
<glyph id="nwtSV_439e2238-3d15-46da-aa67-77a1119a3552" class="state variable">
<state value="xxx" variable="g"/>
<bbox x="1049.1945435615057" y="142.375" w="22.39697265625" h="12"/>
</glyph>
<glyph id="nwtN_d5109825-20cd-40f4-a9ba-1fd707c6b2a1" class="macromolecule">
<label text="macromolecule"/>
<bbox x="1018.296875" y="165" w="60" h="30"/>
</glyph>
</glyph>
</map>
</sbgn>
\ No newline at end of file
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<sbgn xmlns="http://sbgn.org/libsbgn/0.2">
<map language="process description">
<extension>
<renderInformation
xmlns="http://www.sbml.org/sbml/level3/version1/render/version1" id="renderInformation" program-name="sbgnviz" program-version="5.0.0" background-color="#00000000">
<listOfColorDefinitions>
<colorDefinition id="color_1" value="#ffffff7f"/>
<colorDefinition id="color_2" value="#838383"/>
<colorDefinition id="color_3" value="#ffffffff"/>
<colorDefinition id="color_4" value="#555555"/>
<colorDefinition id="color_5" value="#ffffff"/>
<colorDefinition id="color_6" value="#000000"/>
<colorDefinition id="color_7" value="#ff0000"/>
</listOfColorDefinitions>
<listOfBackgroundImages>
<backgroundImage id="image_1" value="http://newteditor.org/color-scheme-images/rb3_3d.png"/>
<backgroundImage id="image_2" value="http://newteditor.org/color-scheme-images/pg5_3d.png"/>
<backgroundImage id="image_3" value="http://newteditor.org/color-scheme-images/pg4_3d.png"/>
<backgroundImage id="image_4" value="http://newteditor.org/color-scheme-images/bw1_3d.png"/>
</listOfBackgroundImages>
<listOfStyles>
<style id="nodeffffff0.58383833.2514normalnormalHelvetica000image_1none5050100100" id-list="nwtN_3ab42db3-7946-4642-a215-98b2f74f5061 nwtN_31dec67c-8c37-40ec-bfad-d038cf1dc815">
<g font-size="14" font-family="Helvetica" font-weight="normal" font-style="normal" font-color="#000" stroke="color_2" stroke-width="3.25" fill="color_1" background-image="image_1" background-fit="none" background-pos-x="50%" background-pos-y="50%" background-width="100%" background-height="100%"/>
</style>
<style id="nodeffffff15555551.2518normalnormalHelvetica000image_2none5050100100" id-list="6cde7a25-b41a-b8cb-d3d3-188533472dae 7813a623-ae26-a5e1-d4e2-e2eb1d2c14d7 1e1a9dc6-32ae-464a-9912-68fc274f8fb4 6f6a1c77-176d-7188-cdd5-048d3908a8b1 2f567801-fc2c-e128-f352-1dfab2f0dbce 7626c6b6-b0e0-b4b7-e5f3-f803fe319ef8 35a3e0be-6e00-7a99-fca5-18ed65c2fac1 bf4e242a-2a4e-49c2-0bf4-9cc45e2eae34 7c5c9a6d-976b-72b0-0c28-422b3279aeba nwtN_5a3ef454-8d2b-46de-b3a1-f9a0c2409ee4 0c291302-4021-844a-0dd2-97d76ee79ad1 nwtN_1eb9a857-e6fe-43e0-ae92-94ac8318e427 a2ee1683-eb5f-030d-3bbe-46c0a02cb659">
<g font-size="18" font-family="Helvetica" font-weight="normal" font-style="normal" font-color="#000" stroke="color_4" stroke-width="1.25" fill="color_3" background-image="image_2" background-fit="none" background-pos-x="50%" background-pos-y="50%" background-width="100%" background-height="100%"/>
</style>
<style id="infoboxffffff5555552.259normalnormalArial0f0f0fstadium" id-list="6cde7a25-b41a-b8cb-d3d3-188533472dae_0 89360553-bab4-532a-c6c7-624272c4e43b_0 c3a94e68-cca7-3c6a-f546-33c23dc59923_0 7813a623-ae26-a5e1-d4e2-e2eb1d2c14d7_0 6f6a1c77-176d-7188-cdd5-048d3908a8b1_0 2f567801-fc2c-e128-f352-1dfab2f0dbce_0 7626c6b6-b0e0-b4b7-e5f3-f803fe319ef8_0 35a3e0be-6e00-7a99-fca5-18ed65c2fac1_0 bf4e242a-2a4e-49c2-0bf4-9cc45e2eae34_0 0c291302-4021-844a-0dd2-97d76ee79ad1_0 nwtN_1eb9a857-e6fe-43e0-ae92-94ac8318e427_0 a2ee1683-eb5f-030d-3bbe-46c0a02cb659_0">
<g font-size="9" font-family="Arial" font-weight="normal" font-style="normal" font-color="#0f0f0f" stroke="color_4" stroke-width="2.25" fill="color_5" shape-name="stadium"/>
</style>
<style id="nodeffffff0.55555551.2511normalnormalHelvetica000image_3none5050100100" id-list="89360553-bab4-532a-c6c7-624272c4e43b c3a94e68-cca7-3c6a-f546-33c23dc59923">
<g font-size="11" font-family="Helvetica" font-weight="normal" font-style="normal" font-color="#000" stroke="color_4" stroke-width="1.25" fill="color_1" background-image="image_3" background-fit="none" background-pos-x="50%" background-pos-y="50%" background-width="100%" background-height="100%"/>
</style>
<style id="nodeffffff10000001.25image_4none5050100100" id-list="9615ba87-e042-ef50-d78e-1ef00df34a6e 2785fbb1-18d0-0b2f-dcf2-968acc6869c0 a8404458-8ee5-6465-5d2e-4be53abad9f9 nwtN_78d6cd14-2e5f-463f-9a30-27ce3baea7d9">
<g stroke="color_6" stroke-width="1.25" fill="color_3" background-image="image_4" background-fit="none" background-pos-x="50%" background-pos-y="50%" background-width="100%" background-height="100%"/>
</style>
<style id="nodeffffff15555551.25image_4none5050100100" id-list="nwtN_7ffe3be6-9a33-4696-a593-d5c0a8a45a4c">
<g stroke="color_4" stroke-width="1.25" fill="color_3" background-image="image_4" background-fit="none" background-pos-x="50%" background-pos-y="50%" background-width="100%" background-height="100%"/>
</style>
<style id="nodeffffff15555551.2511normalnormalHelvetica000image_1none5050100100" id-list="nwtN_617312c5-bae0-423e-a711-c6adfee4193b">
<g font-size="11" font-family="Helvetica" font-weight="normal" font-style="normal" font-color="#000" stroke="color_4" stroke-width="1.25" fill="color_3" background-image="image_1" background-fit="none" background-pos-x="50%" background-pos-y="50%" background-width="100%" background-height="100%"/>
</style>
<style id="edge0000001.25" id-list="nwtE_68ee44c6-86ba-499b-a798-db1c00254138">
<g stroke="color_6" stroke-width="1.25"/>
</style>