Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Haug2018-05-28 09:29:40 +0000
committerJuergen Haug2018-06-01 14:20:53 +0000
commitf6fd7aa313377083b3f2acb49b422e05a7b02552 (patch)
tree673f0441d3e431e320c1281045c06e7e5060551e
parent7c9cb4308864f36e33d4c7ca5aa8c2d203473310 (diff)
downloadorg.eclipse.etrice-f6fd7aa313377083b3f2acb49b422e05a7b02552.tar.gz
org.eclipse.etrice-f6fd7aa313377083b3f2acb49b422e05a7b02552.tar.xz
org.eclipse.etrice-f6fd7aa313377083b3f2acb49b422e05a7b02552.zip
Bug 534702 - improved rename refactoring for diagrams
-rw-r--r--plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/DiagramAccess.java2
-rw-r--r--plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ExecutableExtensionFactory.java8
-rw-r--r--plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ResourceModule.java15
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/.classpath3
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/.project6
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/META-INF/MANIFEST.MF2
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/build.properties3
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/schema/org.eclipse.etrice.ui.common.base.refactoring.rename.exsd2
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramReferenceUpdater.xtend79
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramRenameParticipant.java2
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/resource/DiagramResource.java3
-rw-r--r--plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/support/DiagramAccessBase.java2
-rw-r--r--plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/DiagramAccess.java2
-rw-r--r--plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ExecutableExtensionFactory.java8
-rw-r--r--plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ResourceModule.java16
15 files changed, 132 insertions, 21 deletions
diff --git a/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/DiagramAccess.java b/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/DiagramAccess.java
index 69ec1ea16..ed876868c 100644
--- a/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/DiagramAccess.java
+++ b/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/DiagramAccess.java
@@ -77,7 +77,7 @@ public class DiagramAccess extends DiagramAccessBase {
* @see org.eclipse.etrice.ui.common.DiagramAccessBase#getFileExtension()
*/
@Override
- protected String getDigramFileName(EObject rootObject) {
+ public String getDigramFileName(EObject rootObject) {
if (rootObject instanceof ActorClass) {
ActorClass ac = (ActorClass) rootObject;
String modelName = ((RoomModel) ac.eContainer()).getName();
diff --git a/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ExecutableExtensionFactory.java b/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ExecutableExtensionFactory.java
index efc2f0097..cd2ccabdc 100644
--- a/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ExecutableExtensionFactory.java
+++ b/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ExecutableExtensionFactory.java
@@ -11,8 +11,7 @@ import org.osgi.framework.Bundle;
import com.google.inject.Injector;
-public class ExecutableExtensionFactory extends
- AbstractGuiceAwareExecutableExtensionFactory {
+public class ExecutableExtensionFactory extends AbstractGuiceAwareExecutableExtensionFactory {
@Override
protected Bundle getBundle() {
@@ -21,9 +20,8 @@ public class ExecutableExtensionFactory extends
@Override
protected Injector getInjector() {
- return createInjector(override(
- override(new ResourceModule()).with(new SharedStateModule()))
- .with(new EmfUiModule(Activator.getDefault())));
+ return createInjector(override(override(new SharedStateModule()).with(new EmfUiModule(Activator.getDefault())))
+ .with(new ResourceModule()));
}
}
diff --git a/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ResourceModule.java b/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ResourceModule.java
index 4ce58931f..cf1ec8b00 100644
--- a/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ResourceModule.java
+++ b/plugins/org.eclipse.etrice.ui.behavior/src/org/eclipse/etrice/ui/behavior/link/ResourceModule.java
@@ -8,14 +8,17 @@
package org.eclipse.etrice.ui.behavior.link;
+import org.eclipse.etrice.ui.behavior.DiagramAccess;
+import org.eclipse.etrice.ui.common.base.refactoring.DiagramReferenceUpdater;
+import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase;
import org.eclipse.xtext.resource.generic.AbstractGenericResourceRuntimeModule;
+import org.eclipse.xtext.ui.refactoring.IReferenceUpdater;
/**
* @author Henrik Rentz-Reichert - initial contribution and API
*
*/
-public class ResourceModule extends
- AbstractGenericResourceRuntimeModule {
+public class ResourceModule extends AbstractGenericResourceRuntimeModule {
/* (non-Javadoc)
* @see org.eclipse.xtext.resource.generic.AbstractGenericResourceRuntimeModule#getLanguageName()
@@ -32,5 +35,13 @@ public class ResourceModule extends
protected String getFileExtensions() {
return "behavior";
}
+
+ public Class<? extends IReferenceUpdater> bindIReferenceUpdater() {
+ return DiagramReferenceUpdater.class;
+ }
+
+ public Class<? extends DiagramAccessBase> bindDiagramAccess() {
+ return DiagramAccess.class;
+ }
}
diff --git a/plugins/org.eclipse.etrice.ui.common.base/.classpath b/plugins/org.eclipse.etrice.ui.common.base/.classpath
index eca7bdba8..13a6c6528 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/.classpath
+++ b/plugins/org.eclipse.etrice.ui.common.base/.classpath
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="xtend-gen"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/plugins/org.eclipse.etrice.ui.common.base/.project b/plugins/org.eclipse.etrice.ui.common.base/.project
index 5fc4c5fa1..623f7fcf2 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/.project
+++ b/plugins/org.eclipse.etrice.ui.common.base/.project
@@ -6,6 +6,11 @@
</projects>
<buildSpec>
<buildCommand>
+ <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
@@ -24,5 +29,6 @@
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>
diff --git a/plugins/org.eclipse.etrice.ui.common.base/META-INF/MANIFEST.MF b/plugins/org.eclipse.etrice.ui.common.base/META-INF/MANIFEST.MF
index 62f339de5..38cea1465 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.etrice.ui.common.base/META-INF/MANIFEST.MF
@@ -14,6 +14,7 @@ Require-Bundle: org.eclipse.etrice.core.common.ui;bundle-version="1.1.2",
org.eclipse.graphiti;bundle-version="0.8.0",
org.eclipse.xtext.ui;bundle-version="2.6.0",
org.eclipse.xtext.ui.shared;bundle-version="2.6.0",
+ org.eclipse.xtend.lib;bundle-version="2.6.0",
org.eclipse.emf.databinding,
org.eclipse.jface.databinding,
org.eclipse.core.databinding.property;bundle-version="1.4.200",
@@ -36,5 +37,6 @@ Export-Package: org.eclipse.etrice.ui.common.base,
org.eclipse.etrice.ui.common.base.export,
org.eclipse.etrice.ui.common.base.preferences,
org.eclipse.etrice.ui.common.base.quickfix,
+ org.eclipse.etrice.ui.common.base.refactoring,
org.eclipse.etrice.ui.common.base.resource,
org.eclipse.etrice.ui.common.base.support
diff --git a/plugins/org.eclipse.etrice.ui.common.base/build.properties b/plugins/org.eclipse.etrice.ui.common.base/build.properties
index 060a9e9fd..a5c6610f7 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/build.properties
+++ b/plugins/org.eclipse.etrice.ui.common.base/build.properties
@@ -1,4 +1,5 @@
-source.. = src/
+source.. = src/,\
+ xtend-gen/
output.. = bin/
bin.includes = META-INF/,\
.,\
diff --git a/plugins/org.eclipse.etrice.ui.common.base/schema/org.eclipse.etrice.ui.common.base.refactoring.rename.exsd b/plugins/org.eclipse.etrice.ui.common.base/schema/org.eclipse.etrice.ui.common.base.refactoring.rename.exsd
index f15dd8dd4..cb29e6fc0 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/schema/org.eclipse.etrice.ui.common.base.refactoring.rename.exsd
+++ b/plugins/org.eclipse.etrice.ui.common.base/schema/org.eclipse.etrice.ui.common.base.refactoring.rename.exsd
@@ -3,7 +3,7 @@
<schema targetNamespace="org.eclipse.etrice.ui.common" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appinfo>
- <meta.schema plugin="org.eclipse.etrice.ui.common" id="org.eclipse.etrice.ui.common.refactoring.rename" name="Diagram Rename Participant"/>
+ <meta.schema plugin="org.eclipse.etrice.ui.common.base" id="org.eclipse.etrice.ui.common.base.refactoring.rename" name="Diagram Rename Participant"/>
</appinfo>
<documentation>
[Enter description of this extension point.]
diff --git a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramReferenceUpdater.xtend b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramReferenceUpdater.xtend
new file mode 100644
index 000000000..d2502b191
--- /dev/null
+++ b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramReferenceUpdater.xtend
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2011 protos software gmbh (http://www.protos.de).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * CONTRIBUTORS:
+ * Juergen Haug (initial contribution)
+ *
+ *******************************************************************************/
+
+package org.eclipse.etrice.ui.common.base.refactoring
+
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.xtext.resource.IReferenceDescription
+import org.eclipse.xtext.ui.refactoring.ElementRenameArguments
+import org.eclipse.xtext.ui.refactoring.IRefactoringUpdateAcceptor
+import org.eclipse.xtext.ui.refactoring.impl.EmfResourceReferenceUpdater
+import com.google.common.collect.Multimap
+import org.eclipse.emf.common.util.URI
+import org.eclipse.emf.ecore.resource.ResourceSet
+import org.eclipse.graphiti.mm.pictograms.Diagram
+import org.eclipse.graphiti.services.Graphiti
+import org.eclipse.emf.ecore.util.EcoreUtil
+import org.eclipse.etrice.core.fsm.fSM.ModelComponent
+import com.google.inject.Inject
+import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase
+import org.eclipse.graphiti.ui.internal.GraphitiUIPlugin
+import org.eclipse.graphiti.internal.GraphitiPlugin
+import org.eclipse.xtext.ui.refactoring.impl.EmfResourceChangeUtil
+import org.eclipse.ltk.core.refactoring.resource.RenameResourceChange
+import org.eclipse.etrice.core.common.scoping.StandardModelLocator
+import org.eclipse.core.runtime.Path
+import org.eclipse.core.runtime.Platform
+import org.eclipse.core.resources.ResourcesPlugin
+import com.google.common.collect.Multimaps
+import com.google.common.collect.MultimapBuilder
+import com.google.common.collect.ArrayListMultimap
+
+/**
+ * Update diagrams in case of xtext rename refactoring
+ */
+class DiagramReferenceUpdater extends EmfResourceReferenceUpdater {
+
+ @Inject DiagramAccessBase diagramAccess
+ @Inject EmfResourceChangeUtil changeUtil
+
+
+ override protected createReferenceUpdates(ElementRenameArguments elementRenameArguments, Multimap<URI, IReferenceDescription> resource2references, ResourceSet resourceSet, IRefactoringUpdateAcceptor updateAcceptor, IProgressMonitor monitor) {
+
+ //-- update references in diagrams
+ super.createReferenceUpdates(elementRenameArguments, resource2references, resourceSet, updateAcceptor, monitor)
+
+ //-- rename diagrams
+ val diagramMap = ArrayListMultimap.create => [map |
+ // there could be several (orphaned) diagrams for one ActorClass
+ resource2references.keySet.map[uri | resourceSet.getResource(uri, false)].map[contents].flatten.filter(Diagram).forEach[diagram |
+ map.put(diagram.link.businessObjects.head, diagram)
+ ]
+ ]
+ elementRenameArguments.renamedElementURIs.map[origURI | resourceSet.getEObject(elementRenameArguments.getNewElementURI(origURI), false)].filter(ModelComponent).forEach[mc |
+ val wsDiagrams = diagramMap.get(mc).filter[eResource.URI.isPlatformResource].toList
+ val newFileName = diagramAccess.getDigramFileName(mc)
+
+ val workspaceRoot = ResourcesPlugin.workspace.root
+ val parents = wsDiagrams.groupBy[workspaceRoot.getFile(new Path(eResource.URI.segmentsList.tail.join('/'))).parent]
+ parents.forEach[parent, diagrams |
+ // avoid file name conflicts => choose latest modified
+ val diagram = diagrams.maxBy[eResource.timeStamp]
+ val diagFile = workspaceRoot.getFile(new Path(diagram.eResource.URI.segmentsList.tail.join('/')))
+ updateAcceptor.accept(diagram.eResource.URI, new RenameResourceChange(diagFile.fullPath, newFileName))
+ // TODO update name of diagram
+ ]
+ ]
+
+ }
+
+}
diff --git a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramRenameParticipant.java b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramRenameParticipant.java
index 3c03dee42..631f0c64e 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramRenameParticipant.java
+++ b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/refactoring/DiagramRenameParticipant.java
@@ -62,7 +62,7 @@ public class DiagramRenameParticipant extends RenameParticipant {
private static String[] diagramEditorsIds;
static {
- IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.etrice.ui.common.refactoring.rename");
+ IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.etrice.ui.common.base.refactoring.rename");
diagramExtensions = new String[elements.length];
diagramEditorsIds = new String[elements.length];
for(int i=0;i<elements.length;i++){
diff --git a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/resource/DiagramResource.java b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/resource/DiagramResource.java
index 2ee928879..d17c34742 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/resource/DiagramResource.java
+++ b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/resource/DiagramResource.java
@@ -21,6 +21,9 @@ import org.eclipse.etrice.core.common.scoping.RelativeFileURIHandler;
import com.google.common.collect.Maps;
+/**
+ * Customize load/save of diagram resources, e.g. serialized URIs to .room.
+ */
public class DiagramResource extends XMIResourceImpl {
public DiagramResource() {
diff --git a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/support/DiagramAccessBase.java b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/support/DiagramAccessBase.java
index 232d0ae90..d380b3c07 100644
--- a/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/support/DiagramAccessBase.java
+++ b/plugins/org.eclipse.etrice.ui.common.base/src/org/eclipse/etrice/ui/common/base/support/DiagramAccessBase.java
@@ -245,7 +245,7 @@ public abstract class DiagramAccessBase {
public abstract String getDiagramName(EObject rootObject);
public abstract IBulkDiagramExporter getDiagramExporter();
- abstract protected String getDigramFileName(EObject rootObject);
+ public abstract String getDigramFileName(EObject rootObject);
abstract protected String getDiagramTypeId();
abstract protected String getEditorId();
abstract protected Command getInitialCommand(EObject rootObject, Diagram diagram, TransactionalEditingDomain editingDomain);
diff --git a/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/DiagramAccess.java b/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/DiagramAccess.java
index 041549189..e0c593c15 100644
--- a/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/DiagramAccess.java
+++ b/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/DiagramAccess.java
@@ -53,7 +53,7 @@ public class DiagramAccess extends DiagramAccessBase {
return StructureEditor.STRUCTURE_EDITOR_ID;
}
- protected String getDigramFileName(EObject rootObject) {
+ public String getDigramFileName(EObject rootObject) {
if (rootObject instanceof StructureClass) {
StructureClass sc = (StructureClass) rootObject;
String modelName = ((RoomModel) sc.eContainer()).getName();
diff --git a/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ExecutableExtensionFactory.java b/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ExecutableExtensionFactory.java
index 2a643ed66..d0ae6b8f0 100644
--- a/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ExecutableExtensionFactory.java
+++ b/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ExecutableExtensionFactory.java
@@ -11,8 +11,7 @@ import org.osgi.framework.Bundle;
import com.google.inject.Injector;
-public class ExecutableExtensionFactory extends
- AbstractGuiceAwareExecutableExtensionFactory {
+public class ExecutableExtensionFactory extends AbstractGuiceAwareExecutableExtensionFactory {
@Override
protected Bundle getBundle() {
@@ -21,9 +20,8 @@ public class ExecutableExtensionFactory extends
@Override
protected Injector getInjector() {
- return createInjector(override(
- override(new ResourceModule()).with(new SharedStateModule()))
- .with(new EmfUiModule(Activator.getDefault())));
+ return createInjector(override(override(new SharedStateModule()).with(new EmfUiModule(Activator.getDefault())))
+ .with(new ResourceModule()));
}
}
diff --git a/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ResourceModule.java b/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ResourceModule.java
index ca1d64b75..662de5ee3 100644
--- a/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ResourceModule.java
+++ b/plugins/org.eclipse.etrice.ui.structure/src/org/eclipse/etrice/ui/structure/link/ResourceModule.java
@@ -8,14 +8,18 @@
package org.eclipse.etrice.ui.structure.link;
+
+import org.eclipse.etrice.ui.common.base.refactoring.DiagramReferenceUpdater;
+import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase;
+import org.eclipse.etrice.ui.structure.DiagramAccess;
import org.eclipse.xtext.resource.generic.AbstractGenericResourceRuntimeModule;
+import org.eclipse.xtext.ui.refactoring.IReferenceUpdater;
/**
* @author Henrik Rentz-Reichert - initial contribution and API
*
*/
-public class ResourceModule extends
- AbstractGenericResourceRuntimeModule {
+public class ResourceModule extends AbstractGenericResourceRuntimeModule {
/* (non-Javadoc)
* @see org.eclipse.xtext.resource.generic.AbstractGenericResourceRuntimeModule#getLanguageName()
@@ -32,5 +36,13 @@ public class ResourceModule extends
protected String getFileExtensions() {
return "structure";
}
+
+ public Class<? extends IReferenceUpdater> bindIReferenceUpdater() {
+ return DiagramReferenceUpdater.class;
+ }
+
+ public Class<? extends DiagramAccessBase> bindDiagramAccess() {
+ return DiagramAccess.class;
+ }
}

Back to the top