From 49ccb607c332a27f3822f84981704c95d8677020 Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Wed, 10 Jun 2020 19:32:20 -0400 Subject: [PATCH 1/9] Very dirty example of running from an exploded war --- ext/ExplodedWarMain.java | 359 +++++++++++++++++++++++++++++++++++++++ lib/warbler_jar.jar | Bin 19687 -> 27271 bytes 2 files changed, 359 insertions(+) create mode 100644 ext/ExplodedWarMain.java diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java new file mode 100644 index 00000000..f2808d8c --- /dev/null +++ b/ext/ExplodedWarMain.java @@ -0,0 +1,359 @@ +/** + * Copyright (c) 2010-2012 Engine Yard, Inc. + * Copyright (c) 2007-2009 Sun Microsystems, Inc. + * This source code is available under the MIT license. + * See the file LICENSE.txt for details. + */ + +import java.lang.reflect.Method; +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.SequenceInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.net.URI; +import java.net.URLClassLoader; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.Map; +import java.util.jar.JarEntry; + +/** + * Used as a Main-Class in the manifest for a .war file, so that you can run + * a .war file with java -jar. + * + * WarMain can be used with different web server libraries. WarMain expects + * to have two files present in the .war file, + * WEB-INF/webserver.properties and WEB-INF/webserver.jar. + * + * When WarMain starts up, it extracts the webserver jar to a temporary + * directory, and creates a temporary work directory for the webapp. Both + * are deleted on exit. + * + * It then reads webserver.properties into a java.util.Properties object, + * creates a URL classloader holding the jar, and loads and invokes the + * main method of the main class mentioned in the properties. + * + * An example webserver.properties follows for Jetty. The args + * property indicates the names and ordering of other properties to be used + * as command-line arguments. The special tokens {{warfile}} and + * {{webroot}} are substituted with the location of the .war file + * being run and the temporary work directory, respectively. + *
+ * mainclass = org.eclipse.jetty.runner.Runner
+ * args = args0,args1,args2,args3,args4
+ * props = jetty.home
+ * args0 = --port
+ * args1 = {{port}}
+ * args2 = --config
+ * args3 = {{config}}
+ * args4 = {{warfile}}
+ * jetty.home = {{webroot}}
+ * 
+ * + * System properties can also be set via webserver.properties. For example, + * the following entries set jetty.home before launching the server. + *
+ * props = jetty.home
+ * jetty.home = {{webroot}}
+ * 
+ */ +public class ExplodedWarMain extends JarMain { + + static final String MAIN = '/' + ExplodedWarMain.class.getName().replace('.', '/') + ".class"; + static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties"; + static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar"; + static final String WEBSERVER_CONFIG = "/WEB-INF/webserver.xml"; + + /** + * jruby arguments, consider the following command : + * `java -jar rails.war --1.9 -S rake db:migrate` + * arguments == [ "--1.9" ] + * executable == "rake" + * executableArgv == [ "db:migrate" ] + */ + private final String[] arguments; + + /** + * null to launch webserver or != null to run a executable e.g. rake + */ + private final String executable; + private final String[] executableArgv; + + private File webroot; + private File warRoot; + + ExplodedWarMain(final String[] args) { + super(args); + final List argsList = Arrays.asList(args); + final int sIndex = argsList.indexOf("-S"); + if ( sIndex == -1 ) { + executable = null; executableArgv = null; arguments = null; + } + else { + if ( args.length == sIndex + 1 || args[sIndex + 1].isEmpty() ) { + throw new IllegalArgumentException("missing executable after -S"); + } + arguments = argsList.subList(0, sIndex).toArray(new String[0]); + String execArg = argsList.get(sIndex + 1); + executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); + + if (execArg.equals("rails")) { + // The rails executable doesn't play well with ScriptingContainer, so we've packaged the + // same script that would have been generated by `rake rails:update:bin` + execArg = "META-INF/rails.rb"; + } + else if (execArg.equals("bundle") && executableArgv.length > 0 && executableArgv[0].equals("exec")) { + warn("`bundle exec' may drop out of the Warbler environment and into the system environment"); + } + + executable = execArg; + } + } + + private URL extractWebserver() throws Exception { + this.webroot = new File(this.warRoot.toString(), "WEB-INF"); + debug("webroot directory is " + this.webroot.getPath()); + + File jarFile = new File(this.webroot, "webserver.jar"); + debug("webserver.jar is at" + jarFile.getPath()); + + return jarFile.toURI().toURL(); + } + + private Properties getWebserverProperties() throws Exception { + Properties props = new Properties(); + try { + InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES); + if ( is != null ) props.load(is); + } catch (Exception e) { } + + String port = getSystemProperty("warbler.port", getENV("PORT")); + port = port == null ? "8080" : port; + String host = getSystemProperty("warbler.host", "0.0.0.0"); + String webserverConfig = getSystemProperty("warbler.webserver_config", getENV("WARBLER_WEBSERVER_CONFIG")); + String embeddedWebserverConfig = new URI("jar", entryPath(WEBSERVER_CONFIG), null).toURL().toString(); + webserverConfig = webserverConfig == null ? embeddedWebserverConfig : webserverConfig; + for ( Map.Entry entry : props.entrySet() ) { + String val = (String) entry.getValue(); + val = val.replace("{{warfile}}", archive). + replace("{{port}}", port). + replace("{{host}}", host). + replace("{{config}}", webserverConfig). + replace("{{webroot}}", webroot.getAbsolutePath()); + entry.setValue(val); + } + + if (props.getProperty("props") != null) { + String[] propsToSet = props.getProperty("props").split(","); + for ( String key : propsToSet ) { + setSystemProperty(key, props.getProperty(key)); + } + } + + return props; + } + + private void launchWebServer(URL jar) throws Exception { + URLClassLoader loader = new URLClassLoader(new URL[] {jar}); + Thread.currentThread().setContextClassLoader(loader); + Properties props = getWebserverProperties(); + String mainClass = props.getProperty("mainclass"); + if (mainClass == null) { + throw new IllegalArgumentException("unknown webserver main class (" + + WEBSERVER_PROPERTIES + + " is missing 'mainclass' property)"); + } + Class klass = Class.forName(mainClass, true, loader); + Method main = klass.getDeclaredMethod("main", new Class[] { String[].class }); + String[] newArgs = launchWebServerArguments(props); + debug("invoking webserver with: " + Arrays.deepToString(newArgs)); + main.invoke(null, new Object[] { newArgs }); + } + + private String[] launchWebServerArguments(Properties props) { + String[] newArgs = args; + + if (props.getProperty("args") != null) { + String[] insertArgs = props.getProperty("args").split(","); + newArgs = new String[args.length + insertArgs.length]; + for (int i = 0; i < insertArgs.length; i++) { + newArgs[i] = props.getProperty(insertArgs[i], ""); + } + System.arraycopy(args, 0, newArgs, insertArgs.length, args.length); + } + + return newArgs; + } + + // JarMain overrides to make WarMain "launchable" + // e.g. java -jar rails.war -S rake db:migrate + + @Override + protected String getExtractEntryPath(final JarEntry entry) { + final String name = entry.getName(); + final String start = "WEB-INF"; + if ( name.startsWith(start) ) { + // WEB-INF/app/controllers/application_controller.rb -> + // app/controllers/application_controller.rb + return name.substring(start.length()); + } + if ( name.indexOf('/') == -1 ) { + // 404.html -> public/404.html + return "/public/" + name; + } + return '/' + name; + } + + @Override + protected URL extractEntry(final JarEntry entry, final String path) throws Exception { + // always extract but only return class-path entry URLs : + final URL entryURL = super.extractEntry(entry, path); + return path.endsWith(".jar") && path.startsWith("/lib/") ? entryURL : null; + } + + @Override + protected int launchJRuby(final URL[] jars) throws Exception { + final Object scriptingContainer = newScriptingContainer(jars); + + invokeMethod(scriptingContainer, "setArgv", (Object) executableArgv); + invokeMethod(scriptingContainer, "setCurrentDirectory", warRoot.getAbsolutePath()); + initJRubyScriptingEnv(scriptingContainer); + + final Object provider = invokeMethod(scriptingContainer, "getProvider"); + final Object rubyInstanceConfig = invokeMethod(provider, "getRubyInstanceConfig"); + + invokeMethod(rubyInstanceConfig, "setUpdateNativeENVEnabled", new Class[] { Boolean.TYPE }, false); + + final CharSequence execScriptEnvPre = executableScriptEnvPrefix(); + + final String executablePath = locateExecutable(scriptingContainer, execScriptEnvPre); + if ( executablePath == null ) { + throw new IllegalStateException("failed to locate gem executable: '" + executable + "'"); + } + invokeMethod(scriptingContainer, "setScriptFilename", executablePath); + + invokeMethod(rubyInstanceConfig, "processArguments", (Object) arguments); + + Object runtime = invokeMethod(scriptingContainer, "getRuntime"); + + debug("loading resource: " + executablePath); + Object executableInput = + new SequenceInputStream(new ByteArrayInputStream(execScriptEnvPre.toString().getBytes()), + (InputStream) invokeMethod(rubyInstanceConfig, "getScriptSource")); + + debug("invoking " + executablePath + " with: " + Arrays.toString(executableArgv)); + + Object outcome = invokeMethod(runtime, "runFromMain", + new Class[] { InputStream.class, String.class }, + executableInput, executablePath + ); + return ( outcome instanceof Number ) ? ( (Number) outcome ).intValue() : 0; + } + + @Deprecated + protected String locateExecutable(final Object scriptingContainer) throws Exception { + if ( executable == null ) { + throw new IllegalStateException("no executable"); + } + final File exec = new File(warRoot, executable); + if ( exec.exists() ) { + return exec.getAbsolutePath(); + } + else { + final String script = locateExecutableScript(executable, executableScriptEnvPrefix()); + return (String) invokeMethod(scriptingContainer, "runScriptlet", script); + } + } + + protected String locateExecutable(final Object scriptingContainer, final CharSequence envPreScript) + throws Exception { + if ( executable == null ) { + throw new IllegalStateException("no executable"); + } + final File exec = new File(warRoot, executable); + if ( exec.exists() ) { + return exec.getAbsolutePath(); + } + else { + final String script = locateExecutableScript(executable, envPreScript); + return (String) invokeMethod(scriptingContainer, "runScriptlet", script); + } + } + + protected CharSequence executableScriptEnvPrefix() { + final String gemsDir = new File(warRoot, "WEB-INF/gems").getAbsolutePath(); + final String gemfile = new File(warRoot, "WEB-INF/Gemfile").getAbsolutePath(); + debug("setting GEM_HOME to " + gemsDir); + debug("... and BUNDLE_GEMFILE to " + gemfile); + + // ideally this would look up the config.override_gem_home setting + return "ENV['GEM_HOME'] = ENV['GEM_PATH'] = '"+ gemsDir +"' \n" + + "ENV['BUNDLE_GEMFILE'] ||= '"+ gemfile +"' \n" + + "puts 'Environment:' + ENV.inspect\n" + + "puts 'Load paths:' + $LOAD_PATH.inspect\n" + + "puts 'Current directory:' + __dir__\n" + + "require '" + warRoot + "/META-INF/init.rb'"; + } + + protected String locateExecutableScript(final String executable, final CharSequence envPreScript) { + return ( envPreScript == null ? "" : envPreScript + " \n" ) + + "begin\n" + // locate the executable within gemspecs : + " require 'rubygems' unless defined?(Gem) \n" + + " begin\n" + // add bundled gems to load path : + " require 'bundler' \n" + + " rescue LoadError\n" + // bundler not used + " else\n" + + " env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] \n" + // init.rb sets ENV['RAILS_ENV'] ||= ... + " env ? Bundler.setup(:default, env) : Bundler.setup(:default) \n" + + " end if ENV_JAVA['warbler.bundler.setup'] != 'false' \n" + // java -Dwarbler.bundler.setup=false -jar my.war -S pry + " exec = '"+ executable +"' \n" + + " spec = Gem::Specification.find { |s| s.executables.include?(exec) } \n" + + " spec ? spec.bin_file(exec) : nil \n" + + // returns the full path to the executable + "rescue SystemExit => e\n" + + " e.status\n" + + "end"; + } + + protected void initJRubyScriptingEnv(Object scriptingContainer) throws Exception { + // for some reason, the container needs to run a scriptlet in order for it + // to be able to find the gem executables later + invokeMethod(scriptingContainer, "runScriptlet", "SCRIPTING_CONTAINER_INITIALIZED=true"); + +// invokeMethod(scriptingContainer, "setHomeDirectory", this.warRoot.toString()); + invokeMethod(scriptingContainer, "setHomeDirectory", "uri:classloader:/META-INF/jruby.home"); + } + + @Override + protected int start() throws Exception { + this.warRoot = new File("/Users/kovyrin/Downloads/enterprise-search-7.9.0-exploded/lib/war"); + final URL[] jars = {}; + + if ( executable == null ) { + try { + URL server = extractWebserver(); + launchWebServer(server); + } + catch (FileNotFoundException e) { + final String msg = e.getMessage(); + if ( msg != null && msg.contains("WEB-INF/webserver.jar") ) { + System.out.println("specify the -S argument followed by the bin file to run e.g. `java -jar rails.war -S rake -T` ..."); + System.out.println("(or if you'd like your .war file to start a web server package it using `warbler executable war`)"); + } + throw e; + } + return 0; + } + + + return launchJRuby(jars); + } + + public static void main(String[] args) { + doStart(new ExplodedWarMain(args)); + } +} diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index 966d2e0127583ab7b286a7760f57c977a903df5a..63c50f6eb0b3a39a0539f027f6cecedd7643dafe 100644 GIT binary patch literal 27271 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 H@$P>B+6Wt5 delta 18951 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 uHXbb=#XTrFDi5U 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 From fbc181fb0ae6d935d052b22f1d281185de111302 Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Thu, 11 Jun 2020 06:13:05 -0400 Subject: [PATCH 2/9] Migrations work --- ext/ExplodedWarMain.java | 402 +++++++++++++-------------------------- lib/warbler_jar.jar | Bin 27271 -> 25091 bytes 2 files changed, 127 insertions(+), 275 deletions(-) diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index f2808d8c..dc7f4944 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -12,215 +12,112 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URI; import java.net.URLClassLoader; import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.Map; import java.util.jar.JarEntry; -/** - * Used as a Main-Class in the manifest for a .war file, so that you can run - * a .war file with java -jar. - * - * WarMain can be used with different web server libraries. WarMain expects - * to have two files present in the .war file, - * WEB-INF/webserver.properties and WEB-INF/webserver.jar. - * - * When WarMain starts up, it extracts the webserver jar to a temporary - * directory, and creates a temporary work directory for the webapp. Both - * are deleted on exit. - * - * It then reads webserver.properties into a java.util.Properties object, - * creates a URL classloader holding the jar, and loads and invokes the - * main method of the main class mentioned in the properties. - * - * An example webserver.properties follows for Jetty. The args - * property indicates the names and ordering of other properties to be used - * as command-line arguments. The special tokens {{warfile}} and - * {{webroot}} are substituted with the location of the .war file - * being run and the temporary work directory, respectively. - *
- * mainclass = org.eclipse.jetty.runner.Runner
- * args = args0,args1,args2,args3,args4
- * props = jetty.home
- * args0 = --port
- * args1 = {{port}}
- * args2 = --config
- * args3 = {{config}}
- * args4 = {{warfile}}
- * jetty.home = {{webroot}}
- * 
- * - * System properties can also be set via webserver.properties. For example, - * the following entries set jetty.home before launching the server. - *
- * props = jetty.home
- * jetty.home = {{webroot}}
- * 
- */ -public class ExplodedWarMain extends JarMain { - - static final String MAIN = '/' + ExplodedWarMain.class.getName().replace('.', '/') + ".class"; - static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties"; - static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar"; - static final String WEBSERVER_CONFIG = "/WEB-INF/webserver.xml"; - - /** - * jruby arguments, consider the following command : - * `java -jar rails.war --1.9 -S rake db:migrate` - * arguments == [ "--1.9" ] - * executable == "rake" - * executableArgv == [ "db:migrate" ] - */ - private final String[] arguments; - - /** - * null to launch webserver or != null to run a executable e.g. rake - */ - private final String executable; - private final String[] executableArgv; - - private File webroot; - private File warRoot; - - ExplodedWarMain(final String[] args) { - super(args); - final List argsList = Arrays.asList(args); - final int sIndex = argsList.indexOf("-S"); - if ( sIndex == -1 ) { - executable = null; executableArgv = null; arguments = null; - } - else { - if ( args.length == sIndex + 1 || args[sIndex + 1].isEmpty() ) { - throw new IllegalArgumentException("missing executable after -S"); - } - arguments = argsList.subList(0, sIndex).toArray(new String[0]); - String execArg = argsList.get(sIndex + 1); - executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); - - if (execArg.equals("rails")) { - // The rails executable doesn't play well with ScriptingContainer, so we've packaged the - // same script that would have been generated by `rake rails:update:bin` - execArg = "META-INF/rails.rb"; - } - else if (execArg.equals("bundle") && executableArgv.length > 0 && executableArgv[0].equals("exec")) { - warn("`bundle exec' may drop out of the Warbler environment and into the system environment"); - } +public class ExplodedWarMain { + static void debug(String message) { + System.out.println(message); + } - executable = execArg; + //---------------------------------------------------------------------------------------------- + static boolean setSystemProperty(final String name, final String value) { + try { + System.setProperty(name, value); + return true; + } + catch (SecurityException e) { + return false; } } - private URL extractWebserver() throws Exception { - this.webroot = new File(this.warRoot.toString(), "WEB-INF"); - debug("webroot directory is " + this.webroot.getPath()); - - File jarFile = new File(this.webroot, "webserver.jar"); - debug("webserver.jar is at" + jarFile.getPath()); + //---------------------------------------------------------------------------------------------- + static protected void initJRubyScriptingEnv(Object scriptingContainer) throws Exception { + // for some reason, the container needs to run a scriptlet in order for it + // to be able to find the gem executables later + invokeMethod(scriptingContainer, "runScriptlet", "SCRIPTING_CONTAINER_INITIALIZED=true"); - return jarFile.toURI().toURL(); + invokeMethod(scriptingContainer, "setHomeDirectory", "uri:classloader:/META-INF/jruby.home"); } - private Properties getWebserverProperties() throws Exception { - Properties props = new Properties(); - try { - InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES); - if ( is != null ) props.load(is); - } catch (Exception e) { } - - String port = getSystemProperty("warbler.port", getENV("PORT")); - port = port == null ? "8080" : port; - String host = getSystemProperty("warbler.host", "0.0.0.0"); - String webserverConfig = getSystemProperty("warbler.webserver_config", getENV("WARBLER_WEBSERVER_CONFIG")); - String embeddedWebserverConfig = new URI("jar", entryPath(WEBSERVER_CONFIG), null).toURL().toString(); - webserverConfig = webserverConfig == null ? embeddedWebserverConfig : webserverConfig; - for ( Map.Entry entry : props.entrySet() ) { - String val = (String) entry.getValue(); - val = val.replace("{{warfile}}", archive). - replace("{{port}}", port). - replace("{{host}}", host). - replace("{{config}}", webserverConfig). - replace("{{webroot}}", webroot.getAbsolutePath()); - entry.setValue(val); + //---------------------------------------------------------------------------------------------- + protected static Object invokeMethod(final Object self, final String name, final Object... args) throws NoSuchMethodException, IllegalAccessException, Exception { + final Class[] signature = new Class[args.length]; + for ( int i = 0; i < args.length; i++ ) { + signature[i] = args[i].getClass(); } + return invokeMethod(self, name, signature, args); + } - if (props.getProperty("props") != null) { - String[] propsToSet = props.getProperty("props").split(","); - for ( String key : propsToSet ) { - setSystemProperty(key, props.getProperty(key)); + //---------------------------------------------------------------------------------------------- + protected static Object invokeMethod(final Object self, final String name, final Class[] signature, final Object... args) throws NoSuchMethodException, IllegalAccessException, Exception { + Method method = self.getClass().getDeclaredMethod(name, signature); + try { + return method.invoke(self, args); + } catch (InvocationTargetException e) { + Throwable target = e.getTargetException(); + if (target instanceof Exception) { + throw (Exception) target; } + throw e; } + } - return props; + //---------------------------------------------------------------------------------------------- + protected static CharSequence executableScriptEnvPrefix(String extractRoot) { + final String gemsDir = new File(extractRoot, "gems").getAbsolutePath(); + final String gemfile = new File(extractRoot, "Gemfile").getAbsolutePath(); + System.out.println("setting GEM_HOME to " + gemsDir); + System.out.println("... and BUNDLE_GEMFILE to " + gemfile); + + // ideally this would look up the config.override_gem_home setting + return "ENV['GEM_HOME'] = ENV['GEM_PATH'] = '"+ gemsDir +"' \n" + + "ENV['BUNDLE_GEMFILE'] ||= '"+ gemfile +"' \n" + + "require '" + extractRoot + "/../META-INF/init.rb'"; } - private void launchWebServer(URL jar) throws Exception { - URLClassLoader loader = new URLClassLoader(new URL[] {jar}); - Thread.currentThread().setContextClassLoader(loader); - Properties props = getWebserverProperties(); - String mainClass = props.getProperty("mainclass"); - if (mainClass == null) { - throw new IllegalArgumentException("unknown webserver main class (" - + WEBSERVER_PROPERTIES - + " is missing 'mainclass' property)"); - } - Class klass = Class.forName(mainClass, true, loader); - Method main = klass.getDeclaredMethod("main", new Class[] { String[].class }); - String[] newArgs = launchWebServerArguments(props); - debug("invoking webserver with: " + Arrays.deepToString(newArgs)); - main.invoke(null, new Object[] { newArgs }); + //---------------------------------------------------------------------------------------------- + protected static String locateExecutable(Object scriptingContainer, String root, final CharSequence envPreScript, String executable) throws Exception { + final File exec = new File(root, executable); + debug("locating script " + root + " " + executable); + return exec.exists() ? exec.getAbsolutePath() : null; } - private String[] launchWebServerArguments(Properties props) { - String[] newArgs = args; + //---------------------------------------------------------------------------------------------- + protected static Object newScriptingContainer(final URL[] jars, String[] args) throws Exception { + setSystemProperty("org.jruby.embed.class.path", ""); - if (props.getProperty("args") != null) { - String[] insertArgs = props.getProperty("args").split(","); - newArgs = new String[args.length + insertArgs.length]; - for (int i = 0; i < insertArgs.length; i++) { - newArgs[i] = props.getProperty(insertArgs[i], ""); - } - System.arraycopy(args, 0, newArgs, insertArgs.length, args.length); - } + URLClassLoader classLoader = new URLClassLoader(jars); - return newArgs; - } + Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, classLoader); + Object scriptingContainer = scriptingContainerClass.newInstance(); - // JarMain overrides to make WarMain "launchable" - // e.g. java -jar rails.war -S rake db:migrate - - @Override - protected String getExtractEntryPath(final JarEntry entry) { - final String name = entry.getName(); - final String start = "WEB-INF"; - if ( name.startsWith(start) ) { - // WEB-INF/app/controllers/application_controller.rb -> - // app/controllers/application_controller.rb - return name.substring(start.length()); - } - if ( name.indexOf('/') == -1 ) { - // 404.html -> public/404.html - return "/public/" + name; - } - return '/' + name; - } + System.out.println("scripting container class loader urls: " + Arrays.toString(jars)); + invokeMethod(scriptingContainer, "setArgv", (Object) args); + invokeMethod(scriptingContainer, "setClassLoader", new Class[] { ClassLoader.class }, classLoader); - @Override - protected URL extractEntry(final JarEntry entry, final String path) throws Exception { - // always extract but only return class-path entry URLs : - final URL entryURL = super.extractEntry(entry, path); - return path.endsWith(".jar") && path.startsWith("/lib/") ? entryURL : null; + return scriptingContainer; } - @Override - protected int launchJRuby(final URL[] jars) throws Exception { - final Object scriptingContainer = newScriptingContainer(jars); + //---------------------------------------------------------------------------------------------- + protected static int launchJRuby(final URL[] jars, File root, String executable, String args[]) throws Exception { + final Object scriptingContainer = newScriptingContainer(jars, args); + + invokeMethod(scriptingContainer, "setArgv", (Object) args); + debug("setArgv: " + args); + + invokeMethod(scriptingContainer, "setCurrentDirectory", root.getAbsolutePath()); + debug("setCurrentDirectory: " + root.getAbsolutePath()); - invokeMethod(scriptingContainer, "setArgv", (Object) executableArgv); - invokeMethod(scriptingContainer, "setCurrentDirectory", warRoot.getAbsolutePath()); initJRubyScriptingEnv(scriptingContainer); final Object provider = invokeMethod(scriptingContainer, "getProvider"); @@ -228,132 +125,87 @@ protected int launchJRuby(final URL[] jars) throws Exception { invokeMethod(rubyInstanceConfig, "setUpdateNativeENVEnabled", new Class[] { Boolean.TYPE }, false); - final CharSequence execScriptEnvPre = executableScriptEnvPrefix(); + final CharSequence execScriptEnvPre = executableScriptEnvPrefix(root.getAbsolutePath()); - final String executablePath = locateExecutable(scriptingContainer, execScriptEnvPre); + final String executablePath = locateExecutable(scriptingContainer, root.getCanonicalPath(), execScriptEnvPre, executable); if ( executablePath == null ) { throw new IllegalStateException("failed to locate gem executable: '" + executable + "'"); } + invokeMethod(scriptingContainer, "setScriptFilename", executablePath); + debug("setScriptFilename: " + executablePath); - invokeMethod(rubyInstanceConfig, "processArguments", (Object) arguments); + invokeMethod(rubyInstanceConfig, "processArguments", (Object) args); Object runtime = invokeMethod(scriptingContainer, "getRuntime"); debug("loading resource: " + executablePath); - Object executableInput = - new SequenceInputStream(new ByteArrayInputStream(execScriptEnvPre.toString().getBytes()), - (InputStream) invokeMethod(rubyInstanceConfig, "getScriptSource")); + Object executableInput = new SequenceInputStream( + new ByteArrayInputStream(execScriptEnvPre.toString().getBytes()), + (InputStream) invokeMethod(rubyInstanceConfig, "getScriptSource") + ); - debug("invoking " + executablePath + " with: " + Arrays.toString(executableArgv)); + debug("invoking " + executablePath + " with: " + Arrays.toString(args)); - Object outcome = invokeMethod(runtime, "runFromMain", - new Class[] { InputStream.class, String.class }, - executableInput, executablePath + Object outcome = invokeMethod( + runtime, + "runFromMain", + new Class[] { InputStream.class, String.class }, + executableInput, + executablePath ); return ( outcome instanceof Number ) ? ( (Number) outcome ).intValue() : 0; } - @Deprecated - protected String locateExecutable(final Object scriptingContainer) throws Exception { - if ( executable == null ) { - throw new IllegalStateException("no executable"); - } - final File exec = new File(warRoot, executable); - if ( exec.exists() ) { - return exec.getAbsolutePath(); - } - else { - final String script = locateExecutableScript(executable, executableScriptEnvPrefix()); - return (String) invokeMethod(scriptingContainer, "runScriptlet", script); - } - } + //---------------------------------------------------------------------------------------------- + public static URL[] loadJarUrls(File root) throws Exception { + List jars = new ArrayList(); - protected String locateExecutable(final Object scriptingContainer, final CharSequence envPreScript) - throws Exception { - if ( executable == null ) { - throw new IllegalStateException("no executable"); - } - final File exec = new File(warRoot, executable); - if ( exec.exists() ) { - return exec.getAbsolutePath(); - } - else { - final String script = locateExecutableScript(executable, envPreScript); - return (String) invokeMethod(scriptingContainer, "runScriptlet", script); - } - } + File[] files = new File(root, "lib").listFiles(); - protected CharSequence executableScriptEnvPrefix() { - final String gemsDir = new File(warRoot, "WEB-INF/gems").getAbsolutePath(); - final String gemfile = new File(warRoot, "WEB-INF/Gemfile").getAbsolutePath(); - debug("setting GEM_HOME to " + gemsDir); - debug("... and BUNDLE_GEMFILE to " + gemfile); - - // ideally this would look up the config.override_gem_home setting - return "ENV['GEM_HOME'] = ENV['GEM_PATH'] = '"+ gemsDir +"' \n" + - "ENV['BUNDLE_GEMFILE'] ||= '"+ gemfile +"' \n" + - "puts 'Environment:' + ENV.inspect\n" + - "puts 'Load paths:' + $LOAD_PATH.inspect\n" + - "puts 'Current directory:' + __dir__\n" + - "require '" + warRoot + "/META-INF/init.rb'"; + for (File f : files) { + if (f.isFile() && f.getName().endsWith(".jar")) + jars.add(f.toURI().toURL()); + } + return jars.toArray(new URL[jars.size()]); } - protected String locateExecutableScript(final String executable, final CharSequence envPreScript) { - return ( envPreScript == null ? "" : envPreScript + " \n" ) + - "begin\n" + // locate the executable within gemspecs : - " require 'rubygems' unless defined?(Gem) \n" + - " begin\n" + // add bundled gems to load path : - " require 'bundler' \n" + - " rescue LoadError\n" + // bundler not used - " else\n" + - " env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] \n" + // init.rb sets ENV['RAILS_ENV'] ||= ... - " env ? Bundler.setup(:default, env) : Bundler.setup(:default) \n" + - " end if ENV_JAVA['warbler.bundler.setup'] != 'false' \n" + // java -Dwarbler.bundler.setup=false -jar my.war -S pry - " exec = '"+ executable +"' \n" + - " spec = Gem::Specification.find { |s| s.executables.include?(exec) } \n" + - " spec ? spec.bin_file(exec) : nil \n" + - // returns the full path to the executable - "rescue SystemExit => e\n" + - " e.status\n" + - "end"; + //---------------------------------------------------------------------------------------------- + public static void launchWebServer() { + debug("Jetty will start here"); } - protected void initJRubyScriptingEnv(Object scriptingContainer) throws Exception { - // for some reason, the container needs to run a scriptlet in order for it - // to be able to find the gem executables later - invokeMethod(scriptingContainer, "runScriptlet", "SCRIPTING_CONTAINER_INITIALIZED=true"); + //---------------------------------------------------------------------------------------------- + public static void main(String args[]) throws Exception { + String warRoot = "./lib/war"; + File root = new File(new File(warRoot + "/WEB-INF/").getCanonicalPath()); -// invokeMethod(scriptingContainer, "setHomeDirectory", this.warRoot.toString()); - invokeMethod(scriptingContainer, "setHomeDirectory", "uri:classloader:/META-INF/jruby.home"); - } + debug("Root: " + root.toString()); - @Override - protected int start() throws Exception { - this.warRoot = new File("/Users/kovyrin/Downloads/enterprise-search-7.9.0-exploded/lib/war"); - final URL[] jars = {}; + final List argsList = Arrays.asList(args); + final int sIndex = argsList.indexOf("-S"); - if ( executable == null ) { - try { - URL server = extractWebserver(); - launchWebServer(server); - } - catch (FileNotFoundException e) { - final String msg = e.getMessage(); - if ( msg != null && msg.contains("WEB-INF/webserver.jar") ) { - System.out.println("specify the -S argument followed by the bin file to run e.g. `java -jar rails.war -S rake -T` ..."); - System.out.println("(or if you'd like your .war file to start a web server package it using `warbler executable war`)"); - } - throw e; - } - return 0; + if (sIndex == -1) { + debug("No command specified, starting a web server"); + launchWebServer(); + return; } + String[] arguments = argsList.subList(0, sIndex).toArray(new String[0]); + String execArg = argsList.get(sIndex + 1); + String[] executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); - return launchJRuby(jars); - } + if (execArg.equals("rails")) { + // The rails executable doesn't play well with ScriptingContainer, so we've packaged the + // same script that would have been generated by `rake rails:update:bin` + execArg = "/../META-INF/rails.rb"; + } else { + System.out.println("Only -S rails is supported for now"); + System.exit(1); + } - public static void main(String[] args) { - doStart(new ExplodedWarMain(args)); + URL[] jars = loadJarUrls(root); + debug("Launching jruby with script '" + execArg + "' and arguments: " + executableArgv); + launchJRuby(jars, root, execArg, executableArgv); } } diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index 63c50f6eb0b3a39a0539f027f6cecedd7643dafe..8c8755ef6f654506f5a07fc29ca41c16541cee1c 100644 GIT binary patch delta 4706 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 Zr1x*~G?B`d2Mgc$-%%Rxv+?~K{|8Jg|ET}~ delta 6911 zcmZ9RWmwc*)UT25ROymN>FyGcMnbwl7`h~dKOqf63=9I&IUpt7q7p-Q!_Yl+OPt4Z zz3=&O_J@66zqR*T*ZO{k|9KWQ{S04Q4GkR^<=;t6OU7qG1*atoa=J7m_(~fOqiH9puPB|wk?Yi1tp6ga>_*m7~_1_o1T{0`IvIeFNscvPBDX3Fwcs! z9?2BwRM zSJ80xFdF0r{SxB>q+B1h4Yt@nvX}Hf``Ae*Y-ALDrI+XEAje&&)MzQSRh(9d^!Rh zCL&DuR#7(xq%W*Ky*hoQzMB$K$GQX9K0NcM5xh-;M`?6+Z!)nW98NS?rEJd5?M^V{ zPb1_O7^#KNh6QdE@7F0m<8{5I;}N>q5^#9k^=s1rx2>A=)K%zqnzgHUb2jr{d~N@d ze~W-sisQMfz-he1k;sYb@wse8DDVM;r%m64)1OFkKa*YpG5%Ce)_e<0j2By4Rik`w#3AYdyjF% zgY~Qjgstej8P4|Qf=ykT<5(;6KBQeM<30~glyMJpd=vy&qxp!1%}n0i4gY)E{AR8G+j!)~8>a7Mb_2NmgfBpL#bDnfDS9 z!0n7){jm@Z@ZXO9Xjg;Ea3nqn+`t%?2LZm@>R-Kx^8DLC>)NA!RU8hx@<`G&cDTvldUgaX8LKfRGkq5cG! z$Ddp>+iJvXjamY_O@)P%P{!+G=_~h=(bRk8d>OJ;?f5piz@^5Gy<|tl{Lj^V5Aw@D zo!Uyag@S_3GPw5tG8}JD5%-TeCbBJ$EbWG59bF37FY1QZzO{Hmo9@;%Nz7d%Gh=t% z(|!Bxs!_oPCy8Q#M9uflx{5P>h%E*G)->H{NW%QeN{cffIsQuOt6o|RYt)j0It_*| z)N=AQ~UDO@M_7Q>(e~rU{Qr} zP%vlG4B7$RWz^I?mOY_{VK7o*E&ATJ;Xspd+X)Rf%|HBv!RMp1Z(n9q+?}4Q`h3KI>jgsl=uT=%>b~qEtho7bSsD`Q0 zTPfjxdGq@WR=>5v@5p${Loo5chI-EWuU=562;~DROvW=lQeRZ23*D)gF=DO)kHuJg zW)xn<57`*&@u&JkksVn!7XKbTQX`0AfgE*zKn9(c=orq{tm)+Oeiu*}ZIIf)OnrETaQ|R4_ED9Swy~fn z8Z}j-2aHxqK#)I5D$Z;pKiINOiJv5L9T_gXh*gLVb4^U^^kd}~%~3D;Q7bu@O8lnk z**JlnPp;F;(9P?Zt8@x_aPC2f5ue=5$Q+rHdNtzHAJ@dbO( zLIKYN)61Y|L_!Ki>aXLRmC0~?nW6oFjaDdmNl)RaI%a{mqJ&uO+V?D<%z&EwOc1PY z>W%2WUa^s5W2Oy<$#BDzBp8KlqSo(~4U9^NK6+t%W^v&;a%rI;Fl$oVeHvwoVZsG* z&~TB{Fye4nBY=M4MNFsZI0rxSqU|TpoFM$hk)z2H0b+yFc&@{pRkiwQMr?uQ@d*z# zE^UD|pm?BZcktqC@yl}JC2YlHcV-=~AG>N76#Nr@2N2zW~c*pgr(HLX* zt95WmF_-i;m*Ni_mcfztJH|lyhiNNB!8?|Zjf4TXE?2tVvyDgQYSR^%YC`3_;xkp| zZLPMM>Aw=Dhwo%$ErauF9&+U9dC89)kSkMQo%5lBNlrNstZe|>!$Hsr#(MIsQpluS zu~K--A8K4UqAXwu#MUDsK20|AMk-x9|3WZw=}Dt=vK~dzZY%W8>i4OdyB?}n~3`~+frae6|e7$dyGD~ zgOerI%(vlvvzuOD)O$G!T35MvwYs%l#^w&m_S6YwQ(cCX|8Z(R&n{MCkr+}hQN6H+ zF{5Vj*nX*sxTK@U5wkP&?@PZY;y%w!--!$H*DhwZ-#G&s!BPg!2M%P&!mkdlt}`6g zlUE~LNS8p~R-uI>q8v2HarrP$*)sCGFRqkXWrx8o-B*xNCD{}jB*yZlm-_MxHSe=l zxM+h*&kz~x6IFz{K>0b}O{t7RO?R@qNFm#IN5o94;<2z@&hcUob7AT6eE6|cU>InQ z5>2!6iza|;KCbhwQb&fNE{tmnJtG~znd#Ja%mY`gsPl!;jChMJYR)!({)uX<0`)=O zZ~&I>xti)r{}wT`0|(WN?r#Ut%r1N0oC(|_$sU)eMJw%8Z6<|Cslc(R*nw-8&Vgf2 zb;PdoS+vOS$d=kx?3?-?1|=(>Y_-a2qeE-HO>(8Im7q zv#O)UAiXnxCH%k@+b6P__%>h+Ow@<<>HQM^Fus`bH);V9@r><)ijSEX=3WX%z2bY{ zeO)<|=F2RG(M~t%JTw5wb>LD6!c1eY9jN#a_6m4OKY`6~)?)n>Nv5^%~rfTwr6$ z7O6}~{v6~oPv|{bf2c((8jo9Qhvx}?(_jB{XX(OFJjWx8-}Q}DbM@Z(wpylvNK5c( zKI3iPb3vKnT%!xY2fR=HUeHD;6-2dSdk9!6PJRrCP*!5>x1p@O``w!AwC{12t~=t+ znf#6xy@1fqW~`E_HH{ZjQ`Vnpc*NZ57bxY&Km~Vqk+w?TRk-o7IhM9%*|%cCcb{HX zs1^5k5te#3C}_R{i#e3gc5rH$qomeF-X-qYc89bTYr4BX_5vHu|L3XP(l<4e&+*}!Qy7psR?Y?MPy0zwQ=MDD$1W;D45}lL(T&> zhJJ4X<12%X$n0X8^=oVSXa_X5E4YVN&AYgyU1+-!qjC!nYQLC+qM zN}T|DftKl2#5^9dM<28L%IQf$A(hDh`Leo)`?k72)u7o|qxe{MN4+&pG2IkPYyank zAD=aw#;Ed-xnPSolY4Y2g@!s^tZi1^)oKnK{Tq}sUDqP$Ki&@yWJ4sN(Ky7;9BG~t zm3>d%QB1{F2ePbb{dNydT!4V?+_lWI)(gMuI4=Y^Eu;3Wq=|IRfQ8?Frhlx+eY#ak z-O_^#j2dgkbG5EQ3nyOHmRZksTZD{mW^M1n#F2Bc?TX&SjX> z!=>HLirDf1|0!p3ZI9vyl{STyOMyu{JBK528yAiS0q&Yg##!0}F2K?X>9rZlG21&y zqBwU@7$(88`Pup@G`QPWwK}UFZ`YzGNdQyV#yvcezo^izwZJ;!cIy}>g>p4SHgzjg z$Hd)fE?kXF%_U#jj8-pG3LCuP%t}eZ#l_8|r|2khJ@+a`VHng7o-GQjDIH?Dnzz64 z5DPNOnK&12-fwa900u<|y(n!oYu$7?)7)+P^Fmi1tAxu=LPEmy2+j|Dpxjq%)|W?5 z8RVlLPbNp`q+88dB*nAG3+QFA#Re68gr2mBMpn&`-VqvR!_R3>Ml3e_8PWnZg*P-h~{$>ou>J46l-U^pCz*$-dS3Kj}nrmtevo;H7 z$I$Ir7w(PV^a)(YlBnpi%$KS$u`}{__$%tUiYD*zI%N#b9(X%tEY3PYom=dc7NJ@8 z503?pA3Uqe5f(GY^EZESrNC(xEbFs6A)Mpq4hkFS9vdDyv{r5F=oqq|umHAc!IK9) zjzms>ioV?{pjTH7Ef67RFSOq9@!L?L;5oDY^t~ z8IEIxu0AiDEL-wWltvKbqxf}@PoVEQ`MFN~IQsIr4PbvaJ7&5-P-&({@VxL+P&R#% z7|EEf1p4Y)9ONy5ENxmlc%~|UJ*yB%c_+?pih^5c_(ZTP#L!ycHqjLAeSk9*78iQz zHtCzU(IO~^C_a9V5k$Z7!Rio;;xA(WRCgN0OU%2gj5*A|+lQ~FFQc$Xa0eIDvSDIT zmXNff0RpNYS!0F16=}=7H5b&3L$Z+7Uj!RRc5Xe8ZO*;!1+nx(6DH>!5+=(%#QSo) zhNOMN92fC)4|wxyz3HU)`(SHyNcw`h+XZUEF-h@vJL6Uh??kj^mdh@A5jMT)!AzA! zxxWj)2ImWn)MIXR6_@MaD{E#lmat;M0y`5tc@{y^c}W{bg@Ut3$7Kh z5#%<9FGYvc)_8ad@%Fad7Ywvh&2h+p_E;VF`PuP`Js6;PbE4W66ozJk zixq5zWx~=xfd}x>s;c;a*NHg_Ik^qETU2;;d-j5w;!v|SIvDR-Sk8`Y`zaa!d(E!a zF5bF?IuKcC5F-|Jo|SjS{6KH(@bh~quU2T+@ubCAIZArsq{XM^Kf9t21eK})@^N-N z-rk{B4nWwB$?Q^Q;x%>Q1EUj)egRL$r`PyKm=EWm1%Il3imC3i>tE;(M708OB$A~p zMI+xrI#id>KzHdo&~{3luM{n}%$Ju~ba}K7FA}84yg&7M>_?#;I)BYG%htFOs?ld= z$k_^AbbZ#O%|I-zIs0pa6Db84wl#JA%E1`yd!Er?mcsBevXIo1Zk>4^Hkcyq89AJ~aHZ zURKQ_Sy70Rh(i8T0=pQw8Ajr-FYqT+cDyhEth^-T^T-x@ z#=;QemG7JgXL}MEwH<0_KVxqF%6sp%Ez&!_k9YwWjE+j;RLCH4`2uqV<>)_?{jd_< zz|d>j7vva@s2ZgVUd^myb9!WkHhq12tvM#B*ohW{L$U6Y93AVTNFqEXe=AS!CFrj7 z;iZSWj|^9V$A!k2WAg%l+1@n9Rz}XA({~hLJS1o7i6X!xiRSqMI~}9r@)m5WGCFB| zlC)3~YY$uTtuFyN*~4E{>jgcZ*A_|HNNr`4r1leu z6l`TUCZGLH|0_ppY2zCH&AYRjVUwRCJn8Ip^1epVo!C3!xa0v~RF0|(eVpZ&kRSeY z^u0X9sgZHgYdHO3*D#s_sTvX9u6TLcMfI0LfKL(whp z#9>X4ES{aQx^**&TsGxzAb4_(*6MGhJdw_Z@bWy0J{``YNI{AFX@X%V z+)Y(-arAoqN;*I;v8i!gw1XJWZ6(z9tl*uUf~cODCeO<^Pm8=F9Zul5*8neiu$` zyPxtd0{|BHpfK0CuMwASL)A@)O}-DGzPa)gBv^H|OemCzTwGusW=N&cL0CHlOGT8+ z6{d3wB)}6!`TJ43U=MLzGJ_>EUJv@|)!U$-zlq)pKSXB|uR3XGe^(A7jetic@00b@ ziP?gwlbBWjB>+YC0f%x|_@@_HT_lLk7L}=(jJ>$@FEYL0Yu3Y1?++ zP598@)4;3$4bv-<8OPl2MC=yW*_S+hBlTgoEuIZ%vF4i1=Q{Num52#%ibLD|=C0QD z@RAScSV5b@0$eb9a9z6{R%{3g!49x>_qO3cJ-9&2{qgm_`wZ+MhW3>%;On^E|=3mR5s zh-REXRnYhKLHcsN6`v`K8>r~=7+k`kjn>8>#zp`3UgZOxe66Xg`*!xLMMmr!Hy-cy z-v_(wZ|5XB9Oo0u*lno_FP@C2clo4&>tKO}ffwyQ72#udHqDTYUZ!NJ|GuKfj?uC8VpJH?9jrj<)Kiqj=b2ft=UB%~||2gV)FBh3ZZnYEOW(@U05|MCHl zeN03_H2H+L+Qz@Yps$rFtF0Y>OnM4xdhBeo}dl z(d}r91C^mz`peyO$io`W9dd)E)?apZ(`3C|iSQGKKZ8&Bn!P zq2RT2D}s)`6vv;wPvYLPXE`N7b14BBmiHFk2L}cr6@T)2U=43-egTn3G-p9Qh_Z)g z$6DI69b1U>X9x}N938iUe=cx~p1ba^8g}2Nzh|+CrGcRs5Bg^lUK$(s9QcR7Z0{pq z!o(or?GUhA6^vOB`bk3Feu}6k)uLF-jXozu>Y>@)7s^mnjbS!u>UhaKKaDZk@cvO2 zl)XA%Oey(&zOKFH?&s_2C%dKn$@#KR>Ut)|qjSR>7x4MviD21p$kZKY`a&!_JnlPc zFmn9;y?2P`C{<;A8HK*|6#{K@;^sZ z$6}a``7i!47y2(k{+i4FOHvkM|KMk#@DCjplK;Ok!m~ZD zrF#oVx+N{cKf&~WWz_#%6#p*}qdYxvSVFoDXdow+xc}Pj|7)}OSD}Jv8Dc{ut?>VC iqH0Bhn*G03B1p0oCu-cs|M`Ru*|4I*6u193^#1^TFq_Z- From fcdf540d4f1768921937295f89ee8816835bdcc1 Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Thu, 11 Jun 2020 08:05:56 -0400 Subject: [PATCH 3/9] Switch from static class to a real one --- ext/ExplodedWarMain.java | 330 +++++++++++++++++++++++++++------------ lib/warbler_jar.jar | Bin 25091 -> 26926 bytes 2 files changed, 226 insertions(+), 104 deletions(-) diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index dc7f4944..56d68404 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -24,12 +24,136 @@ import java.util.Map; import java.util.jar.JarEntry; +import java.io.IOException; + public class ExplodedWarMain { + static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties"; + static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar"; + static final String WEBSERVER_CONFIG = "/WEB-INF/webserver.xml"; + + // Shell arguments + private final String[] arguments; + + // The root of the exploded war archive + private File warRoot; + + // The root of the project within the war + private File webRoot; + + // An instance of Jruby scripting container used to run the application + private Object jruby; + private Object rubyInstanceConfig; + + //---------------------------------------------------------------------------------------------- + // Constructor getting args from the system + ExplodedWarMain(String[] arguments) throws IOException { + this.arguments = arguments; + + this.warRoot = new File(new File("./lib/war").getCanonicalPath()); + debug("War root: " + warRoot.toString()); + + this.webRoot = new File(warRoot, "/WEB-INF/"); + debug("Web root: " + webRoot.toString()); + } + + //---------------------------------------------------------------------------------------------- + // FIXME: Catch and log any exceptions to console + public static void main(String[] args) throws Exception { + ExplodedWarMain main = new ExplodedWarMain(args); + System.exit(main.start()); + } + + protected int start() throws Exception { + final List argsList = Arrays.asList(arguments); + final int sIndex = argsList.indexOf("-S"); + + if (sIndex == -1) { + debug("No command specified, starting a web server"); + launchWebServer(); + return 0; + } + + String[] arguments = argsList.subList(0, sIndex).toArray(new String[0]); + String execArg = argsList.get(sIndex + 1); + String[] executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); + return launchCommand(execArg, executableArgv); + } + + //---------------------------------------------------------------------------------------------- + private int launchCommand(String command, String[] commandArgs) throws Exception { + if (command.equals("rails")) { + // The rails executable doesn't play well with ScriptingContainer, so we've packaged the + // same script that would have been generated by `rake rails:update:bin` + command = "/../META-INF/rails.rb"; + } else { + System.out.println("Only -S rails is supported for now"); + return 1; + } + + debug("Initializing JRuby scripting environment..."); + initJRubyContainer(commandArgs); + + debug("Launching jruby with command '" + command + "' and arguments: " + Arrays.toString(commandArgs)); + return launchJRubyCommand(command, commandArgs); + } + + //---------------------------------------------------------------------------------------------- + protected int launchJRubyCommand(String command, String args[]) throws Exception { + // Find the path for the file to execute for the given command + final File commandFile = new File(webRoot, command); + debug("locating script: " + commandFile); + if (!commandFile.exists()) { + throw new IllegalStateException("Failed to locate the command file: '" + commandFile + "'"); + } + final String executablePath = commandFile.getAbsolutePath(); + + // Set the executable file and process arguments on jruby + invokeMethod(jruby, "setScriptFilename", executablePath); + invokeMethod(rubyInstanceConfig, "processArguments", (Object) args); + + // Generate a ruby script that prepares the environment for executing ruby scripts + final CharSequence execScriptEnvPre = executableScriptEnvPrefix(); + + // Load the command script and prepend it with the initialization code + debug("Loading command script: " + executablePath); + Object executableInput = new SequenceInputStream( + new ByteArrayInputStream(execScriptEnvPre.toString().getBytes()), + (InputStream) invokeMethod(rubyInstanceConfig, "getScriptSource") + ); + + // Finally, ask jruby to execute the script + Object runtime = invokeMethod(jruby, "getRuntime"); + + debug("invoking " + executablePath + " with: " + Arrays.toString(args)); + Object outcome = invokeMethod(runtime, "runFromMain", + new Class[] { InputStream.class, String.class }, + executableInput, + executablePath + ); + + /// Cast the result of the script into an exit code + return (outcome instanceof Number) ? ((Number) outcome).intValue() : 0; + } + + //---------------------------------------------------------------------------------------------- static void debug(String message) { System.out.println(message); } //---------------------------------------------------------------------------------------------- + static String getSystemProperty(final String name) { + return getSystemProperty(name, null); + } + + static String getSystemProperty(final String name, final String defaultValue) { + try { + return System.getProperty(name, defaultValue); + } + catch (SecurityException e) { + return defaultValue; + } + } + static boolean setSystemProperty(final String name, final String value) { try { System.setProperty(name, value); @@ -40,13 +164,20 @@ static boolean setSystemProperty(final String name, final String value) { } } - //---------------------------------------------------------------------------------------------- - static protected void initJRubyScriptingEnv(Object scriptingContainer) throws Exception { - // for some reason, the container needs to run a scriptlet in order for it - // to be able to find the gem executables later - invokeMethod(scriptingContainer, "runScriptlet", "SCRIPTING_CONTAINER_INITIALIZED=true"); + static String getENV(final String name) { + return getENV(name, null); + } - invokeMethod(scriptingContainer, "setHomeDirectory", "uri:classloader:/META-INF/jruby.home"); + static String getENV(final String name, final String defaultValue) { + try { + if ( System.getenv().containsKey(name) ) { + return System.getenv().get(name); + } + return defaultValue; + } + catch (SecurityException e) { + return defaultValue; + } } //---------------------------------------------------------------------------------------------- @@ -73,91 +204,107 @@ protected static Object invokeMethod(final Object self, final String name, final } //---------------------------------------------------------------------------------------------- - protected static CharSequence executableScriptEnvPrefix(String extractRoot) { - final String gemsDir = new File(extractRoot, "gems").getAbsolutePath(); - final String gemfile = new File(extractRoot, "Gemfile").getAbsolutePath(); - System.out.println("setting GEM_HOME to " + gemsDir); - System.out.println("... and BUNDLE_GEMFILE to " + gemfile); - - // ideally this would look up the config.override_gem_home setting - return "ENV['GEM_HOME'] = ENV['GEM_PATH'] = '"+ gemsDir +"' \n" + - "ENV['BUNDLE_GEMFILE'] ||= '"+ gemfile +"' \n" + - "require '" + extractRoot + "/../META-INF/init.rb'"; + protected CharSequence executableScriptEnvPrefix() { + final String gemsDir = new File(webRoot, "gems").getAbsolutePath(); + final String gemfile = new File(webRoot, "Gemfile").getAbsolutePath(); + System.out.println("setting GEM_HOME to " + gemsDir); + System.out.println("... and BUNDLE_GEMFILE to " + gemfile); + + // ideally this would look up the config.override_gem_home setting + return ( + "ENV['GEM_HOME'] = ENV['GEM_PATH'] = '"+ gemsDir +"' \n" + + "ENV['BUNDLE_GEMFILE'] ||= '"+ gemfile +"' \n" + + "require '" + webRoot + "/../META-INF/init.rb'" + ); } //---------------------------------------------------------------------------------------------- - protected static String locateExecutable(Object scriptingContainer, String root, final CharSequence envPreScript, String executable) throws Exception { - final File exec = new File(root, executable); - debug("locating script " + root + " " + executable); - return exec.exists() ? exec.getAbsolutePath() : null; - } + protected void initJRubyContainer(String[] commandArgs) throws Exception { + final URL[] jars = loadJarUrls(webRoot); + this.jruby = newScriptingContainer(jars); - //---------------------------------------------------------------------------------------------- - protected static Object newScriptingContainer(final URL[] jars, String[] args) throws Exception { - setSystemProperty("org.jruby.embed.class.path", ""); + invokeMethod(jruby, "setArgv", (Object) commandArgs); + debug("setArgv: " + Arrays.toString(commandArgs)); - URLClassLoader classLoader = new URLClassLoader(jars); + String rootPath = webRoot.getAbsolutePath(); + invokeMethod(jruby, "setCurrentDirectory", rootPath); + debug("setCurrentDirectory: " + rootPath); - Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, classLoader); - Object scriptingContainer = scriptingContainerClass.newInstance(); + invokeMethod(jruby, "setHomeDirectory", "uri:classloader:/META-INF/jruby.home"); - System.out.println("scripting container class loader urls: " + Arrays.toString(jars)); - invokeMethod(scriptingContainer, "setArgv", (Object) args); - invokeMethod(scriptingContainer, "setClassLoader", new Class[] { ClassLoader.class }, classLoader); + // for some reason, the container needs to run a scriptlet in order for it + // to be able to find the gem executables later + invokeMethod(jruby, "runScriptlet", "SCRIPTING_CONTAINER_INITIALIZED=true"); - return scriptingContainer; + // Allow ruby to modify the environment + final Object provider = invokeMethod(jruby, "getProvider"); + this.rubyInstanceConfig = invokeMethod(provider, "getRubyInstanceConfig"); + invokeMethod(rubyInstanceConfig, "setUpdateNativeENVEnabled", new Class[] { Boolean.TYPE }, false); } //---------------------------------------------------------------------------------------------- - protected static int launchJRuby(final URL[] jars, File root, String executable, String args[]) throws Exception { - final Object scriptingContainer = newScriptingContainer(jars, args); - - invokeMethod(scriptingContainer, "setArgv", (Object) args); - debug("setArgv: " + args); - - invokeMethod(scriptingContainer, "setCurrentDirectory", root.getAbsolutePath()); - debug("setCurrentDirectory: " + root.getAbsolutePath()); - - initJRubyScriptingEnv(scriptingContainer); - - final Object provider = invokeMethod(scriptingContainer, "getProvider"); - final Object rubyInstanceConfig = invokeMethod(provider, "getRubyInstanceConfig"); - - invokeMethod(rubyInstanceConfig, "setUpdateNativeENVEnabled", new Class[] { Boolean.TYPE }, false); - - final CharSequence execScriptEnvPre = executableScriptEnvPrefix(root.getAbsolutePath()); - - final String executablePath = locateExecutable(scriptingContainer, root.getCanonicalPath(), execScriptEnvPre, executable); - if ( executablePath == null ) { - throw new IllegalStateException("failed to locate gem executable: '" + executable + "'"); + private Properties getWebserverProperties(File root) throws Exception { + Properties props = new Properties(); + try { + InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES); + if ( is != null ) props.load(is); + } catch (Exception e) { } + + String port = getSystemProperty("warbler.port", getENV("PORT")); + port = port == null ? "8080" : port; + String host = getSystemProperty("warbler.host", "0.0.0.0"); + String webserverConfig = getSystemProperty("warbler.webserver_config", getENV("WARBLER_WEBSERVER_CONFIG")); + String embeddedWebserverConfig = new URI("jar", new File(root, WEBSERVER_CONFIG).getCanonicalPath(), null).toURL().toString(); + webserverConfig = webserverConfig == null ? embeddedWebserverConfig : webserverConfig; + for ( Map.Entry entry : props.entrySet() ) { + String val = (String) entry.getValue(); + val = val.replace("{{warfile}}", root.getAbsolutePath()). + replace("{{port}}", port). + replace("{{host}}", host). + replace("{{config}}", webserverConfig). + replace("{{webroot}}", root.getAbsolutePath()); + entry.setValue(val); } - invokeMethod(scriptingContainer, "setScriptFilename", executablePath); - debug("setScriptFilename: " + executablePath); - - invokeMethod(rubyInstanceConfig, "processArguments", (Object) args); + if (props.getProperty("props") != null) { + String[] propsToSet = props.getProperty("props").split(","); + for ( String key : propsToSet ) { + setSystemProperty(key, props.getProperty(key)); + } + } - Object runtime = invokeMethod(scriptingContainer, "getRuntime"); + return props; + } - debug("loading resource: " + executablePath); - Object executableInput = new SequenceInputStream( - new ByteArrayInputStream(execScriptEnvPre.toString().getBytes()), - (InputStream) invokeMethod(rubyInstanceConfig, "getScriptSource") - ); + //---------------------------------------------------------------------------------------------- + public void launchWebServer() throws Exception { + // Find the Jetty jar file + File jarFile = new File(webRoot, "webserver.jar"); + debug("webserver.jar is at" + jarFile.getPath()); + + // Load Jetty + URLClassLoader loader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}); + Thread.currentThread().setContextClassLoader(loader); + + // Get the name of the main jetty class + Properties props = getWebserverProperties(webRoot); + String mainClass = props.getProperty("mainclass"); + if (mainClass == null) { + throw new IllegalArgumentException("Unknown webserver main class (" + WEBSERVER_PROPERTIES + " is missing 'mainclass' property)"); + } - debug("invoking " + executablePath + " with: " + Arrays.toString(args)); + // Get the jetty class object based on its name + Class klass = Class.forName(mainClass, true, loader); + Method main = klass.getDeclaredMethod("main", new Class[] { String[].class }); - Object outcome = invokeMethod( - runtime, - "runFromMain", - new Class[] { InputStream.class, String.class }, - executableInput, - executablePath - ); - return ( outcome instanceof Number ) ? ( (Number) outcome ).intValue() : 0; + // Start jetty + String[] newArgs = {}; // launchWebServerArguments(props); + debug("invoking webserver with: " + Arrays.deepToString(newArgs)); + main.invoke(null, new Object[] { newArgs }); } //---------------------------------------------------------------------------------------------- + // Finds all jar files in the lib directory of the project and returns them as an array public static URL[] loadJarUrls(File root) throws Exception { List jars = new ArrayList(); @@ -171,41 +318,16 @@ public static URL[] loadJarUrls(File root) throws Exception { } //---------------------------------------------------------------------------------------------- - public static void launchWebServer() { - debug("Jetty will start here"); - } - - //---------------------------------------------------------------------------------------------- - public static void main(String args[]) throws Exception { - String warRoot = "./lib/war"; - File root = new File(new File(warRoot + "/WEB-INF/").getCanonicalPath()); - - debug("Root: " + root.toString()); - - final List argsList = Arrays.asList(args); - final int sIndex = argsList.indexOf("-S"); - - if (sIndex == -1) { - debug("No command specified, starting a web server"); - launchWebServer(); - return; - } + protected static Object newScriptingContainer(final URL[] jars) throws Exception { + setSystemProperty("org.jruby.embed.class.path", ""); - String[] arguments = argsList.subList(0, sIndex).toArray(new String[0]); - String execArg = argsList.get(sIndex + 1); - String[] executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); + URLClassLoader classLoader = new URLClassLoader(jars); + Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, classLoader); + Object jruby = scriptingContainerClass.newInstance(); - if (execArg.equals("rails")) { - // The rails executable doesn't play well with ScriptingContainer, so we've packaged the - // same script that would have been generated by `rake rails:update:bin` - execArg = "/../META-INF/rails.rb"; - } else { - System.out.println("Only -S rails is supported for now"); - System.exit(1); - } + debug("scripting container class loader urls: " + Arrays.toString(jars)); + invokeMethod(jruby, "setClassLoader", new Class[] { ClassLoader.class }, classLoader); - URL[] jars = loadJarUrls(root); - debug("Launching jruby with script '" + execArg + "' and arguments: " + executableArgv); - launchJRuby(jars, root, execArg, executableArgv); + return jruby; } } diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index 8c8755ef6f654506f5a07fc29ca41c16541cee1c..fc6650ccbcf9bbaa82812f18f4b50bcd46648b61 100644 GIT binary patch delta 6583 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 PK1m^l(PMuw|0DVjw(A#7 From ac613b2358c0dd10dea94fceb6419dbed070b042 Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Thu, 11 Jun 2020 11:28:53 -0400 Subject: [PATCH 4/9] It works --- ext/ExplodedWarMain.java | 79 ++++++++++++++++++++++++++------------- lib/warbler_jar.jar | Bin 26926 -> 27238 bytes 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index 56d68404..7ec8ec60 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -7,6 +7,7 @@ import java.lang.reflect.Method; import java.io.InputStream; +import java.io.FileInputStream; import java.io.ByteArrayInputStream; import java.io.SequenceInputStream; import java.io.File; @@ -27,10 +28,6 @@ import java.io.IOException; public class ExplodedWarMain { - static final String WEBSERVER_PROPERTIES = "/WEB-INF/webserver.properties"; - static final String WEBSERVER_JAR = "/WEB-INF/webserver.jar"; - static final String WEBSERVER_CONFIG = "/WEB-INF/webserver.xml"; - // Shell arguments private final String[] arguments; @@ -50,10 +47,10 @@ public class ExplodedWarMain { this.arguments = arguments; this.warRoot = new File(new File("./lib/war").getCanonicalPath()); - debug("War root: " + warRoot.toString()); + debug("Exploded WAR directory: " + warRoot.toString()); this.webRoot = new File(warRoot, "/WEB-INF/"); - debug("Web root: " + webRoot.toString()); + debug("Web Application root: " + webRoot.toString()); } //---------------------------------------------------------------------------------------------- @@ -70,6 +67,7 @@ protected int start() throws Exception { if (sIndex == -1) { debug("No command specified, starting a web server"); launchWebServer(); + debug("Started web server"); return 0; } @@ -84,7 +82,7 @@ private int launchCommand(String command, String[] commandArgs) throws Exception if (command.equals("rails")) { // The rails executable doesn't play well with ScriptingContainer, so we've packaged the // same script that would have been generated by `rake rails:update:bin` - command = "/../META-INF/rails.rb"; + command = "bin/rails"; } else { System.out.println("Only -S rails is supported for now"); return 1; @@ -243,29 +241,41 @@ protected void initJRubyContainer(String[] commandArgs) throws Exception { } //---------------------------------------------------------------------------------------------- - private Properties getWebserverProperties(File root) throws Exception { + private Properties getWebserverProperties() throws Exception { + File propsFilePath = new File(webRoot, "/webserver.properties"); + debug("Loading webserver properties file: " + propsFilePath); + Properties props = new Properties(); try { - InputStream is = getClass().getResourceAsStream(WEBSERVER_PROPERTIES); - if ( is != null ) props.load(is); - } catch (Exception e) { } + InputStream is = new FileInputStream(propsFilePath); + props.load(is); + } catch (Exception e) { + debug("Error while loading webserver properties file: " + e); + } - String port = getSystemProperty("warbler.port", getENV("PORT")); - port = port == null ? "8080" : port; + String port = getSystemProperty("warbler.port", getENV("PORT", "8080")); String host = getSystemProperty("warbler.host", "0.0.0.0"); + String webserverConfig = getSystemProperty("warbler.webserver_config", getENV("WARBLER_WEBSERVER_CONFIG")); - String embeddedWebserverConfig = new URI("jar", new File(root, WEBSERVER_CONFIG).getCanonicalPath(), null).toURL().toString(); - webserverConfig = webserverConfig == null ? embeddedWebserverConfig : webserverConfig; - for ( Map.Entry entry : props.entrySet() ) { + if (webserverConfig == null) { + String defaultWebserverConfigPath = new File(webRoot, "/webserver.xml").getCanonicalPath(); + URI defaultWebserverConfigURI = new URI("jar", defaultWebserverConfigPath, null); + webserverConfig = defaultWebserverConfigURI.toURL().toString(); + } + debug("Jetty config to be used: " + webserverConfig); + + // Substitute template values in webserver props + for (Map.Entry entry : props.entrySet()) { String val = (String) entry.getValue(); - val = val.replace("{{warfile}}", root.getAbsolutePath()). + val = val.replace("{{warfile}}", warRoot.getAbsolutePath()). replace("{{port}}", port). replace("{{host}}", host). replace("{{config}}", webserverConfig). - replace("{{webroot}}", root.getAbsolutePath()); + replace("{{webroot}}", webRoot.getAbsolutePath()); entry.setValue(val); } + // Push all properties from the file into the global system context if (props.getProperty("props") != null) { String[] propsToSet = props.getProperty("props").split(","); for ( String key : propsToSet ) { @@ -280,29 +290,48 @@ private Properties getWebserverProperties(File root) throws Exception { public void launchWebServer() throws Exception { // Find the Jetty jar file File jarFile = new File(webRoot, "webserver.jar"); - debug("webserver.jar is at" + jarFile.getPath()); + debug("Jetty webserver.jar is at" + jarFile.getPath()); - // Load Jetty - URLClassLoader loader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}); - Thread.currentThread().setContextClassLoader(loader); + // Load web server properties file + Properties props = getWebserverProperties(); + debug("Web server props: " + props.toString()); // Get the name of the main jetty class - Properties props = getWebserverProperties(webRoot); String mainClass = props.getProperty("mainclass"); if (mainClass == null) { - throw new IllegalArgumentException("Unknown webserver main class (" + WEBSERVER_PROPERTIES + " is missing 'mainclass' property)"); + throw new IllegalArgumentException("Unknown webserver main class (webserver.properties file is missing 'mainclass' property)"); } + // Load Jetty jar file + URLClassLoader loader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}); + Thread.currentThread().setContextClassLoader(loader); + // Get the jetty class object based on its name Class klass = Class.forName(mainClass, true, loader); Method main = klass.getDeclaredMethod("main", new Class[] { String[].class }); // Start jetty - String[] newArgs = {}; // launchWebServerArguments(props); + String[] newArgs = launchWebServerArguments(props); debug("invoking webserver with: " + Arrays.deepToString(newArgs)); main.invoke(null, new Object[] { newArgs }); } + //---------------------------------------------------------------------------------------------- + private String[] launchWebServerArguments(Properties props) { + String[] newArgs = arguments; + + if (props.getProperty("args") != null) { + String[] insertArgs = props.getProperty("args").split(","); + newArgs = new String[arguments.length + insertArgs.length]; + for (int i = 0; i < insertArgs.length; i++) { + newArgs[i] = props.getProperty(insertArgs[i], ""); + } + System.arraycopy(arguments, 0, newArgs, insertArgs.length, arguments.length); + } + + return newArgs; + } + //---------------------------------------------------------------------------------------------- // Finds all jar files in the lib directory of the project and returns them as an array public static URL[] loadJarUrls(File root) throws Exception { diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index fc6650ccbcf9bbaa82812f18f4b50bcd46648b61..d4ce847e51919b6f3272a80b282ad860cae21f4e 100644 GIT binary patch delta 6949 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 AMgRZ+ delta 6534 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 From 6c310e952e808701063874fa9bbaf1a47409b6f2 Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Thu, 11 Jun 2020 12:47:24 -0400 Subject: [PATCH 5/9] Remove unused code --- ext/ExplodedWarMain.java | 6 ------ lib/warbler_jar.jar | Bin 27238 -> 27237 bytes 2 files changed, 6 deletions(-) diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index 7ec8ec60..a86f9001 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -80,8 +80,6 @@ protected int start() throws Exception { //---------------------------------------------------------------------------------------------- private int launchCommand(String command, String[] commandArgs) throws Exception { if (command.equals("rails")) { - // The rails executable doesn't play well with ScriptingContainer, so we've packaged the - // same script that would have been generated by `rake rails:update:bin` command = "bin/rails"; } else { System.out.println("Only -S rails is supported for now"); @@ -139,10 +137,6 @@ static void debug(String message) { } //---------------------------------------------------------------------------------------------- - static String getSystemProperty(final String name) { - return getSystemProperty(name, null); - } - static String getSystemProperty(final String name, final String defaultValue) { try { return System.getProperty(name, defaultValue); diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index d4ce847e51919b6f3272a80b282ad860cae21f4e..30a20ba34d6f070f0750880a23fd201158bf57c5 100644 GIT binary patch delta 6841 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�r`q23n{Hk1 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 From 2015d6ad1500262e00d6475cdcf08e596834488d Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Thu, 11 Jun 2020 13:23:34 -0400 Subject: [PATCH 6/9] Cleanup + switch to java8 --- Mavenfile | 2 +- ext/ExplodedWarMain.java | 61 +++++++++++++++------------------------ lib/warbler_jar.jar | Bin 27237 -> 27193 bytes 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/Mavenfile b/Mavenfile index 9fc4ae82..63f6e1ee 100644 --- a/Mavenfile +++ b/Mavenfile @@ -15,7 +15,7 @@ scope :provided do jar 'org.eclipse.jetty:jetty-webapp', '${jetty.version}' end -plugin :compiler, '3.1', :source => '1.6', :target => '1.6' +plugin :compiler, '3.1', :source => '8', :target => '8' plugin :invoker, '1.8' do execute_goals( :install, :run, diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index a86f9001..d9bc12ba 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -5,27 +5,27 @@ * See the file LICENSE.txt for details. */ -import java.lang.reflect.Method; import java.io.InputStream; import java.io.FileInputStream; import java.io.ByteArrayInputStream; import java.io.SequenceInputStream; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; + import java.net.URI; import java.net.URLClassLoader; import java.net.URL; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.Map; -import java.util.jar.JarEntry; -import java.io.IOException; public class ExplodedWarMain { // Shell arguments @@ -96,12 +96,7 @@ private int launchCommand(String command, String[] commandArgs) throws Exception //---------------------------------------------------------------------------------------------- protected int launchJRubyCommand(String command, String args[]) throws Exception { // Find the path for the file to execute for the given command - final File commandFile = new File(webRoot, command); - debug("locating script: " + commandFile); - if (!commandFile.exists()) { - throw new IllegalStateException("Failed to locate the command file: '" + commandFile + "'"); - } - final String executablePath = commandFile.getAbsolutePath(); + final String executablePath = findExecutableFile(command); // Set the executable file and process arguments on jruby invokeMethod(jruby, "setScriptFilename", executablePath); @@ -131,6 +126,13 @@ protected int launchJRubyCommand(String command, String args[]) throws Exception return (outcome instanceof Number) ? ((Number) outcome).intValue() : 0; } + //---------------------------------------------------------------------------------------------- + private String findExecutableFile(String command) { + final File commandFile = new File(webRoot, command); + if (commandFile.exists()) return commandFile.getAbsolutePath(); + throw new IllegalStateException("Failed to locate the command file: '" + commandFile + "'"); + } + //---------------------------------------------------------------------------------------------- static void debug(String message) { System.out.println(message); @@ -162,7 +164,7 @@ static String getENV(final String name) { static String getENV(final String name, final String defaultValue) { try { - if ( System.getenv().containsKey(name) ) { + if (System.getenv().containsKey(name)) { return System.getenv().get(name); } return defaultValue; @@ -212,16 +214,10 @@ protected CharSequence executableScriptEnvPrefix() { //---------------------------------------------------------------------------------------------- protected void initJRubyContainer(String[] commandArgs) throws Exception { - final URL[] jars = loadJarUrls(webRoot); - this.jruby = newScriptingContainer(jars); + this.jruby = newScriptingContainer(loadJarUrls(webRoot)); invokeMethod(jruby, "setArgv", (Object) commandArgs); - debug("setArgv: " + Arrays.toString(commandArgs)); - - String rootPath = webRoot.getAbsolutePath(); - invokeMethod(jruby, "setCurrentDirectory", rootPath); - debug("setCurrentDirectory: " + rootPath); - + invokeMethod(jruby, "setCurrentDirectory", webRoot.getAbsolutePath()); invokeMethod(jruby, "setHomeDirectory", "uri:classloader:/META-INF/jruby.home"); // for some reason, the container needs to run a scriptlet in order for it @@ -240,9 +236,8 @@ private Properties getWebserverProperties() throws Exception { debug("Loading webserver properties file: " + propsFilePath); Properties props = new Properties(); - try { - InputStream is = new FileInputStream(propsFilePath); - props.load(is); + try(InputStream propsStream = new FileInputStream(propsFilePath)) { + props.load(propsStream); } catch (Exception e) { debug("Error while loading webserver properties file: " + e); } @@ -282,13 +277,8 @@ private Properties getWebserverProperties() throws Exception { //---------------------------------------------------------------------------------------------- public void launchWebServer() throws Exception { - // Find the Jetty jar file - File jarFile = new File(webRoot, "webserver.jar"); - debug("Jetty webserver.jar is at" + jarFile.getPath()); - // Load web server properties file Properties props = getWebserverProperties(); - debug("Web server props: " + props.toString()); // Get the name of the main jetty class String mainClass = props.getProperty("mainclass"); @@ -297,6 +287,7 @@ public void launchWebServer() throws Exception { } // Load Jetty jar file + File jarFile = new File(webRoot, "webserver.jar"); URLClassLoader loader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}); Thread.currentThread().setContextClassLoader(loader); @@ -305,9 +296,7 @@ public void launchWebServer() throws Exception { Method main = klass.getDeclaredMethod("main", new Class[] { String[].class }); // Start jetty - String[] newArgs = launchWebServerArguments(props); - debug("invoking webserver with: " + Arrays.deepToString(newArgs)); - main.invoke(null, new Object[] { newArgs }); + main.invoke(null, new Object[] { launchWebServerArguments(props) }); } //---------------------------------------------------------------------------------------------- @@ -330,12 +319,12 @@ private String[] launchWebServerArguments(Properties props) { // Finds all jar files in the lib directory of the project and returns them as an array public static URL[] loadJarUrls(File root) throws Exception { List jars = new ArrayList(); + File libDir = new File(root, "lib"); - File[] files = new File(root, "lib").listFiles(); - - for (File f : files) { - if (f.isFile() && f.getName().endsWith(".jar")) - jars.add(f.toURI().toURL()); + for (File f : libDir.listFiles()) { + if (f.isFile() && f.getName().endsWith(".jar")) { + jars.add(f.toURI().toURL()); + } } return jars.toArray(new URL[jars.size()]); } @@ -347,8 +336,6 @@ protected static Object newScriptingContainer(final URL[] jars) throws Exception URLClassLoader classLoader = new URLClassLoader(jars); Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, classLoader); Object jruby = scriptingContainerClass.newInstance(); - - debug("scripting container class loader urls: " + Arrays.toString(jars)); invokeMethod(jruby, "setClassLoader", new Class[] { ClassLoader.class }, classLoader); return jruby; diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index 30a20ba34d6f070f0750880a23fd201158bf57c5..841e6425f7a058d67770cbf8d95fdedbc5f1212c 100644 GIT binary patch delta 25951 zcmV)RK(oK))B(BF0Sr(}0|W{H00000;cAf#B?91Tku#qO%xcR}@O(+2`;ps&f9N9h zNPxb;+XH+R?=bo0Q+Oxus-Q*=%VSU;Ljjt~!v;Ghj|8ZKM`g}#gCp|ZW6(F`y;mMl zlgDIo%;dPq<0iM7e02aM5+)~2`gVX8aY{(0rL|8U`wc!IJqP7uR36vJQnl0jlTM%HyU04fE?ve!a?K0;MgWnvW)qFTW34V*oZw=5GzfF4XH28?gcbR;*>~fDh z-fr?cOupCT`%J#yOn=uDevluU!bkbt@_3KI@0~(@{D{f#e-pjD-{cRN ze9YuWO@2%^{-BJ0$YfI%f7s-V%sMW+oG|#L!5<0G5T6S0NBMDioR*O%On%bjj|qz( zH+i1HpOEHLGW1E4pB6(tWALW}{AvD-X!f%vJ!|skWQWfO_zV2S0Dp48=~ZIicfq?e|o-c@^^&vcTN7DyuWYq4}|Iu<>N;t|JdZ8nEY%7|CE0g zz~krA{|kBiQXaoD_}3=?#^m1y=yo18`FAG&-sC@+{6~ZTWbmJ-@LxoAQ~9p}x|{!I z^4|^qM}Y3)f13O+lb;iD{?Fv+4gPn49^w~FJ_E%m0&&HrQl|2mf68yFGEE zuNKH-p=@@JtXU-DY?oF@^nH!2JJ(c;p$v7Np_VZDJ6qeknCy-{;eFxeXgD_7+?z^7 zVxyNb&FXJk+uPQ&f3>Y=XLrx$?zW!3_O@Q8sq5mgWGWm>Z4F1$4!-l#HnsLJRp!6f zZSLC8zLBXSoES}yIk8ldY3BA)dj*^W&QLlP9*lzGwERbFVssyqvELa?#N#Opxr-z5 z<_(dkgN5ZQBe6(oHPh^x5`=5FLd13PVGy0(5s5in>9Ij4f6?b|V|T=d!qKhaL`1&5 zPDA#_u2`4a9Ra@;9sS`%XE+kWW`4+lE>m6|ktF!3boWfBBGG2)5ss4Wv0>)`6Ssq_ z;yn(IXZKk$Vd2WNnO_ZJQ+re4p}n2qalH)KVW{(gV%XR@kV=GyQvJ?g(n;)d66mU_ zb&15BRP&aee-1474W>t!)b_QIWAI?gN%lD5VYK&z6WGKFk1bpr}9e>1HeTfmqC9r)CI6<+kqixJQabvKoO%(p4aX~eB4Q-A`S-T zX1Ug?$d7;pCHnX63rCsC;5>Pje`HdKR27hbvX4S!I9-X&Yc{Cm#mNmhm5iM(n9>S!GF?gizf<$}W_lyD; z(nBJQf6U97O%ElUk*G72YVLGWyW_)R>6o*>RXg^qi4<1Wt%hAs!b%e)YRw09eNAai z)|L!(@!dcq2F0b^J!ir(+FW1OR_hL@b~7~;5`~_cH-!_fQEN+4ojciVXdo6IgA;&gn?~ErLAqSue_PBg(jU*$I4Pvo)Dx5`>0&4j+pt!ok z)|1Izk|oR0D(m$a3+7c&sL_!KFn(T5?c{1TMxC+b`bffUjc72PJyBKJU5dE&Sot5g zM(qh0lw7DiuQ%&R;1&I)j3EeABkow9e@!61u_RoF!R4YNnD2_GHpJ7h;T)b{idqEI z;Ut;{D48pVqFy2n^v2VPA;--fmX|!6gq}s;rSBQ4)>3t<9`N4Si)?182GwZMH|a|j zeT%+f(bw@%O{$q`ah~b+Xw(@EN3*b#T*S=-c!ie@m@W&6Zj%TCoaEW2wuaIJHK#imXWUb0&(pHXVrq zCos(Y@C2`t3JpgPFsXRrU?`FdS!$hHZ>cs=Q5)p3QP{8w&1SUn#mGO-W z3VA5*42PghOKnl`!C9r!kfr+7l}rmuusmKcX+UkW)OK|h44+qEftOjHNt(RkpnG#q zpQUy{UiEUd6CEp-u2@$`S7ve^H}`+MSi4xE8WhL}9NfhYo=eL88NlEwxAOMdThjBr+X7 ztee8OGy{hYx%|n8ta9B(Rz<}@##GEwaRs;F21|{rt1XpK$*lXGU9uE=Q-|0%WvH~J z_No1rI-m|(^a7pn>Y5?9p1CR=+Z&7TkA-r=hh#LQheI_lYEkj(e=IOm=V(@kycq|9 zLD#55NN*Dg9!p)T4qLp4L%{t=Y+rn@P{=c|Ka$$r0*8Brx~>RPTu?RCD=l@sdX+`b z(l?k$RJ7AjueQ_;>PADoMuNy?+ETAoH(Ba++-<4Xt2YP;-V6gYkEaKtk)dV@$XhI~ zVet7zbrZ0uIT{&6fA_8GO(2qVqE#AnNTfCav zkSfjsX&hN3!R2CS@d)tKjZ`=Jg+>MTa&X-eLdnedn*kQwf5au2;MQ%Gu-K53OcoTJ z0WE=7pV(3@i;WUaQs7wOJ#vgHfGC;Sx}v%`_RU=&YhQU?ralnqdaM9YSKw(?Ut_f z9c?=?x}m+p8$2H--d>$uP`x9xDwON#Ztc5V_rNUYREGk3pqL1Tuf0}JXu^a9G!5qq zRi_h?79DKvF{UM-Mx{PL7OfWNz8C2~6kuL3=!`~Ue}Paaw_d7Qk*+$FjzwYk&@d{k zm@|A?4TP-?VQO|s!6G*qC#pl5QgSHmgamim5{Y;MT~0LV=mp5NSt)y3+dF!9qN(M` z_N}|Z>&i{PEVR}o-UJn=$7@=^PdFV-HOOdfsAZC2&8Z{lene>R+|;_Yb$fL-3k(*n z!EWb5e~%+!aH%B_7jRX7hyG5E>u<>4($b4|WF#`AtKcSRW;k>xbZzq5P_ilSImspg zy!5bhS&ekoh7RY*T&7=5gOS)y@f>fwB@~N9#fVyUy}B@II}k~QR;><+=A0&gMJk;P zKq96kz3Y0~yZhR^HcF=IYi;jB&T8*!?`v=Ee`w#MQ47QQCU$hRj)P1TIkTyvF-6A+N4!%(HH4U0Etc6x@}tVl~Ylz)3-Yj z-|yXv<)^iyjt;|gC`C#iMY33?XKO44e=L=Uz1y+#i|*u#Pl1J3W=2GA%r=iqa#E4v zGm>l@8&4h7=Z$R><`rD_8OijZyZ5Y`_V!X+rQ(`Rrkaw>mFUBsqXN2BHSM*fM*Ydi zHBdx3RDuwmLK| z4DCkh*5}Psm(HKFYDyk)&#NgWS6Z9p;qh@D@r|X_eO8xu)NoI}DfcG9OvT+n)G))& zU>ffVCx6d#!GA><6fgO&lvG-bvQ!*3CkhADez9y7FsCN3(c+s=%T?^=m>^*O>MpA) zeW#qz_o!tx+t-SBmhDeO#1aO+f8lkqv8Rs<&ID}pi2VopIo~O~*3vGZe{Dm88;Xy^4eCmeZZFZLL2GvDt8f6PE?1KM z5%KVnsdt@{&&l65Y6YjnI*cR`f>S+!WL6?X(B-8 zR$rAhXH{0lFaq8EwWy}UtDd#YvuoCs@YhS}Txz5*5Rpl9rRGL!E`1qqrmvu_s1@H| zE%2-oj#>2D>szj)8U-*@SISn+)#f4-IcRED0<)YTs+u0KJl zv%&VAB)_873)Ov8RmUHuGI^BC!#GM0)Sq7H-*qodtH*0uhRh>0^%PYM*n#6T<%zlm z-@=n*`N;P;O+87|6g^4Pv91A=Pg13PPHpkmH7qRK)o_w#FqN2G9`xIGhGrh2fIX|l zf0Sy`QKdT;f7N}6%1^(8=E&Q(%$}`#E9&ey8Jb%c^n=$&A&sAYfahAO#B%`hZKD8f zrMlk&+`To?@JnWZ*xTtIiJE^G?wG57Pn&z92&j``!0B{dK2k z(SUq-@6d5NH$#h$(|I!a6fGGzPUqVfWT@I*QG-^7YBPkf`T@J4&Th(3Gasj=8G1>E zmUY+{f7%yetImcDz4R0q{{{`#OlLn{WBm#KScdSlSg(txe>~qpuL7ML=|Or8y@y^4N;lGDXlKwq zi5Xv|*J*36rgD4*>5ud$So1dc$e&@aG94AJU85AIztCS{yA-_QZ-^S^ ziXrl!0g*Co#eW*~FN2;l=>LeGqq&<5dfuXcYcE7~h_x@!8P}ldI_xtAh7F#g)lkc2 ze;suhT4T3nXl-Z1(`42|DeI1szte8BH=Ll2C+PCdhG)pM+tJz3X>YQxKv$RDVRyQt zE&i+#y9$lCxuq=V$GTwIQ9=uL%TV`8dKptod9eH>^)MZwK56wbytA*x2pT783+v!C zgQmSz94SNn_LU9t9B7p1HZgv`z1{Vrf2+{OTq9_nq#cU-kDhsVz5VhG?R=V6x($0* zhQhL;kUzcL^ewNbs;Dv_pansrs$yA7AQ-3*1~Bmi4ffwq!AH+LTYn5HGhym;pg7kJ zMqnzUThMzepzKW;yA45f2V&^W^imjo6~eZi-iC0#6J|St8F$e=bT>VW=P`uye{p&T z#JZP0MfU+B?*}-(6LjB2zo7@Yj2_|{c+bIXagA{p$EFH|U1duTZ`Lf!<;wX87P zz@NqC=nG(d0~-kbaxtgpI3~|vlPe%Y9sPj=n5V$s_jn3gK5+RZwlsu<=>$(jt4ur7 z9-8tz%{O@3T7#$4^E4Asum*oGf6#I~-G8n4d!8(VE1#onXOJZV;(9zSH$ndco=gYJ za5uor*%Po=fm_P0n1?g#AccvM>rc_pfd6qC9`M!o9w!H0HUbA2tvgP;yBh5XY}Miy z&vF5Oj{ttq?{7Fkd*N|qb`)#J27LDP-VDWB%Ig}BQ@q8HO8NlJfgu;rqqGF^TuUFM3t`libON~!PD>ww*-p_b>7&|& zJ+2@*gub3<@+=5kNmp|f&xXJY$k9gff!+?7UJSC5+ITL^SO%IG@;sgog=~R=7r?+q z4$0kF3q7+f6GOxUBn?bzanRpX>5^*N_E!TX&oW$ZbL^%myDclJiQA! zu+z8PU*&H+{Q%8rsPfl0R{59N`!ck@_Xa=0v;AnuiQ_0X;=a>61Xbr@+-S)Q5bP&1bbVpU(yE`7yJF7eh{;e{h-8+g8t!%YYi9 z1vh)yc?Jx6K#$MJEFi$dMCjjSQr+rOVgMCeg4xvKOjcYS>_*g?_ zbB11l(qc~5FRpWQgZRWTuTSQ@GTWCE@*JHFzXGPd3NwEVrOY>h2j8ai0o|8?0THgw zWgsU=CnEQJEy(43e}Rrj6K1T|5&3IvSoLp2pAL|P5T=G}-Kaon@o8F%>gtgLuZJub zW$0B$sItL+wHC@~1T1r&y#N*xDgp!fKF`Xc94m`FR-{#@SutoX*TX+^tUON(4Q^P2 zzXE^qb0ar-86=4{0fg*W9aMY+YPB2P0FrvB_XNGBzrlWOf3D{yz_jj^Z2P(f`}L@^ z68J_ezrkxtJli+Bar+qE((A7EouD^j;jR71Pj6}|t7`}%&)+6k{tR7kif$jsn(hv_ zuE1!u{btu($LTFkG}v$T;@V{jd%P{jmErMuXO@LLLL3o2WY^p8bQvo@LGQ|=jbT4n<|5R6y#s!GYHyj#q=_%h z>8&jl!HSR3Lq}*@u;NL2C__hKVqd-}*-BM-{tEE$8jk}4V!fr z9^+G-Y^TZ4E`CQ)`E^@`yd>PsjAE&UBICzIR zfX)fGe-GI27V~?h=uI+!LR3o0_Z%S;ud9yLNvF6~h92&!x8Li!MPsiv=hO+Y&Xtg1 z2960c>0E?K4OdYk&jnxwa{<;uHm}jq3{G;P)}b}VNR;*5stY)gx`NaUNwxH^yhyxO zD|;Ot<;1*R`sL?n4+NeGQ3)wdEv#wLxQe)&n;ljcs$mia5Z-F4x-?@J0qT+^&dvFSeO%*Vy?w&_e?F%@mHaXaagSzewo4?(*14W9 z6dJmkyS+`nj<<-h#&zP0QO|v(Lk|3>j#5nrl<>G5KNd9Dr!(}#5t{iJJ!yX|Lm!v- zC-AO+!uJT)JoN}D8!*Hy6kEQ0nZ{e;!B?U(9)KAKX%=q>)?7vNcn4MU%W*E*e@Pc} z7^WSfOWDaqu0>`1GF_a_LqhD)2Cbqc+{=Ah!D~F}M8Px3-)Hcaf74<-q0@gMR11V< z`32MSgC3BP<#WLCC*`d2G)=2>&n!=8=$S`zW_I2M~hE-ZO$z{h7Q zo230&@y*Y}; zov-hYPXH%4uwY=_LKPb(Hcf1q*k;I{%0NafhIFmoWiZaeo?s|AG7vZM&=u;AyFN|I zPUvyJ%au&}>ClKC<%pr;+;c?(b9uN4K=aGeJVmFUH>@$=W zP^6ULY@Y{xyX_8y7cn&E+EYWePp<7V?O(cztI3RC(R>-&SM8ZWGB;PEU+O8rBk}L8 zyEsIeW8Q%wLywZ8OpYloQD;+TlrxPtuvdMYqnOphJS-hG0LxT?>J_XKDj~P1OC{)| zcchG$8Qap+Rgx^|4b@-NbVE`VP$X`N>cm!=zKUkA{Qyu)0|W{H000O8%xcR}K<}ym zla?Kof8D@eanT<7sgwT1ML(lI)#%S$^d|jz3H_Y@LZiQQ(qGB=U%SXgztHG!TvSSb zD?i?n-rq^@?=^Z`*8GDs@3?3J{Ze|rlIGW?^pEsUF7neq%hG?*=wDsrp`W_w-{{|^ z_a9FBPg(e1PWo^8{*P?;FC#ZdvsjuXGPYFXWiD#v<dnDq(uhZDm>et2 zh?!i;RP3$X#$>CDb{I@$4Q9k>O!c%IfAKBB_Ao}=4bf0Aye$|v<#%S#mh3VUOnSri zU>pPS4Z*mG48@IL64R5s4bgaKb$2|~-do*_rbdp?;;Bf|?7{qm;nN~9nApoSW!TK7 zXh$k+VBTfPZtD)lnFey@XQWnd>B5SRx@aV698A^}SkRs_!$~tzT`z*0+PjU=fA4!) z4(f1)9f64Fi^eIj5Vc_u~f1p30r!^EqhGy_jGHa8LeK2-^1207L*SzsBc<( zFl5A%W>iqtLY6<6=De@Va9Y9$?_ruhW;2|Cqb(LpcHtx=l8l=MqQce{OkiO0Feuk! z6kEo%B!i*7n}RVFN*b@#c%8;Ke}QL^RT{4clOS-Ltz);D2@|VUM|W?i#=41s&)e~>8TR7tMl zy+$ui-yaO85Dsht28<*`(fl2&Q+-2~)g-Gj%c|d88c2Ay99DIg}*W z2o18qTjMPN(1?-BQ9`^}B^LJ-sxO;@$xxRe#bDB|LY{UcloX9OY4j~D!g$Y?c+d=E zx+RQYmMpoZfO?gMq`4Gs^^pyt&`NJXeaCK>)}6@sXV%E@&R^;{e`HvxGHv8al|=CQ zGTc89pDRM)OrdqPL{ssQVTD22Q02T<+~pog3E*(!U<^@YbW{W@gpVusMB^37E~6r0AY(8Z?@aZ;2%TGai%wsoG}Fv0 zCN(tVtvY>y9@lvre|770o?Zrm1?rB@+j)o1t-Mp`U3`nqxAJW|xAAW9yv{*x*Ab~5 zI=w;zOjAc8V^FBhMQrFu>rVL50i9VMA@S{ALGyH z{8{eM_;WhNfB0dI9}zISvtTL(hrpyx>eBd8osaVgl~>5 zI6sj!F>`iK&gk?#dPCj3(EKX9m^ITu6E=Kz(KNhg>Hf6MsJkr{1aZN;fMTXFq-G}8811P}^#a<73Ah5Q;Vth_ zh1iU9hiJbnX8ptk7DX!rL#KHQE|r6(!X}WSSR>BOiOdz=g17atS|^G&nqj6&@7Nz4 zWnlgNMm)JCnhlC+-r=YY*3~kcur*?a@Fd)3e_bdidkYp|yLVS@C9cViU@T@taA(#q zP+u?R%Y7po4kd6!_SoyZqh7y9)yIVwXxNG&ro&^soqmw(=a~IDb%gh%ZjKC zM?-krx*E4OG_=(=G}Ud)e}&|&Q}3{79D#WA2YTjOLPpb0U}-QSos#K@`+CXu`mvj> ze??<$!MK5&_P*cS8+`1iyW&P7hTBVG3*KYpg$M$9e9H%kkN;01bs3?(*0wFZF+_JM zTsrh1nUNP5!{3+VRc0lEdyHD^F>3Qx%GKdtcl zOGU9%tf45L?yVdxjIEH8m$-z~zEm)r7?vDa(%30wLHwK%>MykD3Q??uqCGK%{1xKA zz+X;j4%uiA5y1|*8lyK3eZ1b#f9}PvYJ3@AyYDRV8FY#$jMkwB=THw?-C95qisD;B zG1`~eyaB6=@Ez}S7p1AVp~`JblYL0acq&GFHEA>#$IesIrdT`VF^I2*|B{q~yb{_^ z2QUY@d>H#mFdOr|M2>*X{~Bp0sMKR~JJVD$;D430fPKL^as?b0sI=ANe>h8eK=XMt zkNq5t^Jr-r?{S=?vOXFYaH^iiInYP50}c=Ln|K^+RL`BJNgkWWk*3K5^1Hkr=gy(! zv>IoxraJYVK^v)&CSWG4EOw*y!9NRNk)O(GAyzEHt{X7280`}5Uq&mHlx4IY-;H!5 zBm`(P)zA)FLG76B#;kbbe-_v&k`7WYJTV87579>;eKX*?oj!^lyg(nLj}xih9dxHc zBSv?jSEPD}(JRKvZsk)O^w~;x(#m zecdVecv{cW^Z=j{KhJ1g;w*ZcCIBi&aXHYus_*hUz;$MtW(7(-B|i6T00ICj&eI$l z1zdt?na9;1D7AW}0|EOWi1r*1?E)fYEGWO_;66*an)0 z?@Veym~H~7O#o^$f1qooo2dozwn9b=_HBiGw?WEwz_kNVw9@^wOTieUQtVw%N9h=3 z`T_W7=(F(QQiR0k=wWg~(hPb8K$YN}R(h08gCHLp1o_w?$j9hJ2IL1a zAPcm+$$lA!IY)r{d5unL^cc}4n$DMzfR2$%6zG?skA2vje@tY;ATI`7^2Zb_2I$Ao zK$9d{kfsm$UZAVfG`F#MiLKn`Pt&|pROK%RG}jN+;t|DbMekCXMo;raWbrc?v0?QD7}`hAT80+ghI3p9 zdZ*uAd7gYlz^%^jlYUh(ou>s%uaZAtlR&%{kqKL?1CFW-w6Jx-S-LJwi>g317`civAl< z(D=c0lVe$OF7I3`|Bz;qO_{VStMX_n>lXK2{^cM;mRJl~0*0I$aJ)dPGD^5tLjh5{ z#$9WvlBT*d@ZD*^|0cZkCjDG}PtsfT_F!u5ArD#;3DFHq_k#7qV7MM|VFdU^!G`;Q zXdI!Pf28}s{6~>cC&7BBkqZ4thOQ1GArj$KJ&E7x=z~$b1_pzC%Y4p!chI zcnEc57C7^Z^d(?74}tz1($0?auA=8vD(=GnU#72M7A&OFQ=`|QtCf_ek*Hqb?dvt@K&~SrWJU1zOYULzJAQwf)0t^Mg6HSyx0sdD70( zxlEN_kA1RgitjwFlaRT|H$>IzhvZt-`Y84u13ezikv|0WVd3re`bsN4yO{EZq ze|K3Q*&5EM#SU=FhDV-9Y+=Mxi_cj=Ee)u-0Cl0be38IHro<=x!wQD zDVprD`OEE#&e4{D?QT1G=hs!Q6RrULe;!*E2Kxs|XpyRHk0Ugm0I56)B07bjdKw}2 z3_$4v5j~3l?gN`YhidRVs=!y3Ju9K+a<%$l#pZ3Gg)@qT+F-Hx#fhr%8hsOn`9MPb z^evpY1QhlM@QlUgQ^|fwxcuAG-;;X%9fS;sX{sX+)z|5}8UHt{F>Lb*Q*1p>e`UU6 z_+p!_BTd`;eM2@`u)YZYzl7^bI>-N0RiIn`N5GXs{`csOObotGHU(ZYJhY?X0=2f{ zhPYD@*wxzj9hwfJzXdZ@X}T4)Y(YOJZtJ`J)&*+IvY2}}XroH_BZvmNwJSOc4GiP_ z3vk&tpymJ+dKFpx8qJ4$t_2J9WvIKB(gHKbl|!2|4joTx=nv`p&~`H1{{#AACjZK) z_!5oR=tq}mnnr(=>pmw)C429kqdb6{jl1I<886aCaRle&*GaTLQMvKQ{|8V@0|W{H z000O8%xcR}V;w6JP8k3IyfKsUEhT^QUM7!iLXe3FBOqiCiz0;000|5vA(8+FRG1`_ zFff^kGZPl6UDR&2wQB8xt*zQxthFt*5<*c>YqeF|TB}{`zPDc&wQ8$Y<@=xe-YiMR z*8WJ|yYDXNp7npuz2VU}zJ8L3&Q%9|w2&_>q7vR@aJ$JJK63G9d2Er+tp=n0%wjA2s-6vh3pqf5Jy=`H+ZtlRQ3Y@TW|^S#eD+SIoEb=jCx&w0wt;8u<%8zLURb@LfLI#$Ph{%O-!tP5zq6_n3Ut zy~Ip~2ts z(O&+xd_3x-mHe2&kNfCy{*KAtHTiocKVkCsh5C~w|G?y@On%zrA4P=Jbr8N?~3Vq{=Lb65S{+fJY?=s<8+2lESJa6(p41U4n7kzXqZ#MZQga2vpzeLF|`{;Il#mBGm zzvc0osP1)>o|JWOm;{zj3(;GkW<`c#AKeWfRSIjBOCD}{cuarg#h%K5Un$ezW>XcJ z$_HYq*i@FG#xWIzlYN8zk$5`ARI0 zqlvnvXe^?KB3<^7XLoY2>j0BKkHW^T-I4Azruk(o6i=nY@$Sg#M7%fJ$K+iWjYrcf zn5L8$*tTK|lY4)4q9?*Mp*b3lv<~)nMUoxiu2@7iNpy!}Tf)hxd^?@)^sXpmnAF_3 ze;|g1JzK-cmT)wV{e6x5yCVbXXd<36)ObwoM?YQ=9V0k6l_wyTW~UW>K-zYS8NN z+a%X-g3YpY^JHlYr*}a&($U_Xj1Ht5<9pkZkYZ}yKC5?ylkJhq1|u*yIG>PP9*PeP zLbpb8FrI&o_G6im7)*nK2%r;iXsC%mFL2QtjrTNWSBbwd%_$&VMIqH^B$8!-b=bHk z(lrP}l@_7^S2Ow}sZ_WRdraz!q}vaq(vkkQWMUwaOv9-c7g+TcIbo1ID}MkIC8OyB zS&zgVcRVbLuzDiB;lWsXOE@+Nu5Se|sj?xk?e$`RJ1Q1P7jK!`15D1j)haHr3RaZ znq(+H(XGm%BmOf4xPXo@U;xw z`yGFkmK9iNs~hrp4ON1~hfKs2$OS}x5cNg@EoJ2uZyrfTU!*^^CYrQcy*e!X0;Ep7 z#?yed2!_ppWMXf$N19W>?$$_GDw5nANjjbsjUd#gW_HrZlN*r;!t#L>R2>QTXB7qD z*Wqh-FCD4Ce1()buAJS~27Mbk0)+=RZwh~9GfX^^uERGdx!}ZbW#p$MoZr)EzpYRl zLTamv9Hn_u03K)SS+aOf1e1MQl#WEZn0%c65L~dC@#t^C<~LDOW zXOF#X(im@NnmoF1S*4_jsiU}P$R+ry^1@MFqv;Zq`cv`hPNuyEqbtX;9xP^B<0wzi`LeC4_LtnyKN z6^!-?V;Cy#&Z(H`jMNy?j;Va@iNSwlx08D&k18u_g{Vc}=0z4gKo7zv^VI;G*VaMG zI@C^>L@!xtiaNuhZ_q>7akQ>i4Mt;{m#LXef?FFl1$&}Nh>%Dgs1I6dstQ=DOlZ7F zFM)jB*2Yyeq1L84kXL6~^i82W1x61x3=G7gHdF;g?e#$@VHEem)1wwWMNfYlYMQ0a zQqv7J!%{(YHj}DpM{QxLnQ9h1rZo|Cl4&qC5b2KgMk77dL0vL|^I$lLhzQytVexsq z2yoOcgODL_M9o&`plBE^xTWT(xt1zd6_%=`r!D$5{RTdt3`b)rOI4|A2-+2m*Et9dlSiEJh9JEb(WeZYN`qW8l&M@^m1WVV`MOE z?_eapH=0buB{*tpYb`FLN13KK>+q3rUDF2lMbo>oI+%-4oEwx@wr&>dl&Sd^{hoef z(R1{?MGw;>PWIM&iAUHue&T2cwOFysqHoE9iNK<6)FIh`wRj4jA%%YxTvhnV8bVVQ zyPlbGx=f15!)K;xnbB1T(x^d`;RAWYsI)A#KrIyiITs$%m*Lj-dZh6Jm@kvhLu6p` zrc41>q{|B74=ACvC7czbz-vk-`df6VJz*45iP+W%b=U>Ir53>r)cI<$rIskjJ|j0H z6pKar!ZCPPI+9H`D4u_t;0LgMIuVRXhK>Z&yCPXtNrtQs&XxG72Na>PlwQv0t#CzV zsb%!C#f*nqu2vXorKK)V)#9cNmRhA&TWXDJL^8KjlUfTO`yYx0ORZC(jA}=wO`xOX zcIa?zCb3V32WdxL+t{*W-Nu$i5fa%I&Z=E-)#lbU&5b)S+7y3kb_UNuskeP@X2IM` zg3E*1p05h|u34T=O5Ixw#kXaP zpi=F!V~?Q$aJ6}$2Y%BEgYAt#CyjBb%X$p8-clQQnWdUlizpzQ`)ddCil|wc=*$iW zbHk4R!IXvaZYC8tNn=!;wOVSUYO~aZ0;+i)ldV)OwMl>BY*W{mOak}z?E;Bl?5!|k zAuC}$|Z4G#=N4e=S_4Ua8 z3tye&7j^os0_KkFj|#4ohjJ5gej*2euycRKc24=5AKLTp-HfPQyKU?pb%T>xAlF%` z!7iKTmwL5C5K0xWw+UNVnbId5gSZ9N9dYDQvU}JbMmrtpH-a7|B|~ZROKk1M_f$+ z$>siYM2EiR({Pa5AjkYU|AmdL)kI6q39n@2Rf}`3mMg$D5g<}B(vu0$3;xT+s=YR! z+Nk><$Yx)^F)b;;>07Y6GGKxuAvg9pYY8J*H zPdb6T1(?YwA$QO>^|g_{_ZjI==o;xydX5>*LhqCj(=(7PD6%V@YK`m{bc=uM*GT*w z;bcw#8Og{%EG$`MO}>~TF81E6zi^nRva~%Zob}U%Z-onA>S%R^#;8l~+WcegQ%1r& zY!(sQkL$K;`^@*`(e8&{xg3<_j0lCAM&#nM^3ieQ+;-`UcpTwd^-+0w0g<-7*~$V@ zToe|x?@kN=8!8J#T&O^o&R2g$G2or}drG^_m?Z3trtB*o12(pKg`@SPwnhaF3;u;c zasZ+MkQI;Y%bY;yY$~CJMC2jATp^*QxO{q$*F4t5bgc?qlS^IG#tzI6-FTF)H%=hN!sm9x{f=LTi7B#tqYWy+k_w z6OPfuqckZq*>6vtlt1~anwQ7%oK6OwwdAHcDx&!mqy@B$&ZQPQkD|1QzJt*zHh1)0 z`W}&PiIhxFpzX%{`&jv8R+<)a>G@!wq!SWNZmt@l(qWpC+jKmp5G}>BWi*kN=WQ~H zexMatL?%dnFK?5J@qB-Zp0+pP$)MoHNCJ|nVLGF^%0Klu1r#lxrf#7Uf0<}xh|cs+ zL&J4fm228@I?F|_`)K-cnxW`^3bs~FbMHJ(XUoU*dUw?{&(5mjG?Qt}%z95{z#Z@$ zqgi)pW**lXE5`Ezu-O2nSA+dEbS5>@3~Hj;w3g=3dI-3ILezguz0iq>xWZ=H(W6Oy z^h5d)M4LpH(vRsU5N#PM-5h#`eu~|Cp^TrQ&qF`QDhu=NmA^pims(Z)I?XZY zSNXb9as%fW%AFrs~mFv)uVM3@cP$y?xV&|mw#n@r`tch-J_WbcHq{#e;{jTG2y>15 zY3&fLJ4|j@POA%GXrgX7OfOA^xhoNL^Qa%r6{j}1P=p5XFHP^Dy>u(>1I)Z#Yk8Bc zp{$ml$!dT3868;)6rZ9$pw9(*chVo}PtfrIsQ($j|y^nYl1L9vwnf|jA}GK_bTxeJ-Fbh0wInO?5=Y{3R89W?_}YGD62C?P zgI+-EMS96$Z4pLAHzq;>u2PXhD4#~7Yasmx^e&b?kNyeT^8OdS?9k}OOyQuYvTB&x zj z&W3-*vf-w!?z>vxH?pNfM`lYulumRA1a3m_r$F@P?6yUD+ZJcHEe46aZP)2-<-*6= zcAldvZzT^?`;n}syt?4mUwnSR^yOo2j)4r7NqFmfkG?xJb*rL2EU)AD4Ro|S2Oo+_d2K!XVNLAj}Spz&s? zNeEX|pG3H}x)!-h-PI>=qscXRm%0}W(bo2>-F*1;Un;9=5aLZovc70@^fgF(4|3R1 zaC8p}fn%DZb1_y#Q`rqr7duq2N2h(XG;ge1KVYwp$60K!397%;8dR@Sk-OOYcraTE^Sr_n zwD2`qv1+nn)o5Xq?h^rBpgof(@+5yKLIj*GKvF^;4I6)hpa%O5E+H(N{5nm+)8Nuk zg1hCfAJe_}>RvrV(HvQ1 ztuU6KK?D+(6KSrtJ-uObVZ634jUNl9Ws`4{vT9cp_Hi@$J)GbC_@?g`J+|=GsZ-Z{-d233$tYqs>MpNYSml`f&g_CRV;0v?zxUY*RWE&GW1CC@ z9cS2tXBRe}IEg%CAf}#KDwX#qGNy5mX9d3FcophpcohJvjhj$8yKF zz}nkX#w&Y~8LIUeI&28QUu#{7ShWpUyyk}V3oXAfFrIBl3hVuzjZ*`np+c-sAbT0f zoGw@x>s$8ZMn4A#6dkoC1Hah2A*j~z8yzeLyTG&-p{i-y1cx*%YWVd8z9YUbzn%kx zQ9(2Oy07O~hG9S2mO%;cN5-BFwSOkQsDp9#flFW8RMlG>X5QQVlA@=c3wZEzZGsP= zZZk)@NPD@uYt)Q8X@y+UE6n0(gcM25i=W7?^atQKkAu1$oBds_Y+&WzrB1fHpU9f0 z-lqsWd>J+p7Y2e3e!VI2DE{QyBZRo-AqJ_|-d-F|Xgu2!zOv=;w0cEq&7^|`l;yDX0PF0XuvrLKJKvicplG5_>He?l0tmv$RYXeuf!nP)G^~B zWqi$XS`_%OCgXMUgHvB_p$EyzSw(s!Nw4hhl} zh+cU@qX^d;3AnU@EWSqxNAa~&6%YDLa(-0 zf`Ic~+e;1MmScB;^&u>G_;W9R<*k8*0PuA&xab<$!5xbH9S3*)jkEL3w$~qz|IwXl zf;=!u4LBj0HFRAPHnHh+vnqr86_hEl^nKpYgJJ%a{r4S%&b}DYUi9@APo;< zl(lPY+e4>2I9Pl%wfrqeRM|n)@6PO*(|9! zA@L9l>eGRPD9?Kq9}$74aqFEfbHuYWT1tB87}-kNK^znN4D0``%#YqfFG;`Un0);t~nc%)aaRm zW%O&~#`h`pqF0wJQJHtmlGi1`hcfw+_IH*R(TqRjbs3~u*mQq=L3e_wbh+BBWYMUe zz~zN+P=D+w3*(q43k-R zGOg4r=BWN}CCa8AfqwT4wSr6;CTc%}&M<=kW$9e&wUJ5naS+sv;Sq7h3VeV5px#Nx z!aI(LJ_0)Q4Ds08^9m2Sw+e@IbzMJbI4t;i**QUcWB$*XH5)YJk64? zVTODy9S7~%Z`E9XWONsoha>NE76gYrEFJtOpP5~P&2mCBxbI?sp{|de_4bT?_lP&r z|D;_a{F~nzJM$(7PLg7U{%k264<40L0a*sg!dm*Zyt)wH56%Q#)dGc8)-bX)yjA?T z94jOBZ7&o9nGuxzm^mM+0Vyk|+atTaL3-VSXGoJyA6$vyye8%bYl}Rw)fp5EXgrIYR9RdYh#y7F~KpFU2tuCyA48T;wwU(&y`D^o`J;$=-8}} z5K?`>KE8-M;WF(pmCYBaLxX97z+3+l+(WM!ut|te z+;B9#4G$0c-7n>W?Fwh-i6f^@O+6d;gZ1YLX6IO{&nWFP1Lt^s-oi|z*uYh@ixBS@ zV^WZK;tHdo_v}VAj3psxMNEDYv_$Q$ZXiUf#62=IR(+)A)HFDdb$4m8GvkH)X6wha zIT1FSb$n96Bzx;yQ9@dg$eE9p)r~?eh%&N zL5}UFs>={nIj&=CTWaT3rO8`^Df;oz@lD6CV|*R{0_#QL({o~U2P3mF$m21J;h`cr z3tO`ev7K6JJ*kKk|3$3neQ=}5`(+!j+R2*o5~k-%m!!LM#oqL?GN45Gf)og{x?sPW zs@%DWj%}#^c@;tetr-ajx`aZrLrGru2(EHdak(0 zyqMPF5p1mG&xq`Y`}&P3ok*TlVO`sH8lL)#*c1>q@z>88F?q9jjYCtOxHDObY5Cnd z?y25sg{kDATeDa#o&;;9pU>qKYIQ*3hG{wG6YF&r!Jq`nS4~56P)r!JIh{V%2U%j1 zQfeLHpwd9xVlRCY7*=vR)i{^(>8vIWxY?deNlr<=`S;F&jqZH>^R|73*LnS!&!x*l z>HKfIW)a@4Ow`KZa?$bc1Zj6ol}xVjfuf(%`=;WXHgfSYfw~N2Q1zw z#!wN&1!W_&Had2zpz$zh*)n&&rf91~V62SPH@Oc2L+%gg_h=c(*E6p2qm+uE^2^bx z1Z4i!XAasJm^sa~(nZ{8U74{~m^*s?^?-eeCSvcuf7k^WgZ^B~a%kdByZI)TS3mheK*@WE6~(S?~1@jzv|`n#0DjAz3)juW2(4AD)t!T zg#5%jv$X^s)+%lrZmetIkBbbLd)NquHUVtGLC$n9A)Fn)dD^Tq(UTY7iIpo;H|h>V#}`ujGGPyxh0XUU1G$&067|A#*HYb=;sW8)p%#R-xc)qCF1HMGfv5NFI`KTgh5|Ku4_hM2Xj(%`6@sxUV) z@-u4oqe!R^)-^7jZ|o$jEi}gRa@S>JHKCljxMVk6TsNStPkEge=E0J)M;l-ZxSusW z0?8Q=yE^Dq4-~4>g&#l#ARg=g0 z5QO3kq@N5;E>+bKAsG^3q%u2<$uUp01|^nC8mpnZ#Z(IG%_Upcr$QAm=qwE0&E%|H z4l!=dqL(75jcHuRyeM#Hai`JcD~iCV3y`JVFaSeTyVQ|pMXT!ROL|&1cbwH2Rf|$N zB&8HGscUhs&4n$~=bKI0T9stc)fhLkFZ66m`84c{VbwTGsjx{4trMA(5b-LQLDvc3 zl0@2rLynZna`k<6G&>oRiky3}^W|(G26O8I~FyT0|~>9j|%LI@j+y1QB;B z)(L!AIRGQ+)FTGh!V;ZXYqfF}i~R$hKPrs|Hl@y;l)#Bn2Ru{CXywjSXN5Y&a_%|U zx>&2OcV?l_XTtb5&tiw-@KwsLG}p=*2A|lW)0J4U!yPv%3LEZ2 zBo|~+g?zRqK~{~BBaS)EKl5?km+0X;dt#p3%JMU)GE-}qY_nXAe$B$YAZQ~LaVQ!a zCI6<=M$0Q%gP=?pdalN_x)Q8h+i}W%DI(*GR~<0$B*B*ElVoyFVouxC4LWvt^DGPt z3uY!G!PTE3H5dUVgA=N8^;II%@H_3mDfiFVvN~VQb7kmjDWciJM8<~NDJ7^W)%d_8 zkTUc*Ls~hPorHW|c7xsVpt(p$nhY73G9H09gr~wGGuzbGFmA%qfgOTOyJ94Tx{RW{ zQ0_TY*H}voh@Osb`d=+{_s!w^oMC`%0)zqeZmxExaepY0m0GnFojJigstTL4BloG&1MWacx zBQw`Jsl@H~Zee%{$ao0g81{l-%CgKjRkdHt2ZurlwW&4ChAn!ZfLRv+BSZcDzElk{ zz(PdRq3**Mcki)CDWKIBn5AIn%^+b$>F+liv#r_Xtfv#5kYms%I4#=E4_Ra6ABzm6 ziL_@U4RVs1X-%3HxKK%<^Laq+@>NMwyVzC~GbUSu`Ltz0DT6Vbwyx1yu?NB&)e1?a z1)CVX8*d1lZ!*8}sl!H^#QBWTATnfZC~$F^xSPXl@e!$8Fd)j@dv$!OFLQ&YYh~tO ztO-=4&I+o9zl~SbdeohQS#xbJN;co#&T{0Nh5m52Q^x)U=9E|eMrxamxxq@fPCQy+ zl0bDSL=92{5r^f^5!6t$8M|r|?fPHy{izvQXvoAkj2!pgrF%+1+_{3sSI`B{Uxezf zmAf1J(X~}`e5|U!F&{;yZYB0a<*HpIhP_P?hD8& z=4O{D7E3Bh-YCR$__VqM*F~*%{XM9XDT-ibnIz0 zj3tbOz+btmH+?!+z7`0nPwLH#YxeqeuATGpX&lli?eS0#vdB0+r`-srW|!@4$Zc@d zCeTOz;udXm&p1W-uWdeY9db1A(pCu(>g+ZHr-trE95Av=g>BQa?{iXe*u)GH5)-d8!J(;jX^V zc&ZUPJsd&ehpbNV`;2Y#GpkKLHEF;1-~}qvDo%sq_X?s7zEMBDFITwWyf6$e0iwlK z@NAdEJP!dCag3HsW28{9IE9X4(?r$)=lKMP5ROQud5~EBZ+&Wbj;l|JI0M*Cr%hFS zu8Ii$cn5P_dWf~=GkO!6cYe#NCD}by`J0|5Uqh%X)sO4%;aHxwEXG;J^1}7sLcV&T zqC?wb9ij1miE0=&qrFcP$E0t!F!@^@Jv5RoDquE1;L};vs8vSWKb*dVQW+2T+nO62 zl)@};a*P$0j1vsKC(V;mo&J?C=zAW737<6VSe#;dsJXO##kuw?N&I)BAC~(#NRSMX#TQ&?7Y*8kJe8pn~v?S_YWFncGvAG5oyYZ|ZYMOYAiq$Di-g z{a^87vIK6>-O7sq6?GfgsNZgr?RsC>$}9_mYO(E$rh;nI$!i1J^B25W&x%40N3sDG zhx9k_vA&p$@UM0^G(HK~z~Cu5RchhUZj*&;6gwd+N9!Zo8chO~!_|#;bR?%#2 zH>=p9g6gsA#JH!UxICBCHMLAdP*TyZw$7BQj{XyTio#rh)FCqEvTq5(O1WvW`hzKY*0UbyOiAv4MgsdU6FCKqRA zZLE+otrE^TSz&v4>bx!>`Fr23Hpp}QGKD)Jouv+6M}Kt+Uk_YRbFb$5&A~2ld{GJK*DoBo z8kdUuaE5aJPPnRRNiSuuB`y|sh_QSo9dV$J3R#*C$w)-qa177pImmC=mf<@H;+6?BZ8NAkquCdom`FtXkDMdU!(dk}8BNGX`d1)Z}l%@VHYo$h|A zrIfSN=Bq3)jZf8)J$7DOK^4NaR6=pvFagm->Hp%H9D);e{QV2q5ec8$AS2(H-3RZs zdTw*sh2^b%bf$m!m9+b-WZi_?;e_hMLD;%RlIdZ$^%uEi5wigrjXG$=kW#1t#}@cV zVn0bm80-arBKPDfA1ISJ07N=`>;wp=ZVoL}W*+rnU2~hZZN@g#_dkcdFe5cuj(%ro zMNy3mwq)*fKskl%Gj0yt%1+Byk(~m@7ed8D+)|jBA^IsoNq^G%R#`tWx5OxLgZD&V z+osubVh=bi=lJy&1%HJ1x?g_(^Bd5EFSncI8-b_OFB?MG=TV}R{h&8O-TzOL zWvM?~V3RrFXCj8qi|aBXakI>?1lOk{5Jh90TX_Mz-<=P12jV^ z=fhhapaxe?D+uz4!&1BEj4V^mfLFTu5^)TF2`M-b53cCf)Ht#58f6=b)WLL*i}r;R zvsR}3l|^cSUn;%k^m4BXA|uZd1P8Z9ZAT<|UBn7qWRc=tz%KpO$C442 zIxi{kMFqz>l1nj&yI0g-Bz_0CWgIO>=-LL%Q;iTT0f-i=QL zMWSWXWQm;w2>sUsmdua`Z7w)kt3`&xgrqsbpf8fuF1KB+5W}}uO2Ynm9MOV@;rrLu zgkwLr;)>`p4||>6d*czOEo{g4=w%Ky+C5L$BrDTshAlc@fJ_q49God_S-*)1h@)~9 z#%h!}PPgU@uRRX#{NyML#iTN=-R~NY6T5<)uforqu=SzNoGg7`-K+dEso1>XjUNRU zK$4su39~$OQ&L5!uNqMgzD7GJx8H91!*-%N?FRI&o{8IUyUN9OR6~Z;&I-79lf7#i zwKIocN3m%ZxX4O{)Y-{qm9}3pbDJn$DRd#|oe)oKDJhHH7wKp=QeRz451tr*OzW+z zEp2M^H(dI+l;pNMo*im8-|3)5XFkXUf@TBqc8)EH@{ZB0Kc%W{8tiKgpemwGsaLT; z@tUL7YlV6d(=D0*HKhbrr07Cq6$d;A$9M^7X%7`$K(cuA{q;!3v!4IDtI-yYN7nL} zD?@TEsd#up?NJDO#rDDk``xMg)cr7d2HDoqJ-(1AkI*yFo?p~n2(^CwlID?s4ui`Mg_RAlYS)rSxS8!H%fuF z;4c=GLaSGKoev#J^iJqeZn0od4lK%+ zL11$YDvkvztHu&QVX5ji3J`78=*i5|_^}lz*S70-TJ8NjC;9{`r?|#nrLvoD892BL zs{+BEJ<;QxC=_kZ6g_bft6AT(EWxuaKlWGf*Ob2Fl2zeglZL zH6X0*>a$CpFDvz*ur8e&UA@*nPm7NjjNJ;68h2p$Fl|~cH z<{~K%&E_RqL6dyV4d6xMR7A2)tt&SBd0MBek5JZ1bZuEqY;on+FIvtNG?&|m<9Y9# zO`@Xr1^qkdGWibW8`A7O8z^xjxV!KOx;@E+nC`NY`vIAGm7>FwSGgSu8|H`WFSKmB zgPXD&P0v0u3yw{L!yqNk=E~b{+N|I9mH`JX1IL8?B(2DWN`4x{P;*K(wIgAf#}D$T zmhO9{#2(Gj6WwI4HV*Up@hv#7=Kfe^#phbL0D z@RLN)R}wVxM@@Q2H83`NlN^F@nlv!I79#ii)^?n`eb&PfbNN9kp7PK)MguUdQ43-i ztOoX?(;zPcSY%hfOS zW-EtlZV_##^IJMkz2b~@*mKkKt%+-AEI|86$>Zp0YMdO>`Ya(z9z)-3k>85$sX@V~ zil(asK0hdt1VM0rPW4J*d(EMwof|osXNZ#Iudmp~oJ%l=D-0}<>KL=&J!@yWe`Ul8 zKV2)q*^f+H(53D^l9cod*(AXqj0a>P`I4Z2%7Y3y=z+UVu7&Cm_)rrx;-y3F!wdCn zjA*Y6($}F(Dl^s6LP!!#)2lrGn^L9N0jnG!dNUj?p4cGy>EJ;Se$YUEBLC|7|OTDSKSw6 zg((hR3dc%BsdOz~=wlT~KWo?E`6&rVAEs6SZmCg1>6WNz!A96bn^)SWO%1g*@4x zVwq|eiIDX`1@1Tpuvur)2>#>3&fyJmJ!LWyHS6iq6dlIZ#@^r^NWB=l3XOnHlWNoS z(vMZtFH5s4f0hc&X^!-!6`FXH--DJ6#lw^~$ZcOog#{pv!*FFJ&S=Vf$?4-(0=|=B z*^^_Gb7@Mq$p{Kl^yAIX{vGrN{LN8_ci&ZJr-#)9iCFbnYhnm0CZ?~kZ$y=6B3KwX zD{vXTn@r8aBwMHbbXa@FwmfUq510zz(zB)0u?cL2QaHu|f8-)x@VhKDuFGboAgU;n zQ_gUoLhj~vH&E3yPGrWiO&fvd!%IhTQw*CECdQW+vg$YMOzolMLt(l6pqhT`RH7{_ zWZ<-b;Dqsehl}O-{$Ss$Tady5o`R01n{$cEWSEz+Olr^ZcMiYg6*#hsqDTc^mchQ= z?W>B3) zNN(ef1ZQyD`ss7))kCoSvGoc04#9AlUvS%P6SdtFG^w45Cb^{!=2B->g!ZTCZ8Uh~ z6|C*^-0$WRH-$MBDT^IX;Dm3Kpj0)UBEPG}FR-(#82k;k$j;#gk((WlkJkdl^*&u) z!yFn*H&~a9V&w#>r1za1S(h&=dVV8_i_Jj&MJXTmE8e4OL$@{u^cJ!l_s^!O&hs?k zwrPT>tJ3oGE)d{8TD0!WcNVmOy7SdIE>Tv-o%$d5`Q_lU!50Zgv%Y#3(Aeod@4{R4 z4UDCEl+mcPV;QfO7e_?mrJ~2tULtAoPr1dD?EAu8SaE7Z27HOp;wEBhfgv^6l7LlE zgA3W23g!1c#fmLk4>amK%+;hyns3kNE5MQ-ewyelCK}cJa;_bsQCuc@#=YRw8yzK+ zb+6+r2;k=%cHyi7>MT5Qkct+lYm7KvoORI9qT=h>yp)r1hLb9_Kx&=^|At+%)!I>& ziHVamr{8ygP&(@px(xLhA;KP(RFs6ANMpDaF(=ey49E4?R+#e>)~OW{Omrw?_5&vE zMOn7qjP85YnWIzVP21QlGS-zUQ_juvQT4T74Iu47T_-=YN^N)jtiM3q2kX`{n;g2k;|ZSvVQe|hN#*Z94w9y9s! z(`c|a1CS{=u<|YRP|i{JU{%gsc}pxspYbxV>&&ucUxaLp6i9M{n&?G>m;1VEq4c20 z!i@$a_C&VRQ}nZE;B{k0EWMzIb=?q8@H9JyksA*2o8g(hq_0Bv?A;b}>5S;7su0BZ z#CUak@e(#hU3?PA?(8R2?f~b3fQQiMgtR}7+@|;0H4z|)|NWo;AMK*!3T`J;u(vrc z2xX8T@h1y9VA5BS)rfg0^p{alXt$ezQFRpQBn`N?Z@Hz?TbtS-K2QFDN%W6{Tec*Er~*G&lKgXlZ$$*TYWU&Z2*Ao#$p2UjJ}g*99~N?OrWNw%|KAn< r_pbT=D*pgKa`3It{(btt-~VIY^y6guFYevAqcUf=!4Y}yG3Xoe-Ybu& z$zw7(W^&x*ag$q3zB&LB36qm1eLFylI3*<0(%L7F{RSV9o`do+DvxXAame6n1GIz> zoBRrSUniZfl-Bh^?^OoB+T@uAf8Sv8jneU&0M+wr<#AJhhWT|Szux3G$fBDKz9m4* z`Hca(k8hRMo1}G{v~Dx`cA0aB!EX-GYCasG1i!`Pw+3j8-zGhG8hpg$yG*`YcDY9$ zZ#VfJCf{rFeJ0;;@&hKnQ?|TbroU?nKgbVF;iLR+dA!Hq_fDZce#GSWe~Dh+Z}JCB zK4$WxCO;+{e^5q0WU?uXKWuVFW*wJZP8fXB;Ex1oh))Ihqx`r$PRqy>CO>KN$Ara? zn>^3pPe}7A8TzEjPm3X+G5Avf{xp9^H2YbTo;CS%vcu;C{007EfWO4onEYkg>nrm3 zsyx0XkFT5j4N>wp#V5Wce?8we`8z`TyC#26-rqO*2SW9S^6?{+e{AwkOn$b4f66}# z;PG?m|Ajn$DUV+n{A-hcWAbkUbUTll{5z9>Z}J~Z{-eQvGWgF^_%EWmsr=Uf-OYb9 z`R@k*BS3fYKTZCZ$87fbH8bR48){~NKB{J!stS9n*%kZ+HOEwQ11hNInQA`7 zR}18^P&PY9)+`cnwo5A{`o2cioolMaP=-3sP)nHnovrO%Om@ef@V;6z9DFo;g?h{T+(^w^-2f9P|!u{+{J;poGaQLwGe6`&mnpA~ND};1x_hQmk!Z8@2uI2G*sybeiQBQWuyEzs%&!KqslBQ2(B97QxLyYAFx2@#F>LG{NF~BUseWfL=_K|!33S!e zx<32fqo$C#>e8f}k_r&De>mKvBN zI>zjHwwq~Qk^VQQQ~4!`0pKE#%b-6Q>H^rb?ZA*To{GR-pomc?&ue!gKJFw^5eEZv zvs`Oclm9ayYPe~4u!+0{QDPhg&ZcU%lSeSel|xcx{3elf>^4-F4H!~Ml0z+(Wfp{lVc z8cxTCc4I=XXPX%{#ikL*^g+WpkIvhyJQ@!V%bH-(h?ccO4`EWp7(7yUL886xdq#l^ z=^+tDf9B=PriT*FNYoihHFr9x-SJ_ubj;b`svUdQL<%eGR>Q6*VWkNYwdMo5zNWM$ zYfA>Y_--H)gW^)|o-^SXZLTkCt96G{yO|mai9%1!o5Bg#sI{f2&Yf&FG!P4q!HLTN zSz=bpDcFmtWzv00fXPHl`NuV{ruI#AA@?y&e{nUnsV6-M`gRtTa)t*e_^}ZrpT2z} zK|48=h#+EOqj0GdEGKSIh|QY^_rP?RX~K*5MYNmP3GCFaA$iEjI%%cASg)qm7TedI zaB@0wjk_BF;9Q+{u;kJrz;)GcB+{`|MD#X2Kcw*iV}OI9_!z)wDN?qfYOq@rD3@~D ze+n@Cf||40E@`@QS7vBMc7k)Pcg7QrkONQ!dt5%YMv@W92C-N?70x0`0k!-ZP+VPN z>&av<$&%%0mGydz1@kH>)aXbA7(cJ3c5<~Eqs~}zeI((wMl_hto~WwqE=62>to#pL zqxJ+0N-or%*PC@D@QVIY#t;Om5qB)leCe_TeIL~x@H0q3oqgmL=al$lzERsw@&`{n=q3}q`NrW1Ev7uUOf2o(K zW$@97Dznsu>LN?MR4upE#oP^uNQ5KNq@`A8V2-*5F4TRNGP@22|;r3k_f?>B8hlR*baqb!=Xql71tAz2a_ph ztZ>{?Eo!NhJML0TU8+`E^lkc%f2CHbW=pLWtyqPovD9TyoLZw=MOLKwITOWPn~p?* z6By=xc!F0+g@z*tm{dG*Fce9KEVWLpw^SRbs15SiC~Q~-=ma-0JX6Aln^EFv&E%3J z>aCQDsGf3Q@C>O`j6pRZ8-?zAr9WbR~zgizRQsc!W$OZBK;e@per^!Y_w zg*+5@hC@)MrM4*e;H*+<$Ws04N~VP+SROB!G@!OwYP-4$hR-Xoz{@PpBu!p%(7m~* z&r&-euX?%KiH;RZS1c`<<`xge(kA^Mq|FZGw%j)kR=I8?tD@o{V=88;xPn`7gQdpR)s{-AWY+!8E?J7bsY7g>GE~}9 z`_z6*9Z&}?dV$V(b#`?Ty9v$3i*bLoyoD!=aiNwWxS?e-;?3b2O_%-i(95 zplj42q_+tLkEO0vhb>;jA>e)_wlBU{DC8N~A4%C)n=JJ@?zYtH)f)r^Z-xPy$J2w+$WXHc$Bi;Bv9Ecm(+AMyi|qLZbqEIk;{Kp=4(K%>WB-f8r8MaO<{8SZv5iCJPGA zfR@0kPi(1{#YPDysq;nTmxd2+=IPQtmQg4?GG&L44(2J$s zfw1N)xC7CHfAuaOQ8~o;rLw>#8?$A_ET~S>eQ0A_=g!MFceaVPQJyq4HR+_Yc1zd# zj<%f`-O%3Q4W17ZZ?DcSsNNA;70UH=xAtAGdtjDxszU)iP)r2F*Iuh9G+{ylnuha* zs?&)`iw-vT7}JtZqf#Fri&l$s-;4Ag3NSAibVehwe?TadTQAkDNLL+7$D%NNXc(1N z%o)C{2Ex{cFg3fRV3C`Q6V)M2DLIsOLV`POi9|esE+?9F^aAACtdu>i?H#>4(bRHe z`_^6Ib>*gC7Fz2PZ-R=`<25bdC!CI^8f3IK)H2Di=G2jNKO(euZff1yy1hD^1qKV( zV7GIjf5(w9xYQDe3%IJkLw_g7^*7{iY3W5fG7=fmRd5qDGaNb;x;A-jDA|OR#9NSmY_xnDhCsduV(F@=*_Z3lJT)z}-#-baN- z;?Zb)Kfr0w9fMv%q8Et}gd7APZ3^uYCPIx;cete>%qUb6;k}^Nw=0AwGt`5YdPvHq ze{fAaAyz*aPgf6zq7lqNGZE6Ovb6PSG!&N167o{Zcz9@Uc+?3&>uH_0cJ0qrkon3M zUAt;6fMvJETe;s-N7cKfI7Gqp9`&%K^!K7lZPF^X=!^6vfW)S3-8QZG%BiT<>D!%% z@AvM-^3&Q;M~7iLlp>{%B3Ufcvo)3if0oL_-tE}=MR#(=r@+E1Gb185W}8PQIjKnT z8A-N{ji(Ok^TxIb^9nBejAVMy-FsF|dwZ#^QgO{DQ%yw;! zhIS)$>+@!+OXts7H6@R@=hYOGE3M7)@c6in_{LJ|KC8<+YPcuglzWq4rsD1(YM5bX zFpYPGlfUP=;J+daikJLXN-8ZzSt^d26NLk6zgV^km{XJ2Xz|Ubx&V6#Fr(eacoeReT+Bp8WdiH**e=rixcr+}i zwZ2faqPvy<>841^!`8uMJep2*cd`22UNBQ7r;&Ip1rrsW|K`<9baC%8Tf_E9 zJmKQisuFx}n`~u?pbQobMD~YiSqIzqTR44aLXd26ZJ!x0mSBpf$VnRXBiCmn+Hs zhBLe9*o#gBf#;)0rWFP27tBE#8Te`C)6-V(Rt=bh!f zrL<(Zs?KWuiWk2jF5x0C8ou6TRFD3Jaz=i}+IT$bgpu<7eFNP%DjWL*7^KXZU9+u_ zls6HycKpwrxz79F@+x2`$KIrvpjLht)H!TxKE+Q+5|d^QGm`rSxZF8_;wm|zOqet( z^7fUJd?(I$D0@M0f5^2e=**uKoyF07arqe{|GQ;3h~{(N%o5#D{kVKZVT-A{G!YgtaZ*PkHO z*Q689@4AS~0M^Ox;V<8-spdRau5EIeO;T z^%-hu%+RGrsj{U!`w=XEBFDf=Y}-({J3dxn$72xndb*z;ftZib`}NzWt=B`d@J!Pb z+6S%fr}=b%R?tD(Lf61XhbTqYqUSJHUq?6LfB6=A73kbZ57KMsJ@i^ox{)43JA?K~ z%=jw3PFr&|mE$W&f22RbnzzA6{tSDS>8Nn+8l^b>h5icLrQj8RL(~Y5+vxA~5AY^d z43Yl~h?Hq7{?nj;8T6b%|3~y3&D~_s^A`PEdm*YrtbKvbxCT|%VV@~5Z15DVhFUJ` zf2hmQ8oM<^YdagBCbJ$&S$CBDopzhO;RJ0wL6>(nJVU14j?RWody{dq z6qXHz{ORSUZ+S&kMV0vgEeIM_70X%z!9aa5fQct)u>Xb%K6>Wa`eRU;2~(c~#kp=U z0#gy)g5FyJWpBdRZ3v<}5JPXKm%`|)5Vq~~HiYw?FxwH#xQp(gyXj#(k0G3of73f4 z*1hy8x(^U}Kfv*wp!+WR4L!(Z^bpU$dk$ucYmCDF@+N4mWrf)W z{wyv>UjXYH*g)`?i#a{VF?j}?Tmc#C=novgJO%!~$5YVqfy*zkr6D9tCwMAaW!jnc z(3IzCzQNPh8a$nzrKDUe|b>;w?rF1I7{jLE{8nf1Lw?U^!z+ zV!#(Puq4@^$L?joP68fO(g$b`47q?Fr6q{xTKXVe2&1l~6UcRNTKWjgc8Xp}AJr!8 zaRtdC^z}TGXF=dfx|*waHUwTkjy94H^mf4XVvv>8#&coDGSIw`=ka_fWD5+u00uU4 zNbb&B=$UOA@e6dJ!RNSIe=bt(A`ZFv6*;3!V~a#osj-Ig8#+R|WaM0QWy zoxbJ%Du3hY2WU=1mA}5R%D>Fsm!bW=H~0}Azm%E2hQ`x+#R)pla4d(G7f=PBPhhW) zfwPa(JY=v7=qXxCp9JDP1+JcU-Iem;+vc+x(Bd6FSJ0XPRc?Q6Ok>}xV~2o-{ET$`c8#~Lb| zGxQ3S7IU(Gah;nR#3znxfPt#gdSC1TcJ!H8k zL$5kQl@0c*wNOSQV43sm1+b7%5g5q#c~%zXSXtz;BCR^jia~R^9{!nQ<#}3YaKjq> z75I~%8@b8LAW5tVAY{ktpyC@)tKH}ZkkmuHC+Ic(4fbnue?2z=rgf)e+t)SNuScDg zz&B#~4PH~?*}mD0+sEjZUU#kU1icXpZ|z5ZdQ(eTT|*Fg{x-q#XXt`cbo)Toba%LQ z1xBmwH@oIKPH%al!G5b3*Dh1o<83*v43Ez{vn=Eh;)ozbc|nD87k0XPAXs*i?qOu| zw*$>V>t1i=f0K0Iak{_7%&mVQyWW1M%UJmddRHE84Ew<{7oqO!9q`*zd&^uVO?+ui zZ*8dvR(y;eIzrQe6;IMb89E9R`|?G}R;t4DSAd7#pp^VAiuK!rLL{+*_O^2Knga{3(I&nqx$Am4=f z60}UdlB&1`tqSdG4dgom<_w)AE;V>%_TMU=la%gkt?p|%g~niIE9_W!8^nO zbWXT^f53jXnBOZ!Z;}BNqEbq}=Lng2U3IKZI>oIr^l(?b{a)8C8hf=lr%s4s<=ORpMxQZHiE&wZ-3$PZld5w-{aFPqP4y`dpqO9juUBHRd6{KcJs-=JBMdGzu z+3WBqC+79iFF!|nAn+7=1;4NOPeOJzx+7=nz8A>(zhJ-ecZm`%!P$ek>2^N~>VDXqOuyeiJR` ze`dM_F5k@;YSBY3cb>pA;L7d#q`Me1Hfj9y%TL;#Gnu z(9qS~?QQyXyhV&Pt`lF3dhR0~a^OF8lxjMlgvaIhv7o^|ouMa=(9Fl^N&90N`nbG5 zfp`5AzDKa;sYgKBfFWj~*z)DeG~Nmiz7m!30L(Z@vv@nO<|>-UJE)ppj&sRQf4Z2% zFzpas%1$nFEh^)e>Edi25@L@wXcaBtUhdNhUgJq83Z6;+K7+UXn-=2kp979RDQA_ZXo!hci)iVaa0yK0Z^~ zB<;_NZ+_18%@5M&Wed)`C#^-9IUw8eHumd{nfmx)_LW!sKTt~p1PTBE00;oOWy??l zH3->~95#QOxW%y0XrgH(5rc`lX_?@V(wd4HKItwoGg@WKU%vqZUKDR_`(x=V4DU6dW0dn|SC7b;n(wCS@n| zxZmYUCjE41M2~XBP;u_LqJg^Rsw31`dZNjYbNPQrdQQlDgs3^8>e~YqyA%7CLbLwB zV5&HX{~j|~7tfw}iewm!OzcqK31j7nOPL5)7X*(7e9ZI6!Zfj)#~$_>N((4b zN^rK%gTCE%2f~XO8guQbA=@X{_L=rCUB%U8#;<6;4DGA-%pjSYE733Yl;Dy0_tsq; zB28oOz>uLwNl_-p6ql&8DKpBM#v9nHKF(3h>R}$1jv9bvszCJ$Rtc4mThyfz^wB#~ z#>FFv-7W9VdFKW6WsR}3(w?uVft4v=-v)6tAP)h>@3IG5A2mrce%TTORmd2Bp z9hHAA;;*=95B=0hf8wH_(VuGcXD)h^{=9^KPJf}%UpncpWc;sPWTRhb^fxXlrN5OQ zZ%Oa(r1$q4y)A40L7I15G=Y98yr(nh`X?9p>7Qlkzi9NYF7nV%UG#7C@6!7Z zC;g`^{4Xc{w|xIcHvF%PH2O^mU8LW-=n{XuE6sb-T*d?wBr!X=2urzG8k;nBjU70M zHHc-W#w9LV$S!Efr81&RGfsYvm(^t=WP*z)vRmUxE?O=+E$7KjE|>2VnVBlhv=a94 zbSKYn@>MRL$+I+`?V>eYAyVc*W&V(hujaX>Jddx@czy}wdR<(}J{MQ<0%`m%zLtNh zoxD)K*J-@SMa`m_jjxxH8>Cq*%@P?~s_`-xweoUl0%Ams%&m~0AJ%xKlW%nLDp7K^ zi`v-bQvGUSI3P`<6!mXU@~dMBQ;Ep6=uXt zu4F3qR&Ham)kQlDrm_YzVl<|D+KqqsmSB4rBkqQ1C>Y)rjGOX1GiXb8nF%JnVS6x+ zf%t}CTttTAMlgx#N#2HNytBGHo@(!{ZbnlhM`-a>Bx&|we!}o+kr+(uWtuWd5y z6*e&MvShb)2jffwx$-kotG9GvMMqsUk~9t`YYHrAPnqGQ8L6%p!A)`Z5W{hce4n7#D-f6~~Qps2<*^-1UJ>r%gtvwhr zVo5V9C~G0hA53%J*JU^@VTAWE%^$NFPQcL?3nsg8k`YP9O#@M3>k1|?FnJi1>oJNg z<64rz(B4hKm$-kTKtJUIfC>uWLIU?#+%61AooUV&fh zVPFDAMLNwWQ>hYcc|FhJkz6qBYL&+I8XW`EA#j5o9c#0$**=EAy>fp@6mqI0SMgq> z7pLzJhEoU!HUR@h5~67Sj@9vau(w9z4Nz?`Qn1dM(GyZ`|J}7z)8SyGv${n&aLgGb zroiVTnIIzvIAA)97}Qn)9!bIi2GHa45=A)4jI2{BWV6E5JyJEGu0U%H_8=ZNY7FMo zBE|u0UtJ+*6i)stm22p6Gx1hdbw@d3zWc)L0WO(N(tW=pca-~Wl_U?qx>};Cc*wBAplqmeUMnJWGN~Kvl^G5MFadJZxsjW&b!fH5n{~dKn?aj8 z#R=|mkE8@}xN$IsC^9-Kf)&EY6?>xbie#5jkuZ=k7>#$PdSHakExbjiuTh$5<`t6~ z8uC`1zCe%byp4albvjQk1Hl4yN9XOlL+4iBsq-$rMdw@jHl5peH+Wv>Ah+v?)DE3q zp#i3;qmVHuROcc#bfk4B{Aht!-=uSwc%&E!s)Odbb>7Qiot|O@6;6(F4BV#kK91|0 z;G|9`IHmJ`KA=+{JqsQX8q@h8_sY&gI)8+BqgWLp8=Ze|=a1_AG5$D`t}xExlsk03 zlkd{`FizvUrTGM7?-BTb&eAzhiq7}&4wyPT6l;<89Y$PCycZc&t@C~G3*RrzCwYg) z59s_LKZFaD1Wg5sAYe>II%+BqKOe0p)cLRDYbG z$eNfrJ11v!`X0TZ^ONHBQ{tk>_$i%Ur|+VkUn$o_<R&1>%=pIYG*Day%nIoviU=<6OW0%pMz6x+ZBKGAG%eVh5qHYRt0o^p1+LoAum`| zjIxp+9=N%^Pl05bHztAz84~{ah z{(d8#+!D300-=pf|!V5HP#SqisvEEKU$n|r~{+v3(d)CD|ub^c`)P|!W zJZ@c$TN@hMY8#sBHs-%V^46($STv46y!it?b1fmGX(zBW7?DoNbi{qV3yk6K%ke6+62U!2t@RkSc`M~@TF@9|kq+`|gvyzh*$nS!_f1*s6h(|qGh*q4 zS8TY&JOmBx2jZsuUB+%E6mgV-`pkbg?1_p{|Cp}ZnY)TS`jdkkBF`GDYB-F8urQHd zetHv017)k&h{tnZ%=x4`slYHKE2<5{l!@N_hmct667#ZuO>&P&MUg6nEftTWpyZf3 zZ5T4@PX|`nTs6iw(P$EI=EMjoGWcfBGsPAfKo0AU5Km`v9O5~6i@e7juysNNXbiFLTXT!RZB|V_|JetRT zj>dVkG>!K-&QVz(jSDzc&*L2EquBw62l`Dsjy0<1PSYfh&ErVZ=a1{sTZD@1IdTzBaprsaNSNHMGsz}kI~18RPPSDQ=t)~ zyU;6Ay~F4gV`aDUsSWyUrMu}9KFFZ=Hvjqcazlf)W5 zaFI%CHG1$8O+tGS$~=?_gHI{YKRpP}uOL{**f9&71?OoBQ<{IK`m>#LG%aACxQf2+ z6ns3bXK8u>(1@RBv@UTLJx&tJOA!z0!ezeGo)@4v2OE5ysD?4h2*g;c5l4iNKnG{(kk%h4CiL)?;h~O~ZF4 zH6Tnk0n{b{wHbfVHPg-10(n~@qXql6!oAxdWjo;70VrDOe%hsAj8Q4}uBW4P3^M%y z{4?}f_;4vg;&b#cIU#8VJp!Oga84^dO2^^FgBg(R;>|&jj}3x+Y!KvQbRq-t0~wG7 z+TCQojKiEGK>fT%CpCJE=n_rm%Sb@S$R!H&%h1O@Y)*eBGGUMx11|YviWLL&V`!jB zk}OEmhkP&4)oGgBSiHnmZu6&U-YKf`mjjw>kflCBW`4lotMb^h0U{~sz1zlpmwzH$ zVL>uW3EYj)3IdLHs-O^6!ubLGUIhvhH?PN<3OMZvIKz(FiS#6T4l1MT=oH*+Q+b

U>n;P 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 Date: Thu, 11 Jun 2020 13:40:58 -0400 Subject: [PATCH 7/9] Gitignore class files produced by javac during linting --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4c78dc74..9e540d89 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ log integration/**/*.iml build.log .ruby-version +ext/*.class From 354a441556e757f1009273d0557d75f50934b9da Mon Sep 17 00:00:00 2001 From: Oleksiy Kovyrin Date: Thu, 11 Jun 2020 14:11:32 -0400 Subject: [PATCH 8/9] Coe quality fixes --- ext/ExplodedWarMain.java | 11 +++++++---- lib/warbler_jar.jar | Bin 27193 -> 27204 bytes 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index d9bc12ba..dae0b64d 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -71,7 +71,6 @@ protected int start() throws Exception { return 0; } - String[] arguments = argsList.subList(0, sIndex).toArray(new String[0]); String execArg = argsList.get(sIndex + 1); String[] executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); return launchCommand(execArg, executableArgv); @@ -320,12 +319,16 @@ private String[] launchWebServerArguments(Properties props) { public static URL[] loadJarUrls(File root) throws Exception { List jars = new ArrayList(); File libDir = new File(root, "lib"); + File[] libFiles = libDir.listFiles(); - for (File f : libDir.listFiles()) { - if (f.isFile() && f.getName().endsWith(".jar")) { - jars.add(f.toURI().toURL()); + if (libFiles != null) { + for (File f : libFiles) { + if (f.isFile() && f.getName().endsWith(".jar")) { + jars.add(f.toURI().toURL()); + } } } + return jars.toArray(new URL[jars.size()]); } diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index 841e6425f7a058d67770cbf8d95fdedbc5f1212c..9e9841b139c4fb62127e790ef8f715ce9298c583 100644 GIT binary patch delta 6874 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 Date: Thu, 11 Jun 2020 14:18:38 -0400 Subject: [PATCH 9/9] Remove a bunch of debug output --- ext/ExplodedWarMain.java | 19 ++++--------------- lib/warbler_jar.jar | Bin 27204 -> 26855 bytes 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/ext/ExplodedWarMain.java b/ext/ExplodedWarMain.java index dae0b64d..417d5d3e 100644 --- a/ext/ExplodedWarMain.java +++ b/ext/ExplodedWarMain.java @@ -45,12 +45,8 @@ public class ExplodedWarMain { // Constructor getting args from the system ExplodedWarMain(String[] arguments) throws IOException { this.arguments = arguments; - this.warRoot = new File(new File("./lib/war").getCanonicalPath()); - debug("Exploded WAR directory: " + warRoot.toString()); - this.webRoot = new File(warRoot, "/WEB-INF/"); - debug("Web Application root: " + webRoot.toString()); } //---------------------------------------------------------------------------------------------- @@ -64,13 +60,13 @@ protected int start() throws Exception { final List argsList = Arrays.asList(arguments); final int sIndex = argsList.indexOf("-S"); + // No command specified, so starting the web server by default if (sIndex == -1) { - debug("No command specified, starting a web server"); launchWebServer(); - debug("Started web server"); return 0; } + // Extract the command from the args list and launch it in jruby String execArg = argsList.get(sIndex + 1); String[] executableArgv = argsList.subList(sIndex + 2, argsList.size()).toArray(new String[0]); return launchCommand(execArg, executableArgv); @@ -85,10 +81,10 @@ private int launchCommand(String command, String[] commandArgs) throws Exception return 1; } - debug("Initializing JRuby scripting environment..."); + // Setup jruby environment in preparation for running the script initJRubyContainer(commandArgs); - debug("Launching jruby with command '" + command + "' and arguments: " + Arrays.toString(commandArgs)); + // Execute the ruby script return launchJRubyCommand(command, commandArgs); } @@ -105,7 +101,6 @@ protected int launchJRubyCommand(String command, String args[]) throws Exception final CharSequence execScriptEnvPre = executableScriptEnvPrefix(); // Load the command script and prepend it with the initialization code - debug("Loading command script: " + executablePath); Object executableInput = new SequenceInputStream( new ByteArrayInputStream(execScriptEnvPre.toString().getBytes()), (InputStream) invokeMethod(rubyInstanceConfig, "getScriptSource") @@ -113,8 +108,6 @@ protected int launchJRubyCommand(String command, String args[]) throws Exception // Finally, ask jruby to execute the script Object runtime = invokeMethod(jruby, "getRuntime"); - - debug("invoking " + executablePath + " with: " + Arrays.toString(args)); Object outcome = invokeMethod(runtime, "runFromMain", new Class[] { InputStream.class, String.class }, executableInput, @@ -200,10 +193,7 @@ protected static Object invokeMethod(final Object self, final String name, final protected CharSequence executableScriptEnvPrefix() { final String gemsDir = new File(webRoot, "gems").getAbsolutePath(); final String gemfile = new File(webRoot, "Gemfile").getAbsolutePath(); - System.out.println("setting GEM_HOME to " + gemsDir); - System.out.println("... and BUNDLE_GEMFILE to " + gemfile); - // ideally this would look up the config.override_gem_home setting return ( "ENV['GEM_HOME'] = ENV['GEM_PATH'] = '"+ gemsDir +"' \n" + "ENV['BUNDLE_GEMFILE'] ||= '"+ gemfile +"' \n" + @@ -232,7 +222,6 @@ protected void initJRubyContainer(String[] commandArgs) throws Exception { //---------------------------------------------------------------------------------------------- private Properties getWebserverProperties() throws Exception { File propsFilePath = new File(webRoot, "/webserver.properties"); - debug("Loading webserver properties file: " + propsFilePath); Properties props = new Properties(); try(InputStream propsStream = new FileInputStream(propsFilePath)) { diff --git a/lib/warbler_jar.jar b/lib/warbler_jar.jar index 9e9841b139c4fb62127e790ef8f715ce9298c583..b2726ec322156a8234ac3b56ba8041dda809195d 100644 GIT binary patch delta 6530 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 i