X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fbin%2FJalview.java;h=402f9bfcdba5ccc23927f06504d9cc9283c402d8;hb=ad16d6cce49a40ea1943431b980b85a6212bb9bf;hp=cc41c534d9899d85b3e4f8b5a6fe0d7723e0ee85;hpb=16d109024847af92482237e43f99b82fd997451a;p=jalview.git diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index cc41c53..402f9bf 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -20,9 +20,15 @@ */ package jalview.bin; +import jalview.api.AlignViewportI; +import jalview.api.JalviewApp; +import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; import jalview.ext.so.SequenceOntology; import jalview.gui.AlignFrame; import jalview.gui.Desktop; +import jalview.gui.Preferences; import jalview.gui.PromptUserConfig; import jalview.io.AppletFormatAdapter; import jalview.io.BioJsHTMLOutput; @@ -60,6 +66,9 @@ import java.security.Policy; import java.util.HashMap; import java.util.Map; import java.util.Vector; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.LookAndFeel; import javax.swing.UIManager; @@ -82,35 +91,75 @@ import groovy.util.GroovyScriptEngine; * @author $author$ * @version $Revision$ */ -public class Jalview +public class Jalview implements ApplicationSingletonI { - /* - * singleton instance of this class - */ - private static Jalview instance; + + public static Jalview getInstance() + { + return (Jalview) ApplicationSingletonProvider + .getInstance(Jalview.class); + } + + private Jalview() + { + } + + static + { + Platform.getURLCommandArguments(); + } + + private boolean headless; + + public static boolean isHeadlessMode() + { + return getInstance().headless; + } private Desktop desktop; - public static AlignFrame currentAlignFrame; + private AlignFrame currentAlignFrame; + + public boolean isJavaAppletTag; + + public String appletResourcePath; + + public static AlignFrame getCurrentAlignFrame() + { + return getInstance().currentAlignFrame; + } + + public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) + { + getInstance().currentAlignFrame = currentAlignFrame; + } static { - // grab all the rights we can the JVM - Policy.setPolicy(new Policy() + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ { - @Override - public PermissionCollection getPermissions(CodeSource codesource) + // grab all the rights we can for the JVM + Policy.setPolicy(new Policy() { - Permissions perms = new Permissions(); - perms.add(new AllPermission()); - return (perms); - } + @Override + public PermissionCollection getPermissions(CodeSource codesource) + { + Permissions perms = new Permissions(); + perms.add(new AllPermission()); + return (perms); + } - @Override - public void refresh() - { - } - }); + @Override + public void refresh() + { + } + }); + } } /** @@ -172,11 +221,6 @@ public class Jalview } - public static Jalview getInstance() - { - return instance; - } - /** * main class for Jalview application * @@ -185,8 +229,48 @@ public class Jalview */ public static void main(String[] args) { - instance = new Jalview(); - instance.doMain(args); + // setLogging(); // BH - for event debugging in JavaScript + getInstance().doMain(args); + } + + private static void logClass(String name) + { + // BH - for event debugging in JavaScript + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setLevel(Level.ALL); + Logger logger = Logger.getLogger(name); + logger.setLevel(Level.ALL); + logger.addHandler(consoleHandler); + } + + @SuppressWarnings("unused") + private static void setLogging() + { + + /** + * @j2sIgnore + * + */ + { + System.out.println("not in js"); + } + + // BH - for event debugging in JavaScript (Java mode only) + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ + { + Logger.getLogger("").setLevel(Level.ALL); + logClass("java.awt.EventDispatchThread"); + logClass("java.awt.EventQueue"); + logClass("java.awt.Component"); + logClass("java.awt.focus.Component"); + logClass("java.awt.focus.DefaultKeyboardFocusManager"); + } + } /** @@ -194,7 +278,12 @@ public class Jalview */ void doMain(String[] args) { - System.setSecurityManager(null); + + if (!Platform.isJS()) + { + System.setSecurityManager(null); + } + System.out .println("Java version: " + System.getProperty("java.version")); System.out.println(System.getProperty("os.arch") + " " @@ -202,45 +291,68 @@ public class Jalview + System.getProperty("os.version")); ArgsParser aparser = new ArgsParser(args); - boolean headless = false; - if (aparser.contains("help") || aparser.contains("h")) - { - showUsage(); - System.exit(0); - } - if (aparser.contains("nodisplay") || aparser.contains("nogui") - || aparser.contains("headless")) - { - System.setProperty("java.awt.headless", "true"); - headless = true; - } - String usrPropsFile = aparser.getValue("props"); - Cache.loadProperties(usrPropsFile); // must do this before - if (usrPropsFile != null) + String usrPropsFile = aparser.getValue(ArgsParser.PROPS); + Cache.loadProperties(usrPropsFile); + if (Platform.isJS()) { + isJavaAppletTag = aparser.isApplet(); + if (isJavaAppletTag) + { + Preferences.setAppletDefaults(); + Cache.loadProperties(usrPropsFile); // again, because we + // might be changing defaults here? + } System.out.println( - "CMD [-props " + usrPropsFile + "] executed successfully!"); + " found: " + aparser.getValue("Info.j2sAppletID")); + appletResourcePath = aparser.getValue("Info.resourcePath"); } - - // anything else! - - final String jabawsUrl = aparser.getValue("jabaws"); - if (jabawsUrl != null) + else + /** + * Java only + * + * @j2sIgnore + */ { - try + if (usrPropsFile != null) { - Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl); System.out.println( - "CMD [-jabaws " + jabawsUrl + "] executed successfully!"); - } catch (MalformedURLException e) + "CMD [-props " + usrPropsFile + "] executed successfully!"); + } + + if (aparser.contains("help") || aparser.contains("h")) { - System.err.println( - "Invalid jabaws parameter: " + jabawsUrl + " ignored"); + showUsage(); + System.exit(0); + } + if (aparser.contains(ArgsParser.NODISPLAY) + || aparser.contains(ArgsParser.NOGUI) + || aparser.contains(ArgsParser.HEADLESS) + || "true".equals(System.getProperty("java.awt.headless"))) + { + headless = true; + } + + // anything else! + + final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS); + if (jabawsUrl != null) + { + try + { + Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl); + System.out.println( + "CMD [-jabaws " + jabawsUrl + "] executed successfully!"); + } catch (MalformedURLException e) + { + System.err.println( + "Invalid jabaws parameter: " + jabawsUrl + " ignored"); + } } - } - String defs = aparser.getValue("setprop"); + } + // check for property setting + String defs = aparser.getValue(ArgsParser.SETPROP); while (defs != null) { int p = defs.indexOf('='); @@ -251,16 +363,12 @@ public class Jalview else { System.out.println("Executing setprop argument: " + defs); - // DISABLED FOR SECURITY REASONS - // TODO: add a property to allow properties to be overriden by cli args - // Cache.setProperty(defs.substring(0,p), defs.substring(p+1)); + if (Platform.isJS()) + { + Cache.setProperty(defs.substring(0, p), defs.substring(p + 1)); + } } - defs = aparser.getValue("setprop"); - } - if (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true")) - { - headless = true; + defs = aparser.getValue(ArgsParser.SETPROP); } System.setProperty("http.agent", "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown")); @@ -285,7 +393,7 @@ public class Jalview System.err.println("Unexpected Look and Feel Exception"); ex.printStackTrace(); } - if (Platform.isAMac()) + if (Platform.isAMacAndNotJS()) { LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager @@ -304,8 +412,9 @@ public class Jalview "Failed to set QuaQua look and feel: " + e.toString()); } } - if (lookAndFeel == null || !(lookAndFeel.getClass() - .isAssignableFrom(UIManager.getLookAndFeel().getClass())) + if (lookAndFeel == null + || !(lookAndFeel.getClass().isAssignableFrom( + UIManager.getLookAndFeel().getClass())) || !UIManager.getLookAndFeel().getClass().toString() .toLowerCase().contains("quaqua")) { @@ -328,83 +437,93 @@ public class Jalview */ if (Cache.getDefault("USE_FULL_SO", false)) { - SequenceOntologyFactory.setInstance(new SequenceOntology()); + SequenceOntologyFactory.setSequenceOntology(new SequenceOntology()); } if (!headless) { - desktop = new Desktop(); + desktop = Desktop.getInstance(); desktop.setInBatchMode(true); // indicate we are starting up desktop.setVisible(true); - desktop.startServiceDiscovery(); - if (!aparser.contains("nousagestats")) - { - startUsageStats(desktop); - } - else - { - System.err.println("CMD [-nousagestats] executed successfully!"); - } - if (!aparser.contains("noquestionnaire")) + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ { - String url = aparser.getValue("questionnaire"); - if (url != null) + desktop.startServiceDiscovery(); + if (!aparser.contains(ArgsParser.NOUSAGESTATS)) { - // Start the desktop questionnaire prompter with the specified - // questionnaire - Cache.log.debug("Starting questionnaire url at " + url); - desktop.checkForQuestionnaire(url); - System.out.println( - "CMD questionnaire[-" + url + "] executed successfully!"); + startUsageStats(desktop); } else { - if (Cache.getProperty("NOQUESTIONNAIRES") == null) + System.err.println("CMD [-nousagestats] executed successfully!"); + } + + if (!aparser.contains(ArgsParser.NOQUESTIONNAIRE)) + { + String url = aparser.getValue(ArgsParser.QUESTIONNAIRE); + if (url != null) { // Start the desktop questionnaire prompter with the specified // questionnaire - // String defurl = - // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl"; - // // - String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl"; - Cache.log.debug( - "Starting questionnaire with default url: " + defurl); - desktop.checkForQuestionnaire(defurl); + Cache.log.debug("Starting questionnaire url at " + url); + desktop.checkForQuestionnaire(url); + System.out.println("CMD questionnaire[-" + url + + "] executed successfully!"); + } + else + { + if (Cache.getProperty("NOQUESTIONNAIRES") == null) + { + // Start the desktop questionnaire prompter with the specified + // questionnaire + // String defurl = + // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl"; + // // + String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl"; + Cache.log.debug( + "Starting questionnaire with default url: " + defurl); + desktop.checkForQuestionnaire(defurl); + } } } - } - else - { - System.err.println("CMD [-noquestionnaire] executed successfully!"); - } + else + { + System.err + .println("CMD [-noquestionnaire] executed successfully!"); + } - if (!aparser.contains("nonews")) - { - desktop.checkForNews(); - } + if (!aparser.contains(ArgsParser.NONEWS)) + { + desktop.checkForNews(); + } - BioJsHTMLOutput.updateBioJS(); + BioJsHTMLOutput.updateBioJS(); + } } - String file = null, data = null; + String data = null; FileFormatI format = null; DataSourceType protocol = null; FileLoader fileLoader = new FileLoader(!headless); - String groovyscript = null; // script to execute after all loading is + // script to execute after all loading is // completed one way or another // extract groovy argument and execute if necessary - groovyscript = aparser.getValue("groovy", true); - file = aparser.getValue("open", true); + String groovyscript = aparser.getValue(ArgsParser.GROOVY, true); + String file = aparser.getValue(ArgsParser.OPEN, true); if (file == null && desktop == null) { System.out.println("No files to open!"); System.exit(1); } - String vamsasImport = aparser.getValue("vdoc"); - String vamsasSession = aparser.getValue("vsess"); + String vamsasImport = aparser.getValue(ArgsParser.VDOC); + String vamsasSession = aparser.getValue(ArgsParser.VSESS); if (vamsasImport != null || vamsasSession != null) { if (desktop == null || headless) @@ -501,14 +620,24 @@ public class Jalview } System.out.println("CMD [-open " + file + "] executed successfully!"); - if (!file.startsWith("http://")) + if (!Platform.isJS()) + /** + * ignore in JavaScript -- can't just check file existence - could load + * it? + * + * @j2sIgnore + */ { - if (!(new File(file)).exists()) + if (!file.startsWith("http://") && !file.startsWith("https://")) + // BH 2019 added https check for Java { - System.out.println("Can't find " + file); - if (headless) + if (!(new File(file)).exists()) { - System.exit(1); + System.out.println("Can't find " + file); + if (headless) + { + System.exit(1); + } } } } @@ -532,14 +661,13 @@ public class Jalview else { setCurrentAlignFrame(af); - data = aparser.getValue("colour", true); + data = aparser.getValue(ArgsParser.COLOUR, true); if (data != null) { data.replaceAll("%20", " "); - ColourSchemeI cs = ColourSchemeProperty - .getColourScheme(af.getViewport(), - af.getViewport().getAlignment(), data); + ColourSchemeI cs = ColourSchemeProperty.getColourScheme( + af.getViewport(), af.getViewport().getAlignment(), data); if (cs != null) { @@ -550,7 +678,7 @@ public class Jalview } // Must maintain ability to use the groups flag - data = aparser.getValue("groups", true); + data = aparser.getValue(ArgsParser.GROUPS, true); if (data != null) { af.parseFeaturesFile(data, @@ -559,7 +687,7 @@ public class Jalview System.out.println( "CMD groups[-" + data + "] executed successfully!"); } - data = aparser.getValue("features", true); + data = aparser.getValue(ArgsParser.FEATURES, true); if (data != null) { af.parseFeaturesFile(data, @@ -569,7 +697,7 @@ public class Jalview "CMD [-features " + data + "] executed successfully!"); } - data = aparser.getValue("annotations", true); + data = aparser.getValue(ArgsParser.ANNOTATIONS, true); if (data != null) { af.loadJalviewDataFile(data, null, null, null); @@ -578,7 +706,7 @@ public class Jalview "CMD [-annotations " + data + "] executed successfully!"); } // set or clear the sortbytree flag. - if (aparser.contains("sortbytree")) + if (aparser.contains(ArgsParser.SORTBYTREE)) { af.getViewport().setSortByTree(true); if (af.getViewport().getSortByTree()) @@ -586,7 +714,8 @@ public class Jalview System.out.println("CMD [-sortbytree] executed successfully!"); } } - if (aparser.contains("no-annotation")) + if (aparser.contains(ArgsParser.NOANNOTATION) + || aparser.contains(ArgsParser.NOANNOTATION2)) { af.getViewport().setShowAnnotation(false); if (!af.getViewport().isShowAnnotation()) @@ -594,7 +723,7 @@ public class Jalview System.out.println("CMD no-annotation executed successfully!"); } } - if (aparser.contains("nosortbytree")) + if (aparser.contains(ArgsParser.NOSORTBYTREE)) { af.getViewport().setSortByTree(false); if (!af.getViewport().getSortByTree()) @@ -603,7 +732,7 @@ public class Jalview .println("CMD [-nosortbytree] executed successfully!"); } } - data = aparser.getValue("tree", true); + data = aparser.getValue(ArgsParser.TREE, true); if (data != null) { try @@ -633,89 +762,103 @@ public class Jalview + "] executed successfully!"); groovyscript = null; } - String imageName = "unnamed.png"; - while (aparser.getSize() > 1) + + if (isJavaAppletTag) + { + loadAppletParams(aparser, af); + } + else { - String outputFormat = aparser.nextValue(); - file = aparser.nextValue(); - if (outputFormat.equalsIgnoreCase("png")) - { - af.createPNG(new File(file)); - imageName = (new File(file)).getName(); - System.out.println("Creating PNG image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("svg")) + String imageName = "unnamed.png"; + while (aparser.getSize() > 1) { - File imageFile = new File(file); - imageName = imageFile.getName(); - af.createSVG(imageFile); - System.out.println("Creating SVG image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("html")) - { - File imageFile = new File(file); - imageName = imageFile.getName(); - HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); - htmlSVG.exportHTML(file); + // PNG filename + // SVG filename + // HTML filename + // biojsmsa filename + String outputFormat = aparser.nextValue(); + file = aparser.nextValue(); + + if (outputFormat.equalsIgnoreCase("png")) + { + af.createPNG(new File(file)); + imageName = (new File(file)).getName(); + System.out.println("Creating PNG image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("svg")) + { + File imageFile = new File(file); + imageName = imageFile.getName(); + af.createSVG(imageFile); + System.out.println("Creating SVG image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("html")) + { + File imageFile = new File(file); + imageName = imageFile.getName(); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); + htmlSVG.exportHTML(file); - System.out.println("Creating HTML image: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("biojsmsa")) - { - if (file == null) + System.out.println("Creating HTML image: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("biojsmsa")) { - System.err.println("The output html file must not be null"); - return; + if (file == null) + { + System.err.println("The output html file must not be null"); + return; + } + try + { + BioJsHTMLOutput.refreshVersionInfo( + BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); + } catch (URISyntaxException e) + { + e.printStackTrace(); + } + BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); + bjs.exportHTML(file); + System.out.println( + "Creating BioJS MSA Viwer HTML file: " + file); + continue; } - try + else if (outputFormat.equalsIgnoreCase("imgMap")) { - BioJsHTMLOutput.refreshVersionInfo( - BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); - } catch (URISyntaxException e) + af.createImageMap(new File(file), imageName); + System.out.println("Creating image map: " + file); + continue; + } + else if (outputFormat.equalsIgnoreCase("eps")) { - e.printStackTrace(); + File outputFile = new File(file); + System.out.println( + "Creating EPS file: " + outputFile.getAbsolutePath()); + af.createEPS(outputFile); + continue; + } + + af.saveAlignment(file, format); + if (af.isSaveAlignmentSuccessful()) + { + System.out.println("Written alignment in " + format + + " format to " + file); + } + else + { + System.out.println("Error writing file " + file + " in " + + format + " format!!"); } - BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); - bjs.exportHTML(file); - System.out - .println("Creating BioJS MSA Viwer HTML file: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("imgMap")) - { - af.createImageMap(new File(file), imageName); - System.out.println("Creating image map: " + file); - continue; - } - else if (outputFormat.equalsIgnoreCase("eps")) - { - File outputFile = new File(file); - System.out.println( - "Creating EPS file: " + outputFile.getAbsolutePath()); - af.createEPS(outputFile); - continue; - } - if (af.saveAlignment(file, format)) - { - System.out.println("Written alignment in " + format - + " format to " + file); } - else + + while (aparser.getSize() > 0) { - System.out.println("Error writing file " + file + " in " - + format + " format!!"); + System.out.println("Unknown arg: " + aparser.nextValue()); } - - } - - while (aparser.getSize() > 0) - { - System.out.println("Unknown arg: " + aparser.nextValue()); } } } @@ -724,8 +867,14 @@ public class Jalview // And the user // //////////////////// - if (!headless && file == null && vamsasImport == null + if (!Platform.isJS() && !headless && file == null + && vamsasImport == null && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true)) + /** + * Java only + * + * @j2sIgnore + */ { file = jalview.bin.Cache.getDefault("STARTUP_FILE", jalview.bin.Cache.getDefault("www.jalview.org", @@ -843,8 +992,9 @@ public class Jalview /** * start a User Config prompt asking if we can log usage statistics. */ - PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop, - "USAGESTATS", "Jalview Usage Statistics", + PromptUserConfig prompter = new PromptUserConfig( + Desktop.getDesktopPane(), "USAGESTATS", + "Jalview Usage Statistics", "Do you want to help make Jalview better by enabling " + "the collection of usage statistics with Google Analytics ?" + "\n\n(you can enable or disable usage tracking in the preferences)", @@ -987,16 +1137,6 @@ public class Jalview } } - public static boolean isHeadlessMode() - { - String isheadless = System.getProperty("java.awt.headless"); - if (isheadless != null && isheadless.equalsIgnoreCase("true")) - { - return true; - } - return false; - } - public AlignFrame[] getAlignFrames() { return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() } @@ -1020,13 +1160,132 @@ public class Jalview } } - public static AlignFrame getCurrentAlignFrame() + /** + * Get the SwingJS applet ID and combine that with the frameType + * + * @param frameType + * "alignment", "desktop", etc., or null + * @return + */ + public static String getAppID(String frameType) { - return Jalview.currentAlignFrame; + String id = Cache.getProperty("Info.j2sAppletID"); + if (id == null) + { + id = "jalview"; + } + return id + (frameType == null ? "" : "-" + frameType); } - public static void setCurrentAlignFrame(AlignFrame currentAlignFrame) + private void loadAppletParams(ArgsParser aparser, AlignFrame af) { - Jalview.currentAlignFrame = currentAlignFrame; + Jalview me = this; + JalviewApp app = new JalviewApp() + { + + + @Override + public String getParameter(String name) + { + return aparser.getAppletValue(name, null); + } + + @Override + public boolean getDefaultParameter(String name, boolean def) + { + String stn; + return ((stn = getParameter(name)) == null ? def + : "true".equalsIgnoreCase(stn)); + } + + @Override + public URL getDocumentBase() + { + return Platform.getDocumentBase(); + } + + @Override + public URL getCodeBase() + { + return Platform.getCodeBase(); + } + + @Override + public AlignViewportI getViewport() + { + return Jalview.getCurrentAlignFrame().getViewport(); + } + + @Override + public boolean loadScoreFile(String sScoreFile) throws IOException + { + Jalview.getCurrentAlignFrame().loadJalviewDataFile(sScoreFile, null, + null, null); + return true; + } + + @Override + public boolean parseFeaturesFile(String filename, + DataSourceType protocol) + { + return af.parseFeaturesFile(filename, protocol); + } + + @Override + public void loadTree(NewickFile fin, String treeFile) + throws IOException + { + // n/a -- already done + } + + @Override + public void setAlignPdbStructures(boolean defaultParameter) + { + // TODO Auto-generated method stub + + } + + @Override + public void newStructureView(PDBEntry pdb, SequenceI[] seqs, + String[] chains, DataSourceType protocol) + { + // TODO Auto-generated method stub + + } + + @Override + public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs, + String[][] chains, String[] protocols) + { + // TODO Auto-generated method stub + + } + + @Override + public void updateForLoader() + { + // TODO Auto-generated method stub + + } + + @Override + public void setFeatureGroupState(String[] groups, boolean state) + { + // TODO Auto-generated method stub + + } + + @Override + public void newFeatureSettings() + { + // TODO Auto-generated method stub + + } + + }; + + new JalviewAppLoader(true).load(app); + } + }