From d037b419038d0241ffd018dfa4185a25236a5fc1 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Fri, 10 May 2019 17:15:11 -0400 Subject: [PATCH] PT #165890357: Adopt exploded LS jar for all eclipse LSs --- .../pom.xml | 12 +++- .../boot/ls/SpringBootLanguageServer.java | 58 +++-------------- .../pom.xml | 17 ++++- .../tooling/bosh/ls/BoshLanguageServer.java | 26 +++++--- .../pom.xml | 17 ++++- .../CloudFoundryManifestLanguageServer.java | 25 +++++--- .../pom.xml | 17 ++++- .../concourse/ls/ConcourseLanguageServer.java | 26 +++++--- ...4LanguageServerProcessStreamConnector.java | 64 +++++++++++++++++-- .../src/main/resources/application.properties | 2 + .../src/main/resources/application.yml | 2 - .../src/test/resources/application.properties | 3 +- .../src/main/resources/application.properties | 2 + .../src/main/resources/application.yml | 2 - .../src/test/resources/application.properties | 1 + .../src/main/resources/application.properties | 3 + .../src/main/resources/application.yml | 5 -- 17 files changed, 178 insertions(+), 104 deletions(-) create mode 100644 headless-services/bosh-language-server/src/main/resources/application.properties delete mode 100644 headless-services/bosh-language-server/src/main/resources/application.yml create mode 100644 headless-services/concourse-language-server/src/main/resources/application.properties delete mode 100644 headless-services/concourse-language-server/src/main/resources/application.yml create mode 100644 headless-services/manifest-yaml-language-server/src/main/resources/application.properties delete mode 100644 headless-services/manifest-yaml-language-server/src/main/resources/application.yml diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml index ffe2fff8f..b1bf22fa5 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/pom.xml @@ -75,7 +75,17 @@ - + + maven-clean-plugin + 3.1.0 + + + + servers + + + + diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/SpringBootLanguageServer.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/SpringBootLanguageServer.java index 85a30333c..5db96ec76 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/SpringBootLanguageServer.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/SpringBootLanguageServer.java @@ -12,18 +12,12 @@ package org.springframework.tooling.boot.ls; import static org.springframework.tooling.ls.eclipse.commons.preferences.LanguageServerConsolePreferenceConstants.SPRING_BOOT_SERVER; -import java.io.File; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import org.eclipse.core.runtime.FileLocator; -import org.eclipse.core.runtime.Platform; -import org.osgi.framework.Bundle; import org.springframework.tooling.ls.eclipse.commons.JRE; import org.springframework.tooling.ls.eclipse.commons.JRE.MissingJDKException; - -import com.google.common.collect.ImmutableList; - import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessStreamConnector; /** @@ -34,47 +28,12 @@ public class SpringBootLanguageServer extends STS4LanguageServerProcessStreamCon public SpringBootLanguageServer() { super(SPRING_BOOT_SERVER); - try { - ImmutableList.Builder command = ImmutableList.builder(); - JRE runtime = getJRE(); - - command.add(runtime.getJavaExecutable()); - command.add("-cp"); - - Bundle bundle = Platform.getBundle(getPluginId()); - File bundleFile = FileLocator.getBundleFile(bundle); - - String bundleRoot = bundleFile.getAbsoluteFile().toString(); - String languageServerRoot = bundleRoot + File.separator + "servers" + File.separator + "spring-boot-language-server" + File.separator; - - StringBuilder classpath = new StringBuilder(languageServerRoot); - classpath.append("BOOT-INF" + File.separator + "classes"); - classpath.append(File.pathSeparator); - classpath.append(languageServerRoot); - classpath.append("BOOT-INF" + File.separator + "lib" + File.separator + "*"); - - if (runtime.toolsJar != null) { - classpath.append(File.pathSeparator); - classpath.append(runtime.toolsJar); - } - - command.add(classpath.toString()); - - command.addAll(getJVMArgs()); - - StringBuilder configLocation = new StringBuilder(languageServerRoot); - configLocation.append("BOOT-INF" + File.separator + "classes"); - configLocation.append(File.separator); - configLocation.append("application.properties"); - command.add("-Dspring.config.location=file:" + configLocation.toString()); - - command.add("org.springframework.ide.vscode.boot.app.BootLanguagServerBootApp"); - setCommands(command.build()); - } - catch (Exception e) { - // error - e.printStackTrace(); - } + initExplodedJarCommand( + Paths.get("servers", "spring-boot-language-server"), + "org.springframework.ide.vscode.boot.app.BootLanguagServerBootApp", + "application.properties", + getJVMArgs() + ); setWorkingDirectory(getWorkingDirLocation()); } @@ -82,7 +41,6 @@ public class SpringBootLanguageServer extends STS4LanguageServerProcessStreamCon private List getJVMArgs() { List args = new ArrayList<>(); - args.add("-Dsts.lsp.client=eclipse"); args.add("-Dlsp.completions.indentation.enable=true"); args.add("-Xmx1024m"); args.add("-noverify"); @@ -105,7 +63,7 @@ public class SpringBootLanguageServer extends STS4LanguageServerProcessStreamCon } } - private JRE getJRE() { + protected JRE getJRE() { try { return JRE.findJRE(true); } catch (MissingJDKException e) { diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml index 27b06af68..d1dcedae7 100644 --- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/pom.xml @@ -36,10 +36,10 @@ 3.1.1 - copy + unpack-server prepare-package - copy + unpack @@ -49,11 +49,11 @@ ${project.version} exec true - ${project.build.directory}/../servers true true + ${project.build.directory}/../servers/bosh-language-server @@ -79,6 +79,17 @@ + + maven-clean-plugin + 3.1.0 + + + + servers + + + + diff --git a/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/BoshLanguageServer.java b/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/BoshLanguageServer.java index e25ad6a22..2b0b2ba03 100644 --- a/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/BoshLanguageServer.java +++ b/eclipse-language-servers/org.springframework.tooling.bosh.ls/src/org/springframework/tooling/bosh/ls/BoshLanguageServer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 Pivotal, Inc. * 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 @@ -12,10 +12,10 @@ package org.springframework.tooling.bosh.ls; import static org.springframework.tooling.ls.eclipse.commons.preferences.LanguageServerConsolePreferenceConstants.BOSH_SERVER; -import org.springframework.tooling.ls.eclipse.commons.JRE; -import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessStreamConnector; +import java.nio.file.Paths; +import java.util.Arrays; -import com.google.common.collect.ImmutableList; +import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessStreamConnector; /** * @author Martin Lippert @@ -24,12 +24,18 @@ public class BoshLanguageServer extends STS4LanguageServerProcessStreamConnector public BoshLanguageServer() { super(BOSH_SERVER); - setCommands(JRE.currentJRE().jarLaunchCommand(getLanguageServerJARLocation(), ImmutableList.of( - //"-Xdebug", - //"-agentlib:jdwp=transport=dt_socket,address=8899,server=y,suspend=n", - "-Dlsp.lazy.completions.disable=true", - "-Dlsp.completions.indentation.enable=true" - ))); + + initExplodedJarCommand( + Paths.get("servers", "bosh-language-server"), + "org.springframework.ide.vscode.bosh.BoshLanguageServerBootApp", + "application.properties", + Arrays.asList( + "-Dlsp.lazy.completions.disable=true", + "-Dlsp.completions.indentation.enable=true", + "-noverify" + ) + ); + setWorkingDirectory(getWorkingDirLocation()); } diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml index a20df8d04..844706677 100644 --- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/pom.xml @@ -36,10 +36,10 @@ 3.1.1 - copy + unpack-server prepare-package - copy + unpack @@ -49,11 +49,11 @@ ${project.version} exec true - ${project.build.directory}/../servers true true + ${project.build.directory}/../servers/manifest-yaml-language-server @@ -79,6 +79,17 @@ + + maven-clean-plugin + 3.1.0 + + + + servers + + + + diff --git a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/CloudFoundryManifestLanguageServer.java b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/CloudFoundryManifestLanguageServer.java index 2201261bb..695c5ac66 100644 --- a/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/CloudFoundryManifestLanguageServer.java +++ b/eclipse-language-servers/org.springframework.tooling.cloudfoundry.manifest.ls/src/org/springframework/tooling/cloudfoundry/manifest/ls/CloudFoundryManifestLanguageServer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 Pivotal, Inc. * 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 @@ -13,6 +13,8 @@ package org.springframework.tooling.cloudfoundry.manifest.ls; import static org.springframework.tooling.ls.eclipse.commons.preferences.LanguageServerConsolePreferenceConstants.CLOUDFOUNDRY_SERVER; import java.net.URI; +import java.nio.file.Paths; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -21,11 +23,8 @@ import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.jsonrpc.messages.Message; import org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage; import org.eclipse.lsp4j.services.LanguageServer; -import org.springframework.tooling.ls.eclipse.commons.JRE; import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessStreamConnector; -import com.google.common.collect.ImmutableList; - /** * @author Martin Lippert */ @@ -39,12 +38,18 @@ public class CloudFoundryManifestLanguageServer extends STS4LanguageServerProces public CloudFoundryManifestLanguageServer() { super(CLOUDFOUNDRY_SERVER); - setCommands(JRE.currentJRE().jarLaunchCommand(getLanguageServerJARLocation(), ImmutableList.of( - //"-Xdebug", - //"-agentlib:jdwp=transport=dt_socket,address=8899,server=y,suspend=n", - "-Dlsp.lazy.completions.disable=true", - "-Dlsp.completions.indentation.enable=true" - ))); + + initExplodedJarCommand( + Paths.get("servers", "manifest-yaml-language-server"), + "org.springframework.ide.vscode.manifest.yaml.ManifestYamlLanguageServerBootApp", + "application.properties", + Arrays.asList( + "-Dlsp.lazy.completions.disable=true", + "-Dlsp.completions.indentation.enable=true", + "-noverify" + ) + ); + setWorkingDirectory(getWorkingDirLocation()); } diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml b/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml index cd6dd2bf7..655d0700b 100644 --- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml +++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/pom.xml @@ -36,10 +36,10 @@ 2.10 - copy + unpack-server prepare-package - copy + unpack @@ -49,11 +49,11 @@ ${project.version} exec true - ${project.build.directory}/../servers true true + ${project.build.directory}/../servers/concourse-language-server @@ -79,6 +79,17 @@ + + maven-clean-plugin + 3.1.0 + + + + servers + + + + diff --git a/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/ConcourseLanguageServer.java b/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/ConcourseLanguageServer.java index e2a01b15e..ce7a30a1c 100644 --- a/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/ConcourseLanguageServer.java +++ b/eclipse-language-servers/org.springframework.tooling.concourse.ls/src/org/springframework/tooling/concourse/ls/ConcourseLanguageServer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2017 Pivotal, Inc. + * Copyright (c) 2016, 2019 Pivotal, Inc. * 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 @@ -12,10 +12,10 @@ package org.springframework.tooling.concourse.ls; import static org.springframework.tooling.ls.eclipse.commons.preferences.LanguageServerConsolePreferenceConstants.CONCOURSE_SERVER; -import org.springframework.tooling.ls.eclipse.commons.JRE; -import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessStreamConnector; +import java.nio.file.Paths; +import java.util.Arrays; -import com.google.common.collect.ImmutableList; +import org.springframework.tooling.ls.eclipse.commons.STS4LanguageServerProcessStreamConnector; /** * @author Martin Lippert @@ -24,12 +24,18 @@ public class ConcourseLanguageServer extends STS4LanguageServerProcessStreamConn public ConcourseLanguageServer() { super(CONCOURSE_SERVER); - setCommands(JRE.currentJRE().jarLaunchCommand(getLanguageServerJARLocation(), ImmutableList.of( - //"-Xdebug", - //"-agentlib:jdwp=transport=dt_socket,address=8899,server=y,suspend=n", - "-Dlsp.lazy.completions.disable=true", - "-Dlsp.completions.indentation.enable=true" - ))); + + initExplodedJarCommand( + Paths.get("servers", "concourse-language-server"), + "org.springframework.ide.vscode.concourse.ConcourseLanguageServerBootApp", + "application.properties", + Arrays.asList( + "-Dlsp.lazy.completions.disable=true", + "-Dlsp.completions.indentation.enable=true", + "-noverify" + ) + ); + setWorkingDirectory(getWorkingDirLocation()); } diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageServerProcessStreamConnector.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageServerProcessStreamConnector.java index 1606d6ae5..421f1bccf 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageServerProcessStreamConnector.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageServerProcessStreamConnector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 Pivotal, Inc. * 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 @@ -15,12 +15,14 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.List; +import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; @@ -34,6 +36,7 @@ import org.springsource.ide.eclipse.commons.core.util.IOUtil; import com.google.common.base.Charsets; import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; public abstract class STS4LanguageServerProcessStreamConnector extends ProcessStreamConnectionProvider { @@ -69,11 +72,64 @@ public abstract class STS4LanguageServerProcessStreamConnector extends ProcessSt } } - }.start();; + }.start(); } } } + protected JRE getJRE() { + return JRE.currentJRE(); + } + + protected final void initExplodedJarCommand(Path lsFolder, String mainClass, String configFileName, List extraVmArgs) { + try { + Assert.isNotNull(lsFolder); + Assert.isNotNull(mainClass); + + ImmutableList.Builder command = ImmutableList.builder(); + JRE runtime = getJRE(); + + command.add(runtime.getJavaExecutable()); + command.add("-cp"); + + Bundle bundle = Platform.getBundle(getPluginId()); + File bundleFile = FileLocator.getBundleFile(bundle); + + File bundleRoot = bundleFile.getAbsoluteFile(); + Path languageServerRoot = bundleRoot.toPath().resolve(lsFolder); + + StringBuilder classpath = new StringBuilder(); + classpath.append(languageServerRoot.resolve("BOOT-INF/classes").toFile()); + classpath.append(File.pathSeparator); + classpath.append(languageServerRoot.resolve("BOOT-INF/lib").toFile()); + // Cannot have * in the java.nio.Path on Windows + classpath.append(File.separator); + classpath.append('*'); + + if (runtime.toolsJar != null) { + classpath.append(File.pathSeparator); + classpath.append(runtime.toolsJar); + } + + command.add(classpath.toString()); + + command.add("-Dsts.lsp.client=eclipse"); + + command.addAll(extraVmArgs); + + if (configFileName != null) { + command.add("-Dspring.config.location=file:" + languageServerRoot.resolve("BOOT-INF/classes").resolve(configFileName).toFile()); + } + + command.add(mainClass); + + setCommands(command.build()); + } + catch (Exception e) { + LanguageServerCommonsActivator.logError(e, "Failed to assemble exploded LS JAR launch command"); + } + } + @Override protected ProcessBuilder createProcessBuilder() { if (consoles==null) { @@ -195,7 +251,7 @@ public abstract class STS4LanguageServerProcessStreamConnector extends ProcessSt protected final void copyLanguageServerJAR(String languageServerJarName, String languageServerLocalCopy) throws Exception { Bundle bundle = Platform.getBundle(getPluginId()); - InputStream stream = FileLocator.openStream( bundle, new Path("servers/" + languageServerJarName), false ); + InputStream stream = FileLocator.openStream( bundle, new org.eclipse.core.runtime.Path("servers/" + languageServerJarName), false ); File dataFile = bundle.getDataFile(languageServerLocalCopy); Files.copy(stream, dataFile.toPath(), StandardCopyOption.REPLACE_EXISTING); diff --git a/headless-services/bosh-language-server/src/main/resources/application.properties b/headless-services/bosh-language-server/src/main/resources/application.properties new file mode 100644 index 000000000..d8c965060 --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/application.properties @@ -0,0 +1,2 @@ +languageserver.extension-id=vscode-bosh +spring.main.banner-mode=off diff --git a/headless-services/bosh-language-server/src/main/resources/application.yml b/headless-services/bosh-language-server/src/main/resources/application.yml deleted file mode 100644 index 7cdfa7e8d..000000000 --- a/headless-services/bosh-language-server/src/main/resources/application.yml +++ /dev/null @@ -1,2 +0,0 @@ -languageserver: - extension-id: vscode-bosh \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/test/resources/application.properties b/headless-services/bosh-language-server/src/test/resources/application.properties index b6b497cfb..d8c965060 100644 --- a/headless-services/bosh-language-server/src/test/resources/application.properties +++ b/headless-services/bosh-language-server/src/test/resources/application.properties @@ -1 +1,2 @@ -spring.main.banner-mode=off \ No newline at end of file +languageserver.extension-id=vscode-bosh +spring.main.banner-mode=off diff --git a/headless-services/concourse-language-server/src/main/resources/application.properties b/headless-services/concourse-language-server/src/main/resources/application.properties new file mode 100644 index 000000000..d62823b7b --- /dev/null +++ b/headless-services/concourse-language-server/src/main/resources/application.properties @@ -0,0 +1,2 @@ +languageserver.extension-id=vscode-concourse +spring.main.banner-mode=off diff --git a/headless-services/concourse-language-server/src/main/resources/application.yml b/headless-services/concourse-language-server/src/main/resources/application.yml deleted file mode 100644 index e8e8b39e4..000000000 --- a/headless-services/concourse-language-server/src/main/resources/application.yml +++ /dev/null @@ -1,2 +0,0 @@ -languageserver: - extension-id: vscode-concourse \ No newline at end of file diff --git a/headless-services/concourse-language-server/src/test/resources/application.properties b/headless-services/concourse-language-server/src/test/resources/application.properties index 9123f8ace..3b00f9361 100644 --- a/headless-services/concourse-language-server/src/test/resources/application.properties +++ b/headless-services/concourse-language-server/src/test/resources/application.properties @@ -1,2 +1,3 @@ spring.main.banner-mode=off +languageserver.extension-id=vscode-concourse logging.level.org.springframework.ide.vscode=debug \ No newline at end of file diff --git a/headless-services/manifest-yaml-language-server/src/main/resources/application.properties b/headless-services/manifest-yaml-language-server/src/main/resources/application.properties new file mode 100644 index 000000000..c750c0043 --- /dev/null +++ b/headless-services/manifest-yaml-language-server/src/main/resources/application.properties @@ -0,0 +1,3 @@ +#logging.level.org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer=debug +languageserver.extension-id=vscode-manifest-yaml +spring.main.banner-mode=off diff --git a/headless-services/manifest-yaml-language-server/src/main/resources/application.yml b/headless-services/manifest-yaml-language-server/src/main/resources/application.yml deleted file mode 100644 index 4f1ba5414..000000000 --- a/headless-services/manifest-yaml-language-server/src/main/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -#logging: -# level: -# org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer: debug -languageserver: - extension-id: vscode-manifest-yaml \ No newline at end of file