Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Barbin2018-11-28 09:50:51 +0000
committerFlorian Barbin2018-11-30 13:54:59 +0000
commitf177417cd2a5f7429a5128ae53b777754f2c14c0 (patch)
tree7b05d242860c86ea1dd9a5e73dd6cee233362451
parentcb4fcb1e251fc40f083a62f641c5734a8538ed3a (diff)
downloadorg.eclipse.sirius-f177417cd2a5f7429a5128ae53b777754f2c14c0.tar.gz
org.eclipse.sirius-f177417cd2a5f7429a5128ae53b777754f2c14c0.tar.xz
org.eclipse.sirius-f177417cd2a5f7429a5128ae53b777754f2c14c0.zip
[507064] Adds SWTBot test to check behavior with CCE at diagram opening.
* This test makes sure that the popup asking for refreshing the diagram is open when a CCE occurs. Bug: 507064 Change-Id: I3adce2091044a44611e0eadcad165fe455aa86be Signed-off-by: Florian Barbin <florian.barbin@obeo.fr>
-rw-r--r--plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.aird82
-rw-r--r--plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.odesign44
-rw-r--r--plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My1.ecore5
-rw-r--r--plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/OpenDiagramWithClassCastExceptionTest.java86
-rw-r--r--plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java1
5 files changed, 218 insertions, 0 deletions
diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.aird b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.aird
new file mode 100644
index 0000000000..fd55bf24c4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.aird
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:description="http://www.eclipse.org/sirius/description/1.1.0" xmlns:description_1="http://www.eclipse.org/sirius/diagram/description/1.1.0" xmlns:diagram="http://www.eclipse.org/sirius/diagram/1.1.0" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.2/notation" xmlns:style="http://www.eclipse.org/sirius/diagram/description/style/1.1.0" xmlns:viewpoint="http://www.eclipse.org/sirius/1.1.0" xsi:schemaLocation="http://www.eclipse.org/sirius/description/1.1.0 http://www.eclipse.org/sirius/1.1.0#//description http://www.eclipse.org/sirius/diagram/description/1.1.0 http://www.eclipse.org/sirius/diagram/1.1.0#//description http://www.eclipse.org/sirius/diagram/description/style/1.1.0 http://www.eclipse.org/sirius/diagram/1.1.0#//description/style">
+ <viewpoint:DAnalysis xmi:id="_lkC5AHtrEeaxgIZfSWRqEw" selectedViews="_LZLSIHtsEeaxgIZfSWRqEw" version="12.1.4.201810100944">
+ <semanticResources>My1.ecore</semanticResources>
+ <ownedViews xmi:type="viewpoint:DView" xmi:id="_LZLSIHtsEeaxgIZfSWRqEw">
+ <viewpoint xmi:type="description:Viewpoint" href="My.odesign#//@ownedViewpoints[name='Test']"/>
+ <ownedRepresentationDescriptors xmi:type="viewpoint:DRepresentationDescriptor" xmi:id="_Q0kgIJxjEeahp4VUHwaXKA" name="new Diag" repPath="#_DKHeUOjwEeiSyLm8raHF1g">
+ <description xmi:type="description_1:DiagramDescription" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']"/>
+ <target xmi:type="ecore:EPackage" href="My1.ecore#/"/>
+ </ownedRepresentationDescriptors>
+ <ownedRepresentationDescriptors xmi:type="viewpoint:DRepresentationDescriptor" xmi:id="_4xdL8OjwEeiSyLm8raHF1g" name="dfgdfgfd" repPath="#_4xSM0OjwEeiSyLm8raHF1g">
+ <description xmi:type="description_1:DiagramDescription" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']"/>
+ <target xmi:type="ecore:EPackage" href="My1.ecore#//p1"/>
+ </ownedRepresentationDescriptors>
+ </ownedViews>
+ </viewpoint:DAnalysis>
+ <diagram:DSemanticDiagram xmi:id="_Q0mVUJxjEeahp4VUHwaXKA" name="new Diag" uid="_DKHeUOjwEeiSyLm8raHF1g">
+ <ownedAnnotationEntries xmi:type="description:AnnotationEntry" xmi:id="_Q0mVUZxjEeahp4VUHwaXKA" source="DANNOTATION_CUSTOMIZATION_KEY">
+ <data xmi:type="diagram:ComputedStyleDescriptionRegistry" xmi:id="_Q0mVUpxjEeahp4VUHwaXKA"/>
+ </ownedAnnotationEntries>
+ <ownedAnnotationEntries xmi:type="description:AnnotationEntry" xmi:id="_Q00-0JxjEeahp4VUHwaXKA" source="GMF_DIAGRAMS">
+ <data xmi:type="notation:Diagram" xmi:id="_Q00-0ZxjEeahp4VUHwaXKA" type="Sirius" element="_Q0mVUJxjEeahp4VUHwaXKA" measurementUnit="Pixel">
+ <children xmi:type="notation:Node" xmi:id="_Q0_W4JxjEeahp4VUHwaXKA" type="2002" element="_Q0mVU5xjEeahp4VUHwaXKA">
+ <children xmi:type="notation:Node" xmi:id="_Q1EPYJxjEeahp4VUHwaXKA" type="5006"/>
+ <children xmi:type="notation:Node" xmi:id="_Q1E2cJxjEeahp4VUHwaXKA" type="7001">
+ <children xmi:type="notation:Node" xmi:id="_Q1LkIJxjEeahp4VUHwaXKA" type="3008">
+ <children xmi:type="notation:Node" xmi:id="_Q1MLMJxjEeahp4VUHwaXKA" type="5005"/>
+ <children xmi:type="notation:Node" xmi:id="_Q1MyQJxjEeahp4VUHwaXKA" type="7002">
+ <styles xmi:type="notation:SortingStyle" xmi:id="_Q1MyQZxjEeahp4VUHwaXKA"/>
+ <styles xmi:type="notation:FilteringStyle" xmi:id="_Q1MyQpxjEeahp4VUHwaXKA"/>
+ </children>
+ <children xmi:type="notation:Node" xmi:id="_Q1NZUJxjEeahp4VUHwaXKA" type="3012">
+ <children xmi:type="notation:Node" xmi:id="_jIPPUJxkEeaxotNNNTYa6g" type="3005">
+ <styles xmi:type="notation:ShapeStyle" xmi:id="_jIPPUZxkEeaxotNNNTYa6g" fontName="Segoe UI"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_jIPPUpxkEeaxotNNNTYa6g"/>
+ </children>
+ <styles xmi:type="notation:ShapeStyle" xmi:id="_Q1NZUZxjEeahp4VUHwaXKA" fontName="Segoe UI" fontHeight="8"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_Q1NZUpxjEeahp4VUHwaXKA" x="140" y="20" width="16" height="16"/>
+ </children>
+ <styles xmi:type="notation:ShapeStyle" xmi:id="_Q1LkIZxjEeahp4VUHwaXKA" fontName="Segoe UI" fontHeight="8"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_Q1LkIpxjEeahp4VUHwaXKA" x="45" y="44"/>
+ </children>
+ <styles xmi:type="notation:SortingStyle" xmi:id="_Q1E2cZxjEeahp4VUHwaXKA"/>
+ <styles xmi:type="notation:FilteringStyle" xmi:id="_Q1E2cpxjEeahp4VUHwaXKA"/>
+ </children>
+ <styles xmi:type="notation:ShapeStyle" xmi:id="_Q0_W4ZxjEeahp4VUHwaXKA" fontName="Segoe UI" fontHeight="8"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_Q0_W4pxjEeahp4VUHwaXKA" x="140" y="100" width="263" height="153"/>
+ </children>
+ <styles xmi:type="notation:DiagramStyle" xmi:id="_Q00-0pxjEeahp4VUHwaXKA"/>
+ </data>
+ </ownedAnnotationEntries>
+ <ownedDiagramElements xmi:type="diagram:DNodeContainer" xmi:id="_Q0mVU5xjEeahp4VUHwaXKA" name="p1">
+ <target xmi:type="ecore:EPackage" href="My1.ecore#//p1"/>
+ <semanticElements xmi:type="ecore:EPackage" href="My1.ecore#//p1"/>
+ <arrangeConstraints>KEEP_LOCATION</arrangeConstraints>
+ <arrangeConstraints>KEEP_SIZE</arrangeConstraints>
+ <arrangeConstraints>KEEP_RATIO</arrangeConstraints>
+ <ownedStyle xmi:type="diagram:FlatContainerStyle" xmi:id="_Q0mVVJxjEeahp4VUHwaXKA" borderSize="1" borderSizeComputationExpression="1">
+ <description xmi:type="style:FlatContainerStyleDescription" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']/@defaultLayer/@containerMappings[name='Packages']/@style"/>
+ </ownedStyle>
+ <actualMapping xmi:type="description_1:ContainerMapping" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']/@defaultLayer/@containerMappings[name='Packages']"/>
+ </ownedDiagramElements>
+ <description xmi:type="description_1:DiagramDescription" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']"/>
+ <filterVariableHistory xmi:type="diagram:FilterVariableHistory" xmi:id="_Q0mVWZxjEeahp4VUHwaXKA"/>
+ <activatedLayers xmi:type="description_1:Layer" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']/@defaultLayer"/>
+ <target xmi:type="ecore:EPackage" href="My1.ecore#/"/>
+ </diagram:DSemanticDiagram>
+ <diagram:DSemanticDiagram xmi:id="_4xXsYOjwEeiSyLm8raHF1g" name="dfgdfgfd" uid="_4xSM0OjwEeiSyLm8raHF1g">
+ <ownedAnnotationEntries xmi:type="description:AnnotationEntry" xmi:id="_4xXsYejwEeiSyLm8raHF1g" source="DANNOTATION_CUSTOMIZATION_KEY">
+ <data xmi:type="diagram:ComputedStyleDescriptionRegistry" xmi:id="_4xXsYujwEeiSyLm8raHF1g"/>
+ </ownedAnnotationEntries>
+ <ownedAnnotationEntries xmi:type="description:AnnotationEntry" xmi:id="_4xkgsOjwEeiSyLm8raHF1g" source="GMF_DIAGRAMS">
+ <data xmi:type="notation:Diagram" xmi:id="_4xkgsejwEeiSyLm8raHF1g" type="Sirius" element="_4xXsYOjwEeiSyLm8raHF1g" measurementUnit="Pixel">
+ <styles xmi:type="notation:DiagramStyle" xmi:id="_4xkgsujwEeiSyLm8raHF1g"/>
+ </data>
+ </ownedAnnotationEntries>
+ <description xmi:type="description_1:DiagramDescription" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']"/>
+ <filterVariableHistory xmi:type="diagram:FilterVariableHistory" xmi:id="_4xXsZOjwEeiSyLm8raHF1g"/>
+ <activatedLayers xmi:type="description_1:Layer" href="My.odesign#//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']/@defaultLayer"/>
+ <target xmi:type="ecore:EPackage" href="My1.ecore#//p1"/>
+ </diagram:DSemanticDiagram>
+</xmi:XMI>
diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.odesign b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.odesign
new file mode 100644
index 0000000000..204640ce92
--- /dev/null
+++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My.odesign
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<description:Group xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:description="http://www.eclipse.org/sirius/description/1.1.0" xmlns:description_1="http://www.eclipse.org/sirius/diagram/description/1.1.0" xmlns:style="http://www.eclipse.org/sirius/diagram/description/style/1.1.0" name="My" version="11.1.1.201610211630">
+ <ownedViewpoints name="Test" modelFileExtension="ecore">
+ <ownedRepresentations xsi:type="description_1:DiagramDescription" name="Diag" domainClass="ecore.EPackage" enablePopupBars="true">
+ <defaultLayer name="Default">
+ <nodeMappings name="Classes" semanticCandidatesExpression="feature:eClassifiers" domainClass="ecore.EClass">
+ <borderedNodeMappings name="borderNode" semanticCandidatesExpression="var:self" domainClass="ecore.EClass">
+ <style xsi:type="style:WorkspaceImageDescription" showIcon="false" labelExpression="" hideLabelByDefault="true" sizeComputationExpression="-1" resizeKind="NSEW" workspacePath="/ModelingProjectB_after/Sirius.gif">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ </style>
+ </borderedNodeMappings>
+ <style xsi:type="style:SquareDescription" labelPosition="node" resizeKind="NSEW">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <color xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='gray']"/>
+ </style>
+ </nodeMappings>
+ <containerMappings name="Packages" semanticCandidatesExpression="feature:eSubpackages" domainClass="ecore.EPackage" reusedNodeMappings="//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']/@defaultLayer/@nodeMappings[name='Classes']">
+ <subContainerMappings name="SubPackages" semanticCandidatesExpression="feature:eSubpackages" domainClass="ecore.EPackage" reusedNodeMappings="//@ownedViewpoints[name='Test']/@ownedRepresentations[name='Diag']/@defaultLayer/@nodeMappings[name='Classes']">
+ <borderedNodeMappings name="borderNode" semanticCandidatesExpression="var:self" domainClass="ecore.EPackage">
+ <style xsi:type="style:WorkspaceImageDescription" showIcon="false" labelExpression="" hideLabelByDefault="true" sizeComputationExpression="-1" resizeKind="NSEW" workspacePath="/ModelingProjectB_after/Sirius.gif">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ </style>
+ </borderedNodeMappings>
+ <style xsi:type="style:FlatContainerStyleDescription" borderSizeComputationExpression="1">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <backgroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/>
+ <foregroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='light_blue']"/>
+ </style>
+ </subContainerMappings>
+ <style xsi:type="style:FlatContainerStyleDescription" borderSizeComputationExpression="1">
+ <borderColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <labelColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='black']"/>
+ <backgroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='white']"/>
+ <foregroundColor xsi:type="description:SystemColor" href="environment:/viewpoint#//@systemColors/@entries[name='light_gray']"/>
+ </style>
+ </containerMappings>
+ </defaultLayer>
+ </ownedRepresentations>
+ </ownedViewpoints>
+</description:Group>
diff --git a/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My1.ecore b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My1.ecore
new file mode 100644
index 0000000000..3c1ec8d2c6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.tests.swtbot/data/unit/classCastDiagram/My1.ecore
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
+ name="root2">
+ <eSubpackages name="p1"/>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/OpenDiagramWithClassCastExceptionTest.java b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/OpenDiagramWithClassCastExceptionTest.java
new file mode 100644
index 0000000000..24823ebd90
--- /dev/null
+++ b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/OpenDiagramWithClassCastExceptionTest.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2018 THALES GLOBAL SERVICES.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.tests.swtbot;
+
+import org.eclipse.sirius.diagram.DDiagram;
+import org.eclipse.sirius.tests.swtbot.support.api.AbstractSiriusSwtBotGefTestCase;
+import org.eclipse.sirius.tests.swtbot.support.api.business.UIResource;
+import org.eclipse.sirius.tests.swtbot.support.api.editor.SWTBotSiriusDiagramEditor;
+import org.eclipse.sirius.ui.business.api.preferences.SiriusUIPreferencesKeys;
+import org.eclipse.swtbot.swt.finder.waits.Conditions;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+
+/**
+ * Test suite to make sure that ClassCastException at diagram opening is properly handled.
+ *
+ * @author fbarbin
+ */
+public class OpenDiagramWithClassCastExceptionTest extends AbstractSiriusSwtBotGefTestCase {
+
+ private static final String PATH = "/data/unit/classCastDiagram/";
+
+ private static final String MODELER_PATH = "My.odesign";
+
+ private static final String SEMANTIC_MODEL_PATH = "My1.ecore";
+
+ private static final String AIRD_MODEL_PATH = "My.aird";
+
+ private static final String DESC_NAME = "Diag";
+
+ private static final String REPRESENTATION_NAME = "new " + DESC_NAME;
+
+ @Override
+ protected void onSetUpBeforeClosingWelcomePage() throws Exception {
+ copyFileToTestProject(Activator.PLUGIN_ID, PATH, SEMANTIC_MODEL_PATH, AIRD_MODEL_PATH, MODELER_PATH);
+ }
+
+ @Override
+ protected void onSetUpAfterOpeningDesignerPerspective() throws Exception {
+ sessionAirdResource = new UIResource(designerProject, "/", AIRD_MODEL_PATH);
+ localSession = designerPerspective.openSessionFromFile(sessionAirdResource, true);
+ }
+
+ /**
+ * Make sure that when a ClassCastException occurs while opening a diagram (because of an unsynchronized issue
+ * between GMF and Sirius model), the dialog asking for refreshing the editor is open and when accepting, the editor
+ * is refreshed.
+ */
+ public void testClassCastException() {
+
+ // If the refresh at opening is activated, the error does not occur.
+ changeSiriusUIPreference(SiriusUIPreferencesKeys.PREF_REFRESH_ON_REPRESENTATION_OPENING.name(), false);
+
+ // We perform the openRepresentation in a separate thread to avoid blocking the swtbot thread while the popup
+ // asking for refreshing the representation is open. Indeed, openReprensation will call
+ // DialectUIManager.INSTANCE.openEditor that will perform an EclipseUIUtil.displaySyncExec. That causes the
+ // SWTBot thread waiting for the UI Thread end of execution but this one is waiting for the user with the
+ // popup.
+ Thread thread = new Thread(() -> {
+ editor = (SWTBotSiriusDiagramEditor) openRepresentation(localSession.getOpenedSession(), DESC_NAME, REPRESENTATION_NAME, DDiagram.class);
+ });
+ thread.start();
+ bot.waitUntil(Conditions.shellIsActive("Refresh the diagram"));
+ bot.activeShell().bot().button("OK").click();
+ bot.waitUntil(new DefaultCondition() {
+
+ @Override
+ public boolean test() throws Exception {
+ // After having performed the refresh, the editor is expected to be dirty.
+ return editor != null && editor.isDirty() && editor.getTitle().equals(REPRESENTATION_NAME);
+ }
+
+ @Override
+ public String getFailureMessage() {
+ return "The editor should be opened and dirty.";
+ }
+ });
+ }
+}
diff --git a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java
index 519fe26653..62f0fe20cf 100644
--- a/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java
+++ b/plugins/org.eclipse.sirius.tests.swtbot/src/org/eclipse/sirius/tests/swtbot/suite/AllTestSuite.java
@@ -167,6 +167,7 @@ public class AllTestSuite extends TestCase {
suite.addTestSuite(NodeWithDecoratorSelectionTest.class);
suite.addTestSuite(ManualAirdModificationTest.class);
suite.addTestSuite(SpecificClosedOrNotClosedEditorTest.class);
+ suite.addTestSuite(OpenDiagramWithClassCastExceptionTest.class);
}
/**

Back to the top