Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Descher2014-01-25 16:38:45 -0500
committerGerrit Code Review @ Eclipse.org2014-02-06 16:29:11 -0500
commit03391ad065e385539a43d4fb16cbd6930cf037ed (patch)
tree945cc3cd14faa4ad7c180cded3ad7bb41a84c094
parentf31260f28814f614872221d46b9852763d954157 (diff)
downloadorg.eclipse.e4.tools-03391ad065e385539a43d4fb16cbd6930cf037ed.tar.gz
org.eclipse.e4.tools-03391ad065e385539a43d4fb16cbd6930cf037ed.tar.xz
org.eclipse.e4.tools-03391ad065e385539a43d4fb16cbd6930cf037ed.zip
Bug 426653 - Export application model element IDsI20140206-2200
Change-Id: I2eda59d32be78e72e51b3676d0ee68609353b57e Signed-off-by: Marco Descher <marco@descher.at>
-rw-r--r--bundles/org.eclipse.e4.tools.emf.ui/META-INF/MANIFEST.MF6
-rw-r--r--bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java13
-rw-r--r--bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties13
-rw-r--r--bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java15
-rw-r--r--bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ExportIdsHandler.java317
5 files changed, 356 insertions, 8 deletions
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.tools.emf.ui/META-INF/MANIFEST.MF
index 605ac24f..f76095a5 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.tools.emf.ui/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@ Bundle-ClassPath: .
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
-Require-Bundle: org.eclipse.core.databinding;bundle-version="1.3.0",
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.9.0",
+ org.eclipse.core.databinding;bundle-version="1.3.0",
org.eclipse.core.databinding.property;bundle-version="1.2.100",
org.eclipse.e4.ui.model.workbench;bundle-version="0.9.1",
org.eclipse.emf.databinding;bundle-version="1.2.0",
@@ -32,7 +33,8 @@ Require-Bundle: org.eclipse.core.databinding;bundle-version="1.3.0",
org.eclipse.e4.ui.widgets;bundle-version="0.11.0",
org.eclipse.equinox.preferences;bundle-version="3.4.0",
org.eclipse.e4.ui.workbench.swt;bundle-version="0.10.0",
- org.eclipse.emf.ecore.xmi;bundle-version="2.9.0"
+ org.eclipse.emf.ecore.xmi;bundle-version="2.9.0",
+ org.eclipse.jdt.core
Bundle-ActivationPolicy: lazy
Import-Package: javax.annotation;version="1.0.0",
javax.inject;version="1.0.0",
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
index c15752e3..6e3d3ccd 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010-2013 BestSolution.at and others.
+ * Copyright (c) 2010-2014 BestSolution.at and others.
* 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
@@ -7,7 +7,7 @@
*
* Contributors:
* Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
- * Marco Descher <marco@descher.at> - Bug 395982, Bug 396975
+ * Marco Descher <marco@descher.at> - Bug 395982, 396975, 426653
******************************************************************************/
package org.eclipse.e4.tools.emf.ui.internal;
@@ -626,6 +626,7 @@ public class Messages {
public String ModelEditor_Form;
public String ModelEditor_XMI;
public String ModelEditor_ExternalizeStrings;
+ public String ModelEditor_ExportIds;
public String ModelEditor_Script;
public String ModelEditor_ShowControl;
@@ -637,6 +638,14 @@ public class Messages {
public String ExternalizeStringHandler_Dialog_DialogTitle;
public String ExternalizeStringHandler_Dialog_DialogMessage;
+ public String ExportIdsHandler_Dialog_ElementName;
+ public String ExportIdsHandler_Dialog_Key;
+ public String ExportIdsHandler_Dialog_Id_Value;
+ public String ExportIdsHandler_Dialog_ShellTitle;
+ public String ExportIdsHandler_Dialog_DialogTitle;
+ public String ExportIdsHandler_Dialog_DialogMessage;
+ public String ExportIdsHandler_Dialog_SelectProject;
+
public String ObjectViewer_Tooltip_Value;
public String ObjectViewer_Tooltip_InjectionKey;
public String ObjectViewer_Script;
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
index 4811b311..49868efd 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
@@ -1,5 +1,5 @@
# ******************************************************************************
-# * Copyright (c) 2010-2013 BestSolution.at and others.
+# * Copyright (c) 2010-2014 BestSolution.at and others.
# * 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
@@ -8,7 +8,7 @@
# * Contributors:
# * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
# * Sopot Cela <sopotcela@gmail.com> - enhancements
-# * Marco Descher <marco@descher.at> - Bug 395982, Bug 396975
+# * Marco Descher <marco@descher.at> - Bug 395982, 396975, 426653
# ******************************************************************************
ModelTooling_Common_Up=Up
ModelTooling_Common_Down=Down
@@ -627,6 +627,7 @@ ModelEditor_ExpandSubtree=Expand/Collapse (CTRL + Mouse)
ModelEditor_Form=Form
ModelEditor_XMI=XMI
ModelEditor_ExternalizeStrings=Externalize Strings
+ModelEditor_ExportIds=Export Element Ids
ModelEditor_Script=Execute Script
ModelEditor_ShowControl=Show control
@@ -638,6 +639,14 @@ ExternalizeStringHandler_Dialog_ShellTitle=Externalize Strings
ExternalizeStringHandler_Dialog_DialogTitle=Externalize Strings
ExternalizeStringHandler_Dialog_DialogMessage=Externalizing manifest files extracts translatable strings and stores them in a properties file for multi-language support.
+ExportIdsHandler_Dialog_ElementName=Element
+ExportIdsHandler_Dialog_Key=Key
+ExportIdsHandler_Dialog_Id_Value=Id Value
+ExportIdsHandler_Dialog_ShellTitle=Export Element Ids
+ExportIdsHandler_Dialog_DialogTitle=Export Element Ids
+ExportIdsHandler_Dialog_DialogMessage=Export application model element Ids into a java file for static reference
+ExportIdsHandler_Dialog_SelectProject=Please select a Java project to continue
+
ObjectViewer_Tooltip_Value=Value
ObjectViewer_Tooltip_InjectionKey=Injection key
ObjectViewer_Script=Execute Script
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java
index d0285fe9..ecc096ff 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010-2013 BestSolution.at and others.
+ * Copyright (c) 2010-2014 BestSolution.at and others.
* 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
@@ -8,7 +8,7 @@
* Contributors:
* Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
* Wim Jongman <wim.jongman@remainsoftware.com> - Maintenance
- * Marco Descher <marco@descher.at> - Bug395982
+ * Marco Descher <marco@descher.at> - Bug395982, Bug426653
******************************************************************************/
package org.eclipse.e4.tools.emf.ui.internal.common;
@@ -130,6 +130,7 @@ import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowCont
import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowSharedElementsEditor;
import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowTrimEditor;
import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowWindowsEditor;
+import org.eclipse.e4.tools.emf.ui.internal.common.properties.ExportIdsHandler;
import org.eclipse.e4.tools.emf.ui.internal.common.properties.ExternalizeStringHandler;
import org.eclipse.e4.tools.emf.ui.internal.common.properties.ProjectOSGiTranslationProvider;
import org.eclipse.e4.tools.emf.ui.internal.common.xml.AnnotationAccess;
@@ -820,7 +821,17 @@ public class ModelEditor {
ContextInjectionFactory.invoke(h, Execute.class, context);
}
};
+
+ Action extIdAction = new Action(messages.ModelEditor_ExportIds) {
+ @Override
+ public void run() {
+ ExportIdsHandler h = ContextInjectionFactory.make(ExportIdsHandler.class, context);
+ ContextInjectionFactory.invoke(h, Execute.class, context);
+ }
+ };
+
manager.add(nlsAction);
+ manager.add(extIdAction);
} else {
if (addSeparator) {
manager.add(new Separator());
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ExportIdsHandler.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ExportIdsHandler.java
new file mode 100644
index 00000000..7d8dc032
--- /dev/null
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ExportIdsHandler.java
@@ -0,0 +1,317 @@
+/*******************************************************************************
+ * Copyright (c) 2014 MEDEVIT, FHV and others.
+ * 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:
+ * Marco Descher <marco@descher.at> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.e4.tools.emf.ui.internal.common.properties;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.inject.Named;
+import org.eclipse.core.databinding.observable.list.IObservableList;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.tools.emf.ui.common.IModelResource;
+import org.eclipse.e4.tools.emf.ui.internal.Messages;
+import org.eclipse.e4.tools.emf.ui.internal.ResourceProvider;
+import org.eclipse.e4.tools.services.IResourcePool;
+import org.eclipse.e4.tools.services.Translation;
+import org.eclipse.e4.ui.model.application.MApplicationElement;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * This handler exports all Id values within the application model to a file for
+ * static reference. Currently the location of this file is fixed to be in the
+ * location of the selected projects main package with name
+ * <code>AppModelId.java</code>.
+ */
+public class ExportIdsHandler {
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell, @Translation Messages messages, IModelResource resource, IResourcePool pool, IProject project) {
+ TitleAreaDialog dialog = new ExportIdDialog(shell, messages, resource.getRoot(), pool, project);
+ dialog.open();
+ }
+
+ static class ExportIdDialog extends TitleAreaDialog {
+ private Messages messages;
+ private IObservableList list;
+ private IResourcePool pool;
+ private JavaClass clazz;
+ private CheckboxTableViewer viewer;
+
+ public ExportIdDialog(Shell parentShell, Messages messages, IObservableList list, IResourcePool pool, IProject project) {
+ super(parentShell);
+ this.messages = messages;
+ this.list = list;
+ this.pool = pool;
+
+ clazz = new JavaClass();
+ clazz.name = "AppModelId"; //$NON-NLS-1$
+
+ if (JavaProject.hasJavaNature(project)) {
+ try {
+ IJavaProject javaProject = JavaCore.create(project);
+ for (IPackageFragmentRoot iPackageFragmentRoot : javaProject.getAllPackageFragmentRoots()) {
+ if (iPackageFragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE) {
+ clazz.packageFragment = iPackageFragmentRoot.createPackageFragment(project.getName(), false, new NullProgressMonitor());
+ break;
+ }
+ }
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
+ } else {
+ setErrorMessage(messages.ExportIdsHandler_Dialog_SelectProject);
+ getButton(IDialogConstants.OK_ID).setEnabled(false);
+ }
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ getShell().setText(messages.ExportIdsHandler_Dialog_ShellTitle);
+ setTitle(messages.ExportIdsHandler_Dialog_DialogTitle);
+ setMessage(messages.ExportIdsHandler_Dialog_DialogMessage);
+ setTitleImage(pool.getImageUnchecked(ResourceProvider.IMG_Wizban16_extstr_wiz));
+
+ Composite container = (Composite) super.createDialogArea(parent);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ Table t = new Table(container, SWT.BORDER | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CHECK);
+
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = t.getItemHeight() * 18;
+ container.setLayoutData(gd);
+
+ GridData gd2 = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd2.heightHint = t.getItemHeight() * 17;
+ t.setHeaderVisible(true);
+ t.setLinesVisible(true);
+ t.setLayoutData(gd2);
+
+ viewer = new CheckboxTableViewer(t);
+
+ {
+ TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ return ""; //$NON-NLS-1$
+ }
+ });
+ }
+
+ {
+ TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setText(messages.ExportIdsHandler_Dialog_ElementName);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ Entry e = (Entry) element;
+ return ((EObject) e.object).eClass().getName();
+ }
+ });
+ }
+
+ {
+ TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setText(messages.ExportIdsHandler_Dialog_Key);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ Entry e = (Entry) element;
+ return e.idFieldKey;
+ }
+ });
+ }
+
+ {
+ TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
+ column.getColumn().setText(messages.ExportIdsHandler_Dialog_Id_Value);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ Entry e = (Entry) element;
+ return e.elementId;
+ }
+ });
+ }
+
+ for (int i = 1; i < viewer.getTable().getColumnCount(); i++) {
+ TableColumn c = viewer.getTable().getColumn(i);
+ c.pack();
+ if (c.getWidth() < 120) {
+ c.setWidth(120);
+ }
+ }
+
+ {
+ Label l = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
+ l.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 3, 1));
+ }
+
+ List<Entry> entries = new ArrayList<ExportIdsHandler.Entry>();
+ TreeIterator<EObject> it = EcoreUtil.getAllContents(list);
+
+ while (it.hasNext()) {
+ Object next = it.next();
+ if (next instanceof MApplicationElement) {
+ MApplicationElement o = (MApplicationElement) next;
+ if (o.getElementId() != null && o.getElementId().length() > 1) {
+ String idFieldKey = findIdFieldKey(o);
+ entries.add(new Entry(o, idFieldKey, o.getElementId()));
+ }
+ }
+ }
+
+ Collections.sort(entries);
+
+ viewer.setContentProvider(new ArrayContentProvider());
+ viewer.setInput(entries);
+ viewer.setAllChecked(true);
+
+ for (int i = 1; i < viewer.getTable().getColumnCount(); i++) {
+ TableColumn c = viewer.getTable().getColumn(i);
+ c.pack();
+ if (c.getWidth() < 120) {
+ c.setWidth(120);
+ }
+ }
+
+ return container;
+ }
+
+ @Override
+ protected void okPressed() { // See AbstractNewClassWizard
+ Object[] els = viewer.getCheckedElements();
+ if (els.length > 0) {
+ try {
+ String content = compileFileContent(els);
+
+ IPackageFragment fragment = clazz.packageFragment;
+ String cuName = clazz.name + ".java"; //$NON-NLS-1$
+ ICompilationUnit unit = fragment.getCompilationUnit(cuName);
+ IResource resource = unit.getResource();
+ IFile file = (IFile) resource;
+
+ ByteArrayInputStream stream = new ByteArrayInputStream(content.toString().getBytes());
+ if (file.exists()) {
+ file.delete(true, new NullProgressMonitor());
+ }
+
+ createParent(file.getParent());
+ // NPE
+ file.create(stream, IResource.KEEP_HISTORY, new NullProgressMonitor());
+
+ stream.close();
+ super.okPressed();
+ } catch (CoreException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private String compileFileContent(Object[] els) {
+ StringBuilder b = new StringBuilder();
+ b.append("package " + clazz.packageFragment.getElementName() + ";" + System.getProperty("line.separator")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ b.append(System.getProperty("line.separator")); //$NON-NLS-1$
+ b.append("public class " + clazz.name + " {" + System.getProperty("line.separator")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ for (Object o : els) {
+ Entry e = (Entry) o;
+ b.append("\tpublic static final String " + e.idFieldKey + " = \"" + e.elementId + "\";" + System.getProperty("line.separator")); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ b.append("}"); //$NON-NLS-1$
+ return b.toString();
+ }
+
+ private void createParent(IContainer container) throws CoreException {
+ if (!container.exists()) {
+
+ createParent(container.getParent());
+
+ if (container instanceof IFolder) {
+ IFolder f = (IFolder) container;
+ f.create(true, true, new NullProgressMonitor());
+ }
+ }
+ }
+ }
+
+ private static String findIdFieldKey(MApplicationElement object) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(((EObject) object).eClass().getName());
+ sb.append("_"); //$NON-NLS-1$
+ sb.append(replaceInvalidChar(object.getElementId()));
+ return sb.toString().toUpperCase();
+ }
+
+ private static String replaceInvalidChar(String elementId) {
+ return elementId.replaceAll("[^A-Za-z0-9]", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private static class Entry implements Comparable<Entry> {
+ private MApplicationElement object;
+ private String idFieldKey;
+ private String elementId;
+
+ public Entry(MApplicationElement object, String idFieldKey, String elementId) {
+ this.object = object;
+ this.idFieldKey = idFieldKey;
+ this.elementId = elementId;
+ }
+
+ @Override
+ public int compareTo(Entry o) {
+ return this.idFieldKey.compareTo(o.idFieldKey);
+ }
+ }
+
+ /**
+ * @see org.eclipse.e4.internal.tools.wizards.classes.AbstractNewClassPage
+ */
+ private static class JavaClass {
+ private IPackageFragment packageFragment;
+ private String name;
+ }
+
+} \ No newline at end of file

Back to the top