JAL-3225 JAL-3196 JAL-3179 JAL-3227 JAL-3228 JAL-3229 JAL-3007 JAL-3111 Jalview 2.11 gradle/Java 11 build is now main develop branch
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="utils"/>
- <classpathentry kind="src" path="test"/>
- <classpathentry kind="lib" path="lib/activation.jar"/>
- <classpathentry kind="lib" path="lib/axis.jar" sourcepath="D:/axis-1_2RC2-src/axis-1_2RC2"/>
- <classpathentry kind="lib" path="lib/commons-discovery.jar"/>
- <classpathentry kind="lib" path="lib/jaxrpc.jar"/>
- <classpathentry kind="lib" path="lib/jhall.jar"/>
- <classpathentry kind="lib" path="lib/mail.jar"/>
- <classpathentry kind="lib" path="lib/regex.jar"/>
- <classpathentry kind="lib" path="lib/saaj.jar"/>
- <classpathentry kind="lib" path="lib/wsdl4j.jar"/>
- <classpathentry kind="lib" path="lib/xercesImpl.jar"/>
- <classpathentry kind="lib" path="lib/JGoogleAnalytics_0.3.jar" sourcepath="/JGoogleAnalytics/src/main/java"/>
- <classpathentry kind="lib" path="lib/vamsas-client.jar"/>
- <classpathentry kind="lib" path="lib/commons-logging-1.1.1.jar"/>
- <classpathentry kind="lib" path="lib/apache-mime4j-0.6.jar" sourcepath="G:/InstallsDir/Sources for Development/apache-mime4j-0.6-src.zip"/>
- <classpathentry kind="lib" path="lib/httpclient-4.0.3.jar">
- <attributes>
- <attribute name="javadoc_location" value="file:/D:/InstallsDir/Sources for Development/httpconnect/httpcomponents-client-4.0.3/javadoc/"/>
- </attributes>
- </classpathentry>
- <classpathentry kind="lib" path="lib/httpcore-4.0.1.jar">
- <attributes>
- <attribute name="javadoc_location" value="file:/D:/InstallsDir/Sources for Development/httpconnect/httpcomponents-client-4.0.3/javadoc/"/>
- </attributes>
- </classpathentry>
- <classpathentry kind="lib" path="lib/httpmime-4.0.3.jar">
- <attributes>
- <attribute name="javadoc_location" value="file:/D:/InstallsDir/Sources for Development/httpconnect/httpcomponents-client-4.0.3/javadoc/"/>
- </attributes>
- </classpathentry>
- <classpathentry kind="lib" path="lib/miglayout-4.0-swing.jar"/>
- <classpathentry kind="lib" path="lib/jswingreader-0.3.jar" sourcepath="/jswingreader"/>
- <classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
- <classpathentry kind="lib" path="lib/jabaws-min-client-2.2.0.jar" sourcepath="/clustengine"/>
- <classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
- <classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
- <classpathentry kind="lib" path="lib/jsoup-1.8.1.jar"/>
- <classpathentry kind="lib" path="lib/log4j-to-slf4j-2.0-rc2.jar"/>
- <classpathentry kind="lib" path="lib/slf4j-log4j12-1.7.7.jar"/>
- <classpathentry kind="lib" path="lib/VARNAv3-93.jar"/>
- <classpathentry kind="lib" path="lib/jfreesvg-2.1.jar"/>
- <classpathentry kind="lib" path="lib/quaqua-filechooser-only-8.0.jar"/>
- <classpathentry kind="lib" path="lib/VAqua5-patch.jar"/>
- <classpathentry kind="lib" path="utils/classgraph-4.1.6.jar"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/plugin"/>
- <classpathentry kind="lib" path="lib/xml-apis.jar"/>
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Plugin.jar"/>
- <classpathentry kind="lib" path="lib/jersey-client-1.19.jar"/>
- <classpathentry kind="lib" path="lib/jersey-core-1.19.jar"/>
- <classpathentry kind="lib" path="lib/jsr311-api-1.1.1.jar"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/plugin.jar"/>
- <classpathentry kind="lib" path="lib/jetty-server-9.2.10.v20150310.jar"/>
- <classpathentry kind="lib" path="lib/servlet-api-3.1.jar"/>
- <classpathentry kind="lib" path="lib/jetty-util-9.2.10.v20150310.jar"/>
- <classpathentry kind="lib" path="lib/jetty-http-9.2.10.v20150310.jar"/>
- <classpathentry kind="lib" path="lib/jetty-io-9.2.10.v20150310.jar"/>
- <classpathentry kind="lib" path="lib/java-json.jar"/>
- <classpathentry kind="lib" path="lib/Jmol-14.6.4_2016.10.26.jar"/>
- <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
- <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
- <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
- <classpathentry kind="lib" path="lib/htsjdk-2.12.0.jar"/>
- <classpathentry kind="lib" path="lib/groovy-all-2.4.12-indy.jar"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
- <classpathentry kind="lib" path="lib/intervalstore-v1.0.jar"/>
- <classpathentry kind="output" path="classes"/>
+ <classpathentry kind="output" path="bin/default"/>
+ <classpathentry output="bin/main" kind="src" path="src">
+ <attributes>
+ <attribute name="gradle_scope" value="main"/>
+ <attribute name="gradle_used_by_scope" value=""/>
+ </attributes>
+ </classpathentry>
+ <classpathentry output="bin/main" kind="src" path="resources">
+ <attributes>
+ <attribute name="gradle_scope" value="main"/>
+ <attribute name="gradle_used_by_scope" value=""/>
+ </attributes>
+ </classpathentry>
+ <classpathentry output="bin/test" kind="src" path="test">
+ <attributes>
+ <attribute name="gradle_scope" value="test"/>
+ <attribute name="gradle_used_by_scope" value=""/>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
+ <classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
+ <classpathentry kind="output" path="bin/main"/>
+ <classpathentry kind="lib" path="j11lib/jsoup-1.8.1.jar"/>
+ <classpathentry kind="lib" path="j11lib/jswingreader-0.3.jar"/>
+ <classpathentry kind="lib" path="j11lib/mail-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.servlet-api-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/httpclient-4.0.3.jar"/>
+ <classpathentry kind="lib" path="j11lib/regex.jar"/>
+ <classpathentry kind="lib" path="j11lib/getdown-core.jar"/>
+ <classpathentry kind="lib" path="j11lib/policy.jar"/>
+ <classpathentry kind="lib" path="j11lib/jaxb-api-java9.jar"/>
+ <classpathentry kind="lib" path="j11lib/JGoogleAnalytics_0.3.jar"/>
+ <classpathentry kind="lib" path="j11lib/jetty-http-9.2.10.v20150310.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.activation-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/commons-logging-1.1.1.jar"/>
+ <classpathentry kind="lib" path="j11lib/slf4j-log4j12-1.7.7.jar"/>
+ <classpathentry kind="lib" path="j11lib/miglayout-4.0-swing.jar"/>
+ <classpathentry kind="lib" path="j11lib/txw2.jar"/>
+ <classpathentry kind="lib" path="j11lib/quaqua-filechooser-only-8.0.jar"/>
+ <classpathentry kind="lib" path="j11lib/VARNAv3-93.jar"/>
+ <classpathentry kind="lib" path="j11lib/groovy-2.5.6.jar"/>
+ <classpathentry kind="lib" path="j11lib/jersey-client-1.19.jar"/>
+ <classpathentry kind="lib" path="j11lib/jaxb-runtime.jar"/>
+ <classpathentry kind="lib" path="j11lib/commons-discovery.jar"/>
+ <classpathentry kind="lib" path="j11lib/slf4j-api-1.7.7.jar"/>
+ <classpathentry kind="lib" path="j11lib/VAqua5-patch.jar"/>
+ <classpathentry kind="lib" path="j11lib/jaxws-api.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.xml.soap-api.jar"/>
+ <classpathentry kind="lib" path="j11lib/libquaqua-8.0.jnilib.jar"/>
+ <classpathentry kind="lib" path="j11lib/istack-commons-runtime.jar"/>
+ <classpathentry kind="lib" path="j11lib/jersey-json-1.19.jar"/>
+ <classpathentry kind="lib" path="j11lib/stax-ex.jar"/>
+ <classpathentry kind="lib" path="j11lib/httpmime-4.0.3.jar"/>
+ <classpathentry kind="lib" path="j11lib/biojava-core-4.1.0.jar"/>
+ <classpathentry kind="lib" path="j11lib/libquaqua64-8.0.jnilib.jar"/>
+ <classpathentry kind="lib" path="j11lib/jabaws-min-client-2.2.0.jar"/>
+ <classpathentry kind="lib" path="j11lib/jetty-io-9.2.10.v20150310.jar"/>
+ <classpathentry kind="lib" path="j11lib/intervalstore-v1.0.jar"/>
+ <classpathentry kind="lib" path="j11lib/htsjdk-2.12.0.jar"/>
+ <classpathentry kind="lib" path="j11lib/groovy-console-2.5.6.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.ws.rs-api-2.1.1.jar"/>
+ <classpathentry kind="lib" path="j11lib/commons-codec-1.3.jar"/>
+ <classpathentry kind="lib" path="j11lib/jaxws-rt-java9.jar"/>
+ <classpathentry kind="lib" path="j11lib/vamsas-client.jar"/>
+ <classpathentry kind="lib" path="j11lib/saaj-impl.jar"/>
+ <classpathentry kind="lib" path="j11lib/jetty-server-9.2.10.v20150310.jar"/>
+ <classpathentry kind="lib" path="j11lib/jetty-util-9.2.10.v20150310.jar"/>
+ <classpathentry kind="lib" path="j11lib/xercesImpl.jar"/>
+ <classpathentry kind="lib" path="j11lib/Jmol-14.6.4_2016.10.26-no_netscape.jar"/>
+ <classpathentry kind="lib" path="j11lib/FastInfoset.jar"/>
+ <classpathentry kind="lib" path="j11lib/commons-compress-1.18.jar"/>
+ <classpathentry kind="lib" path="j11lib/biojava-ontology-4.1.0.jar"/>
+ <classpathentry kind="lib" path="j11lib/log4j-to-slf4j-2.0-rc2.jar"/>
+ <classpathentry kind="lib" path="j11lib/jersey-core-1.19.jar"/>
+ <classpathentry kind="lib" path="j11lib/wsdl4j-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/httpcore-4.0.1.jar"/>
+ <classpathentry kind="lib" path="j11lib/jhall.jar"/>
+ <classpathentry kind="lib" path="j11lib/stax2-api-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/gmbal-api-only-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.jws-api-1.1.jar"/>
+ <classpathentry kind="lib" path="j11lib/axis.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.xml.rpc-api-1.1.2.jar"/>
+ <classpathentry kind="lib" path="j11lib/javax.annotation-api-MODULE.jar"/>
+ <classpathentry kind="lib" path="j11lib/java-json.jar"/>
+ <classpathentry kind="lib" path="j11lib/mimepull.jar"/>
+ <classpathentry kind="lib" path="j11lib/jfreesvg-2.1.jar"/>
+ <classpathentry kind="lib" path="j11lib/streambuffer.jar"/>
+ <classpathentry kind="lib" path="j11lib/apache-mime4j-0.6.jar"/>
+ <classpathentry kind="lib" path="j11lib/json_simple-1.1.jar"/>
+ <classpathentry kind="lib" path="utils/proguard_5.3.3.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/junit-4.12.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/wsdl4j.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/axis-ant.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/classgraph-4.1.6.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/testng-sources.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/jcommander.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/snakeyaml.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/junit-4.12.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/bsh-2.0b4.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/testng.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/guava-collections-r03.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/testnglibs/guava-base-r03.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/jhindexer.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/ant-contrib-1.0b3.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/hamcrest-core-1.3.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/roxes-ant-tasks-1.2-2004-01-30.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="lib" path="utils/jhall.jar">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
</classpath>
/*.project
-.classpath
+/.classpath
+/.settings/org.eclipse.jdt.core.prefs
/dist
/clover
/classes
/test-reports
/test-output
.externalToolBuilders/*
-.settings/*
/.DS_Store
.DS_Store
/.com.apple.timemachine.supported
/benchmarking/lib
*.class
/site
+/.gradle
+/build
+/utils/HelpLinksChecker.out
+/getdown/website
+/getdown/full_app
+/getdown/files
+/utils/install4j/jalview-installers-*.install4j
+*.swp
+/bin
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>Jalview Release 2.7</name>
+ <name>Jalview with gradle build</name>
<comment></comment>
- <projects>
- </projects>
+ <projects/>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
+ <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
+ </natures>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.wst.common.project.facet.core.builder</name>
- <arguments>
- </arguments>
+ <arguments/>
</buildCommand>
<buildCommand>
- <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
- <triggers>full,incremental,</triggers>
- <arguments>
- <dictionary>
- <key>LaunchConfigHandle</key>
- <value><project>/.externalToolBuilders/Jalview Release indices [Builder].launch</value>
- </dictionary>
- </arguments>
+ <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
+ <arguments/>
</buildCommand>
</buildSpec>
- <natures>
- <nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
- <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
- <nature>de.tud.st.ispace.builder.ISpaceNature</nature>
- <nature>org.eclipse.jem.beaninfo.BeanInfoNature</nature>
- </natures>
+ <linkedResources/>
+ <filteredResources/>
</projectDescription>
--- /dev/null
+connection.project.dir=
+eclipse.preferences.version=1
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=52
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=next_line_on_wrap
+org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=false
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=4
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=8
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=76
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.8
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.8
-org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=52
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
-org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
-org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+#
+#Thu Apr 25 12:37:19 BST 2019
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_after_package=1
-org.eclipse.jdt.core.formatter.blank_lines_before_field=1
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=0
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=next_line_on_wrap
-org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=false
-org.eclipse.jdt.core.formatter.comment.format_header=false
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=true
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
-org.eclipse.jdt.core.formatter.comment.line_length=80
-org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
-org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
-org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
-org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=4
-org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.indentation.size=8
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.continuation_indentation=4
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
-org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
-org.eclipse.jdt.core.formatter.indentation.size=8
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+eclipse.preferences.version=1
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=52
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.comment.format_block_comments=false
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=next_line_on_wrap
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
-org.eclipse.jdt.core.formatter.join_wrapped_lines=true
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=true
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=76
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=2
-org.eclipse.jdt.core.formatter.use_on_off_tags=true
-org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
-org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.lineSplit=76
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
--- /dev/null
+eclipse.preferences.version=1
+groovy.compiler.level=25
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Jalview
-formatter_settings_version=12
+formatter_settings_version=16
org.eclipse.jdt.ui.ignorelowercasenames=true
org.eclipse.jdt.ui.importorder=jalview;java;javax;org;com;
org.eclipse.jdt.ui.ondemandthreshold=99
--- /dev/null
+Java 11 module replacements
+
+As Java 11 no longer ships with Java EE libraries, which were standard in Java 8, and available (modularised, through the --add-modules CLI mechanism) in Java 9 and 10, third party replacement libraries for these libraries/modules have to be found.
+
+Ideally, these jar files would be packaged as modules (i.e. would contains a module-info.class with the relevant provision and requirements information for that module package). However, as at time of writing (end Nov 2018) the available packages are not fully mature.
+There also seems to be no single place to look when trying to obtain modules jar files.
+
+A couple of good places to start:
+https://javaee.github.io/
+(see Metro, Glassfish etc)
+
+https://search.maven.org/
+(search for e.g. a:javax.activation)
+
+https://mvnrepository.com/
+(if the other two fail!)
+
+Unfortunately there seems to be multiple projects providing the same modules, with little indication of which is "best".
+Here's an example of what to do with search.maven.org, looking for, say, the java.activation module
+
+Firstly, remember this might be called javax.activation (in fact it is), so searching for
+
+a:javax.activation
+
+shows 3 possible candidates.
+
+The "Updated" date gives a clue if a library might be up-to-date or still being maintained, and of the three listed, com.sun.activation version 1.2.0 was updated in Sep 2017, and is the only one updated in the last 5 years, so it looks like a good candidate.
+Click on the arrow in the Download column which gives various download options. Choose "jar" and this should download straight away.
+
+If you have a peek inside the jar file:
+
+$ jar -tvf ~/Downloads/javax.activation-1.2.0.jar
+
+ 0 Wed Sep 06 16:13:08 BST 2017 META-INF/
+ 1307 Wed Sep 06 16:13:06 BST 2017 META-INF/MANIFEST.MF
+ 0 Wed Sep 06 14:23:50 BST 2017 javax/
+ 0 Wed Sep 06 14:23:50 BST 2017 javax/activation/
+ 0 Wed Sep 06 14:23:50 BST 2017 com/
+ 0 Wed Sep 06 14:23:50 BST 2017 com/sun/
+ 0 Wed Sep 06 14:23:50 BST 2017 com/sun/activation/
+...
+ 2238 Wed Sep 06 14:23:50 BST 2017 com/sun/activation/registries/LineTokenizer.class
+ 39394 Wed Sep 06 16:13:06 BST 2017 META-INF/LICENSE.txt
+ 581 Wed Sep 06 16:13:06 BST 2017 META-INF/mimetypes.default
+ 292 Wed Sep 06 16:13:06 BST 2017 META-INF/mailcap.default
+ 0 Wed Sep 06 16:13:08 BST 2017 META-INF/maven/
+ 0 Wed Sep 06 16:13:08 BST 2017 META-INF/maven/com.sun.activation/
+ 0 Wed Sep 06 16:13:08 BST 2017 META-INF/maven/com.sun.activation/javax.activation/
+ 6515 Fri Sep 01 16:13:04 BST 2017 META-INF/maven/com.sun.activation/javax.activation/pom.xml
+ 119 Wed Sep 06 14:23:52 BST 2017 META-INF/maven/com.sun.activation/javax.activation/pom.properties
+
+
+you can see that it doesn't have a module-info.class file, meaning it can only be used as an "automatic" module. This will probably mean it can't be used with jlink when creating a JRE.
+HAVE NO FEAR!
+We can semi-manually (urgh!) create a module-info.class for this library and turn it into a module. This really should be scripted. I might just do it.
+
+So, assuming we downloaded that jar to ~/Downloads/javax.activation-1.2.0.jar, and JAVA_HOME is set to a java distribution, we can do:
+
+mkdir tmp
+cd tmp
+jar -xvf ~/Downloads/javax.activation-1.2.0.jar
+jdeps --generate-module-info . ~/Downloads/javax.activation-1.2.0.jar
+# --generate-module-info creates the module-info.java file we are looking for! but for some reason insists on sticking it in a java.activation subdir (even though we ask for '.')
+mv java.activation/module-info.java .
+rmdir java.activation
+javac -d . module-info.java
+# we could clean up (rm) module-info.java, but I think it'll be more useful to keep a hold of it in the jar, it's not causing a problem or taking up space
+cd ..
+jar -cvf javax.activation-1.2.0-MODULE.jar -C ./tmp .
+/bin/rm -rf ./tmp
+
+and voila, you have a modulified version of the library in the jar file ./javax.activation-1.2.0-MODULE.jar. This can be used with jlink.
+[ timeout: I scripted this as utils/modulify.sh Usage: modulify.sh /path/to/jarfile.jar ... creates /path/to/jarfile-MODULE.jar ]
+
+Once we have enough modulified jar files (note, we kind of keep downloading a new file or files until jalview starts without Exceptions, jdeps could probably provide a better way(!), and jaxws-rt provides quite a few of the needed jar files, hopefully in a coherent way).
+
+A list of module dependencies can be found with (note module-path doesn't need jar files, just the dirs to look in, unlike class-path)
+
+jdeps --class-path="lib/*:j11lib/*" --module-path="$JAVA_HOME/jmods:j11lib" --list-deps dist/jalview.jar libs/*.jar
+
+will end with a list of modules required in the JRE, these need to be comma-separated-listed for jlink. We /ought/ to be able to do this by using "--print-module-deps" like this
+
+jdeps --class-path="lib/*:j11lib/*" --module-path="$JAVA_HOME/jmods:j11lib" --print-module-deps dist/jalview.jar libs/*.jar
+
+but that ends with an Exception. Perhaps should look into that...
+
+Anyway, with the list of modules required (in the file "modules") you can do
+
+jlink --module-path $JAVA_HOME/jmods:j11lib --compress=2 --add-modules `cat modules` --no-header-files --no-man-pages --bind-services --output j11jre/openjdk11_platform
+
+To create a Java 11 JRE in j11jre/openjdk11_platform (or whatever you wish to call it).
+You can point JAVA_HOME at the JDK11 of a different platform, so long as the jlink in your path is to the jlink for the platform you're running on.
+
+
--- /dev/null
+YEAR=2018
+AUTHORS=J Procter, M Carstairs, B Soares, K Mourao, TC Ofoegbu, AM Waterhouse, J Engelhardt, LM Lui, A Menard, D Barton, N Sherstnev, D Roldan-Martinez, M Clamp, S Searle, G Barton
+AUTHORFNAMES=Jim Procter, Mungo Carstairs, Ben Soares, Kira Mourao, Tochukwu 'Charles' Ofoegbu, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Anne Menard, Daniel Barton, Natasha Sherstnev, David Roldan-Martinez, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
+
\ No newline at end of file
--- /dev/null
+import org.apache.tools.ant.filters.ReplaceTokens
+import org.gradle.internal.os.OperatingSystem
+
+buildscript {
+ dependencies {
+ classpath 'org.openclover:clover:4.3.1'
+ classpath 'org.apache.commons:commons-compress:1.18'
+ }
+}
+
+plugins {
+ id 'java'
+ id 'application'
+ id 'eclipse'
+ id 'com.github.johnrengelman.shadow' version '4.0.3'
+ id 'com.install4j.gradle' version '7.0.9'
+}
+
+repositories {
+ jcenter()
+ mavenCentral()
+ mavenLocal()
+ flatDir {
+ dirs gradlePluginsDir
+ }
+}
+
+mainClassName = launcherClass
+def cloverInstrDir = file("$buildDir/$cloverSourcesInstrDir")
+def classes = "$jalviewDir/$classesDir"
+
+if (clover.equals("true")) {
+ use_clover = true
+ classes = "$buildDir/$cloverClassesDir"
+} else {
+ use_clover = false
+ classes = "$jalviewDir/$classesDir"
+}
+
+// configure classpath/args for j8/j11 compilation
+
+def jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
+def libDir
+def libDistDir
+def compile_source_compatibility
+def compile_target_compatibility
+
+ext {
+ // where the getdown channel will be built.
+ // TODO: consider allowing this expression to be overrriden by -P arg
+ getdownWebsiteDir = jalviewDir + '/' + getdown_website_dir + '/' + JAVA_VERSION + '/'
+ getdownAppDir = getdownWebsiteDir + '/' + getdown_app_dir
+ getdownJ11libDir = getdownWebsiteDir + '/' + getdown_j11lib_dir
+ getdownResourceDir = getdownWebsiteDir + '/' + getdown_resource_dir
+ getdownLauncher = jalviewDir + '/' + getdown_launcher
+ getdownFilesDir = jalviewDir + '/' + getdown_files_dir + '/' + JAVA_VERSION + '/'
+ getdownLib1 = jalviewDir + '/' + getdown_lib1
+ def getdownChannel = getdown_channel_name
+ if (getdown_channel_name.equals("COMMIT")) {
+ getdownChannel = getGitHash()
+ }
+ getdown_app_base = getdown_channel_base+"/"+getdownChannel+"/"+JAVA_VERSION+"/"
+ modules_compileClasspath = fileTree(dir: "$jalviewDir/$j11modDir", include: ["*.jar"])
+ modules_runtimeClasspath = modules_compileClasspath
+}
+
+def JAVA_INTEGER_VERSION
+def additional_compiler_args = []
+// these are getdown.txt properties defined dependent on the JAVA_VERSION
+def getdown_alt_java_min_version
+// this property is assigned below and expanded to multiple lines in the getdown task
+def getdown_alt_multi_java_location
+if (JAVA_VERSION.equals("1.8")) {
+ JAVA_INTEGER_VERSION = "8"
+ libDir = j11libDir
+ libDistDir = j8libDir
+ compile_source_compatibility = 1.8
+ compile_target_compatibility = 1.8
+ getdown_alt_java_min_version = getdown_alt_java8_min_version
+ getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
+} else if (JAVA_VERSION.equals("11")) {
+ JAVA_INTEGER_VERSION = "11"
+ libDir = j11libDir
+ libDistDir = j11libDir
+ compile_source_compatibility = 11
+ compile_target_compatibility = 11
+ getdown_alt_java_min_version = getdown_alt_java11_min_version
+ getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
+ additional_compiler_args += [
+ '--module-path', ext.modules_compileClasspath.asPath,
+ '--add-modules', j11modules
+ ]
+} else {
+ throw new GradleException("JAVA_VERSION=$JAVA_VERSION not currently supported by Jalview")
+}
+
+sourceSets {
+
+ main {
+ java {
+ srcDirs "$jalviewDir/$sourceDir"
+ outputDir = file("$classes")
+ }
+
+ resources {
+ srcDirs "$jalviewDir/$resourceDir"
+ srcDirs "$jalviewDir/$libDistDir"
+ }
+
+ jar.destinationDir = file("$jalviewDir/$packageDir")
+
+ compileClasspath = files(sourceSets.main.java.outputDir)
+ compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
+
+ runtimeClasspath = compileClasspath
+ }
+ clover {
+ java {
+ srcDirs = [ cloverInstrDir ]
+ outputDir = file("${buildDir}/${cloverClassesDir}")
+ }
+
+ resources {
+ srcDirs = sourceSets.main.resources.srcDirs
+ }
+ compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
+ compileClasspath += files(sourceSets.main.java.outputDir)
+ compileClasspath += sourceSets.main.compileClasspath
+ compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
+ compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
+
+ runtimeClasspath = compileClasspath
+ }
+
+ test {
+ java {
+ srcDirs "$jalviewDir/$testSourceDir"
+ outputDir = file("$jalviewDir/$testOutputDir")
+ }
+
+ resources {
+ srcDirs = sourceSets.main.resources.srcDirs
+ }
+
+ compileClasspath = files( sourceSets.test.java.outputDir )
+
+ if (use_clover) {
+ compileClasspath += sourceSets.clover.compileClasspath
+ } else {
+ compileClasspath += files(sourceSets.main.java.outputDir)
+ }
+ compileClasspath += sourceSets.main.compileClasspath
+ compileClasspath += files( sourceSets.main.resources.srcDirs)
+ compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
+ compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
+
+ runtimeClasspath = compileClasspath
+ }
+}
+
+// clover bits
+dependencies {
+ if (use_clover) {
+ cloverCompile 'org.openclover:clover:4.3.1'
+ testCompile 'org.openclover:clover:4.3.1'
+ }
+}
+
+configurations {
+ cloverRuntime
+ cloverRuntime.extendsFrom cloverCompile
+}
+
+eclipse {
+ project {
+ name = "Jalview with gradle build"
+
+ natures 'org.eclipse.jdt.core.javanature',
+ 'org.eclipse.jdt.groovy.core.groovyNature',
+ 'org.eclipse.buildship.core.gradleprojectnature'
+
+ buildCommand 'org.eclipse.jdt.core.javabuilder'
+ buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
+ }
+
+ classpath {
+ //defaultOutputDir = sourceSets.main.java.outputDir
+ def removeThese = []
+ configurations.each{ if (it.isCanBeResolved()) {
+ removeThese += it
+ }
+ }
+ containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
+
+ minusConfigurations += removeThese
+ plusConfigurations = [ ]
+ file {
+
+ whenMerged { cp ->
+ def removeTheseToo = []
+ HashMap<String, Boolean> addedSrcPath = new HashMap<>();
+ cp.entries.each { entry ->
+ if (entry.kind == 'src') {
+ if (addedSrcPath.getAt(entry.path) || !(entry.path == "src" || entry.path == "test")) {
+ removeTheseToo += entry
+ } else {
+ addedSrcPath.putAt(entry.path, true)
+ }
+ }
+ }
+ cp.entries.removeAll(removeTheseToo)
+ }
+
+ withXml {
+ def node = it.asNode()
+ def srcTestAttributes
+ node.children().each{ cpe ->
+ def attributes = cpe.attributes()
+ if (attributes.get("kind") == "src" && attributes.get("path") == "test") {
+ srcTestAttributes = cpe.find { a -> a.name() == "attributes" }
+ return
+ }
+ }
+ def addTestAttribute = true
+ srcTestAttributes.each{a ->
+ if (a.name() == "attribute" && a.attributes().getAt("name") == "test") {
+ addTestAttribute = false
+ }
+ }
+ if (addTestAttribute) {
+ srcTestAttributes.append(new Node(null, "attribute", [name:"test", value:"true"]))
+ }
+
+ node.appendNode('classpathentry', [kind:"output", path:"bin/main"])
+ node.appendNode('classpathentry', [kind:"lib", path:helpParentDir])
+ node.appendNode('classpathentry', [kind:"lib", path:resourceDir])
+ HashMap<String, Boolean> addedLibPath = new HashMap<>();
+ def allPaths = sourceSets.test.compileClasspath + sourceSets.main.compileClasspath
+ sourceSets.main.compileClasspath.each{
+ //if ((it.isDirectory() || ! it.exists()) && ! (it.equals(sourceSets.main.java.outputDir))) {
+ //no longer want to add outputDir as eclipse is using its own output dir in bin/main
+ if (it.isDirectory() || ! it.exists()) {
+ // don't add dirs to classpath
+ //println("Not adding directory "+it)
+ return
+ }
+ def itPath = it.toString()
+ if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
+ itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
+ }
+ if (addedLibPath.get(itPath)) {
+ //println("Not adding duplicate entry "+itPath)
+ } else {
+ //println("Adding entry "+itPath)
+ node.appendNode('classpathentry', [kind:"lib", path:itPath])
+ addedLibPath.put(itPath, true)
+ }
+ }
+ sourceSets.test.compileClasspath.each{
+ //if ((it.isDirectory() || ! it.exists()) && ! (it.equals(sourceSets.main.java.outputDir))) {
+ //no longer want to add outputDir as eclipse is using its own output dir in bin/main
+ if (it.isDirectory() || ! it.exists()) {
+ // don't add dirs to classpath
+ //println("Not adding directory "+it)
+ return
+ }
+ def itPath = it.toString()
+ if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
+ itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
+ }
+ if (addedLibPath.get(itPath)) {
+ //println("Not adding duplicate entry "+itPath)
+ } else {
+ //println("Adding entry "+itPath)
+ node.appendNode('classpathentry', [kind:"lib", path:itPath])
+ .appendNode('attributes')
+ .appendNode('attribute', [name:"test", value:"true"])
+ addedLibPath.put(itPath, true)
+ }
+ }
+ }
+
+ }
+ }
+
+ jdt {
+ // for the IDE, use java 11 compatibility
+ sourceCompatibility = 11
+ targetCompatibility = 11
+ javaRuntimeName = "JavaSE-11"
+
+ file {
+ withProperties { props ->
+ def jalview_prefs = new Properties()
+ def ins = new FileInputStream(eclipse_extra_jdt_prefs_file)
+ jalview_prefs.load(ins)
+ ins.close()
+ jalview_prefs.forEach { t, v ->
+ if (props.getAt(t) == null) {
+ props.putAt(t, v)
+ }
+ }
+ }
+ }
+ }
+
+}
+
+task cloverInstr() {
+ // only instrument source, we build test classes as normal
+ inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
+ outputs.dir cloverInstrDir
+
+ doFirst {
+ delete cloverInstrDir
+ def argsList = ["--initstring", "${buildDir}/clover/clover.db",
+ "-d", "${buildDir}/${cloverSourcesInstrDir}"]
+ argsList.addAll(inputs.files.files.collect({ file ->
+ file.absolutePath
+ }))
+ String[] args = argsList.toArray()
+ println("About to instrument "+args.length +" files")
+ com.atlassian.clover.CloverInstr.mainImpl(args)
+ }
+}
+
+
+task cloverReport {
+ group = "Verification"
+ description = "Createst the Clover report"
+ inputs.dir "${buildDir}/clover"
+ outputs.dir "${reportsDir}/clover"
+ onlyIf {
+ file("${buildDir}/clover/clover.db").exists()
+ }
+ doFirst {
+ def argsList = ["--initstring", "${buildDir}/clover/clover.db",
+ "-o", "${reportsDir}/clover"]
+ String[] args = argsList.toArray()
+ com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
+
+ // and generate ${reportsDir}/clover/clover.xml
+ args = ["--initstring", "${buildDir}/clover/clover.db",
+ "-o", "${reportsDir}/clover/clover.xml"].toArray()
+ com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
+ }
+}
+
+// end clover bits
+
+
+compileJava {
+
+ doFirst {
+ sourceCompatibility = compile_source_compatibility
+ targetCompatibility = compile_target_compatibility
+ options.compilerArgs = additional_compiler_args
+ print ("Setting target compatibility to "+targetCompatibility+"\n")
+ }
+
+}
+
+compileTestJava {
+ if (use_clover) {
+ dependsOn compileCloverJava
+ classpath += configurations.cloverRuntime
+ } else {
+ classpath += sourceSets.main.runtimeClasspath
+ }
+ doFirst {
+ sourceCompatibility = compile_source_compatibility
+ targetCompatibility = compile_target_compatibility
+ options.compilerArgs = additional_compiler_args
+ print ("Setting target compatibility to "+targetCompatibility+"\n")
+ }
+}
+
+
+compileCloverJava {
+
+ doFirst {
+ sourceCompatibility = compile_source_compatibility
+ targetCompatibility = compile_target_compatibility
+ options.compilerArgs += additional_compiler_args
+ print ("Setting target compatibility to "+targetCompatibility+"\n")
+ }
+ classpath += configurations.cloverRuntime
+}
+
+clean {
+ delete sourceSets.main.java.outputDir
+}
+
+cleanTest {
+ delete sourceSets.test.java.outputDir
+ delete cloverInstrDir
+}
+
+def getDate(format) {
+ def date = new Date()
+ //return date.format("dd MMMM yyyy")
+ return date.format(format)
+}
+
+def getGitHash() {
+ def stdout = new ByteArrayOutputStream()
+ exec {
+ commandLine "git", "rev-parse", "--short", "HEAD"
+ standardOutput = stdout
+ workingDir = jalviewDir
+ }
+ return stdout.toString().trim()
+}
+
+def getGitBranch() {
+ def stdout = new ByteArrayOutputStream()
+ exec {
+ commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
+ standardOutput = stdout
+ workingDir = jalviewDir
+ }
+ return stdout.toString().trim()
+}
+
+task createBuildProperties(type: WriteProperties) {
+ inputs.dir("$jalviewDir/$sourceDir")
+ inputs.dir("$jalviewDir/$resourceDir")
+ outputFile "$classes/$buildPropertiesFile"
+ /* taking time/date specific comment out to allow better incremental builds */
+ //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
+ comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
+ property "BUILD_DATE", getDate("dd MMMM yyyy")
+ property "VERSION", JALVIEW_VERSION
+ property "INSTALLATION", INSTALLATION+" git-commit:"+getGitHash()+" ["+getGitBranch()+"]"
+ outputs.file(outputFile)
+ outputs.dir("$classes")
+}
+
+task syncDocs(type: Sync) {
+ def syncDir = "$classes/$docDir"
+ from fileTree("$jalviewDir/$docDir")
+ into syncDir
+
+}
+
+def helpFile = "$classes/$helpDir/help.jhm"
+
+task copyHelp(type: Copy) {
+ def inputDir = "$jalviewDir/$helpParentDir/$helpDir"
+ def outputDir = "$classes/$helpDir"
+ from(inputDir) {
+ exclude '**/*.gif'
+ exclude '**/*.jpg'
+ exclude '**/*.png'
+ filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION])
+ }
+ from(inputDir) {
+ include '**/*.gif'
+ include '**/*.jpg'
+ include '**/*.png'
+ }
+ into outputDir
+
+ inputs.dir(inputDir)
+ outputs.files(helpFile)
+ outputs.dir(outputDir)
+}
+
+task syncLib(type: Sync) {
+ def syncDir = "$classes/$libDistDir"
+ from fileTree("$jalviewDir/$libDistDir")
+ into syncDir
+}
+
+task syncResources(type: Sync) {
+ from "$jalviewDir/$resourceDir"
+ include "**/*.*"
+ exclude "install4j"
+ into "$classes"
+ preserve {
+ include "**"
+ }
+}
+
+task prepare {
+ dependsOn syncResources
+ dependsOn syncDocs
+ dependsOn copyHelp
+}
+
+
+//testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
+test {
+ dependsOn prepare
+ dependsOn compileJava
+ if (use_clover) {
+ dependsOn cloverInstr
+ }
+
+ print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
+
+ useTestNG() {
+ includeGroups testngGroups
+ preserveOrder true
+ useDefaultListeners=true
+ }
+
+ workingDir = jalviewDir
+ //systemProperties 'clover.jar' System.properties.clover.jar
+ sourceCompatibility = compile_source_compatibility
+ targetCompatibility = compile_target_compatibility
+ jvmArgs += additional_compiler_args
+ print ("Setting target compatibility to "+targetCompatibility+"\n")
+}
+
+task buildIndices(type: JavaExec) {
+ dependsOn copyHelp
+ classpath = sourceSets.main.compileClasspath
+ main = "com.sun.java.help.search.Indexer"
+ workingDir = "$classes/$helpDir"
+ def argDir = "html"
+ args = [ argDir ]
+ inputs.dir("$workingDir/$argDir")
+
+ outputs.dir("$classes/doc")
+ outputs.dir("$classes/help")
+ outputs.file("$workingDir/JavaHelpSearch/DOCS")
+ outputs.file("$workingDir/JavaHelpSearch/DOCS.TAB")
+ outputs.file("$workingDir/JavaHelpSearch/OFFSETS")
+ outputs.file("$workingDir/JavaHelpSearch/POSITIONS")
+ outputs.file("$workingDir/JavaHelpSearch/SCHEMA")
+ outputs.file("$workingDir/JavaHelpSearch/TMAP")
+}
+
+task compileLinkCheck(type: JavaCompile) {
+ options.fork = true
+ classpath = files("$jalviewDir/$utilsDir")
+ destinationDir = file("$jalviewDir/$utilsDir")
+ source = fileTree(dir: "$jalviewDir/$utilsDir", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
+
+ outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.class")
+ outputs.file("$jalviewDir/$utilsDir/BufferedLineReader.class")
+}
+
+def helplinkscheckeroutputfile = file("$jalviewDir/$utilsDir/HelpLinksChecker.out")
+task linkCheck(type: JavaExec) {
+ dependsOn prepare, compileLinkCheck
+ classpath = files("$jalviewDir/$utilsDir")
+ main = "HelpLinksChecker"
+ workingDir = jalviewDir
+ def help = "$classes/$helpDir"
+ args = [ "$classes/$helpDir", "-nointernet" ]
+ //args = [ "$classesDir/$helpDir", "-nointernet" ]
+
+ doFirst {
+ helplinkscheckeroutputfile.createNewFile()
+ standardOutput new FileOutputStream(helplinkscheckeroutputfile, false)
+ }
+
+ outputs.file(helplinkscheckeroutputfile)
+}
+
+task cleanPackageDir(type: Delete) {
+ delete fileTree("$jalviewDir/$packageDir").include("*.jar")
+}
+
+jar {
+ dependsOn linkCheck
+ dependsOn buildIndices
+ dependsOn createBuildProperties
+
+ manifest {
+ attributes "Main-Class": mainClass,
+ "Permissions": "all-permissions",
+ "Application-Name": "Jalview Desktop",
+ "Codebase": application_codebase
+ }
+
+ destinationDir = file("$jalviewDir/$packageDir")
+ archiveName = rootProject.name+".jar"
+
+ exclude "cache*/**"
+ exclude "*.jar"
+ exclude "*.jar.*"
+ exclude "**/*.jar"
+ exclude "**/*.jar.*"
+
+ inputs.dir("$classes")
+ outputs.file("$jalviewDir/$packageDir/$archiveName")
+}
+
+task copyJars(type: Copy) {
+ from fileTree("$classes").include("**/*.jar").include("*.jar").files
+ into "$jalviewDir/$packageDir"
+}
+
+// doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
+task syncJars(type: Sync) {
+ from fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").files
+ into "$jalviewDir/$packageDir"
+ preserve {
+ include jar.archiveName
+ }
+}
+
+task makeDist {
+ group = "build"
+ description = "Put all required libraries in dist"
+ // order of "cleanPackageDir", "copyJars", "jar" important!
+ jar.mustRunAfter cleanPackageDir
+ syncJars.mustRunAfter cleanPackageDir
+ dependsOn cleanPackageDir
+ dependsOn syncJars
+ dependsOn jar
+ outputs.dir("$jalviewDir/$packageDir")
+}
+
+task cleanDist {
+ dependsOn cleanPackageDir
+ dependsOn cleanTest
+ dependsOn clean
+}
+
+shadowJar {
+ dependsOn makeDist
+ from ("$jalviewDir/$libDistDir") {
+ include("*.jar")
+ }
+ mainClassName = shadowJarMainClass
+ mergeServiceFiles()
+ classifier = "all-"+JAVA_VERSION
+ minimize()
+}
+
+task getdownWebsite() {
+ group = "distribution"
+ description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
+ dependsOn makeDist
+ def getdownWebsiteResourceFilenames = []
+ def getdownTextString = ""
+ def getdownResourceDir = project.ext.getdownResourceDir
+ def getdownAppDir = project.ext.getdownAppDir
+ def getdownResourceFilenames = []
+ doFirst {
+ // go through properties looking for getdown_txt_...
+ def props = project.properties.sort { it.key }
+ props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
+ props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
+
+ props.put("getdown_txt_appbase", getdown_app_base)
+ props.each{ prop, val ->
+ if (prop.startsWith("getdown_txt_") && val != null) {
+ if (prop.startsWith("getdown_txt_multi_")) {
+ def key = prop.substring(18)
+ val.split(",").each{ v ->
+ def line = key + " = " + v + "\n"
+ getdownTextString += line
+ }
+ } else {
+ // file values rationalised
+ if (val.indexOf('/') > -1) {
+ def r = null
+ if (val.indexOf('/') == 0) {
+ // absolute path
+ r = file(val)
+ } else if (val.indexOf('/') > 0) {
+ // relative path (relative to jalviewDir)
+ r = file( jalviewDir + '/' + val )
+ }
+ if (r.exists()) {
+ val = getdown_resource_dir + '/' + r.getName()
+ getdownWebsiteResourceFilenames += val
+ getdownResourceFilenames += r.getPath()
+ }
+ }
+ def line = prop.substring(12) + " = " + val + "\n"
+ getdownTextString += line
+ }
+ }
+ }
+
+ getdownWebsiteResourceFilenames.each{ filename ->
+ getdownTextString += "resource = "+filename+"\n"
+ }
+ getdownResourceFilenames.each{ filename ->
+ copy {
+ from filename
+ into project.ext.getdownResourceDir
+ }
+ }
+
+ def codeFiles = []
+ makeDist.outputs.files.each{ f ->
+ if (f.isDirectory()) {
+ def files = fileTree(dir: f, include: ["*"]).getFiles()
+ codeFiles += files
+ } else if (f.exists()) {
+ codeFiles += f
+ }
+ }
+ codeFiles.sort().each{f ->
+ def line = "code = " + getdown_app_dir + '/' + f.getName() + "\n"
+ getdownTextString += line
+ copy {
+ from f.getPath()
+ into project.ext.getdownAppDir
+ }
+ }
+
+ // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
+ /*
+ if (JAVA_VERSION.equals("11")) {
+ def j11libFiles = fileTree(dir: "$jalviewDir/$j11libDir", include: ["*.jar"]).getFiles()
+ j11libFiles.sort().each{f ->
+ def line = "code = " + getdown_j11lib_dir + '/' + f.getName() + "\n"
+ getdownTextString += line
+ copy {
+ from f.getPath()
+ into project.ext.getdownJ11libDir
+ }
+ }
+ }
+ */
+
+ getdownTextString += "code = " + file(getdownLauncher).getName() + "\n"
+ getdownTextString += "class = " + mainClass + "\n"
+
+ def getdown_txt = file(project.ext.getdownWebsiteDir + "/getdown.txt")
+ getdown_txt.write(getdownTextString)
+
+ copy {
+ from getdown_txt
+ into project.ext.getdownFilesDir
+ }
+
+ copy {
+ from getdownLauncher
+ into project.ext.getdownFilesDir
+ }
+
+ copy {
+ from getdownLauncher
+ into project.ext.getdownWebsiteDir
+ }
+
+ copy {
+ from getdownLib1
+ into project.ext.getdownFilesDir + '/' + packageDir
+ }
+
+ copy {
+ from jalviewDir + '/' + project.getProperty('getdown_txt_ui.background_image')
+ from jalviewDir + '/' + project.getProperty('getdown_txt_ui.error_background')
+ from jalviewDir + '/' + project.getProperty('getdown_txt_ui.progress_image')
+ from jalviewDir + '/' + project.getProperty('getdown_txt_ui.icon')
+ from jalviewDir + '/' + project.getProperty('getdown_txt_ui.mac_dock_icon')
+ into project.ext.getdownFilesDir + '/' + getdown_resource_dir
+ }
+ }
+
+ inputs.dir(jalviewDir + '/' + packageDir)
+ outputs.dir(project.ext.getdownWebsiteDir)
+ outputs.dir(project.ext.getdownFilesDir)
+}
+
+task getdownDigest(type: JavaExec) {
+ group = "distribution"
+ description = "Digest the getdown website folder"
+ dependsOn getdownWebsite
+ classpath = files(jalviewDir + '/' + getdown_core)
+ classpath file(jalviewDir + '/' + getdown_lib1)
+ main = "com.threerings.getdown.tools.Digester"
+ args project.ext.getdownWebsiteDir
+ outputs.file(project.ext.getdownWebsiteDir + '/' + "digest2.txt")
+}
+
+task getdown() {
+ group = "distribution"
+ description = "Create the minimal and full getdown app folder for installers and website and create digest file"
+ dependsOn getdownDigest
+}
+
+clean {
+ delete project.ext.getdownWebsiteDir
+ delete project.ext.getdownFilesDir
+}
+
+install4j {
+ def install4jHomeDir = "/opt/install4j"
+ def hostname = "hostname".execute().text.trim()
+ if (hostname.equals("jv-bamboo")) {
+ install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
+ } else if (OperatingSystem.current().isMacOsX()) {
+ install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
+ if (! file(install4jHomeDir).exists()) {
+ install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
+ }
+ } else if (OperatingSystem.current().isLinux()) {
+ install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
+ }
+ installDir = file(install4jHomeDir)
+ mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
+}
+
+def install4jConf
+def macosJavaVMDir
+def macosJavaVMTgz
+def windowsJavaVMDir
+def windowsJavaVMTgz
+def install4jDir = "$jalviewDir/$install4jResourceDir"
+def install4jConfFile = "jalview-installers-java"+JAVA_VERSION+".install4j"
+install4jConf = "$install4jDir/$install4jConfFile"
+
+task copyInstall4jTemplate(type: Copy) {
+ macosJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/macos-jre"+JAVA_VERSION+"/jre"
+ macosJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre"+JAVA_VERSION+".tar.gz"
+ windowsJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/windows-jre"+JAVA_VERSION+"/jre"
+ windowsJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre"+JAVA_VERSION+".tar.gz"
+ from (install4jDir) {
+ include install4jTemplate
+ rename (install4jTemplate, install4jConfFile)
+ filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
+ filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['JAVA_VERSION': JAVA_VERSION, 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION, 'VERSION': JALVIEW_VERSION, 'MACOS_JAVA_VM_DIR': macosJavaVMDir, 'MACOS_JAVA_VM_TGZ': macosJavaVMTgz, 'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir, 'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz])
+ }
+ into install4jDir
+ inputs.files("$install4jDir/$install4jTemplate")
+ outputs.files(install4jConf)
+}
+
+task installers(type: com.install4j.gradle.Install4jTask) {
+ group = "distribution"
+ description = "Create the install4j installers"
+ dependsOn getdown
+ dependsOn copyInstall4jTemplate
+ projectFile = file(install4jConf)
+ println("Using projectFile "+projectFile)
+ variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
+ destination = "$jalviewDir/$install4jBuildDir/$JAVA_VERSION"
+ buildSelected = true
+
+ if (OSX_KEYPASS) {
+ macKeystorePassword=OSX_KEYPASS
+
+ }
+
+ inputs.dir(project.ext.getdownWebsiteDir)
+ inputs.file(install4jConf)
+ inputs.dir(macosJavaVMDir)
+ inputs.dir(windowsJavaVMDir)
+ outputs.dir("$jalviewDir/$install4jBuildDir/$JAVA_VERSION")
+}
+
+clean {
+ delete install4jConf
+}
+++ /dev/null
-<?xml version="1.0"?>
-<!--
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
--->
-<project name="jalviewX" default="usage" basedir="."
- xmlns:if="ant:if"
- xmlns:unless="ant:unless">
- <taskdef classpath="${clover.jar}" resource="cloverlib.xml" if:set="clover.jar"/>
- <clover-env if:set="clover.jar"/>
-
- <target name="help" depends="usage" />
- <target name="usage" depends="init">
- <echo message="~~~Jalview Ant build.xml Usage~~~~" />
- <echo message="Targets include:" />
- <echo message="usage - default target, displays this message" />
- <echo message="buildindices - generates JavaHelpSearch from the help files" />
- <echo message="build - compiles all necessary files for Application" />
- <echo message="makedist - compiles and places all necessary jar files into directory dist" />
- <echo message="makefulldist - signs all jar files and builds jnlp file for full distribution" />
- <echo message=" this needs a keystore and key."/>
- <echo message=" Add -Dtimestamp to timestamp signed jars"/>
- <echo message=" -Djalview.keyalg and -Djalview.keydig are SHA1/SHA1withRSA"/>
- <echo message=" See docs/building.html for more information." />
- <echo message="compileApplet - compiles all necessary files for Applet" />
- <echo message="makeApplet - compiles, then packages and obfuscates the Applet" />
- <echo message="testng - run jalview's tests via testNG. Default group is '${testng-groups}'" />
- <echo message=" you can specify particular test groups as a list via -Dtestng-groups=" />
- <echo message="See docs/building.html and the comments in build file for other targets." />
- <echo message="note: compile and makeApplet optionally compile/obfuscate applet against a different Java version by specifying -Djava118.home=PathtoJDK/lib which is the lib directory in the JDK install that contains rt.jar " />
- <echo message="Useful -D flags: -Ddonotobfuscate will prevent applet obfuscation" />
- <echo message="Useful -D flags: -Dclover.jar to specify path to openclover for testng coverage report" />
- </target>
-
-
- <!-- utils is a class path to additional utilities needed for
- building docs, jars and webstart stuff -->
- <!--
- Userdefined build property defaults
-
- wsdl.server list (plus namespace mapping info ???) - also want
- ... to make this a dynamically generatable property
- WebStart Location
- Build location - provide a temporary root for speed
- jarsigner keystore and info
- Jakarta and axis classpath ?
- Default argument for starting Jalview (if it exists).
-
--->
-
- <target name="init">
- <path id="axis.classpath">
- <!-->
- <fileset dir="/usr/local/axis/lib">
- <include name="**/*.jar" />
- </fileset>
- <fileset dir="/usr/local/jakarta-tomcat-5/webapps/axis/WEB-INF/lib">
- <include name="**/*.jar"/>
- <include name="*.jar"/>
- </fileset> -->
- </path>
-
- <!-- Jalview Version String displayed by application on startup and used to check for updates -->
- <property name="JALVIEW_VERSION" value="DEVELOPMENT" />
-
- <property name="INSTALLATION" value="Source" />
-
- <!-- 2.4 (VAMSAS)" -->
- <!-- Include debugging information in javac true or false -->
- <property name="javac.debug" value="true" />
-
- <!-- JarSigner Key Store for Webstart Distribution -->
- <property name="jalview.keystore" value="./keys/.keystore" />
- <!-- Keystore Password -->
- <property name="jalview.keystore.pass" value="alignmentisfun" />
- <!-- Key Name -->
- <property name="jalview.key" value="jalview" />
- <!-- Key Password -->
- <property name="jalview.key.pass" value="alignmentisfun" />
- <!-- time stamp server URL -->
- <property name="jalview.tsaurl" value="" />
- <!-- locally valid proxy for signing with external time server -->
- <property name="proxyPort" value="80"/>
- <property name="proxyHost" value="sqid"/>
- <!-- key sign/digest algorithms -->
- <property name="jalview.keyalg" value="SHA1withRSA" description="key algorithm for signing"/>
- <property name="jalview.keydig" value="SHA1" description="algorithm for jar digest"/>
-
- <!-- default TestNG groups to run -->
- <property name="testng-groups" value="Functional" />
- <!-- Java 9 JVM args -->
- <condition property="java9">
- <equals arg1="${ant.java.version}" arg2="9"/>
- </condition>
-
- <!-- Don't change anything below here unless you know what you are doing! -->
- <!-- Url path for WebStart in JNLP file -->
- <property name="WebStartLocation" value="http://www.jalview.org/webstart" />
- <!-- Webstart Image - looked for in resources/images -->
- <property name="WebStartImage" value="JalviewLogo_big.png" />
- <!-- J2SE version needed for webstart launch -->
- <!-- Anne's version needs 1.7 - should rebuild VARNA to java 1.6 for release -->
- <property name="j2sev" value="1.7+" />
- <!-- Java Compilation settings - source and target javac version -->
- <property name="javac.source" value="1.8" />
- <property name="javac.target" value="1.8" />
-
- <!-- Permissions for running Java applets and applications. -->
- <!-- Defaults are those suitable for deploying jalview webstart www.jalview.org -->
- <property name="application.codebase" value="*.jalview.org" />
- <!-- and allowing the applet to be deployed from any URL -->
- <!-- note - if you want to make sure LiveConnect works without any warnings, please rebuild and sign your applet jar with your own domain included in the codebase/allowable-codebase properties -->
- <property name="applet.codebase" value="*.jalview.org *.dundee.ac.uk *" />
- <property name="applet.caller-codebase" value="${applet.codebase}" />
-
- <!-- build directory configuration -->
- <property name="libDir" value="lib" />
- <property name="resourceDir" value="resources" />
- <property name="helpDir" value="help" />
- <property name="docDir" value="doc" />
- <property name="sourceDir" value="src" />
- <property name="schemaDir" value="schemas" />
- <property name="outputDir" value="classes" unless:set="clover.jar"/>
- <property name="outputDir" value="cloverclasses" if:set="clover.jar"/>
- <property name="packageDir" value="dist" />
- <property name="outputJar" value="jalview.jar" />
- <!-- Jalview Applet JMol Jar Dependency -->
- <property name="jmolJar" value="JmolApplet-14.6.4_2016.10.26.jar" />
- <property name="varnaJar" value="VARNAv3-93.jar" />
- <property name="jsoup" value="jsoup-1.8.1.jar" />
- <property name="jsonSimple" value="json_simple-1.1.jar" />
- <property name="javaJson" value="java-json.jar" />
- <property name="jalviewLiteJar" value="jalviewApplet.jar" />
- <property name="reportDir" value="test-reports" />
- <property name="testDir" value="test" />
- <property name="testOutputDir" value="tests" />
- <!-- switch to indicate if we should obfuscate jalviewLite -->
- <!-- <property name="donotobfuscate" value="true"/> -->
- <!-- switch to exclude associations from generated jnlp files -->
- <!-- <property name="nojnlpfileassocs" value="true"/> -->
-
- <!-- Jalview Web Service Clients - see the comments in 'buildextclients' for details -->
- <property name="wsdl.File" value="http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred?wsdl" />
- <property name="wsdl.Files" value="http://www.compbio.dundee.ac.uk/JalviewWS/services/vamsas?wsdlFiles" />
- <property name="wsdl.MsaWS" value="http://www.compbio.dundee.ac.uk/JalviewWS/services/MuscleWS?wsdl" />
- <property name="wsdl.MsaWS2" value="http://www.compbio.dundee.ac.uk/JalviewWS/services/ClustalWS?wsdl" />
- <property name="WSInterf" value="MsaWS" />
- <property name="wsdl.Namespace" value="vamsas" />
- <property name="wsdl.ClientNS" value="ext.vamsas" />
- <!-- the class path for building the application -->
- <path id="build.classpath">
- <fileset dir="utils">
- <include name="*.jar" />
- <include name="**/*.jar" />
- </fileset>
- <fileset dir="${libDir}">
- <include name="*.jar" />
- <include name="**/*.jar" />
- </fileset>
- <fileset dir="${java.home}/lib">
- <include name="plugin.jar" />
- </fileset>
- <fileset dir="appletlib">
- <!-- the JmolApplet includes the JmolApplet console and the application javac seems to always try and build all packages
- -->
- <include name="${jmolJar}" />
- <include name="${varnaJar}" />
- </fileset>
- </path>
- <path id="test.classpath">
- <pathelement path="${outputDir}" />
- <path refid="build.classpath" />
- </path>
- <property name="source.dist.name" value="${basedir}/jalview-src.tar.gz" />
- <!-- The Location of the java 1.1.8 jdk -->
- <property name="java118.home" value="${java.home}" />
- <!-- jre for 1.4 version -->
- <property name="applet.jre.tools" value="${java118.home}/lib/rt.jar" />
-
- <!-- the classpath for building the 1.1 applet -->
- <path id="jalviewlite.deps">
- <fileset dir="${java118.home}">
- <include name="lib/rt.jar" />
- </fileset>
- <fileset dir="${java.home}/lib">
- <include name="plugin.jar" />
- </fileset>
- <pathelement location="appletlib/${jmolJar}" />
- <pathelement location="lib/${varnaJar}" />
- <pathelement location="appletlib/${jsoup}" />
- <pathelement location="appletlib/${jsonSimple}" />
- <pathelement location="appletlib/${javaJson}" />
-
- </path>
- <!-- default location for outputting javadoc -->
- <property name="javadocDir" value="${packageDir}/javadoc" />
- </target>
-
-
- <taskdef classpath="utils/roxes-ant-tasks-1.2-2004-01-30.jar" resource="com/roxes/tools/ant/taskdefs.properties" />
- <target name="buildPropertiesFile" depends="init">
- <tstamp prefix="build">
- <format property="date" pattern="dd MMMM yyyy" />
- </tstamp>
- <exec executable="/usr/bin/git" outputproperty="git.commit" failifexecutionfails="false">
- <arg value="rev-parse" />
- <arg value="--short" />
- <arg value="HEAD" />
- </exec>
- <exec executable="/usr/bin/git" outputproperty="git.branch" failifexecutionfails="false">
- <arg value="rev-parse" />
- <arg value="--abbrev-ref" />
- <arg value="HEAD" />
- </exec>
- <properties file="${outputDir}/.build_properties">
- <header>
- ---Jalview Build Details---
- </header>
- <property name="VERSION" value="${JALVIEW_VERSION}" />
- <property name="INSTALLATION" value="${INSTALLATION} git-commit:${git.commit} [${git.branch}]" />
- <property name="BUILD_DATE" value="${build.date}" />
- </properties>
- </target>
-
-
- <target name="clean" depends="init">
- <!-- not efficient yet. -->
- <delete dir="${outputDir}" includes="*,**/*" />
- </target>
-
- <target name="distclean" depends="init, clean">
-
- <echo message="REMOVING ALL BACKUP/AUTOSAVES!" />
- <delete>
- <fileset dir=".">
- <include name="${outputJar}" />
- <include name="#*#" />
- <include name="#*.*#" />
- <include name="**/#*#" />
- <include name="**/#*.*#" />
- <include name="*~" />
- <include name="*.*~" />
- <include name="**/*~" />
- <include name="**/*.*~" />
- </fileset>
- </delete>
- </target>
-
- <target name="prepare" depends="init">
- <mkdir dir="${outputDir}" />
- <copy todir="${outputDir}">
- <fileset dir=".">
- <include name="${docDir}/**/*.*" />
- <include name="${helpDir}/**/*.*" />
- <include name="${libDir}/*.jar" />
- </fileset>
- <fileset dir="${resourceDir}">
- <include name="**/*.*" />
- </fileset>
- </copy>
- </target>
-
- <target name="build" depends="prepare">
- <!-- not efficient yet. -->
- <javac source="${javac.source}" target="${javac.target}" srcdir="${sourceDir}" destdir="${outputDir}" debug="${javac.debug}" classpathref="build.classpath">
- <exclude name="jalview/*applet*" />
- <exclude name="jalview/appletgui/**" />
- <exclude name="com/stevesoft/**" />
- </javac>
- </target>
-
-
- <target name="testclean" depends="init">
- <delete dir="${testOutputDir}" includes="*,**/*" />
- </target>
-
- <target name="prepareTests" depends="init,testclean">
- <mkdir dir="${testOutputDir}" />
- </target>
-
- <target name="buildTests" depends="build,buildindices,prepareTests">
- <javac source="${javac.source}" target="${javac.target}" srcdir="${testDir}" destdir="${testOutputDir}" debug="${javac.debug}" classpathref="test.classpath" includeantruntime="false">
- </javac>
- </target>
-
- <taskdef resource="testngtasks" classpath="utils/testnglibs/testng.jar" />
-
- <target name="testng" depends="buildTests">
- <testng outputDir="${reportDir}" haltOnFailure="false" groups="${testng-groups}" mode="testng"
- verbose="2">
- <classpath>
- <pathelement location="${testOutputDir}" />
- <pathelement location="${clover.jar}" if:set="clover.jar"/>
- <path refid="test.classpath" />
- </classpath>
- <jvmarg value="--add-modules=java.se.ee" if:set="java9"/>
- <jvmarg value="--illegal-access=warn" if:set="java9"/>
- <classfileset dir="${testOutputDir}" includes="**/*.class" />
- </testng>
- </target>
-
- <target name="buildindices" depends="init, prepare" unless="help.uptodate">
- <replace value="${JALVIEW_VERSION}">
- <replacetoken><![CDATA[$$Version-Rel$$]]></replacetoken>
- <fileset dir="${outputDir}/${helpDir}">
- <include name="help.jhm" />
- </fileset>
- </replace>
-
- <java classname="com.sun.java.help.search.Indexer" classpathref="build.classpath" fork="true" dir="${outputDir}/${helpDir}">
- <arg line="html" />
- </java>
- </target>
-
- <target name="preparejnlp" depends="makedist">
- <copy todir="${packageDir}">
- <fileset dir="${resourceDir}/images">
- <include name="${WebStartImage}" />
- </fileset>
- </copy>
-
- <taskdef classpathref="build.classpath" resource="com/roxes/tools/ant/taskdefs.properties" />
-
- <!-- create a dummy jar which will eventually contain the jnlp template -->
- <jar destfile="${packageDir}/jalview_jnlp_vm.jar" index="true">
- <fileset dir="${packageDir}">
- <include name="jalview.jar" />
- </fileset>
- </jar>
-
- <mkdir dir="${packageDir}/JNLP-INF" />
- <antcall target="writejnlpf">
- <param name="jnlpFile" value="${packageDir}/JNLP-INF/APPLICATION-TEMPLATE.JNLP" />
- <param name="inih" value="*" />
- <param name="maxh" value="*" />
- </antcall>
-
- <jar destfile="${packageDir}/jalview_jnlp_vm.jar" index="true">
- <fileset dir="${packageDir}">
- <include name="JNLP-INF/APPLICATION-TEMPLATE.JNLP" />
- </fileset>
- </jar>
-
- <antcall target="writejnlpf">
- <param name="jnlpFile" value="${packageDir}/jalview_256M.jnlp" />
- <param name="inih" value="10M" />
- <param name="maxh" value="256M" />
- </antcall>
- <antcall target="writejnlpf">
- <param name="jnlpFile" value="${packageDir}/jalview.jnlp" />
- <param name="inih" value="800M" />
- <param name="maxh" value="1024M" />
- </antcall>
-
- <antcall target="writejnlpf">
- <param name="jnlpFile" value="${packageDir}/jalview_1G.jnlp" />
- <param name="inih" value="128M" />
- <param name="maxh" value="512M" />
- </antcall>
-
- <antcall target="writejnlpf">
- <param name="jnlpFile" value="${packageDir}/jalview_2G.jnlp" />
- <param name="inih" value="800M" />
- <param name="maxh" value="1024M" />
- </antcall>
-
- <!-- finally, need to postprocess to add in associations at end of 'information' element
-
- <xslt in="${packageDir}/jalview_noa_1G.jnlp" out="${packageDir}/jalview_1G.jnlp">
-
- </xslt>
-
-
- -->
- <!--
- <association mime-type="application-x/ext-file" extensions="fa"/>
- <association mime-type="application-x/ext-file" extensions="fasta"/>
- <association mime-type="application-x/ext-file" extensions="mfa"/>
- <association mime-type="application-x/ext-file" extensions="fastq"/>
- <association mime-type="application-x/ext-file" extensions="blc"/>
- <association mime-type="application-x/ext-file" extensions="msf"/>
- <association mime-type="application-x/ext-file" extensions="pfam"/>
- <association mime-type="application-x/ext-file" extensions="aln"/>
- <association mime-type="application-x/ext-file" extensions="pir"/>
- <association mime-type="application-x/ext-file" extensions="amsa"/>
- <association mime-type="application-x/ext-file" extensions="stk"/>
- <association mime-type="application-x/ext-file" extensions="jar"/>-->
- </target>
-
- <target name="-jarsignwithtsa" depends="makedist,preparejnlp" if="timestamp" unless="nosign">
- <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}"
- tsaproxyhost="${proxyHost}" tsaproxyport="${proxyPort}" tsaurl="${jalview.tsaurl}">
- <fileset dir="${packageDir}">
- <include name="*.jar" />
- </fileset>
- </signjar>
- </target>
- <target name="-jarsignnotsa" depends="makedist,preparejnlp" if:blank="timestamp" unless="nosign">
- <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}">
- <fileset dir="${packageDir}">
- <include name="*.jar" />
- </fileset>
- </signjar>
- </target>
-
- <target name="makefulldist" depends="makedist,preparejnlp,-jarsignwithtsa,-jarsignnotsa">
- <!-- and sign the jars -->
- <!-- the default keystore details might need to be edited here -->
- </target>
-
- <target name="runenv" depends="init">
- <path id="run.classpath">
- <pathelement location="${outputDir}" />
- <fileset dir="${outputDir}">
- <include name="${libDir}/*.jar" />
- </fileset>
- </path>
- <pathconvert targetos="unix" refid="run.classpath" property="run.classpath" />
-
- <echo>java -classpath ${run.classpath} jalview.bin.Jalview
- </echo>
- </target>
-
- <target name="-generatejnlpf">
- <presetdef name="jnlpf">
- <jnlp codebase="${WebStartLocation}">
- <information>
- <title>Jalview</title>
- <vendor>The Barton Group</vendor>
- <homepage href="http://www.jalview.org" />
- <description>Jalview Multiple Alignment Editor</description>
- <description kind="short">Jalview</description>
- <icon href="${WebStartImage}" />
- <offline_allowed />
- </information>
- <resources>
- <j2se version="1.8+" />
- <jar main="true" href="jalview.jar"/>
- <fileset dir="${packageDir}">
- <exclude name="jalview.jar" />
- <include name="*.jar" />
- <include name="*_*.jar" />
- <exclude name="*quaqua*.jar" />
- </fileset>
- <property name="jalview.version" value="${JALVIEW_VERSION}" />
- </resources>
- <resources os="Mac OS X">
- <fileset dir="${packageDir}">
- <include name="quaqua-filechooser-only-8.0.jar"/>
- <include name="*quaqua64*.jnilib.jar" />
- </fileset>
- </resources>
-
- <application_desc main_class="jalview.bin.Jalview">
- </application_desc>
- <security>
- <all_permissions />
- </security>
- </jnlp>
- </presetdef>
-
- <jnlpf toFile="${jnlpFile}" />
- <!-- add the add-modules j2se attribute for java 9 -->
- <replace file="${jnlpFile}" value="j2se version="1.8+" initial-heap-size="${inih}" max-heap-size="${maxh}" java-vm-args="--add-modules=java.se.ee --illegal-access=warn"">
- <replacetoken>j2se version="1.8+"</replacetoken>
- </replace>
- </target>
-
- <target name="-dofakejnlpfileassoc" depends="-generatejnlpf" if="nojnlpfileassocs">
- <echo message="Not adding JNLP File Associations" />
- </target>
-
- <target name="-dojnlpfileassoc" depends="-generatejnlpf" unless="nojnlpfileassocs">
- <replace file="${jnlpFile}">
- <replacetoken>
- <![CDATA[</information>]]></replacetoken>
- <replacevalue>
- <![CDATA[
- <association mime-type="application-x/ext-file" extensions="fa" />
- <association mime-type="application-x/ext-file" extensions="fasta" />
- <association mime-type="application-x/ext-file" extensions="mfa" />
- <association mime-type="application-x/ext-file" extensions="fastq" />
- <association mime-type="application-x/ext-file" extensions="blc" />
- <association mime-type="application-x/ext-file" extensions="msf" />
- <association mime-type="application-x/ext-file" extensions="pfam" />
- <association mime-type="application-x/ext-file" extensions="aln"/>
- <association mime-type="application-x/ext-file" extensions="pir"/>
- <association mime-type="application-x/ext-file" extensions="amsa"/>
- <association mime-type="application-x/ext-file" extensions="stk"/>
- <association mime-type="application-x/ext-file" extensions="jvp"/>
- </information>]]></replacevalue>
- </replace>
- <echo message="Added file associations to JNLP file" />
-</target>
-<target name="writejnlpf" depends="-dojnlpfileassoc,-dofakejnlpfileassoc">
-</target>
-
-<target name="buildextclients" depends="init">
- <input message="Building external client source from WSDLs - Do you really want to do this ? (Yy/Nn)" validargs="Y,y,n,N" defaultvalue="N" addproperty="doextbuild.response" />
- <condition property="dontextbuild">
- <equals arg1="n" arg2="${doextbuild.response}" />
- </condition>
- <condition property="dontextbuild">
- <equals arg1="N" arg2="${doextbuild.response}" />
- </condition>
- <fail if="dontextbuild">
- Build External Client Code process aborted by user. Jalview source is unchanged.
- </fail>
- <!-- Currently, this doesn't happen automatically.
- 1. Run WSDL2Java as below, which generates an ext.vamsas +
- vamsas.<datapackages> fileset.
- 2. refactor ext.vamsas.SpecificserviceWS* to
- ext.vamsas.ServiceclassWS* that implements the ServiceclassWSI interface.
- 3. Update the jalview.ws.*WServices classes to reflect the
- interface type, and all locations of this wsdl type that Jalview
- might be using.
-
--->
- <path id="axisbuild">
- <path refid="build.classpath" />
- </path>
- <taskdef resource="axis-tasks.properties" classpathref="axisbuild" />
- <move todir="./bak">
- <fileset dir="${sourceDir}" id="client">
- <include name="${wsdl.ClientNS}/*.*" />
- </fileset>
- </move>
-
- <axis-wsdl2java output="${sourceDir}" verbose="true" url="${wsdl.MsaWS2}" serverside="false" deployscope="Request" debug="false" helpergen="true" all="true">
- <mappingSet>
- <mapping namespace="${wsdl.Namespace}" package="${wsdl.ClientNS}" />
- <mapping namespace="http://dataTypes.vamsas" package="${wsdl.ClientNS}" />
- </mappingSet>
- </axis-wsdl2java>
-</target>
-
-<target name="makedist" depends="build, buildPropertiesFile, linkcheck, buildindices">
- <fail if="clover.jar">
- Ignoring request to build jalview distribution with clover-instrumented classes
- </fail>
- <!-- make the package jar if not already existing -->
- <mkdir dir="${packageDir}" />
- <!-- clean dir if it already existed -->
- <delete>
- <fileset dir="${packageDir}">
- <include name="*.jar" />
- </fileset>
- </delete>
- <jar destfile="${packageDir}/${outputJar}" index="true">
- <manifest>
- <attribute name="Main-Class" value="jalview.bin.Jalview" />
- <attribute name="Permissions" value="all-permissions" />
- <attribute name="Application-Name" value="Jalview Desktop" />
- <attribute name="Codebase" value="${application.codebase}" />
- </manifest>
- <fileset dir="${outputDir}/">
- <exclude name="cache*/**" />
- <exclude name="*.jar" />
- <exclude name="*.jar.*" />
- <exclude name="**/*.jar" />
- <exclude name="**/*.jar.*" />
- </fileset>
- </jar>
-
- <copy toDir="${packageDir}" flatten="true">
- <fileset dir="${outputDir}">
- <include name="*.jar" />
- <include name="**/*.jar" />
- </fileset>
- </copy>
-</target>
-
-
-<!-- jalopy code reformatter -->
-<target name="sourcescrub" depends="init,build">
- <jalopy destdir="jsrc" classpathref="run.classpath" convention="jalview-jalopy.xml">
- <fileset dir="${sourceDir}">
- <include name="*.java" />
- <include name="**/*.java" />
- <include name="**/**/*.java" />
- </fileset>
- </jalopy>
-</target>
-
-
-
-<!-- Compile, package and obfuscate Jalview Applet -->
-<target name="makeApplet" depends="obfuscate" description="assemble the final jalviewLite applet jar with or without obfuscation" />
-
-<target name="compileApplet" depends="init,clean">
- <mkdir dir="${outputDir}" />
- <javac source="${javac.source}" target="${javac.target}" srcdir="${sourceDir}" destdir="${outputDir}" debug="${javac.debug}" classpathref="jalviewlite.deps" includes="jalview/appletgui/**" excludes="ext/**,gui/**,jbgui/**,MCview/**,org/**,vamsas/**,jalview/ext/rbvi/**,jalview/ext/paradise/**,jalview/ext/ensembl/**,jalview/ext/so/**" />
-</target>
-
-<target name="packageApplet" depends="compileApplet, buildPropertiesFile">
- <copy file="${resourceDir}/images/link.gif" toFile="${outputDir}/images/link.gif" />
- <copy todir="${outputDir}/lang">
- <fileset dir="${resourceDir}/lang">
- <include name="**.*" />
- </fileset>
- </copy>
- <jar destfile="in.jar" index="true">
- <manifest>
- <attribute name="Main-Class" value="jalview.bin.JalviewLite" />
- <attribute name="Application-Name" value="JalviewLite" />
- <attribute name="Codebase" value="${applet.codebase}" />
- </manifest>
- <fileset dir="${outputDir}">
- <include name="com/**" />
- <include name="MCview/**" />
- <include name="jalview/**" />
- <include name=".build_properties" />
- <include name="images/link.gif" />
- <include name="lang/**" />
- </fileset>
- </jar>
-</target>
-<target name="obfuscate" depends="-obfuscatefake,-obfuscatereally">
-</target>
-<target name="-obfuscatefake" depends="packageApplet" if="donotobfuscate">
- <copy file="in.jar" tofile="${jalviewLiteJar}" overwrite="true" />
- <delete file="in.jar" />
-</target>
-<target name="-obfuscatereally" unless="donotobfuscate">
-
- <path id="obfuscateDeps.path">
- <pathelement location="${applet.jre.tools}" />
- <pathelement location="appletlib/${jmolJar}" />
- <pathelement location="lib/${varnaJar}" />
- <pathelement location="appletlib/${jsoup}" />
- <pathelement location="appletlib/${jsonSimple}" />
- <pathelement location="appletlib/${javaJson}" />
- <fileset dir="${java.home}/lib">
- <include name="plugin.jar" />
- </fileset>
- </path>
- <taskdef resource="proguard/ant/task.properties" classpath="utils/proguard_5.3.3.jar" />
-
- <proguard verbose="true" >
- <injar file="in.jar" />
- <outjar file="${jalviewLiteJar}" />
- <libraryjar refid="obfuscateDeps.path" />
- <dontwarn />
- <keep access="public" type="class" name="jalview.bin.JalviewLite">
- <field access="public" />
- <method access="public" />
- <constructor access="public" />
- </keep>
- <keep access="public" type="class" name="jalview.appletgui.AlignFrame">
- <field access="public" />
- <method access="public" />
- <constructor access="public" />
- </keep>
-
- <keep name="jalview.json.binding**">
- <constructor/>
- <method name="*"/>
- </keep>
-
- <keep access="public" type="class" name="MCview.PDBfile">
- <field access="public" />
- <method access="public" />
- <constructor access="public" />
- </keep>
-
- <keep access="public" type="class" name="jalview.ws.jws1.Annotate3D">
- <field access="public" />
- <method access="public" />
- <constructor access="public" />
- </keep>
-
- <keep access="public" type="class" name="jalview.ext.jmol.JmolParser">
- <field access="public" />
- <method access="public" />
- <constructor access="public" />
- </keep>
-
-
- <!-- -libraryjars "${obfuscateDeps}"
- -injars in.jar
- -outjars jalviewApplet.jar
- -keep public class jalview.bin.JalviewLite
- { public * ; } -->
- </proguard>
- <delete file="in.jar" />
-</target>
-
-<target name="jaxb-bindings" depends="init" description="Generates JAXB bindings for supported Jalview XML models (needs xjc on the path)">
- <delete>
- <fileset dir="${sourceDir}/jalview/xml/binding/jalview">
- <include name="*.java" />
- </fileset>
- </delete>
- <exec executable="xjc">
- <arg value="${schemaDir}/jalview.xsd"/>
- <arg value="-d"/>
- <arg value="${sourceDir}"/>
- <arg value="-p"/>
- <arg value="jalview.xml.binding.jalview"/>
- </exec>
- <delete>
- <fileset dir="${sourceDir}/jalview/xml/binding/embl">
- <include name="*.java" />
- </fileset>
- </delete>
-
- <exec executable="xjc">
- <arg value="${schemaDir}/embl.xsd"/>
- <arg value="-d"/>
- <arg value="${sourceDir}"/>
- <arg value="-b"/>
- <arg value="${schemaDir}/embl_bindings.xml"/>
- <arg value="-p"/>
- <arg value="jalview.xml.binding.embl"/>
- </exec>
-
- <delete>
- <fileset dir="${sourceDir}/jalview/xml/binding/uniprot">
- <include name="*.java" />
- </fileset>
- </delete>
-
- <exec executable="xjc">
- <arg value="${schemaDir}/uniprot.xsd"/>
- <arg value="-d"/>
- <arg value="${sourceDir}"/>
- <arg value="-p"/>
- <arg value="jalview.xml.binding.uniprot"/>
- </exec>
-</target>
-
-<target name="sourcedist" description="create jalview source distribution" depends="init">
- <delete file="${source.dist.name}" />
- <!-- temporary copy of source to update timestamps -->
- <copy todir="_sourcedist">
- <fileset dir=".">
- <exclude name=".*" />
- <exclude name="**/.*" />
- <exclude name="*.class" />
- <exclude name="**/*.class" />
- <include name="LICENSE" />
- <include name="README" />
- <include name="build.xml" />
- <include name="jalview-jalopy.xml" />
- <include name="JalviewApplet.jpx" />
- <include name="JalviewX.jpx" />
- <include name="nbbuild.xml" />
- <include name="nbproject/genfiles.properties" />
- <include name="nbproject/project.properties" />
- <include name="nbproject/project.xml" />
- <include name="${sourceDir}/*.java" />
- <include name="${sourceDir}/**/*.java" />
- <include name="${sourceDir}/**/*.cdr" />
- <include name="${libDir}/**/*" />
- <include name="${resourceDir}/**/*" />
- <include name="${helpDir}/**/*" />
- <include name="appletlib/${jmolJar}" />
- <include name="appletlib/${jsonSimple}" />
- <include name="appletlib/${javaJson}" />
- <exclude name="**/*locales" />
- <exclude name="*locales/**" />
- <exclude name="utils/InstallAnywhere/**Build.iap_xml" />
- <exclude name="utils/InstallAnywhere/**Build*/**" />
- <exclude name="utils/InstallAnywhere/**Build*/**" />
- <exclude name="utils/InstallAnywhere/.build*.*/**" />
- <exclude name="utils/InstallAnywhere/**locale*" />
- <exclude name="utils/InstallAnywhere/**locale*/**" />
- <exclude name="utils/InstallAnywhere/**locale*/**" />
- <include name="${schemaDir}/**/*" />
- <include name="utils/**/*" />
- <include name="${docDir}/**/*" />
- <include name="examples/**/*" />
- </fileset>
- </copy>
-
- <tstamp prefix="build">
- <format property="year" pattern="yyyy" />
- </tstamp>
- <!-- each replacetoken CDATA body must be on one line -
- otherwise the pattern doesn't match -->
- <replace value="${JALVIEW_VERSION}">
- <replacetoken><![CDATA[$$Version-Rel$$]]></replacetoken>
- <fileset dir="_sourcedist">
- <include name="**/*" />
- </fileset>
- </replace>
- <replace dir="_sourcedist" value="${build.year}">
- <replacetoken><![CDATA[$$Year-Rel$$]]></replacetoken>
- <fileset dir="_sourcedist">
- <include name="**/*" />
- </fileset>
- </replace>
-
- <tar destfile="${source.dist.name}" compression="gzip">
- <tarfileset dir="_sourcedist/" prefix="jalview" preserveLeadingSlashes="true">
- </tarfileset>
- </tar>
-
- <delete dir="_sourcedist" />
-</target>
-<target name="prepubapplet_1" depends="makeApplet">
- <copy todir="${packageDir}/examples">
- <fileset dir="examples">
- <include name="**/*" />
- <include name="javascript/*" />
- <include name="jmol/*" />
- </fileset>
- <fileset dir=".">
- <include name="${jalviewLiteJar}" />
- </fileset>
- <fileset dir="appletlib">
- <include name="**/*" />
- </fileset>
- </copy>
- <jar update="true" index="true" jarfile="${packageDir}/examples/${jalviewLiteJar}" />
- <jar update="true" index="true" jarfile="${packageDir}/examples/${javaJson}" />
- <jar update="true" index="true" jarfile="${packageDir}/examples/${jsonSimple}" />
- <jar update="true" index="true" jarfile="${packageDir}/examples/${jmolJar}">
- <manifest>
- <attribute name="Application-Name" value="Jmol (bundled with JalviewLite)" />
- <!-- <attribute name="Permissions" value="sandbox" /> -->
- <!--<attribute name="Trusted-Lib" value="true" /> -->
- <attribute name="Codebase" value="${applet.codebase}" />
- <attribute name="Caller-Allowable-Codebase" value="${applet.caller-codebase}" />
- </manifest>
- </jar>
-
- <presetdef name="ap_applet.jar">
- <!-- build a signed applet with 'all-permissions' -
- Needs 'param name="permissions' value="all-permissions"' in applet tag
- JalviewLite+JmolApplet linked sequence/structure fails
- Mixed code warnings are raised
- -->
- <jar update="true" index="true">
- <manifest>
- <attribute name="Application-Name" value="JalviewLite" />
- <attribute name="Permissions" value="all-permissions" />
- <attribute name="Codebase" value="${applet.codebase}" />
- <attribute name="Caller-Allowable-Codebase" value="${applet.caller-codebase}" />
- <attribute name="Application-Library-Allowable-Codebase" value="${applet.codebase}" />
- </manifest>
- </jar>
- </presetdef>
- <presetdef name="applet.jar">
- <!-- build signed applet with sandbox permissions -
- Needs 'param name="permissions' value="sandbox"' in applet tag
- Preserves Pre-Java 1.7_u45 behavior once 'permissions' parameter added to applet tag
- -->
-
- <jar update="true" index="true">
- <manifest>
- <attribute name="Application-Name" value="JalviewLite" />
- <attribute name="Permissions" value="sandbox" />
- <attribute name="Codebase" value="${applet.codebase}" />
- <attribute name="Caller-Allowable-Codebase" value="${applet.caller-codebase}" />
- <attribute name="Application-Library-Allowable-Codebase" value="${applet.codebase}" />
- </manifest>
- </jar>
- </presetdef>
- <presetdef name="tl_applet.jar">
- <!-- build signed applet with trusted library/trusted permissions -
- Needs 'param name="permissions' value="all-permissions"' in applet tag
- j1.7_45:
- No mixed code warnings raised
- Jmol/JalviewLite sequence/structure example doesn't link structures
- Raises dialog asking user to allow page to control applet via LiveConnect javascript
-
- -->
-
- <jar update="true" index="true">
- <manifest>
- <attribute name="Application-Name" value="JalviewLite" />
- <attribute name="Permissions" value="all-permissions" />
- <attribute name="Codebase" value="${applet.codebase}" />
- <attribute name="Trusted-Only" value="true" />
- <attribute name="Trusted-Library" value="true" />
- </manifest>
- </jar>
- </presetdef>
- <presetdef name="to_applet.jar">
- <!-- not fully test variant (yet) -->
- <jar update="true" index="true">
- <manifest>
- <attribute name="Application-Name" value="JalviewLite" />
- <attribute name="Permissions" value="all-permissions" />
- <attribute name="Codebase" value="${applet.codebase}" />
- <attribute name="Trusted-Only" value="true" />
- </manifest>
- </jar>
- </presetdef>
- <!-- create differently privileged artefacts -->
- <copy file="${packageDir}/examples/${jalviewLiteJar}" tofile="${packageDir}/examples/u_${jalviewLiteJar}" />
- <copy file="${packageDir}/examples/${jmolJar}" tofile="${packageDir}/examples/u_${jmolJar}" overwrite="true" />
- <copy file="${packageDir}/examples/${javaJson}" tofile="${packageDir}/examples/u_${javaJson}" overwrite="true" />
- <copy file="${packageDir}/examples/${jsonSimple}" tofile="${packageDir}/examples/u_${jsonSimple}" overwrite="true" />
- <copy file="${packageDir}/examples/${jalviewLiteJar}" tofile="${packageDir}/examples/ap_${jalviewLiteJar}" />
- <copy file="${packageDir}/examples/${jmolJar}" tofile="${packageDir}/examples/ap_${jmolJar}" />
- <copy file="${packageDir}/examples/${javaJson}" tofile="${packageDir}/examples/ap_${javaJson}" />
- <copy file="${packageDir}/examples/${jsonSimple}" tofile="${packageDir}/examples/ap_${jsonSimple}" />
- <ap_applet.jar jarfile="${packageDir}/examples/ap_${jalviewLiteJar}" />
- <ap_applet.jar jarfile="${packageDir}/examples/ap_${jmolJar}" />
- <ap_applet.jar jarfile="${packageDir}/examples/ap_${javaJson}" />
- <ap_applet.jar jarfile="${packageDir}/examples/ap_${jsonSimple}" />
- <copy file="${packageDir}/examples/${jalviewLiteJar}" tofile="${packageDir}/examples/tl_${jalviewLiteJar}" />
- <copy file="${packageDir}/examples/${jmolJar}" tofile="${packageDir}/examples/tl_${jmolJar}" />
- <copy file="${packageDir}/examples/${javaJson}" tofile="${packageDir}/examples/tl_${javaJson}" />
- <copy file="${packageDir}/examples/${jsonSimple}" tofile="${packageDir}/examples/tl_${jsonSimple}" />
- <tl_applet.jar jarfile="${packageDir}/examples/tl_${jalviewLiteJar}" />
- <tl_applet.jar jarfile="${packageDir}/examples/tl_${jmolJar}" />
- <tl_applet.jar jarfile="${packageDir}/examples/tl_${javaJson}" />
- <tl_applet.jar jarfile="${packageDir}/examples/tl_${jsonSimple}" />
- <copy file="${packageDir}/examples/${jalviewLiteJar}" tofile="${packageDir}/examples/to_${jalviewLiteJar}" />
- <copy file="${packageDir}/examples/${jmolJar}" tofile="${packageDir}/examples/to_${jmolJar}" />
- <copy file="${packageDir}/examples/${javaJson}" tofile="${packageDir}/examples/to_${javaJson}" />
- <copy file="${packageDir}/examples/${jsonSimple}" tofile="${packageDir}/examples/to_${jsonSimple}" />
- <to_applet.jar jarfile="${packageDir}/examples/to_${jalviewLiteJar}" />
- <to_applet.jar jarfile="${packageDir}/examples/to_${jmolJar}" />
- <to_applet.jar jarfile="${packageDir}/examples/to_${javaJson}" />
- <to_applet.jar jarfile="${packageDir}/examples/to_${jsonSimple}" />
- <!-- finally, create manifest for original jars -->
- <applet.jar jarfile="${packageDir}/examples/${jalviewLiteJar}" />
- <applet.jar jarfile="${packageDir}/examples/${jmolJar}" />
- <applet.jar jarfile="${packageDir}/examples/${javaJson}" />
- <applet.jar jarfile="${packageDir}/examples/${jsonSimple}" />
-
- <!-- todo - write examples/downloads for alternate versions of the applet
- probably don't need to do this now since we don't have alternate versions anymore !-->
-</target>
-<target name="-signapplet" depends="prepubapplet_1">
- <fileset id="signappletjarset" dir="${packageDir}/examples">
- <exclude name="u_*.jar" />
- <include name="${jalviewLiteJar}" />
- <include name="${jmolJar}" />
- <include name="${javaJson}" />
- <include name="${jsonSimple}" />
- <include name="to_${jalviewLiteJar}" />
- <include name="to_${jmolJar}" />
- <include name="to_${javaJson}" />
- <include name="to_${jsonSimple}" />
- <include name="tl_${jalviewLiteJar}" />
- <include name="tl_${jmolJar}" />
- <include name="tl_${javaJson}" />
- <include name="tl_${jsonSimple}" />
- <include name="ap_${jalviewLiteJar}" />
- <include name="ap_${jmolJar}" />
- <include name="ap_${javaJson}" />
- <include name="ap_${jsonSimple}" />
- </fileset>
-</target>
-<target name="-signappletnotsa" if:blank="timestamp" depends="-signapplet" unless="nosign">
- <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false">
- <fileset refid="signappletjarset" />
- </signjar>
-</target>
-
-<target name="-signapplettsa" if="timestamp" depends="-signapplet" unless="nosign">
- <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" tsaproxyhost="${proxyHost}" tsaproxyport="${proxyPort}" tsaurl="${jalview.tsaurl}">
- <fileset refid="signappletjarset" />
- </signjar>
-</target>
-
-<target name="signApplet" description="internal target to sign applet" depends="-signappletnotsa,-signapplettsa" />
-<target name="pubapplet" description="Dummy target to keep legacy Jalview build system happy. We don't actually publish the applet anymore."/>
-
-<target name="_pubapplet" description="installs the jalviewLite applet and dependent jars into an applet examples directory built under ${outputDir}" depends="makeApplet, signApplet">
-
- <!-- bizarre bug causes JmolApplet to always get signed, even if excluded from above. so copy explicitly -->
- <copy file="appletlib/${jmolJar}" tofile="${packageDir}/examples/u_${jmolJar}" overwrite="true" />
- <copy file="appletlib/${jsonSimple}" tofile="${packageDir}/examples/u_${jsonSimple}" overwrite="true" />
- <copy file="appletlib/${javaJson}" tofile="${packageDir}/examples/u_${javaJson}" overwrite="true" />
- <!-- finally, replace any launchApp servlet tags with a version specification -->
- <replace value="http://www.jalview.org/services/launchApp?version=${JALVIEW_VERSION}"">
- <replacetoken>
- <![CDATA[http://www.jalview.org/services/launchApp"]]>
- </replacetoken>
- <fileset dir="${packageDir}/examples">
- <include name="**/*.html" />
- </fileset>
- </replace>
- <replace value="http://www.jalview.org/services/launchApp?version=${JALVIEW_VERSION}'">
- <replacetoken>
- <![CDATA[http://www.jalview.org/services/launchApp']]>
- </replacetoken>
- <fileset dir="${packageDir}/examples">
- <include name="**/*.html" />
- </fileset>
- </replace>
-
-</target>
-<target name="sourcedoc" description="Create jalview source documentation pages" depends="init">
- <javadoc destdir="${javadocDir}">
- <packageset dir="${sourceDir}" includes="jalview/*,MCView/*">
- </packageset>
- </javadoc>
-</target>
-<target name="linkcheck" depends="init,prepare">
- <javac srcdir="utils" destdir="utils" includes="HelpLinksChecker.java"/>
- <java fork="true" dir="${helpDir}" classpath="utils" classname="HelpLinksChecker" failonerror="true">
- <arg file="${helpDir}"/>
- <arg value="-nointernet"/>
- </java>
-</target>
-</project>
</head>
<body>
<h1>Building Jalview from Source</h1>
-<P>
+<p/>
+
+<p>
+You will need the following:<br/>
+<ul>
+ <li> Obtain: git</li>
+ <li> Build/run: Java Development Kit (JDK). JDK11 is now the recommended platform for developing with Jalview. You can obtain a pre-compiled JDK11 for many platforms from https://adoptopenjdk.net/</li>
+ <li> Build: Gradle 5.1 or later. On linux you can obtain this with your package manager (e.g. <code>sudo yum install gradle</code> or <code>sudo apt install gradle</code> or on macOS with brew with <code>brew install gradle</code></li>
+</ul>
+With any luck, once you check out the Jalview source from git and set your JAVA_HOME and PATH correctly, you just need to change to the <code>jalview</code> directory and run <code>gradle getdown</code>.
+</p>
+
+<h2>Obtaining Jalview</h2>
+<p>This is easiest achieved with git:
+<pre>git clone http://www.jalview.org/git/jalview.git</pre>
+Then you can <code>cd jalview</code> to get into the top level jalview dir.
+
+
+<p>
+<h2>Minimal Jalview build</h2>
+<p>To run Jalview, you just need the jalview classes and the .jar libraries that Jalview depends on.</p>
+
+
+<!--
<p>
You will need the following (hopefully):<br>
<ul>
mechanism (e.g. Netbeans' executable Jar and dependent lib directory).
The hand-crafted ant build.xml is (currently) the only officially
supported method of building distributable versions of Jalview.</p>
+ -->
<address>
<a href="mailto:help@jalview.org">Jalview development team</a>
</address>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>getdown</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
--- /dev/null
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
--- /dev/null
+language: java
+sudo: false
+script: "mvn -B clean verify"
+
+cache:
+ directories:
+ - '$HOME/.m2/repository'
+
+jdk:
+ - openjdk7
+ - oraclejdk8
--- /dev/null
+#
+# This is the official list of the AUTHORS of Getdown for copyright purposes.
+#
+# This is not the full list of contributors, see
+# https://github.com/threerings/getdown/graphs/contributors
+# for the full list of contributors.
+#
+# Contributors assign copyright of their work to the authors listed in the this file to keep life
+# simple.
+
+Michael Bayne <mdb@samskivert.com>
+Ray Greenwell <ray@threerings.net>
--- /dev/null
+# Getdown Releases
+
+## 1.8.3 - Unreleased
+
+* Added support for `nresource` resources which must be jar files that contain native libraries.
+ Prior to launching the application, these resources will be unpacked and their contents added to
+ the `java.library.path` system property.
+
+* When the app is updated to require a new version of the JVM, that JVM will be downloaded and used
+ immediately during that app invocation (instead of one invocation later). Via PR#169.
+
+* When a custom JVM is installed, old JVM files will be deleted prior to unpacking the new JVM. Via
+ PR#170.
+
+* Number of concurrent downloads now defaults to num-cores minus one. Though downloads are I/O
+ bound rather than CPU bound, this still turns out to be a decent default.
+
+* Avoid checking for proxy config if `https.proxyHost` is set. This matches existing behavior when
+ `http.proxyHost` is set.
+
+* Added support for proxy authentication. A deployment must also use the
+ `com.threerings.getdown.spi.ProxyAuth` service provider interface to persist the proxy
+ credentials supplied by the user. Otherwise they will be requested every time Getdown runs, which
+ is not a viable user experience.
+
+## 1.8.2 - Nov 27, 2018
+
+* Fixed a data corruption bug introduced at last minute into 1.8.1 release. Oops.
+
+## 1.8.1 - Nov 26, 2018
+
+* If both an `appbase` and `appdir` are provided via some means (bootstrap properties file, system
+ property, etc.) and the app dir does not yet exist, Getdown will create it.
+
+* Added `max_concurrent_downloads` setting to `getdown.txt`. Controls what you would expect.
+ Defaults to two.
+
+* `bootstrap.properties` can now contain system properties which will be set prior to running
+ Getdown. They must be prefixed by `sys.`: for example `sys.silent = true` will set the `silent`
+ system property to `true`.
+
+* If Getdown is run in a headless JVM, it will avoid showing a UI but will attempt to install and
+ launch the application anyhow. Note that passing `-Dsilent` will override this behavior (because
+ in silent mode the default is only to install the app, not also launch it).
+
+* Fixed issue with `appid` not being properly used when specified via command line arg.
+
+* Fixed issue with running Getdown on single CPU systems (or virtual systems). It was attempting to
+ create a thread pool of size zero, which failed.
+
+* Fixed issue with backslashes (or other regular expression escape characters) in environment
+ variables being substituted into app arguments.
+
+## 1.8.0 - Oct 19, 2018
+
+* Added support for manually specifying the thread pool size via `-Dthread_pool_size`. Also reduced
+ the default thread pool size to `num_cpus-1` from `num_cpus`.
+
+* Added support for bundling a `bootstrap.properties` file with the Getdown jar file, which can
+ specify defaults for `appdir`, `appbase` and `appid`.
+
+* Added support for a host URL whitelist. Getdown can be custom built to refuse to operate with any
+ URL that does not match the built-time-specified whitelist. See `core/pom.xml` for details.
+
+* Removed the obsolete support for running Getdown in a signed applet. Applets are no longer
+ supported by any widely used browser.
+
+* Split the project into multiple Maven modules. See the notes on [migrating from 1.7 to 1.8] for
+ details.
+
+* A wide variety of small cleanups resulting from a security review generously performed by a
+ prospective user. This includes various uses of deterministic locales and encodings instead of
+ the platform default locale/encoding, in cases where platform/locale-specific behavior is not
+ desired or needed.
+
+* Made use of `appid` fall back to main app class if no `appid`-specific class is specified.
+
+* Added support for marking resources as executable (via `xresource`).
+
+* Fixed issue where entire tracking URL was being URL encoded.
+
+* Changed translations to avoid the use of the term 'game'. Use 'app' instead.
+
+## 1.7.1 - Jun 6, 2018
+
+* Made it possible to use `appbase_domain` with `https` URLs.
+
+* Fixed issue with undecorated splash window being unclosable if failures happen early in
+ initialization process. (#57)
+
+* Added support for transparent splash window. (#92)
+
+* Fixed problem with unpacked code resources (`ucode`) and `pack.gz` files. (#95)
+
+* Changed default Java version regex to support new Java 9+ version formats. (#93)
+
+* Ensure correct signature algorithm is used for each version of digest files. (#91)
+
+* Use more robust delete in all cases where Getdown needs to delete files. This should fix issues
+ with lingering files on Windows (where sometimes delete fails spuriously).
+
+## 1.7.0 - Dec 12, 2017
+
+* Fixed issue with `Digester` thread pool not being shutdown. (#89)
+
+* Fixed resource unpacking, which was broken by earlier change introducing resource installation
+ (downloading to `_new` files and then renaming into place). (#88)
+
+* The connect and read timeouts specified by system properties are now used for all the various
+ connections made by Getdown.
+
+* Proxy detection now uses a 5 second connect/read timeout, to avoid stalling for a long time in
+ certain problematic network conditions.
+
+* Getdown is now built against JDK 1.7 and requires JDK 1.7 (or newer) to run. Use the latest
+ Getdown 1.6.x release if you need to support Java 1.6.
+
+## 1.6.4 - Sep 17, 2017
+
+* `digest.txt` (and `digest2.txt`) computation now uses parallel jobs. Each resource to be verified
+ is a single job and the jobs are doled out to a thread pool with #CPUs threads. This allows large
+ builds to proceed faster as most dev machines have more than one core.
+
+* Resource verification is now performed in parallel (similar to the `digest.txt` computation, each
+ resource is a job farmed out to a thread pool). For large installations on multi-core machines,
+ this speeds up the verification phase of an installation or update.
+
+* Socket reads now have a 30 second default timeout. This can be changed by passing
+ `-Dread_timeout=N` (where N is seconds) to the JVM running Getdown.
+
+* Fixed issue with failing to install a downloaded and validated `_new` file.
+
+* Added support for "strict comments". In this mode, Getdown only treats `#` as starting a comment
+ if it appears in column zero. This allows `#` to occur on the right hand side of configuration
+ values (like in file names). To enable, put `strict_comments = true` in your `getdown.txt` file.
+
+## 1.6.3 - Apr 23, 2017
+
+* Fixed error parsing `cache_retention_days`. (#82)
+
+* Fixed error with new code cache. (9e23a426)
+
+## 1.6.2 - Feb 12, 2017
+
+* Fixed issue with installing local JVM, caused by new resource installation process. (#78)
+
+* Local JVM now uses absolute path to avoid issues with cwd.
+
+* Added `override_appbase` system property. This enables a Getdown app that normally talks to some
+ download server to be installed in such a way that it instead talks to some other download
+ server.
+
+## 1.6.1 - Feb 12, 2017
+
+* Fix issues with URL path encoding when downloading resources. (84af080b0)
+
+* Parsing `digest.txt` changed to allow `=` to appear in the filename. In `getdown.txt` we split on
+ the first `=` because `=` never appears in a key but may appear in a value. But in `digest.txt`
+ the format is `filename = hash` and `=` never appears in the hash but may appear in the filename,
+ so there we want to split on the _last_ `=` not the first.
+
+* Fixed bug with progress tracking and reporting. (256e0933)
+
+* Fix executable permissions on `jspawnhelper`. (#74)
+
+## 1.6 - Nov 5, 2016
+
+* This release and all those before it are considered ancient history. Check the commit history for
+ more details on what was in each of these releases.
+
+## 1.0 - Sep 21, 2010
+
+* The first Maven release of Getdown.
+
+## 0.1 - July 19, 2004
+
+* The first production use of Getdown (on https://www.puzzlepirates.com which is miraculously still
+ operational as of 2018 when this changelog was created).
+
+[migrating from 1.7 to 1.8]: https://github.com/threerings/getdown/wiki/Migrate17to18
--- /dev/null
+Getdown - application installer, patcher and launcher
+
+Copyright (C) 2004-2016 Getdown authors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
--- /dev/null
+## What is it?
+
+Getdown (yes, it's the funky stuff) is a system for deploying Java applications to end-user
+computers, as well as keeping those applications up to date.
+
+It was designed as a replacement for [Java Web Start](https://docs.oracle.com/javase/8/docs/technotes/guides/javaws/)
+due to limitations in Java Web Start's architecture which are outlined in the
+[rationale](https://github.com/threerings/getdown/wiki/Rationale) section.
+
+Note: Getdown was designed *in 2004* as an alternative to Java Web Start, because of design choices
+made by JWS that were problematic to the use cases its authors had. It is _not_ a drop-in
+replacement for JWS, aimed to help the developers left in the lurch by the deprecation of JWS in
+Java 9. It may still be a viable alternative for developers looking to replace JWS, but don't
+expect to find feature parity with JWS.
+
+## How do I use it?
+
+A tutorial and more detailed specification are available from the [Documentation] page. Questions
+can be posted to the [OOO Libs Google group].
+
+Note that because one can not rely on users having a JRE installed, you must create a custom
+installer for each platform that you plan to support (Windows, macOS, Linux) that installs a JRE,
+the Getdown launcher jar file, a stub configuration file that identifies the URL at which your real
+app manifest is hosted, and whatever the appropiate "desktop integration" is that provides an icon
+the user can click on. We have some details on the
+[installers](https://github.com/threerings/getdown/wiki/Installers) documentation page, though it
+is unfortunately not very detailed.
+
+## How does it work?
+
+The main design and operation of Getdown is detailed on the
+[design](https://github.com/threerings/getdown/wiki/Design) page. You can also browse the
+[javadoc documentation] and [source code] if you're interested in implementation details.
+
+## Where can I see it in action?
+
+Getdown was originally written by developers at [OOO] for the deployment of their Java-based
+massively multiplayer games. Try out any of the following games to see it in action:
+
+ * [Puzzle Pirates](https://www.puzzlepirates.com/) - OOO
+ * [Spiral Knights](https://www.spiralknights.com/) - OOO
+
+Getdown is implemented in Java, and is designed to deploy and update JVM-based applications. While
+it would be technically feasible to use Getdown to deploy non-JVM-based applications, it is not
+currently supported and it is unlikely that the overhead of bundling a JVM just to run Getdown
+would be worth it if the JVM were not also being used to run the target application.
+
+## Release notes
+
+See [CHANGELOG.md](CHANGELOG.md) for release notes.
+
+## Obtaining Getdown
+
+Getdown will likely need to be integrated into your build. We have separate instructions for
+[build integration]. You can also download the individual jar files from Maven Central if needed.
+Getdown is comprised of three Maven artifacts (jar files), though you probably only need the first
+one:
+
+ * [getdown-launcher](http://repo2.maven.org/maven2/com/threerings/getdown/getdown-launcher)
+ contains minified (via Proguard) code that you actually run to update and launch your app. It
+ also contains the tools needed to build a Getdown app distribution.
+
+ * [getdown-core](http://repo2.maven.org/maven2/com/threerings/getdown/getdown-core) contains the
+ core logic for downloading, verifying, patching and launching an app as well as the core logic
+ for creating an app distribution. It does not contain any user interface code. You would only
+ use this artifact if you were planning to integrate Getdown directly into your app.
+
+ * [getdown-ant](http://repo2.maven.org/maven2/com/threerings/getdown/getdown-ant) contains an Ant
+ task for building a Getdown app distribution. See the [build integration] instructions for
+ details.
+
+You can also:
+
+ * [Check out the code](https://github.com/threerings/getdown) and build it yourself.
+ * Browse the [source code] online.
+ * View the [javadoc documentation] online.
+
+## JVM Version Requirements
+
+ * Getdown version 1.8.x requires Java 7 VM or newer.
+ * Getdown version 1.7.x requires Java 7 VM or newer.
+ * Getdown version 1.6.x requires Java 6 VM or newer.
+ * Getdown version 1.5 and earlier requires Java 5 VM or newer.
+
+## Migrating from Getdown 1.7 to Getdown 1.8
+
+See [this document](https://github.com/threerings/getdown/wiki/Migrating-from-1.7-to-1.8) on the
+changes needed to migrate from Getdown 1.7 to 1.8.
+
+## Building
+
+Getdown is built with Maven in the standard ways. Invoke the following commands, for fun and
+profit:
+
+```
+% mvn compile # builds the classes
+% mvn test # builds and runs the unit tests
+% mvn package # builds and creates jar file
+% mvn install # builds, jars and installs in your local Maven repository
+```
+
+## Discussion
+
+Feel free to pop over to the [OOO Libs Google Group] to ask questions and get (and give) answers.
+
+[Documentation]: https://github.com/threerings/getdown/wiki
+[OOO Libs Google group]: http://groups.google.com/group/ooo-libs
+[source code]: https://github.com/threerings/getdown/tree/master/src/main/java/com/threerings/getdown/launcher
+[javadoc documentation]: https://threerings.github.com/getdown/apidocs/
+[OOO]: https://en.wikipedia.org/wiki/Three_Rings_Design
+[build integration]: https://github.com/threerings/getdown/wiki/Build-Integration
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>getdown-ant</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding/<project>=UTF-8
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.7
--- /dev/null
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown</artifactId>
+ <version>1.8.3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>getdown-ant</artifactId>
+ <packaging>jar</packaging>
+ <name>Getdown Ant Task</name>
+ <description>An Ant task for building Getdown app distributions</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.7.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tools;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.security.GeneralSecurityException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+import com.threerings.getdown.data.Digest;
+
+/**
+ * An ant task used to create a <code>digest.txt</code> for a Getdown
+ * application deployment.
+ */
+public class DigesterTask extends Task
+{
+ /**
+ * Sets the application directory.
+ */
+ public void setAppdir (File appdir)
+ {
+ _appdir = appdir;
+ }
+
+ /**
+ * Sets the digest signing keystore.
+ */
+ public void setKeystore (File path)
+ {
+ _storepath = path;
+ }
+
+ /**
+ * Sets the keystore decryption key.
+ */
+ public void setStorepass (String password)
+ {
+ _storepass = password;
+ }
+
+ /**
+ * Sets the private key alias.
+ */
+ public void setAlias (String alias)
+ {
+ _storealias = alias;
+ }
+
+ /**
+ * Performs the actual work of the task.
+ */
+ @Override
+ public void execute () throws BuildException
+ {
+ // make sure appdir is set
+ if (_appdir == null) {
+ throw new BuildException("Must specify the path to the application directory " +
+ "via the 'appdir' attribute.");
+ }
+
+ // make sure _storepass and _keyalias are set, if _storepath is set
+ if (_storepath != null && (_storepass == null || _storealias == null)) {
+ throw new BuildException(
+ "Must specify both a keystore password and a private key alias.");
+ }
+
+ try {
+ Digester.createDigests(_appdir, _storepath, _storepass, _storealias);
+ } catch (IOException ioe) {
+ throw new BuildException("Error creating digest: " + ioe.getMessage(), ioe);
+ } catch (GeneralSecurityException gse) {
+ throw new BuildException("Error creating signature: " + gse.getMessage(), gse);
+ }
+ }
+
+ /** The application directory in which we're creating a digest file. */
+ protected File _appdir;
+
+ /** The path to the keystore we'll use to sign the digest file, if any. */
+ protected File _storepath;
+
+ /** The decryption key for the keystore. */
+ protected String _storepass;
+
+ /** The private key alias. */
+ protected String _storealias;
+}
--- /dev/null
+#!/bin/sh
+
+# we'll magically try to match dist/getdown.jar or target/getdown-1.x-SNAPSHOT.jar
+java -classpath */getdown*.jar com.threerings.getdown.tools.Differ "$@"
--- /dev/null
+#!/bin/sh
+
+# we'll magically try to match dist/getdown.jar or target/getdown-1.x-SNAPSHOT.jar
+java -classpath */getdown*.jar com.threerings.getdown.tools.Patcher "$@"
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>getdown-core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+encoding//src/it/java=UTF-8
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/<project>=UTF-8
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.7
--- /dev/null
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown</artifactId>
+ <version>1.8.3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>getdown-core</artifactId>
+ <packaging>jar</packaging>
+ <name>Getdown Core</name>
+ <description>Core Getdown functionality</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>2.22.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <!-- By default, no host whitelist is added to the binary, so it can be used
+ to download and run applications from any server. To create a custom
+ Getdown build that can only talk to whitelisted servers, set this
+ property on the command line, e.g. -Dgetdown.host.whitelist=my.server.com
+ Wildcards can be used (*.mycompany.com) and multiple values can be
+ separated by commas (app1.foo.com,app2.bar.com,app3.baz.com). -->
+ <properties>
+ <getdown.host.whitelist />
+ </properties>
+
+ <build>
+ <resources>
+ <resource> <!-- include the LICENSE file in the jar -->
+ <directory>..</directory>
+ <includes><include>LICENSE</include></includes>
+ </resource>
+ </resources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>add-test-source</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/it/java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>gen-build</id>
+ <phase>generate-sources</phase>
+ <configuration>
+ <target>
+ <tstamp>
+ <format property="getdown.build.time" pattern="yyyy-MM-dd HH:mm" />
+ </tstamp>
+ <copy file="${project.build.sourceDirectory}/com/threerings/getdown/data/Build.java.tmpl" tofile="${project.build.sourceDirectory}/com/threerings/getdown/data/Build.java" overwrite="true">
+ <filterset>
+ <filter token="build_time" value="${getdown.build.time}" />
+ <filter token="build_version" value="${project.version}" />
+ <filter token="host_whitelist" value="${getdown.host.whitelist}" />
+ </filterset>
+ </copy>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>${project.build.sourceDirectory}/</directory>
+ <includes>
+ <include>com/threerings/getdown/data/Build.java</include>
+ </includes>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.22.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <useFile>false</useFile>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tests;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.*;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import com.threerings.getdown.tools.Digester;
+
+public class DigesterIT {
+
+ @Test
+ public void testDigester () throws Exception {
+ Path appdir = Paths.get("src/it/resources/testapp");
+ Digester.createDigests(appdir.toFile(), null, null, null);
+
+ Path digest = appdir.resolve("digest.txt");
+ List<String> digestLines = Files.readAllLines(digest, StandardCharsets.UTF_8);
+ Files.delete(digest);
+
+ Path digest2 = appdir.resolve("digest2.txt");
+ List<String> digest2Lines = Files.readAllLines(digest2, StandardCharsets.UTF_8);
+ Files.delete(digest2);
+
+ assertEquals(Arrays.asList(
+ "getdown.txt = 779c74fb4b251e18faf6e240a0667964",
+ "testapp.jar = 404dafa55e78b25ec0e3a936357b1883",
+ "funny%test dir/some=file.txt = d8e8fca2dc0f896fd7cb4cb0031ba249",
+ "crazyhashfile#txt = f29d23fd5ab1781bd8d0760b3a516f16",
+ "foo.jar = 46ca4cc9079d9d019bb30cd21ebbc1ec",
+ "script.sh = f66e8ea25598e67e99c47d9b0b2a2cdf",
+ "digest.txt = f5561d85e4d80cc85883963897e58ff6"
+ ), digestLines);
+
+ assertEquals(Arrays.asList(
+ "getdown.txt = 4f0c657895c3c3a35fa55bf5951c64fa9b0694f8fc685af3f1d8635c639e066b",
+ "testapp.jar = c9cb1906afbf48f8654b416c3f831046bd3752a76137e5bf0a9af2f790bf48e0",
+ "funny%test dir/some=file.txt = f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2",
+ "crazyhashfile#txt = 6816889f922de38f145db215a28ad7c5e1badf7354b5cdab225a27486789fa3b",
+ "foo.jar = ea188b872e0496debcbe00aaadccccb12a8aa9b025bb62c130cd3d9b8540b062",
+ "script.sh = cca1c5c7628d9bf7533f655a9cfa6573d64afb8375f81960d1d832dc5135c988",
+ "digest2.txt = 70b442c9f56660561921da3368e1a206f05c379182fab3062750b7ddcf303407"
+ ), digest2Lines);
+ }
+}
--- /dev/null
+Hello crazy world.
--- /dev/null
+# where our app is hosted on the internets
+appbase = http://notused.com/testapp
+
+# the jar file that contains our code
+code = testapp.jar
+
+# the main entry point of our app
+class = com.threerings.testapp.TestApp
+
+# we pass the appdir to our app so that it can upgrade getdown
+apparg = %APPDIR%
+
+# test the %env% mechanism
+jvmarg = -Dusername=\%ENV.USER%
+
+strict_comments = true
+resource = funny%test dir/some=file.txt
+resource = crazyhashfile#txt
+uresource = foo.jar
+xresource = script.sh
+
+ui.name = Getdown Test App
+ui.background_image = background.png
+ui.progress = 17, 321, 458, 22
+ui.progress_bar = 336600
+ui.progress_text = FFFFFF
+ui.status = 57, 245, 373, 68
+ui.status_text = 000000
--- /dev/null
+#!/bin/sh
+
+echo "Hello world!"
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.FieldPosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.*;
+
+/**
+ * A placeholder class that contains a reference to the log object used by the Getdown code.
+ */
+public class Log
+{
+ public static class Shim {
+ /**
+ * Logs a debug message.
+ *
+ * @param message the message to be logged.
+ * @param args a list of key/value pairs and an optional final Throwable.
+ */
+ public void debug (Object message, Object... args) { doLog(0, message, args); }
+
+ /**
+ * Logs an info message.
+ *
+ * @param message the message to be logged.
+ * @param args a list of key/value pairs and an optional final Throwable.
+ */
+ public void info (Object message, Object... args) { doLog(1, message, args); }
+
+ /**
+ * Logs a warning message.
+ *
+ * @param message the message to be logged.
+ * @param args a list of key/value pairs and an optional final Throwable.
+ */
+ public void warning (Object message, Object... args) { doLog(2, message, args); }
+
+ /**
+ * Logs an error message.
+ *
+ * @param message the message to be logged.
+ * @param args a list of key/value pairs and an optional final Throwable.
+ */
+ public void error (Object message, Object... args) { doLog(3, message, args); }
+
+ protected void doLog (int levIdx, Object message, Object[] args) {
+ if (_impl.isLoggable(LEVELS[levIdx])) {
+ Throwable err = null;
+ int nn = args.length;
+ if (message instanceof Throwable) {
+ err = (Throwable)message;
+ } else if (nn % 2 == 1 && (args[nn - 1] instanceof Throwable)) {
+ err = (Throwable)args[--nn];
+ }
+ _impl.log(LEVELS[levIdx], format(message, args), err);
+ }
+ }
+
+ protected final Logger _impl = Logger.getLogger("com.threerings.getdown");
+ }
+
+ /** We dispatch our log messages through this logging shim. */
+ public static final Shim log = new Shim();
+
+ public static String format (Object message, Object... args) {
+ if (args.length < 2) return String.valueOf(message);
+ StringBuilder buf = new StringBuilder(String.valueOf(message));
+ if (buf.length() > 0) {
+ buf.append(' ');
+ }
+ buf.append('[');
+ for (int ii = 0; ii < args.length; ii += 2) {
+ if (ii > 0) {
+ buf.append(',').append(' ');
+ }
+ buf.append(args[ii]).append('=');
+ try {
+ buf.append(args[ii+1]);
+ } catch (Throwable t) {
+ buf.append("<toString() failure: ").append(t).append(">");
+ }
+ }
+ return buf.append(']').toString();
+ }
+
+ static {
+ Formatter formatter = new OneLineFormatter();
+ Logger logger = LogManager.getLogManager().getLogger("");
+ for (Handler handler : logger.getHandlers()) {
+ handler.setFormatter(formatter);
+ }
+ }
+
+ protected static class OneLineFormatter extends Formatter {
+ @Override public String format (LogRecord record) {
+ StringBuffer buf = new StringBuffer();
+
+ // append the timestamp
+ _date.setTime(record.getMillis());
+ _format.format(_date, buf, _fpos);
+
+ // append the log level
+ buf.append(" ");
+ buf.append(record.getLevel().getLocalizedName());
+ buf.append(" ");
+
+ // append the message itself
+ buf.append(formatMessage(record));
+ buf.append(System.lineSeparator());
+
+ // if an exception was also provided, append that
+ if (record.getThrown() != null) {
+ try {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ record.getThrown().printStackTrace(pw);
+ pw.close();
+ buf.append(sw.toString());
+ } catch (Exception ex) {
+ buf.append("Format failure:").append(ex);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ protected Date _date = new Date();
+ protected SimpleDateFormat _format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS");
+ protected FieldPosition _fpos = new FieldPosition(SimpleDateFormat.DATE_FIELD);
+ }
+
+ protected static final String DATE_FORMAT = "{0,date} {0,time}";
+ protected static final Level[] LEVELS = {Level.FINE, Level.INFO, Level.WARNING, Level.SEVERE};
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.cache;
+
+import java.io.File;
+import com.threerings.getdown.util.FileUtil;
+
+/**
+ * Collects elements in the {@link ResourceCache cache} which became unused and deletes them
+ * afterwards.
+ */
+public class GarbageCollector
+{
+ /**
+ * Collect and delete the garbage in the cache.
+ */
+ public static void collect (File cacheDir, final long retentionPeriodMillis)
+ {
+ FileUtil.walkTree(cacheDir, new FileUtil.Visitor() {
+ @Override public void visit (File file) {
+ File cachedFile = getCachedFile(file);
+ File lastAccessedFile = getLastAccessedFile(file);
+ if (!cachedFile.exists() || !lastAccessedFile.exists()) {
+ if (cachedFile.exists()) {
+ FileUtil.deleteHarder(cachedFile);
+ } else {
+ FileUtil.deleteHarder(lastAccessedFile);
+ }
+ } else if (shouldDelete(lastAccessedFile, retentionPeriodMillis)) {
+ FileUtil.deleteHarder(lastAccessedFile);
+ FileUtil.deleteHarder(cachedFile);
+ }
+
+ File folder = file.getParentFile();
+ if (folder != null) {
+ String[] children = folder.list();
+ if (children != null && children.length == 0) {
+ FileUtil.deleteHarder(folder);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Collect and delete garbage in the native cache. It tries to find a jar file with a matching
+ * last modified file, and deletes the entire directory accordingly.
+ */
+ public static void collectNative (File cacheDir, final long retentionPeriodMillis)
+ {
+ File[] subdirs = cacheDir.listFiles();
+ if (subdirs != null) {
+ for (File dir : subdirs) {
+ if (dir.isDirectory()) {
+ // Get all the native jars in the directory (there should only be one)
+ for (File file : dir.listFiles()) {
+ if (!file.getName().endsWith(".jar")) {
+ continue;
+ }
+ File cachedFile = getCachedFile(file);
+ File lastAccessedFile = getLastAccessedFile(file);
+ if (!cachedFile.exists() || !lastAccessedFile.exists() ||
+ shouldDelete(lastAccessedFile, retentionPeriodMillis)) {
+ FileUtil.deleteDirHarder(dir);
+ }
+ }
+ } else {
+ // @TODO There shouldn't be any loose files in native/ but if there are then
+ // what? Delete them? file.delete();
+ }
+ }
+ }
+ }
+
+ private static boolean shouldDelete (File lastAccessedFile, long retentionMillis)
+ {
+ return System.currentTimeMillis() - lastAccessedFile.lastModified() > retentionMillis;
+ }
+
+ private static File getLastAccessedFile (File file)
+ {
+ return isLastAccessedFile(file) ? file : new File(
+ file.getParentFile(), file.getName() + ResourceCache.LAST_ACCESSED_FILE_SUFFIX);
+ }
+
+ private static boolean isLastAccessedFile (File file)
+ {
+ return file.getName().endsWith(ResourceCache.LAST_ACCESSED_FILE_SUFFIX);
+ }
+
+ private static File getCachedFile (File file)
+ {
+ return !isLastAccessedFile(file) ? file : new File(
+ file.getParentFile(), file.getName().substring(0, file.getName().lastIndexOf(".")));
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.cache;
+
+import java.io.File;
+import java.io.IOException;
+
+import com.threerings.getdown.util.FileUtil;
+
+/**
+ * Maintains a cache of code resources. The cache allows multiple application instances of different
+ * versions to open at the same time.
+ */
+public class ResourceCache
+{
+ public ResourceCache (File _cacheDir) throws IOException
+ {
+ this._cacheDir = _cacheDir;
+ createDirectoryIfNecessary(_cacheDir);
+ }
+
+ private void createDirectoryIfNecessary (File dir) throws IOException
+ {
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new IOException("unable to create directory: " + dir.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Caches the given file under its {@code digest}.
+ * @param fileToCache file to cache.
+ * @param cacheSubdir the subdirectory of the cache directory in which to store the cached
+ * file. Usually either {@code digest} or a prefix of {@code digest}.
+ * @param digest a crypto digest of the cached files contents.
+ * @return the cached file.
+ */
+ public File cacheFile (File fileToCache, String cacheSubdir, String digest) throws IOException
+ {
+ File cacheLocation = new File(_cacheDir, cacheSubdir);
+ createDirectoryIfNecessary(cacheLocation);
+
+ File cachedFile = new File(cacheLocation, digest + getFileSuffix(fileToCache));
+ File lastAccessedFile = new File(
+ cacheLocation, cachedFile.getName() + LAST_ACCESSED_FILE_SUFFIX);
+
+ if (!cachedFile.exists()) {
+ createNewFile(cachedFile);
+ FileUtil.copy(fileToCache, cachedFile);
+ }
+
+ if (lastAccessedFile.exists()) {
+ lastAccessedFile.setLastModified(System.currentTimeMillis());
+ } else {
+ createNewFile(lastAccessedFile);
+ }
+
+ return cachedFile;
+ }
+
+ private void createNewFile (File fileToCreate) throws IOException
+ {
+ if (!fileToCreate.exists() && !fileToCreate.createNewFile()) {
+ throw new IOException("unable to create new file: " + fileToCreate.getAbsolutePath());
+ }
+ }
+
+ private String getFileSuffix (File fileToCache) {
+ String fileName = fileToCache.getName();
+ int index = fileName.lastIndexOf(".");
+
+ return index > -1 ? fileName.substring(index) : "";
+ }
+
+ private final File _cacheDir;
+
+ static final String LAST_ACCESSED_FILE_SUFFIX = ".lastAccessed";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPInputStream;
+import com.sun.management.OperatingSystemMXBean;
+import java.lang.management.ManagementFactory;
+
+
+import com.threerings.getdown.util.*;
+// avoid ambiguity with java.util.Base64 which we can't use as it's 1.8+
+import com.threerings.getdown.util.Base64;
+
+import static com.threerings.getdown.Log.log;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Parses and provide access to the information contained in the <code>getdown.txt</code>
+ * configuration file.
+ */
+public class Application
+{
+ /** The name of our configuration file. */
+ public static final String CONFIG_FILE = "getdown.txt";
+
+ /** The name of our target version file. */
+ public static final String VERSION_FILE = "version.txt";
+
+ /** System properties that are prefixed with this string will be passed through to our
+ * application (minus this prefix). */
+ public static final String PROP_PASSTHROUGH_PREFIX = "app.";
+
+ /** Suffix used for control file signatures. */
+ public static final String SIGNATURE_SUFFIX = ".sig";
+
+ /** A special classname that means 'use -jar code.jar' instead of a classname. */
+ public static final String MANIFEST_CLASS = "manifest";
+
+ /** Used to communicate information about the UI displayed when updating the application. */
+ public static final class UpdateInterface
+ {
+ /**
+ * The major steps involved in updating, along with some arbitrary percentages
+ * assigned to them, to mark global progress.
+ */
+ public enum Step
+ {
+ UPDATE_JAVA(10),
+ VERIFY_METADATA(15, 65, 95),
+ DOWNLOAD(40),
+ PATCH(60),
+ VERIFY_RESOURCES(70, 97),
+ REDOWNLOAD_RESOURCES(90),
+ UNPACK(98),
+ LAUNCH(99);
+
+ /** What is the final percent value for this step? */
+ public final List<Integer> defaultPercents;
+
+ /** Enum constructor. */
+ Step (int... percents)
+ {
+ this.defaultPercents = intsToList(percents);
+ }
+ }
+
+ /** The human readable name of this application. */
+ public final String name;
+
+ /** A background color, just in case. */
+ public final int background;
+
+ /** Background image specifiers for `RotatingBackgrounds`. */
+ public final List<String> rotatingBackgrounds;
+
+ /** The error background image for `RotatingBackgrounds`. */
+ public final String errorBackground;
+
+ /** The paths (relative to the appdir) of images for the window icon. */
+ public final List<String> iconImages;
+
+ /** The path (relative to the appdir) to a single background image. */
+ public final String backgroundImage;
+
+ /** The path (relative to the appdir) to the progress bar image. */
+ public final String progressImage;
+
+ /** The dimensions of the progress bar. */
+ public final Rectangle progress;
+
+ /** The color of the progress text. */
+ public final int progressText;
+
+ /** The color of the progress bar. */
+ public final int progressBar;
+
+ /** The dimensions of the status display. */
+ public final Rectangle status;
+
+ /** The color of the status text. */
+ public final int statusText;
+
+ /** The color of the text shadow. */
+ public final int textShadow;
+
+ /** Where to point the user for help with install errors. */
+ public final String installError;
+
+ /** The dimensions of the patch notes button. */
+ public final Rectangle patchNotes;
+
+ /** The patch notes URL. */
+ public final String patchNotesUrl;
+
+ /** Whether window decorations are hidden for the UI. */
+ public final boolean hideDecorations;
+
+ /** Whether progress text should be hidden or not. */
+ public final boolean hideProgressText;
+
+ /** The minimum number of seconds to display the GUI. This is to prevent the GUI from
+ * flashing up on the screen and immediately disappearing, which can be confusing to the
+ * user. */
+ public final int minShowSeconds;
+
+ /** The global percentages for each step. A step may have more than one, and
+ * the lowest reasonable one is used if a step is revisited. */
+ public final Map<Step, List<Integer>> stepPercentages;
+
+ /** Generates a string representation of this instance. */
+ @Override
+ public String toString ()
+ {
+ return "[name=" + name + ", bg=" + background + ", bg=" + backgroundImage +
+ ", pi=" + progressImage + ", prect=" + progress + ", pt=" + progressText +
+ ", pb=" + progressBar + ", srect=" + status + ", st=" + statusText +
+ ", shadow=" + textShadow + ", err=" + installError + ", nrect=" + patchNotes +
+ ", notes=" + patchNotesUrl + ", stepPercentages=" + stepPercentages +
+ ", hideProgressText" + hideProgressText + ", minShow=" + minShowSeconds + "]";
+ }
+
+ public UpdateInterface (Config config)
+ {
+ this.name = config.getString("ui.name");
+ this.progress = config.getRect("ui.progress", new Rectangle(5, 5, 300, 15));
+ this.progressText = config.getColor("ui.progress_text", Color.BLACK);
+ this.hideProgressText = config.getBoolean("ui.hide_progress_text");
+ this.minShowSeconds = config.getInt("ui.min_show_seconds", 5);
+ this.progressBar = config.getColor("ui.progress_bar", 0x6699CC);
+ this.status = config.getRect("ui.status", new Rectangle(5, 25, 500, 100));
+ this.statusText = config.getColor("ui.status_text", Color.BLACK);
+ this.textShadow = config.getColor("ui.text_shadow", Color.CLEAR);
+ this.hideDecorations = config.getBoolean("ui.hide_decorations");
+ this.backgroundImage = config.getString("ui.background_image");
+ // default to black or white bg color, depending on the brightness of the progressText
+ int defaultBackground = (0.5f < Color.brightness(this.progressText)) ?
+ Color.BLACK : Color.WHITE;
+ this.background = config.getColor("ui.background", defaultBackground);
+ this.progressImage = config.getString("ui.progress_image");
+ this.rotatingBackgrounds = stringsToList(
+ config.getMultiValue("ui.rotating_background"));
+ this.iconImages = stringsToList(config.getMultiValue("ui.icon"));
+ this.errorBackground = config.getString("ui.error_background");
+
+ // On an installation error, where do we point the user.
+ String installError = config.getUrl("ui.install_error", null);
+ this.installError = (installError == null) ?
+ "m.default_install_error" : MessageUtil.taint(installError);
+
+ // the patch notes bits
+ this.patchNotes = config.getRect("ui.patch_notes", new Rectangle(5, 50, 112, 26));
+ this.patchNotesUrl = config.getUrl("ui.patch_notes_url", null);
+
+ // step progress percentage (defaults and then customized values)
+ EnumMap<Step, List<Integer>> stepPercentages = new EnumMap<>(Step.class);
+ for (Step step : Step.values()) {
+ stepPercentages.put(step, step.defaultPercents);
+ }
+ for (UpdateInterface.Step step : UpdateInterface.Step.values()) {
+ String spec = config.getString("ui.percents." + step.name());
+ if (spec != null) {
+ try {
+ stepPercentages.put(step, intsToList(StringUtil.parseIntArray(spec)));
+ } catch (Exception e) {
+ log.warning("Failed to parse percentages for " + step + ": " + spec);
+ }
+ }
+ }
+ this.stepPercentages = Collections.unmodifiableMap(stepPercentages);
+ }
+ }
+
+ /**
+ * Used by {@link #verifyMetadata} to communicate status in circumstances where it needs to
+ * take network actions.
+ */
+ public static interface StatusDisplay
+ {
+ /** Requests that the specified status message be displayed. */
+ public void updateStatus (String message);
+ }
+
+ /**
+ * Contains metadata for an auxiliary resource group.
+ */
+ public static class AuxGroup {
+ public final String name;
+ public final List<Resource> codes;
+ public final List<Resource> rsrcs;
+
+ public AuxGroup (String name, List<Resource> codes, List<Resource> rsrcs) {
+ this.name = name;
+ this.codes = Collections.unmodifiableList(codes);
+ this.rsrcs = Collections.unmodifiableList(rsrcs);
+ }
+ }
+
+ /** The proxy that should be used to do HTTP downloads. This must be configured prior to using
+ * the application instance. Yes this is a public mutable field, no I'm not going to create a
+ * getter and setter just to pretend like that's not the case. */
+ public Proxy proxy = Proxy.NO_PROXY;
+
+ /**
+ * Creates an application instance which records the location of the <code>getdown.txt</code>
+ * configuration file from the supplied application directory.
+ *
+ */
+ public Application (EnvConfig envc) {
+ _envc = envc;
+ _config = getLocalPath(envc.appDir, CONFIG_FILE);
+ }
+
+ /**
+ * Returns the configured application directory.
+ */
+ public File getAppDir () {
+ return _envc.appDir;
+ }
+
+ /**
+ * Returns whether the application should cache code resources prior to launching the
+ * application.
+ */
+ public boolean useCodeCache ()
+ {
+ return _useCodeCache;
+ }
+
+ /**
+ * Returns the number of days a cached code resource is allowed to stay unused before it
+ * becomes eligible for deletion.
+ */
+ public int getCodeCacheRetentionDays ()
+ {
+ return _codeCacheRetentionDays;
+ }
+
+ /**
+ * Returns the configured maximum concurrent downloads. Used to cap simultaneous downloads of
+ * app files from its hosting server.
+ */
+ public int maxConcurrentDownloads () {
+ return _maxConcDownloads;
+ }
+
+ /**
+ * Returns a resource that refers to the application configuration file itself.
+ */
+ public Resource getConfigResource ()
+ {
+ try {
+ return createResource(CONFIG_FILE, Resource.NORMAL);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid appbase '" + _vappbase + "'.", e);
+ }
+ }
+
+ /**
+ * Returns a list of the code {@link Resource} objects used by this application.
+ */
+ public List<Resource> getCodeResources ()
+ {
+ return _codes;
+ }
+
+ /**
+ * Returns a list of the non-code {@link Resource} objects used by this application.
+ */
+ public List<Resource> getResources ()
+ {
+ return _resources;
+ }
+
+ /**
+ * Returns the digest of the given {@code resource}.
+ */
+ public String getDigest (Resource resource)
+ {
+ return _digest.getDigest(resource);
+ }
+
+ /**
+ * Returns a list of all the active {@link Resource} objects used by this application (code and
+ * non-code).
+ */
+ public List<Resource> getAllActiveResources ()
+ {
+ List<Resource> allResources = new ArrayList<>();
+ allResources.addAll(getActiveCodeResources());
+ allResources.addAll(getActiveResources());
+ return allResources;
+ }
+
+ /**
+ * Returns the auxiliary resource group with the specified name, or null.
+ */
+ public AuxGroup getAuxGroup (String name)
+ {
+ return _auxgroups.get(name);
+ }
+
+ /**
+ * Returns the set of all auxiliary resource groups defined by the application. An auxiliary
+ * resource group is a collection of resource files that are not downloaded unless a group
+ * token file is present in the application directory.
+ */
+ public Iterable<AuxGroup> getAuxGroups ()
+ {
+ return _auxgroups.values();
+ }
+
+ /**
+ * Returns true if the specified auxgroup has been "activated", false if not. Non-activated
+ * groups should be ignored, activated groups should be downloaded and patched along with the
+ * main resources.
+ */
+ public boolean isAuxGroupActive (String auxgroup)
+ {
+ Boolean active = _auxactive.get(auxgroup);
+ if (active == null) {
+ // TODO: compare the contents with the MD5 hash of the auxgroup name and the client's
+ // machine ident
+ active = getLocalPath(auxgroup + ".dat").exists();
+ _auxactive.put(auxgroup, active);
+ }
+ return active;
+ }
+
+ /**
+ * Returns all main code resources and all code resources from active auxiliary resource groups.
+ */
+ public List<Resource> getActiveCodeResources ()
+ {
+ ArrayList<Resource> codes = new ArrayList<>();
+ codes.addAll(getCodeResources());
+ for (AuxGroup aux : getAuxGroups()) {
+ if (isAuxGroupActive(aux.name)) {
+ codes.addAll(aux.codes);
+ }
+ }
+ return codes;
+ }
+
+ /**
+ * Returns all resources indicated to contain native library files (.dll, .so, etc.).
+ */
+ public List<Resource> getNativeResources ()
+ {
+ List<Resource> natives = new ArrayList<>();
+ for (Resource resource: _resources) {
+ if (resource.isNative()) {
+ natives.add(resource);
+ }
+ }
+ return natives;
+ }
+
+ /**
+ * Returns all non-code resources and all resources from active auxiliary resource groups.
+ */
+ public List<Resource> getActiveResources ()
+ {
+ ArrayList<Resource> rsrcs = new ArrayList<>();
+ rsrcs.addAll(getResources());
+ for (AuxGroup aux : getAuxGroups()) {
+ if (isAuxGroupActive(aux.name)) {
+ rsrcs.addAll(aux.rsrcs);
+ }
+ }
+ return rsrcs;
+ }
+
+ /**
+ * Returns a resource that can be used to download a patch file that will bring this
+ * application from its current version to the target version.
+ *
+ * @param auxgroup the auxiliary resource group for which a patch resource is desired or null
+ * for the main application patch resource.
+ */
+ public Resource getPatchResource (String auxgroup)
+ {
+ if (_targetVersion <= _version) {
+ log.warning("Requested patch resource for up-to-date or non-versioned application",
+ "cvers", _version, "tvers", _targetVersion);
+ return null;
+ }
+
+ String infix = (auxgroup == null) ? "" : ("-" + auxgroup);
+ String pfile = "patch" + infix + _version + ".dat";
+ try {
+ URL remote = new URL(createVAppBase(_targetVersion), encodePath(pfile));
+ return new Resource(pfile, remote, getLocalPath(pfile), Resource.NORMAL);
+ } catch (Exception e) {
+ log.warning("Failed to create patch resource path",
+ "pfile", pfile, "appbase", _appbase, "tvers", _targetVersion, "error", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns a resource for a zip file containing a Java VM that can be downloaded to use in
+ * place of the installed VM (in the case where the VM that launched Getdown does not meet the
+ * application's version requirements) or null if no VM is available for this platform.
+ */
+ public Resource getJavaVMResource ()
+ {
+ if (StringUtil.isBlank(_javaLocation)) {
+ return null;
+ }
+
+ String extension = (_javaLocation.endsWith(".tgz"))?".tgz":".jar";
+ String vmfile = LaunchUtil.LOCAL_JAVA_DIR + extension;
+ log.info("vmfile is '"+vmfile+"'");
+ System.out.println("vmfile is '"+vmfile+"'");
+ try {
+ URL remote = new URL(createVAppBase(_targetVersion), encodePath(_javaLocation));
+ log.info("Attempting to fetch jvm at "+remote.toString());
+ System.out.println("Attempting to fetch jvm at "+remote.toString());
+ return new Resource(vmfile, remote, getLocalPath(vmfile),
+ EnumSet.of(Resource.Attr.UNPACK, Resource.Attr.CLEAN));
+ } catch (Exception e) {
+ log.warning("Failed to create VM resource", "vmfile", vmfile, "appbase", _appbase,
+ "tvers", _targetVersion, "javaloc", _javaLocation, "error", e);
+ System.out.println("Failed to create VM resource: vmfile="+vmfile+", appbase="+_appbase+
+ ", tvers="+_targetVersion+", javaloc="+_javaLocation+", error="+e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns a resource that can be used to download an archive containing all files belonging to
+ * the application.
+ */
+ public Resource getFullResource ()
+ {
+ String file = "full";
+ try {
+ URL remote = new URL(createVAppBase(_targetVersion), encodePath(file));
+ return new Resource(file, remote, getLocalPath(file), Resource.NORMAL);
+ } catch (Exception e) {
+ log.warning("Failed to create full resource path",
+ "file", file, "appbase", _appbase, "tvers", _targetVersion, "error", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the URL to use to report an initial download event. Returns null if no tracking
+ * start URL was configured for this application.
+ *
+ * @param event the event to be reported: start, jvm_start, jvm_complete, complete.
+ */
+ public URL getTrackingURL (String event)
+ {
+ try {
+ String suffix = _trackingURLSuffix == null ? "" : _trackingURLSuffix;
+ String ga = getGATrackingCode();
+ return _trackingURL == null ? null :
+ HostWhitelist.verify(new URL(_trackingURL + encodePath(event + suffix + ga)));
+ } catch (MalformedURLException mue) {
+ log.warning("Invalid tracking URL", "path", _trackingURL, "event", event, "error", mue);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the URL to request to report that we have reached the specified percentage of our
+ * initial download. Returns null if no tracking request was configured for the specified
+ * percentage.
+ */
+ public URL getTrackingProgressURL (int percent)
+ {
+ if (_trackingPcts == null || !_trackingPcts.contains(percent)) {
+ return null;
+ }
+ return getTrackingURL("pct" + percent);
+ }
+
+ /**
+ * Returns the name of our tracking cookie or null if it was not set.
+ */
+ public String getTrackingCookieName ()
+ {
+ return _trackingCookieName;
+ }
+
+ /**
+ * Returns the name of our tracking cookie system property or null if it was not set.
+ */
+ public String getTrackingCookieProperty ()
+ {
+ return _trackingCookieProperty;
+ }
+
+ /**
+ * Instructs the application to parse its {@code getdown.txt} configuration and prepare itself
+ * for operation. The application base URL will be parsed first so that if there are errors
+ * discovered later, the caller can use the application base to download a new {@code
+ * getdown.txt} file and try again.
+ *
+ * @return a {@code Config} instance that contains information from the config file.
+ *
+ * @exception IOException thrown if there is an error reading the file or an error encountered
+ * during its parsing.
+ */
+ public Config init (boolean checkPlatform)
+ throws IOException
+ {
+ Config config = null;
+ File cfgfile = _config;
+ Config.ParseOpts opts = Config.createOpts(checkPlatform);
+ try {
+ // if we have a configuration file, read the data from it
+ if (cfgfile.exists()) {
+ config = Config.parseConfig(_config, opts);
+ }
+ // otherwise, try reading data from our backup config file; thanks to funny windows
+ // bullshit, we have to do this backup file fiddling in case we got screwed while
+ // updating getdown.txt during normal operation
+ else if ((cfgfile = getLocalPath(CONFIG_FILE + "_old")).exists()) {
+ config = Config.parseConfig(cfgfile, opts);
+ }
+ // otherwise, issue a warning that we found no getdown file
+ else {
+ log.info("Found no getdown.txt file", "appdir", getAppDir());
+ }
+ } catch (Exception e) {
+ log.warning("Failure reading config file", "file", config, e);
+ }
+
+ // if we failed to read our config file, check for an appbase specified via a system
+ // property; we can use that to bootstrap ourselves back into operation
+ if (config == null) {
+ String appbase = _envc.appBase;
+ log.info("Using 'appbase' from bootstrap config", "appbase", appbase);
+ Map<String, Object> cdata = new HashMap<>();
+ cdata.put("appbase", appbase);
+ config = new Config(cdata);
+ }
+
+ // first determine our application base, this way if anything goes wrong later in the
+ // process, our caller can use the appbase to download a new configuration file
+ _appbase = config.getString("appbase");
+ if (_appbase == null) {
+ throw new RuntimeException("m.missing_appbase");
+ }
+
+ // check if we're overriding the domain in the appbase
+ _appbase = SysProps.overrideAppbase(_appbase);
+
+ // make sure there's a trailing slash
+ if (!_appbase.endsWith("/")) {
+ _appbase = _appbase + "/";
+ }
+
+ // extract our version information
+ _version = config.getLong("version", -1L);
+
+ // if we are a versioned deployment, create a versioned appbase
+ try {
+ _vappbase = createVAppBase(_version);
+ } catch (MalformedURLException mue) {
+ String err = MessageUtil.tcompose("m.invalid_appbase", _appbase);
+ throw (IOException) new IOException(err).initCause(mue);
+ }
+
+ // check for a latest config URL
+ String latest = config.getString("latest");
+ if (latest != null) {
+ if (latest.startsWith(_appbase)) {
+ latest = _appbase + latest.substring(_appbase.length());
+ } else {
+ latest = SysProps.replaceDomain(latest);
+ }
+ try {
+ _latest = HostWhitelist.verify(new URL(latest));
+ } catch (MalformedURLException mue) {
+ log.warning("Invalid URL for latest attribute.", mue);
+ }
+ }
+
+ String appPrefix = _envc.appId == null ? "" : (_envc.appId + ".");
+
+ // determine our application class name (use app-specific class _if_ one is provided)
+ _class = config.getString("class");
+ if (appPrefix.length() > 0) {
+ _class = config.getString(appPrefix + "class", _class);
+ }
+ if (_class == null) {
+ throw new IOException("m.missing_class");
+ }
+
+ // determine whether we want strict comments
+ _strictComments = config.getBoolean("strict_comments");
+
+ // check to see if we're using a custom java.version property and regex
+ _javaVersionProp = config.getString("java_version_prop", _javaVersionProp);
+ _javaVersionRegex = config.getString("java_version_regex", _javaVersionRegex);
+
+ // check to see if we require a particular JVM version and have a supplied JVM
+ _javaMinVersion = config.getLong("java_version", _javaMinVersion);
+ // we support java_min_version as an alias of java_version; it better expresses the check
+ // that's going on and better mirrors java_max_version
+ _javaMinVersion = config.getLong("java_min_version", _javaMinVersion);
+ // check to see if we require a particular max JVM version and have a supplied JVM
+ _javaMaxVersion = config.getLong("java_max_version", _javaMaxVersion);
+ // check to see if we require a particular JVM version and have a supplied JVM
+ _javaExactVersionRequired = config.getBoolean("java_exact_version_required");
+
+ // this is a little weird, but when we're run from the digester, we see a String[] which
+ // contains java locations for all platforms which we can't grok, but the digester doesn't
+ // need to know about that; when we're run in a real application there will be only one!
+ Object javaloc = config.getRaw("java_location");
+ if (javaloc instanceof String) {
+ _javaLocation = (String)javaloc;
+ }
+
+ // determine whether we have any tracking configuration
+ _trackingURL = config.getString("tracking_url");
+
+ // check for tracking progress percent configuration
+ String trackPcts = config.getString("tracking_percents");
+ if (!StringUtil.isBlank(trackPcts)) {
+ _trackingPcts = new HashSet<>();
+ for (int pct : StringUtil.parseIntArray(trackPcts)) {
+ _trackingPcts.add(pct);
+ }
+ } else if (!StringUtil.isBlank(_trackingURL)) {
+ _trackingPcts = new HashSet<>();
+ _trackingPcts.add(50);
+ }
+
+ // Check for tracking cookie configuration
+ _trackingCookieName = config.getString("tracking_cookie_name");
+ _trackingCookieProperty = config.getString("tracking_cookie_property");
+
+ // Some app may need an extra suffix added to the tracking URL
+ _trackingURLSuffix = config.getString("tracking_url_suffix");
+
+ // Some app may need to generate google analytics code
+ _trackingGAHash = config.getString("tracking_ga_hash");
+
+ // clear our arrays as we may be reinitializing
+ _codes.clear();
+ _resources.clear();
+ _auxgroups.clear();
+ _jvmargs.clear();
+ _appargs.clear();
+ _txtJvmArgs.clear();
+
+ // parse our code resources
+ if (config.getMultiValue("code") == null &&
+ config.getMultiValue("ucode") == null) {
+ throw new IOException("m.missing_code");
+ }
+ parseResources(config, "code", Resource.NORMAL, _codes);
+ parseResources(config, "ucode", Resource.UNPACK, _codes);
+
+ // parse our non-code resources
+ parseResources(config, "resource", Resource.NORMAL, _resources);
+ parseResources(config, "uresource", Resource.UNPACK, _resources);
+ parseResources(config, "xresource", Resource.EXEC, _resources);
+ parseResources(config, "presource", Resource.PRELOAD, _resources);
+ parseResources(config, "nresource", Resource.NATIVE, _resources);
+
+ // parse our auxiliary resource groups
+ for (String auxgroup : config.getList("auxgroups")) {
+ ArrayList<Resource> codes = new ArrayList<>();
+ parseResources(config, auxgroup + ".code", Resource.NORMAL, codes);
+ parseResources(config, auxgroup + ".ucode", Resource.UNPACK, codes);
+ ArrayList<Resource> rsrcs = new ArrayList<>();
+ parseResources(config, auxgroup + ".resource", Resource.NORMAL, rsrcs);
+ parseResources(config, auxgroup + ".xresource", Resource.EXEC, rsrcs);
+ parseResources(config, auxgroup + ".uresource", Resource.UNPACK, rsrcs);
+ parseResources(config, auxgroup + ".presource", Resource.PRELOAD, rsrcs);
+ parseResources(config, auxgroup + ".nresource", Resource.NATIVE, rsrcs);
+ _auxgroups.put(auxgroup, new AuxGroup(auxgroup, codes, rsrcs));
+ }
+
+ // transfer our JVM arguments (we include both "global" args and app_id-prefixed args)
+ String[] jvmargs = config.getMultiValue("jvmarg");
+ addAll(jvmargs, _jvmargs);
+ if (appPrefix.length() > 0) {
+ jvmargs = config.getMultiValue(appPrefix + "jvmarg");
+ addAll(jvmargs, _jvmargs);
+ }
+
+ // see if a percentage of physical memory option exists
+ int jvmmempc = config.getInt("jvmmempc", -1);
+ // app_id prefixed setting overrides
+ if (appPrefix.length() > 0) {
+ jvmmempc = config.getInt(appPrefix + "jvmmempc", jvmmempc);
+ }
+ if (0 <= jvmmempc && jvmmempc <= 100) {
+ final Object o = ManagementFactory.getOperatingSystemMXBean();
+
+ try {
+ if (o instanceof OperatingSystemMXBean) {
+ final OperatingSystemMXBean osb = (OperatingSystemMXBean) o;
+ long physicalMem = osb.getTotalPhysicalMemorySize();
+ long requestedMem = physicalMem*jvmmempc/100;
+ String[] maxMemHeapArg = new String[]{"-Xmx"+Long.toString(requestedMem)};
+ // remove other max heap size arg
+ ARG: for (int i = 0; i < _jvmargs.size(); i++) {
+ if (_jvmargs.get(i) instanceof java.lang.String && _jvmargs.get(i).startsWith("-Xmx")) {
+ _jvmargs.remove(i);
+ }
+ }
+ addAll(maxMemHeapArg, _jvmargs);
+
+ }
+ }
+ catch (NoClassDefFoundError e) {
+ // com.sun.management.OperatingSystemMXBean doesn't exist in this JVM
+ System.out.println("No com.sun.management.OperatingSystemMXBean. Cannot use 'jvmmempc'.");
+ }
+ } else if (jvmmempc != -1) {
+ System.out.println("'jvmmempc' value must be in range 0 to 100 (read as '"+Integer.toString(jvmmempc)+"')");
+ }
+
+ // get the set of optimum JVM arguments
+ _optimumJvmArgs = config.getMultiValue("optimum_jvmarg");
+
+ // transfer our application arguments
+ String[] appargs = config.getMultiValue(appPrefix + "apparg");
+ addAll(appargs, _appargs);
+
+ // add the launch specific application arguments
+ _appargs.addAll(_envc.appArgs);
+
+ // look for custom arguments
+ fillAssignmentListFromPairs("extra.txt", _txtJvmArgs);
+
+ // determine whether we want to allow offline operation (defaults to false)
+ _allowOffline = config.getBoolean("allow_offline");
+
+ // look for a debug.txt file which causes us to run in java.exe on Windows so that we can
+ // obtain a thread dump of the running JVM
+ _windebug = getLocalPath("debug.txt").exists();
+
+ // whether to cache code resources and launch from cache
+ _useCodeCache = config.getBoolean("use_code_cache");
+ _codeCacheRetentionDays = config.getInt("code_cache_retention_days", 7);
+
+ // maximum simultaneous downloads
+ _maxConcDownloads = Math.max(1, config.getInt("max_concurrent_downloads",
+ SysProps.threadPoolSize()));
+
+ // extract some info used to configure our child process on macOS
+ _dockName = config.getString("ui.name");
+ _dockIconPath = config.getString("ui.mac_dock_icon", "../desktop.icns");
+
+ return config;
+ }
+
+ /**
+ * Adds strings of the form pair0=pair1 to collector for each pair parsed out of pairLocation.
+ */
+ protected void fillAssignmentListFromPairs (String pairLocation, List<String> collector)
+ {
+ File pairFile = getLocalPath(pairLocation);
+ if (pairFile.exists()) {
+ try {
+ List<String[]> args = Config.parsePairs(pairFile, Config.createOpts(false));
+ for (String[] pair : args) {
+ if (pair[1].length() == 0) {
+ collector.add(pair[0]);
+ } else {
+ collector.add(pair[0] + "=" + pair[1]);
+ }
+ }
+ } catch (Throwable t) {
+ log.warning("Failed to parse '" + pairFile + "': " + t);
+ }
+ }
+ }
+
+ /**
+ * Returns a URL from which the specified path can be fetched. Our application base URL is
+ * properly versioned and combined with the supplied path.
+ */
+ public URL getRemoteURL (String path)
+ throws MalformedURLException
+ {
+ return new URL(_vappbase, encodePath(path));
+ }
+
+ /**
+ * Returns the local path to the specified resource.
+ */
+ public File getLocalPath (String path)
+ {
+ return getLocalPath(getAppDir(), path);
+ }
+
+ /**
+ * Returns true if we either have no version requirement, are running in a JVM that meets our
+ * version requirements or have what appears to be a version of the JVM that meets our
+ * requirements.
+ */
+ public boolean haveValidJavaVersion ()
+ {
+ // if we're doing no version checking, then yay!
+ if (_javaMinVersion == 0 && _javaMaxVersion == 0) return true;
+
+ try {
+ // parse the version out of the java.version (or custom) system property
+ long version = SysProps.parseJavaVersion(_javaVersionProp, _javaVersionRegex);
+
+ log.info("Checking Java version", "current", version,
+ "wantMin", _javaMinVersion, "wantMax", _javaMaxVersion);
+
+ // if we have an unpacked VM, check the 'release' file for its version
+ Resource vmjar = getJavaVMResource();
+ if (vmjar != null && vmjar.isMarkedValid()) {
+ File vmdir = new File(getAppDir(), LaunchUtil.LOCAL_JAVA_DIR);
+ File relfile = new File(vmdir, "release");
+ if (!relfile.exists()) {
+ log.warning("Unpacked JVM missing 'release' file. Assuming valid version.");
+ return true;
+ }
+
+ long vmvers = VersionUtil.readReleaseVersion(relfile, _javaVersionRegex);
+ if (vmvers == 0L) {
+ log.warning("Unable to read version from 'release' file. Assuming valid.");
+ return true;
+ }
+
+ version = vmvers;
+ log.info("Checking version of unpacked JVM [vers=" + version + "].");
+ }
+
+ if (_javaExactVersionRequired) {
+ if (version == _javaMinVersion) return true;
+ else {
+ log.warning("An exact Java VM version is required.", "current", version,
+ "required", _javaMinVersion);
+ return false;
+ }
+ }
+
+ boolean minVersionOK = (_javaMinVersion == 0) || (version >= _javaMinVersion);
+ boolean maxVersionOK = (_javaMaxVersion == 0) || (version <= _javaMaxVersion);
+ return minVersionOK && maxVersionOK;
+
+ } catch (RuntimeException re) {
+ // if we can't parse the java version we're in weird land and should probably just try
+ // our luck with what we've got rather than try to download a new jvm
+ log.warning("Unable to parse VM version, hoping for the best",
+ "error", re, "needed", _javaMinVersion);
+ return true;
+ }
+ }
+
+ /**
+ * Checks whether the app has a set of "optimum" JVM args that we wish to try first, detecting
+ * whether the launch is successful and, if necessary, trying again without the optimum
+ * arguments.
+ */
+ public boolean hasOptimumJvmArgs ()
+ {
+ return _optimumJvmArgs != null;
+ }
+
+ /**
+ * Returns true if the app should attempt to run even if we have no Internet connection.
+ */
+ public boolean allowOffline ()
+ {
+ return _allowOffline;
+ }
+
+ /**
+ * Attempts to redownload the <code>getdown.txt</code> file based on information parsed from a
+ * previous call to {@link #init}.
+ */
+ public void attemptRecovery (StatusDisplay status)
+ throws IOException
+ {
+ status.updateStatus("m.updating_metadata");
+ downloadConfigFile();
+ }
+
+ /**
+ * Downloads and replaces the <code>getdown.txt</code> and <code>digest.txt</code> files with
+ * those for the target version of our application.
+ */
+ public void updateMetadata ()
+ throws IOException
+ {
+ try {
+ // update our versioned application base with the target version
+ _vappbase = createVAppBase(_targetVersion);
+ } catch (MalformedURLException mue) {
+ String err = MessageUtil.tcompose("m.invalid_appbase", _appbase);
+ throw (IOException) new IOException(err).initCause(mue);
+ }
+
+ try {
+ // now re-download our control files; we download the digest first so that if it fails,
+ // our config file will still reference the old version and re-running the updater will
+ // start the whole process over again
+ downloadDigestFiles();
+ downloadConfigFile();
+
+ } catch (IOException ex) {
+ // if we are allowing offline execution, we want to allow the application to run in its
+ // current form rather than aborting the entire process; to do this, we delete the
+ // version.txt file and "trick" Getdown into thinking that it just needs to validate
+ // the application as is; next time the app runs when connected to the internet, it
+ // will have to rediscover that it needs updating and reattempt to update itself
+ if (_allowOffline) {
+ log.warning("Failed to update digest files. Attempting offline operaton.", ex);
+ if (!FileUtil.deleteHarder(getLocalPath(VERSION_FILE))) {
+ log.warning("Deleting version.txt failed. This probably isn't going to work.");
+ }
+ } else {
+ throw ex;
+ }
+ }
+ }
+
+ /**
+ * Invokes the process associated with this application definition.
+ *
+ * @param optimum whether or not to include the set of optimum arguments (as opposed to falling
+ * back).
+ */
+ public Process createProcess (boolean optimum)
+ throws IOException
+ {
+ ArrayList<String> args = new ArrayList<>();
+
+ // reconstruct the path to the JVM
+ args.add(LaunchUtil.getJVMPath(getAppDir(), _windebug || optimum));
+
+ // check whether we're using -jar mode or -classpath mode
+ boolean dashJarMode = MANIFEST_CLASS.equals(_class);
+
+ // add the -classpath arguments if we're not in -jar mode
+ ClassPath classPath = PathBuilder.buildClassPath(this);
+ if (!dashJarMode) {
+ args.add("-classpath");
+ args.add(classPath.asArgumentString());
+ }
+
+ // we love our Mac users, so we do nice things to preserve our application identity
+ if (LaunchUtil.isMacOS()) {
+ args.add("-Xdock:icon=" + getLocalPath(_dockIconPath).getAbsolutePath());
+ args.add("-Xdock:name=" + _dockName);
+ }
+
+ // pass along our proxy settings
+ String proxyHost;
+ if ((proxyHost = System.getProperty("http.proxyHost")) != null) {
+ args.add("-Dhttp.proxyHost=" + proxyHost);
+ args.add("-Dhttp.proxyPort=" + System.getProperty("http.proxyPort"));
+ args.add("-Dhttps.proxyHost=" + proxyHost);
+ args.add("-Dhttps.proxyPort=" + System.getProperty("http.proxyPort"));
+ }
+
+ // add the marker indicating the app is running in getdown
+ args.add("-D" + Properties.GETDOWN + "=true");
+
+ // set the native library path if we have native resources
+ // @TODO optional getdown.txt parameter to set addCurrentLibraryPath to true or false?
+ ClassPath javaLibPath = PathBuilder.buildLibsPath(this, true);
+ if (javaLibPath != null) {
+ args.add("-Djava.library.path=" + javaLibPath.asArgumentString());
+ }
+
+ // pass along any pass-through arguments
+ for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
+ String key = (String)entry.getKey();
+ if (key.startsWith(PROP_PASSTHROUGH_PREFIX)) {
+ key = key.substring(PROP_PASSTHROUGH_PREFIX.length());
+ args.add("-D" + key + "=" + entry.getValue());
+ }
+ }
+
+ // add the JVM arguments
+ for (String string : _jvmargs) {
+ args.add(processArg(string));
+ }
+
+ // add the optimum arguments if requested and available
+ if (optimum && _optimumJvmArgs != null) {
+ for (String string : _optimumJvmArgs) {
+ args.add(processArg(string));
+ }
+ }
+
+ // add the arguments from extra.txt (after the optimum ones, in case they override them)
+ for (String string : _txtJvmArgs) {
+ args.add(processArg(string));
+ }
+
+ // if we're in -jar mode add those arguments, otherwise add the app class name
+ if (dashJarMode) {
+ args.add("-jar");
+ args.add(classPath.asArgumentString());
+ } else {
+ args.add(_class);
+ }
+
+ // finally add the application arguments
+ for (String string : _appargs) {
+ args.add(processArg(string));
+ }
+
+ String[] envp = createEnvironment();
+ String[] sargs = args.toArray(new String[args.size()]);
+ log.info("Running " + StringUtil.join(sargs, "\n "));
+
+ return Runtime.getRuntime().exec(sargs, envp, getAppDir());
+ }
+
+ /**
+ * If the application provided environment variables, combine those with the current
+ * environment and return that in a style usable for {@link Runtime#exec(String, String[])}.
+ * If the application didn't provide any environment variables, null is returned to just use
+ * the existing environment.
+ */
+ protected String[] createEnvironment ()
+ {
+ List<String> envvar = new ArrayList<>();
+ fillAssignmentListFromPairs("env.txt", envvar);
+ if (envvar.isEmpty()) {
+ log.info("Didn't find any custom environment variables, not setting any.");
+ return null;
+ }
+
+ List<String> envAssignments = new ArrayList<>();
+ for (String assignment : envvar) {
+ envAssignments.add(processArg(assignment));
+ }
+ for (Map.Entry<String, String> environmentEntry : System.getenv().entrySet()) {
+ envAssignments.add(environmentEntry.getKey() + "=" + environmentEntry.getValue());
+ }
+ String[] envp = envAssignments.toArray(new String[envAssignments.size()]);
+ log.info("Environment " + StringUtil.join(envp, "\n "));
+ return envp;
+ }
+
+ /**
+ * Runs this application directly in the current VM.
+ */
+ public void invokeDirect () throws IOException
+ {
+ ClassPath classPath = PathBuilder.buildClassPath(this);
+ URL[] jarUrls = classPath.asUrls();
+
+ // create custom class loader
+ URLClassLoader loader = new URLClassLoader(jarUrls, ClassLoader.getSystemClassLoader()) {
+ @Override protected PermissionCollection getPermissions (CodeSource code) {
+ Permissions perms = new Permissions();
+ perms.add(new AllPermission());
+ return perms;
+ }
+ };
+ Thread.currentThread().setContextClassLoader(loader);
+
+ log.info("Configured URL class loader:");
+ for (URL url : jarUrls) log.info(" " + url);
+
+ // configure any system properties that we can
+ for (String jvmarg : _jvmargs) {
+ if (jvmarg.startsWith("-D")) {
+ jvmarg = processArg(jvmarg.substring(2));
+ int eqidx = jvmarg.indexOf("=");
+ if (eqidx == -1) {
+ log.warning("Bogus system property: '" + jvmarg + "'?");
+ } else {
+ System.setProperty(jvmarg.substring(0, eqidx), jvmarg.substring(eqidx+1));
+ }
+ }
+ }
+
+ // pass along any pass-through arguments
+ Map<String, String> passProps = new HashMap<>();
+ for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
+ String key = (String)entry.getKey();
+ if (key.startsWith(PROP_PASSTHROUGH_PREFIX)) {
+ key = key.substring(PROP_PASSTHROUGH_PREFIX.length());
+ passProps.put(key, (String)entry.getValue());
+ }
+ }
+ // we can't set these in the above loop lest we get a ConcurrentModificationException
+ for (Map.Entry<String, String> entry : passProps.entrySet()) {
+ System.setProperty(entry.getKey(), entry.getValue());
+ }
+
+ // prepare our app arguments
+ String[] args = new String[_appargs.size()];
+ for (int ii = 0; ii < args.length; ii++) args[ii] = processArg(_appargs.get(ii));
+
+ try {
+ log.info("Loading " + _class);
+ Class<?> appclass = loader.loadClass(_class);
+ Method main = appclass.getMethod("main", EMPTY_STRING_ARRAY.getClass());
+ log.info("Invoking main({" + StringUtil.join(args, ", ") + "})");
+ main.invoke(null, new Object[] { args });
+ } catch (Exception e) {
+ log.warning("Failure invoking app main", e);
+ }
+ }
+
+ /** Replaces the application directory and version in any argument. */
+ protected String processArg (String arg)
+ {
+ arg = arg.replace("%APPDIR%", getAppDir().getAbsolutePath());
+ arg = arg.replace("%VERSION%", String.valueOf(_version));
+
+ // if this argument contains %ENV.FOO% replace those with the associated values looked up
+ // from the environment
+ if (arg.contains(ENV_VAR_PREFIX)) {
+ StringBuffer sb = new StringBuffer();
+ Matcher matcher = ENV_VAR_PATTERN.matcher(arg);
+ while (matcher.find()) {
+ String varName = matcher.group(1), varValue = System.getenv(varName);
+ String repValue = varValue == null ? "MISSING:"+varName : varValue;
+ matcher.appendReplacement(sb, Matcher.quoteReplacement(repValue));
+ }
+ matcher.appendTail(sb);
+ arg = sb.toString();
+ }
+
+ return arg;
+ }
+
+ /**
+ * Loads the <code>digest.txt</code> file and verifies the contents of both that file and the
+ * <code>getdown.text</code> file. Then it loads the <code>version.txt</code> and decides
+ * whether or not the application needs to be updated or whether we can proceed to verification
+ * and execution.
+ *
+ * @return true if the application needs to be updated, false if it is up to date and can be
+ * verified and executed.
+ *
+ * @exception IOException thrown if we encounter an unrecoverable error while verifying the
+ * metadata.
+ */
+ public boolean verifyMetadata (StatusDisplay status)
+ throws IOException
+ {
+ log.info("Verifying application: " + _vappbase);
+ log.info("Version: " + _version);
+ log.info("Class: " + _class);
+
+ // this will read in the contents of the digest file and validate itself
+ try {
+ _digest = new Digest(getAppDir(), _strictComments);
+ } catch (IOException ioe) {
+ log.info("Failed to load digest: " + ioe.getMessage() + ". Attempting recovery...");
+ }
+
+ // if we have no version, then we are running in unversioned mode so we need to download
+ // our digest.txt file on every invocation
+ if (_version == -1) {
+ // make a note of the old meta-digest, if this changes we need to revalidate all of our
+ // resources as one or more of them have also changed
+ String olddig = (_digest == null) ? "" : _digest.getMetaDigest();
+ try {
+ status.updateStatus("m.checking");
+ downloadDigestFiles();
+ _digest = new Digest(getAppDir(), _strictComments);
+ if (!olddig.equals(_digest.getMetaDigest())) {
+ log.info("Unversioned digest changed. Revalidating...");
+ status.updateStatus("m.validating");
+ clearValidationMarkers();
+ }
+ } catch (IOException ioe) {
+ log.warning("Failed to refresh non-versioned digest: " +
+ ioe.getMessage() + ". Proceeding...");
+ }
+ }
+
+ // regardless of whether we're versioned, if we failed to read the digest from disk, try to
+ // redownload the digest file and give it another good college try; this time we allow
+ // exceptions to propagate up to the caller as there is nothing else we can do
+ if (_digest == null) {
+ status.updateStatus("m.updating_metadata");
+ downloadDigestFiles();
+ _digest = new Digest(getAppDir(), _strictComments);
+ }
+
+ // now verify the contents of our main config file
+ Resource crsrc = getConfigResource();
+ if (!_digest.validateResource(crsrc, null)) {
+ status.updateStatus("m.updating_metadata");
+ // attempt to redownload both of our metadata files; again we pass errors up to our
+ // caller because there's nothing we can do to automatically recover
+ downloadConfigFile();
+ downloadDigestFiles();
+ _digest = new Digest(getAppDir(), _strictComments);
+ // revalidate everything if we end up downloading new metadata
+ clearValidationMarkers();
+ // if the new copy validates, reinitialize ourselves; otherwise report baffling hoseage
+ if (_digest.validateResource(crsrc, null)) {
+ init(true);
+ } else {
+ log.warning(CONFIG_FILE + " failed to validate even after redownloading. " +
+ "Blindly forging onward.");
+ }
+ }
+
+ // start by assuming we are happy with our version
+ _targetVersion = _version;
+
+ // if we are a versioned application, read in the contents of the version.txt file
+ // and/or check the latest config URL for a newer version
+ if (_version != -1) {
+ File vfile = getLocalPath(VERSION_FILE);
+ long fileVersion = VersionUtil.readVersion(vfile);
+ if (fileVersion != -1) {
+ _targetVersion = fileVersion;
+ }
+
+ if (_latest != null) {
+ try (InputStream in = ConnectionUtil.open(proxy, _latest, 0, 0).getInputStream();
+ InputStreamReader reader = new InputStreamReader(in, UTF_8);
+ BufferedReader bin = new BufferedReader(reader)) {
+ for (String[] pair : Config.parsePairs(bin, Config.createOpts(false))) {
+ if (pair[0].equals("version")) {
+ _targetVersion = Math.max(Long.parseLong(pair[1]), _targetVersion);
+ if (fileVersion != -1 && _targetVersion > fileVersion) {
+ // replace the file with the newest version
+ try (FileOutputStream fos = new FileOutputStream(vfile);
+ PrintStream out = new PrintStream(fos)) {
+ out.println(_targetVersion);
+ }
+ }
+ break;
+ }
+ }
+ } catch (Exception e) {
+ log.warning("Unable to retrieve version from latest config file.", e);
+ }
+ }
+ }
+
+ // finally let the caller know if we need an update
+ return _version != _targetVersion;
+ }
+
+ /**
+ * Verifies the code and media resources associated with this application. A list of resources
+ * that do not exist or fail the verification process will be returned. If all resources are
+ * ready to go, null will be returned and the application is considered ready to run.
+ *
+ * @param obs a progress observer that will be notified of verification progress. NOTE: this
+ * observer may be called from arbitrary threads, so if you update a UI based on calls to it,
+ * you have to take care to get back to your UI thread.
+ * @param alreadyValid if non-null a 1 element array that will have the number of "already
+ * validated" resources filled in.
+ * @param unpacked a set to populate with unpacked resources.
+ * @param toInstall a list into which to add resources that need to be installed.
+ * @param toDownload a list into which to add resources that need to be downloaded.
+ */
+ public void verifyResources (
+ ProgressObserver obs, int[] alreadyValid, Set<Resource> unpacked,
+ Set<Resource> toInstall, Set<Resource> toDownload)
+ throws InterruptedException
+ {
+ // resources are verified on background threads supplied by the thread pool, and progress
+ // is reported by posting runnable actions to the actions queue which is processed by the
+ // main (UI) thread
+ ExecutorService exec = Executors.newFixedThreadPool(SysProps.threadPoolSize());
+ final BlockingQueue<Runnable> actions = new LinkedBlockingQueue<Runnable>();
+ final int[] completed = new int[1];
+
+ long start = System.currentTimeMillis();
+
+ // obtain the sizes of the resources to validate
+ List<Resource> rsrcs = getAllActiveResources();
+ long[] sizes = new long[rsrcs.size()];
+ long totalSize = 0;
+ for (int ii = 0; ii < sizes.length; ii++) {
+ totalSize += sizes[ii] = rsrcs.get(ii).getLocal().length();
+ }
+ final ProgressObserver fobs = obs;
+ // as long as we forward aggregated progress updates to the UI thread, having multiple
+ // threads update a progress aggregator is "mostly" thread-safe
+ final ProgressAggregator pagg = new ProgressAggregator(new ProgressObserver() {
+ public void progress (final int percent) {
+ actions.add(new Runnable() {
+ public void run () {
+ fobs.progress(percent);
+ }
+ });
+ }
+ }, sizes);
+
+ final int[] fAlreadyValid = alreadyValid;
+ final Set<Resource> toInstallAsync = new ConcurrentSkipListSet<>(toInstall);
+ final Set<Resource> toDownloadAsync = new ConcurrentSkipListSet<>();
+ final Set<Resource> unpackedAsync = new ConcurrentSkipListSet<>();
+
+ for (int ii = 0; ii < sizes.length; ii++) {
+ final Resource rsrc = rsrcs.get(ii);
+ final int index = ii;
+ exec.execute(new Runnable() {
+ public void run () {
+ verifyResource(rsrc, pagg.startElement(index), fAlreadyValid,
+ unpackedAsync, toInstallAsync, toDownloadAsync);
+ actions.add(new Runnable() {
+ public void run () {
+ completed[0] += 1;
+ }
+ });
+ }
+ });
+ }
+
+ while (completed[0] < rsrcs.size()) {
+ // we should be getting progress completion updates WAY more often than one every
+ // minute, so if things freeze up for 60 seconds, abandon ship
+ Runnable action = actions.poll(60, TimeUnit.SECONDS);
+ action.run();
+ }
+
+ exec.shutdown();
+
+ toInstall.addAll(toInstallAsync);
+ toDownload.addAll(toDownloadAsync);
+ unpacked.addAll(unpackedAsync);
+
+ long complete = System.currentTimeMillis();
+ log.info("Verified resources", "count", rsrcs.size(), "size", (totalSize/1024) + "k",
+ "duration", (complete-start) + "ms");
+ }
+
+ private void verifyResource (Resource rsrc, ProgressObserver obs, int[] alreadyValid,
+ Set<Resource> unpacked,
+ Set<Resource> toInstall, Set<Resource> toDownload) {
+ if (rsrc.isMarkedValid()) {
+ if (alreadyValid != null) {
+ alreadyValid[0]++;
+ }
+ obs.progress(100);
+ return;
+ }
+
+ try {
+ if (_digest.validateResource(rsrc, obs)) {
+ // if the resource has a _new file, add it to to-install list
+ if (rsrc.getLocalNew().exists()) {
+ toInstall.add(rsrc);
+ return;
+ }
+ rsrc.applyAttrs();
+ unpacked.add(rsrc);
+ rsrc.markAsValid();
+ return;
+ }
+
+ } catch (Exception e) {
+ log.info("Failure verifying resource. Requesting redownload...",
+ "rsrc", rsrc, "error", e);
+
+ } finally {
+ obs.progress(100);
+ }
+ toDownload.add(rsrc);
+ }
+
+ /**
+ * Unpacks the resources that require it (we know that they're valid).
+ *
+ * @param unpacked a set of resources to skip because they're already unpacked.
+ */
+ public void unpackResources (ProgressObserver obs, Set<Resource> unpacked)
+ throws InterruptedException
+ {
+ List<Resource> rsrcs = getActiveResources();
+
+ // remove resources that we don't want to unpack
+ for (Iterator<Resource> it = rsrcs.iterator(); it.hasNext(); ) {
+ Resource rsrc = it.next();
+ if (!rsrc.shouldUnpack() || unpacked.contains(rsrc)) {
+ it.remove();
+ }
+ }
+
+ // obtain the sizes of the resources to unpack
+ long[] sizes = new long[rsrcs.size()];
+ for (int ii = 0; ii < sizes.length; ii++) {
+ sizes[ii] = rsrcs.get(ii).getLocal().length();
+ }
+
+ ProgressAggregator pagg = new ProgressAggregator(obs, sizes);
+ for (int ii = 0; ii < sizes.length; ii++) {
+ Resource rsrc = rsrcs.get(ii);
+ ProgressObserver pobs = pagg.startElement(ii);
+ try {
+ rsrc.unpack();
+ } catch (IOException ioe) {
+ log.warning("Failure unpacking resource", "rsrc", rsrc, ioe);
+ }
+ pobs.progress(100);
+ }
+ }
+
+ /**
+ * Clears all validation marker files.
+ */
+ public void clearValidationMarkers ()
+ {
+ clearValidationMarkers(getAllActiveResources().iterator());
+ }
+
+ /**
+ * Returns the version number for the application. Should only be called after successful
+ * return of verifyMetadata.
+ */
+ public long getVersion ()
+ {
+ return _version;
+ }
+
+ /**
+ * Creates a versioned application base URL for the specified version.
+ */
+ protected URL createVAppBase (long version)
+ throws MalformedURLException
+ {
+ String url = version < 0 ? _appbase : _appbase.replace("%VERSION%", "" + version);
+ return HostWhitelist.verify(new URL(url));
+ }
+
+ /**
+ * Clears all validation marker files for the resources in the supplied iterator.
+ */
+ protected void clearValidationMarkers (Iterator<Resource> iter)
+ {
+ while (iter.hasNext()) {
+ iter.next().clearMarker();
+ }
+ }
+
+ /**
+ * Downloads a new copy of CONFIG_FILE.
+ */
+ protected void downloadConfigFile ()
+ throws IOException
+ {
+ downloadControlFile(CONFIG_FILE, 0);
+ }
+
+ /**
+ * @return true if gettingdown.lock was unlocked, already locked by this application or if
+ * we're not locking at all.
+ */
+ public synchronized boolean lockForUpdates ()
+ {
+ if (_lock != null && _lock.isValid()) {
+ return true;
+ }
+ try {
+ _lockChannel = new RandomAccessFile(getLocalPath("gettingdown.lock"), "rw").getChannel();
+ } catch (FileNotFoundException e) {
+ log.warning("Unable to create lock file", "message", e.getMessage(), e);
+ return false;
+ }
+ try {
+ _lock = _lockChannel.tryLock();
+ } catch (IOException e) {
+ log.warning("Unable to create lock", "message", e.getMessage(), e);
+ return false;
+ } catch (OverlappingFileLockException e) {
+ log.warning("The lock is held elsewhere in this JVM", e);
+ return false;
+ }
+ log.info("Able to lock for updates: " + (_lock != null));
+ return _lock != null;
+ }
+
+ /**
+ * Release gettingdown.lock
+ */
+ public synchronized void releaseLock ()
+ {
+ if (_lock != null) {
+ log.info("Releasing lock");
+ try {
+ _lock.release();
+ } catch (IOException e) {
+ log.warning("Unable to release lock", "message", e.getMessage(), e);
+ }
+ try {
+ _lockChannel.close();
+ } catch (IOException e) {
+ log.warning("Unable to close lock channel", "message", e.getMessage(), e);
+ }
+ _lockChannel = null;
+ _lock = null;
+ }
+ }
+
+ /**
+ * Downloads the digest files and validates their signature.
+ * @throws IOException
+ */
+ protected void downloadDigestFiles ()
+ throws IOException
+ {
+ for (int version = 1; version <= Digest.VERSION; version++) {
+ downloadControlFile(Digest.digestFile(version), version);
+ }
+ }
+
+ /**
+ * Downloads a new copy of the specified control file, optionally validating its signature.
+ * If the download is successful, moves it over the old file on the filesystem.
+ *
+ * <p> TODO: Switch to PKCS #7 or CMS.
+ *
+ * @param sigVersion if {@code 0} no validation will be performed, if {@code > 0} then this
+ * should indicate the version of the digest file being validated which indicates which
+ * algorithm to use to verify the signature. See {@link Digest#VERSION}.
+ */
+ protected void downloadControlFile (String path, int sigVersion)
+ throws IOException
+ {
+ File target = downloadFile(path);
+
+ if (sigVersion > 0) {
+ if (_envc.certs.isEmpty()) {
+ log.info("No signing certs, not verifying digest.txt", "path", path);
+
+ } else {
+ File signatureFile = downloadFile(path + SIGNATURE_SUFFIX);
+ byte[] signature = null;
+ try (FileInputStream signatureStream = new FileInputStream(signatureFile)) {
+ signature = StreamUtil.toByteArray(signatureStream);
+ } finally {
+ FileUtil.deleteHarder(signatureFile); // delete the file regardless
+ }
+
+ byte[] buffer = new byte[8192];
+ int length, validated = 0;
+ for (Certificate cert : _envc.certs) {
+ try (FileInputStream dataInput = new FileInputStream(target)) {
+ Signature sig = Signature.getInstance(Digest.sigAlgorithm(sigVersion));
+ sig.initVerify(cert);
+ while ((length = dataInput.read(buffer)) != -1) {
+ sig.update(buffer, 0, length);
+ }
+
+ if (!sig.verify(Base64.decode(signature, Base64.DEFAULT))) {
+ log.info("Signature does not match", "cert", cert.getPublicKey());
+ continue;
+ } else {
+ log.info("Signature matches", "cert", cert.getPublicKey());
+ validated++;
+ }
+
+ } catch (IOException ioe) {
+ log.warning("Failure validating signature of " + target + ": " + ioe);
+
+ } catch (GeneralSecurityException gse) {
+ // no problem!
+
+ }
+ }
+
+ // if we couldn't find a key that validates our digest, we are the hosed!
+ if (validated == 0) {
+ // delete the temporary digest file as we know it is invalid
+ FileUtil.deleteHarder(target);
+ throw new IOException("m.corrupt_digest_signature_error");
+ }
+ }
+ }
+
+ // now move the temporary file over the original
+ File original = getLocalPath(path);
+ if (!FileUtil.renameTo(target, original)) {
+ throw new IOException("Failed to rename(" + target + ", " + original + ")");
+ }
+ }
+
+ /**
+ * Download a path to a temporary file, returning a {@link File} instance with the path
+ * contents.
+ */
+ protected File downloadFile (String path)
+ throws IOException
+ {
+ File target = getLocalPath(path + "_new");
+
+ URL targetURL = null;
+ try {
+ targetURL = getRemoteURL(path);
+ } catch (Exception e) {
+ log.warning("Requested to download invalid control file",
+ "appbase", _vappbase, "path", path, "error", e);
+ throw (IOException) new IOException("Invalid path '" + path + "'.").initCause(e);
+ }
+
+ log.info("Attempting to refetch '" + path + "' from '" + targetURL + "'.");
+
+ // stream the URL into our temporary file
+ URLConnection uconn = ConnectionUtil.open(proxy, targetURL, 0, 0);
+ // we have to tell Java not to use caches here, otherwise it will cache any request for
+ // same URL for the lifetime of this JVM (based on the URL string, not the URL object);
+ // if the getdown.txt file, for example, changes in the meanwhile, we would never hear
+ // about it; turning off caches is not a performance concern, because when Getdown asks
+ // to download a file, it expects it to come over the wire, not from a cache
+ uconn.setUseCaches(false);
+ uconn.setRequestProperty("Accept-Encoding", "gzip");
+ try (InputStream fin = uconn.getInputStream()) {
+ String encoding = uconn.getContentEncoding();
+ boolean gzip = "gzip".equalsIgnoreCase(encoding);
+ try (InputStream fin2 = (gzip ? new GZIPInputStream(fin) : fin)) {
+ try (FileOutputStream fout = new FileOutputStream(target)) {
+ StreamUtil.copy(fin2, fout);
+ }
+ }
+ }
+
+ return target;
+ }
+
+ /** Helper function for creating {@link Resource} instances. */
+ protected Resource createResource (String path, EnumSet<Resource.Attr> attrs)
+ throws MalformedURLException
+ {
+ return new Resource(path, getRemoteURL(path), getLocalPath(path), attrs);
+ }
+
+ /** Helper function to add all values in {@code values} (if non-null) to {@code target}. */
+ protected static void addAll (String[] values, List<String> target) {
+ if (values != null) {
+ for (String value : values) {
+ target.add(value);
+ }
+ }
+ }
+
+ /**
+ * Make an immutable List from the specified int array.
+ */
+ public static List<Integer> intsToList (int[] values)
+ {
+ List<Integer> list = new ArrayList<>(values.length);
+ for (int val : values) {
+ list.add(val);
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Make an immutable List from the specified String array.
+ */
+ public static List<String> stringsToList (String[] values)
+ {
+ return values == null ? null : Collections.unmodifiableList(Arrays.asList(values));
+ }
+
+ /** Used to parse resources with the specified name. */
+ protected void parseResources (Config config, String name, EnumSet<Resource.Attr> attrs,
+ List<Resource> list)
+ {
+ String[] rsrcs = config.getMultiValue(name);
+ if (rsrcs == null) {
+ return;
+ }
+ for (String rsrc : rsrcs) {
+ try {
+ list.add(createResource(rsrc, attrs));
+ } catch (Exception e) {
+ log.warning("Invalid resource '" + rsrc + "'. " + e);
+ }
+ }
+ }
+
+ /** Possibly generates and returns a google analytics tracking cookie. */
+ protected String getGATrackingCode ()
+ {
+ if (_trackingGAHash == null) {
+ return "";
+ }
+ long time = System.currentTimeMillis() / 1000;
+ if (_trackingStart == 0) {
+ _trackingStart = time;
+ }
+ if (_trackingId == 0) {
+ int low = 100000000, high = 1000000000;
+ _trackingId = low + _rando.nextInt(high-low);
+ }
+ StringBuilder cookie = new StringBuilder("&utmcc=__utma%3D").append(_trackingGAHash);
+ cookie.append(".").append(_trackingId);
+ cookie.append(".").append(_trackingStart).append(".").append(_trackingStart);
+ cookie.append(".").append(time).append(".1%3B%2B");
+ cookie.append("__utmz%3D").append(_trackingGAHash).append(".");
+ cookie.append(_trackingStart).append(".1.1.");
+ cookie.append("utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B");
+ int low = 1000000000, high = 2000000000;
+ cookie.append("&utmn=").append(_rando.nextInt(high-low));
+ return cookie.toString();
+ }
+
+ /**
+ * Encodes a path for use in a URL.
+ */
+ protected static String encodePath (String path)
+ {
+ try {
+ // we want to keep slashes because we're encoding an entire path; also we need to turn
+ // + into %20 because web servers don't like + in paths or file names, blah
+ return URLEncoder.encode(path, "UTF-8").replace("%2F", "/").replace("+", "%20");
+ } catch (UnsupportedEncodingException ue) {
+ log.warning("Failed to URL encode " + path + ": " + ue);
+ return path;
+ }
+ }
+
+ protected File getLocalPath (File appdir, String path)
+ {
+ return new File(appdir, path);
+ }
+
+ protected final EnvConfig _envc;
+ protected File _config;
+ protected Digest _digest;
+
+ protected long _version = -1;
+ protected long _targetVersion = -1;
+ protected String _appbase;
+ protected URL _vappbase;
+ protected URL _latest;
+ protected String _class;
+ protected String _dockName;
+ protected String _dockIconPath;
+ protected boolean _strictComments;
+ protected boolean _windebug;
+ protected boolean _allowOffline;
+ protected int _maxConcDownloads;
+
+ protected String _trackingURL;
+ protected Set<Integer> _trackingPcts;
+ protected String _trackingCookieName;
+ protected String _trackingCookieProperty;
+ protected String _trackingURLSuffix;
+ protected String _trackingGAHash;
+ protected long _trackingStart;
+ protected int _trackingId;
+
+ protected String _javaVersionProp = "java.version";
+ protected String _javaVersionRegex = "(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(_\\d+)?)?)?";
+ protected long _javaMinVersion, _javaMaxVersion;
+ protected boolean _javaExactVersionRequired;
+ protected String _javaLocation;
+
+ protected List<Resource> _codes = new ArrayList<>();
+ protected List<Resource> _resources = new ArrayList<>();
+
+ protected boolean _useCodeCache;
+ protected int _codeCacheRetentionDays;
+
+ protected Map<String,AuxGroup> _auxgroups = new HashMap<>();
+ protected Map<String,Boolean> _auxactive = new HashMap<>();
+
+ protected List<String> _jvmargs = new ArrayList<>();
+ protected List<String> _appargs = new ArrayList<>();
+
+ protected String[] _optimumJvmArgs;
+
+ protected List<String> _txtJvmArgs = new ArrayList<>();
+
+ /** If a warning has been issued about not being able to set modtimes. */
+ protected boolean _warnedAboutSetLastModified;
+
+ /** Locks gettingdown.lock in the app dir. Held the entire time updating is going on.*/
+ protected FileLock _lock;
+
+ /** Channel to the file underlying _lock. Kept around solely so the lock doesn't close. */
+ protected FileChannel _lockChannel;
+
+ protected Random _rando = new Random();
+
+ protected static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ protected static final String ENV_VAR_PREFIX = "%ENV.";
+ protected static final Pattern ENV_VAR_PATTERN = Pattern.compile("%ENV\\.(.*?)%");
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2016 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.threerings.getdown.util.StringUtil;
+
+/**
+ * Contains static data provided during the build process.
+ */
+public class Build {
+
+ /** The date and time at which the code was built: in {@code yyyy-MM-dd HH:mm} format. */
+ public static String time () {
+ return "@build_time@";
+ }
+
+ /** The Maven version of the Getdown project. */
+ public static String version () {
+ return "@build_version@";
+ }
+
+ /**
+ * <p>The hosts which Getdown is allowed to communicate with. An empty list indicates that
+ * no whitelist is configured and there are no limitations. By default, no host whitelist
+ * is added to the binary, so it can be used to download and run applications from any
+ * server.
+ *
+ * <p>To create a custom Getdown build that can only talk to whitelisted servers, set
+ * the {@code getdown.host.whitelist} property on the command line while building the JAR
+ * (e.g. {@code mvn package -Dgetdown.host.whitelist=my.server.com}). Wildcards can be used
+ * (e.g. {@code *.mycompany.com}) and multiple values can be separated by commas
+ * (e.g. {@code app1.foo.com,app2.bar.com,app3.baz.com}).
+ */
+ public static List<String> hostWhitelist () {
+ return Arrays.asList(StringUtil.parseStringArray("@host_whitelist@"));
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Represents the class path and it's elements of the application to be launched. The class path
+ * can either be represented as an {@link #asArgumentString() argument string} for the java command
+ * line or as an {@link #asUrls() array of URLs} to be used by a {@link URLClassLoader}.
+ */
+public class ClassPath
+{
+ public ClassPath (LinkedHashSet<File> classPathEntries)
+ {
+ _classPathEntries = Collections.unmodifiableSet(classPathEntries);
+ }
+
+ /**
+ * Returns the class path as an java command line argument string, e.g.
+ *
+ * <pre>
+ * /path/to/a.jar:/path/to/b.jar
+ * </pre>
+ */
+ public String asArgumentString ()
+ {
+ StringBuilder builder = new StringBuilder();
+ String delimiter = "";
+ for (File entry: _classPathEntries) {
+ builder.append(delimiter).append(entry.getAbsolutePath());
+ delimiter = File.pathSeparator;
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns the class path entries as an array of URLs to be used for example by an
+ * {@link URLClassLoader}.
+ */
+ public URL[] asUrls ()
+ {
+ URL[] urls = new URL[_classPathEntries.size()];
+ int i = 0;
+ for (File entry : _classPathEntries) {
+ urls[i++] = getURL(entry);
+ }
+ return urls;
+ }
+
+ public Set<File> getClassPathEntries ()
+ {
+ return _classPathEntries;
+ }
+
+
+ private static URL getURL (File file)
+ {
+ try {
+ return file.toURI().toURL();
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException("URL of file is illegal: " + file.getAbsolutePath(), e);
+ }
+ }
+
+ private final Set<File> _classPathEntries;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.threerings.getdown.util.Config;
+import com.threerings.getdown.util.MessageUtil;
+import com.threerings.getdown.util.ProgressObserver;
+import com.threerings.getdown.util.StringUtil;
+
+import static com.threerings.getdown.Log.log;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Manages the <code>digest.txt</code> file and the computing and processing of digests for an
+ * application.
+ */
+public class Digest
+{
+ /** The current version of the digest protocol. */
+ public static final int VERSION = 2;
+
+ /**
+ * Returns the name of the digest file for the specified protocol version.
+ */
+ public static String digestFile (int version) {
+ String infix = version > 1 ? String.valueOf(version) : "";
+ return FILE_NAME + infix + FILE_SUFFIX;
+ }
+
+ /**
+ * Returns the crypto algorithm used to sign digest files of the specified version.
+ */
+ public static String sigAlgorithm (int version) {
+ switch (version) {
+ case 1: return "SHA1withRSA";
+ case 2: return "SHA256withRSA";
+ default: throw new IllegalArgumentException("Invalid digest version " + version);
+ }
+ }
+
+ /**
+ * Creates a digest file at the specified location using the supplied list of resources.
+ * @param version the version of the digest protocol to use.
+ */
+ public static void createDigest (int version, List<Resource> resources, File output)
+ throws IOException
+ {
+ // first compute the digests for all the resources in parallel
+ ExecutorService exec = Executors.newFixedThreadPool(SysProps.threadPoolSize());
+ final Map<Resource, String> digests = new ConcurrentHashMap<>();
+ final BlockingQueue<Object> completed = new LinkedBlockingQueue<>();
+ final int fversion = version;
+
+ long start = System.currentTimeMillis();
+
+ Set<Resource> pending = new HashSet<>(resources);
+ for (final Resource rsrc : resources) {
+ exec.execute(new Runnable() {
+ public void run () {
+ try {
+ MessageDigest md = getMessageDigest(fversion);
+ digests.put(rsrc, rsrc.computeDigest(fversion, md, null));
+ completed.add(rsrc);
+ } catch (Throwable t) {
+ completed.add(new IOException("Error computing digest for: " + rsrc).
+ initCause(t));
+ }
+ }
+ });
+ }
+
+ // queue a shutdown of the thread pool when the tasks are done
+ exec.shutdown();
+
+ try {
+ while (pending.size() > 0) {
+ Object done = completed.poll(600, TimeUnit.SECONDS);
+ if (done instanceof IOException) {
+ throw (IOException)done;
+ } else if (done instanceof Resource) {
+ pending.remove((Resource)done);
+ } else {
+ throw new AssertionError("What is this? " + done);
+ }
+ }
+ } catch (InterruptedException ie) {
+ throw new IOException("Timeout computing digests. Wow.");
+ }
+
+ StringBuilder data = new StringBuilder();
+ try (FileOutputStream fos = new FileOutputStream(output);
+ OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
+ PrintWriter pout = new PrintWriter(osw)) {
+ // compute and append the digest of each resource in the list
+ for (Resource rsrc : resources) {
+ String path = rsrc.getPath();
+ String digest = digests.get(rsrc);
+ note(data, path, digest);
+ pout.println(path + " = " + digest);
+ }
+ // finally compute and append the digest for the file contents
+ MessageDigest md = getMessageDigest(version);
+ byte[] contents = data.toString().getBytes(UTF_8);
+ String filename = digestFile(version);
+ pout.println(filename + " = " + StringUtil.hexlate(md.digest(contents)));
+ }
+
+ long elapsed = System.currentTimeMillis() - start;
+ log.debug("Computed digests [rsrcs=" + resources.size() + ", time=" + elapsed + "ms]");
+ }
+
+ /**
+ * Obtains an appropriate message digest instance for use by the Getdown system.
+ */
+ public static MessageDigest getMessageDigest (int version)
+ {
+ String algo = version > 1 ? "SHA-256" : "MD5";
+ try {
+ return MessageDigest.getInstance(algo);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new RuntimeException("JVM does not support " + algo + ". Gurp!");
+ }
+ }
+
+ /**
+ * Creates a digest instance which will parse and validate the digest in the supplied
+ * application directory, using the current digest version.
+ */
+ public Digest (File appdir, boolean strictComments) throws IOException {
+ this(appdir, VERSION, strictComments);
+ }
+
+ /**
+ * Creates a digest instance which will parse and validate the digest in the supplied
+ * application directory.
+ * @param version the version of the digest protocol to use.
+ */
+ public Digest (File appdir, int version, boolean strictComments) throws IOException
+ {
+ // parse and validate our digest file contents
+ String filename = digestFile(version);
+ StringBuilder data = new StringBuilder();
+ File dfile = new File(appdir, filename);
+ Config.ParseOpts opts = Config.createOpts(false);
+ opts.strictComments = strictComments;
+ // bias = toward key: the key is the filename and could conceivably contain = signs, value
+ // is the hex encoded hash which will not contain =
+ opts.biasToKey = true;
+ for (String[] pair : Config.parsePairs(dfile, opts)) {
+ if (pair[0].equals(filename)) {
+ _metaDigest = pair[1];
+ break;
+ }
+ _digests.put(pair[0], pair[1]);
+ note(data, pair[0], pair[1]);
+ }
+
+ // we've reached the end, validate our contents
+ MessageDigest md = getMessageDigest(version);
+ byte[] contents = data.toString().getBytes(UTF_8);
+ String hash = StringUtil.hexlate(md.digest(contents));
+ if (!hash.equals(_metaDigest)) {
+ String err = MessageUtil.tcompose("m.invalid_digest_file", _metaDigest, hash);
+ throw new IOException(err);
+ }
+ }
+
+ /**
+ * Returns the digest for the digest file.
+ */
+ public String getMetaDigest ()
+ {
+ return _metaDigest;
+ }
+
+ /**
+ * Computes the hash of the specified resource and compares it with the value parsed from
+ * the digest file. Logs a message if the resource fails validation.
+ *
+ * @return true if the resource is valid, false if it failed the digest check or if an I/O
+ * error was encountered during the validation process.
+ */
+ public boolean validateResource (Resource resource, ProgressObserver obs)
+ {
+ try {
+ String chash = resource.computeDigest(VERSION, getMessageDigest(VERSION), obs);
+ String ehash = _digests.get(resource.getPath());
+ if (chash.equals(ehash)) {
+ return true;
+ }
+ log.info("Resource failed digest check",
+ "rsrc", resource, "computed", chash, "expected", ehash);
+ } catch (Throwable t) {
+ log.info("Resource failed digest check", "rsrc", resource, "error", t);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the digest of the given {@code resource}.
+ */
+ public String getDigest (Resource resource)
+ {
+ return _digests.get(resource.getPath());
+ }
+
+ /** Used by {@link #createDigest} and {@link Digest}. */
+ protected static void note (StringBuilder data, String path, String digest)
+ {
+ data.append(path).append(" = ").append(digest).append("\n");
+ }
+
+ protected HashMap<String, String> _digests = new HashMap<>();
+ protected String _metaDigest = "";
+
+ protected static final String FILE_NAME = "digest";
+ protected static final String FILE_SUFFIX = ".txt";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.*;
+
+import com.threerings.getdown.util.StringUtil;
+
+/** Configuration that comes from our "environment" (command line args, sys props, etc.). */
+public final class EnvConfig {
+
+ /** Used to report problems or feedback by {@link #create}. */
+ public static final class Note {
+ public static enum Level { INFO, WARN, ERROR };
+ public static Note info (String msg) { return new Note(Level.INFO, msg); }
+ public static Note warn (String msg) { return new Note(Level.WARN, msg); }
+ public static Note error (String msg) { return new Note(Level.ERROR, msg); }
+ public final Level level;
+ public final String message;
+ public Note (Level level, String message) {
+ this.level = level;
+ this.message = message;
+ }
+ }
+
+ /**
+ * Creates an environment config, obtaining information (in order) from the following sources:
+ *
+ * <ul>
+ * <li> A {@code bootstrap.properties} file bundled with the jar. </li>
+ * <li> System properties supplied to the JVM. </li>
+ * <li> The supplied command line arguments ({@code argv}). </li>
+ * </ul>
+ *
+ * If a later source supplies a configuration already provided by a prior source, a warning
+ * message will be logged to indicate the conflict, and the prior source will be used.
+ *
+ * @param notes a list into which notes are added, to be logged after the logging system has
+ * been initialized (which cannot happen until the appdir is known). If any {@code ERROR} notes
+ * are included, the app should terminate after reporting them.
+ * @return an env config instance, or {@code null} if no appdir could be located via any
+ * configuration source.
+ */
+ public static EnvConfig create (String[] argv, List<Note> notes) {
+ String appDir = null, appDirProv = null;
+ String appId = null, appIdProv = null;
+ String appBase = null, appBaseProv = null;
+
+ // start with bootstrap.properties config, if avaialble
+ try {
+ ResourceBundle bundle = ResourceBundle.getBundle("bootstrap");
+ if (bundle.containsKey("appdir")) {
+ appDir = bundle.getString("appdir");
+ appDir = appDir.replace(USER_HOME_KEY, System.getProperty("user.home"));
+ appDirProv = "bootstrap.properties";
+ }
+ if (bundle.containsKey("appid")) {
+ appId = bundle.getString("appid");
+ appIdProv = "bootstrap.properties";
+ }
+ if (bundle.containsKey("appbase")) {
+ appBase = bundle.getString("appbase");
+ appBaseProv = "bootstrap.properties";
+ }
+ // if any system properties are specified (keys prefixed with sys.), set those up
+ for (String key : bundle.keySet()) {
+ if (key.startsWith("sys.")) {
+ String skey = key.substring(4);
+ String svalue = bundle.getString(key);
+ notes.add(Note.info("Setting system property from bundle: " +
+ skey + "='" + svalue + "'"));
+ System.setProperty(skey, svalue);
+ }
+ }
+
+ } catch (MissingResourceException e) {
+ // bootstrap.properties is optional; no need for a warning
+ }
+
+ // next seek config from system properties
+ String spropsAppDir = SysProps.appDir();
+ if (!StringUtil.isBlank(spropsAppDir)) {
+ if (appDir == null) {
+ appDir = spropsAppDir;
+ appDirProv = "system property";
+ } else {
+ notes.add(Note.warn("Ignoring 'appdir' system property, have appdir via '" +
+ appDirProv + "'"));
+ }
+ }
+ String spropsAppId = SysProps.appId();
+ if (!StringUtil.isBlank(spropsAppId)) {
+ if (appId == null) {
+ appId = spropsAppId;
+ appIdProv = "system property";
+ } else {
+ notes.add(Note.warn("Ignoring 'appid' system property, have appid via '" +
+ appIdProv + "'"));
+ }
+ }
+ String spropsAppBase = SysProps.appBase();
+ if (!StringUtil.isBlank(spropsAppBase)) {
+ if (appBase == null) {
+ appBase = spropsAppBase;
+ appBaseProv = "system property";
+ } else {
+ notes.add(Note.warn("Ignoring 'appbase' system property, have appbase via '" +
+ appBaseProv + "'"));
+ }
+ }
+
+ // finally obtain config from command line arguments
+ String argvAppDir = argv.length > 0 ? argv[0] : null;
+ if (!StringUtil.isBlank(argvAppDir)) {
+ if (appDir == null) {
+ appDir = argvAppDir;
+ appDirProv = "command line";
+ } else {
+ notes.add(Note.warn("Ignoring 'appdir' command line arg, have appdir via '" +
+ appDirProv + "'"));
+ }
+ }
+ String argvAppId = argv.length > 1 ? argv[1] : null;
+ if (!StringUtil.isBlank(argvAppId)) {
+ if (appId == null) {
+ appId = argvAppId;
+ appIdProv = "command line";
+ } else {
+ notes.add(Note.warn("Ignoring 'appid' command line arg, have appid via '" +
+ appIdProv + "'"));
+ }
+ }
+
+ // ensure that we were able to fine an app dir
+ if (appDir == null) {
+ return null; // caller will report problem to user
+ }
+
+ notes.add(Note.info("Using appdir from " + appDirProv + ": " + appDir));
+ if (appId != null) notes.add(Note.info("Using appid from " + appIdProv + ": " + appId));
+ if (appBase != null) notes.add(
+ Note.info("Using appbase from " + appBaseProv + ": " + appBase));
+
+ // ensure that the appdir refers to a directory that exists
+ File appDirFile = new File(appDir);
+ if (!appDirFile.exists()) {
+ // if we have a bootstrap URL then we auto-create the app dir; this enables an
+ // installer to simply place a getdown.jar file somewhere and create an OS shortcut
+ // that runs getdown with an appdir and appbase specified, and have getdown create the
+ // appdir and download the app into it
+ if (!StringUtil.isBlank(appBase)) {
+ if (appDirFile.mkdirs()) {
+ notes.add(Note.info("Auto-created app directory '" + appDir + "'"));
+ } else {
+ notes.add(Note.warn("Unable to auto-create app dir: '" + appDir + "'"));
+ }
+ } else {
+ notes.add(Note.error("Invalid appdir '" + appDir + "': directory does not exist"));
+ return null;
+ }
+ } else if (!appDirFile.isDirectory()) {
+ notes.add(Note.error("Invalid appdir '" + appDir + "': refers to non-directory"));
+ return null;
+ }
+
+ // pass along anything after the first two args as extra app args
+ List<String> appArgs = argv.length > 2 ?
+ Arrays.asList(argv).subList(2, argv.length) :
+ Collections.<String>emptyList();
+
+ // load X.509 certificate if it exists
+ File crtFile = new File(appDirFile, Digest.digestFile(Digest.VERSION) + ".crt");
+ List<Certificate> certs = new ArrayList<>();
+ if (crtFile.exists()) {
+ try (FileInputStream fis = new FileInputStream(crtFile)) {
+ X509Certificate certificate = (X509Certificate)
+ CertificateFactory.getInstance("X.509").generateCertificate(fis);
+ certs.add(certificate);
+ } catch (Exception e) {
+ notes.add(Note.error("Certificate error: " + e.getMessage()));
+ }
+ }
+
+ return new EnvConfig(appDirFile, appId, appBase, certs, appArgs);
+ }
+
+ /** The directory in which the application and metadata is stored. */
+ public final File appDir;
+
+ /** Either {@code null} or an identifier for a secondary application that should be
+ * launched. That app will use {@code appid.class} and {@code appid.apparg} to configure
+ * itself but all other parameters will be the same as the primary app. */
+ public final String appId;
+
+ /** Either {@code null} or fallback {@code appbase} to use if one cannot be read from a
+ * {@code getdown.txt} file during startup. */
+ public final String appBase;
+
+ /** Zero or more signing certificates used to verify the digest file. */
+ public final List<Certificate> certs;
+
+ /** Additional arguments to pass on to launched application. These will be added after the
+ * args in the getdown.txt file. */
+ public final List<String> appArgs;
+
+ public EnvConfig (File appDir) {
+ this(appDir, null, null, Collections.<Certificate>emptyList(),
+ Collections.<String>emptyList());
+ }
+
+ private EnvConfig (File appDir, String appId, String appBase, List<Certificate> certs,
+ List<String> appArgs) {
+ this.appDir = appDir;
+ this.appId = appId;
+ this.appBase = appBase;
+ this.certs = certs;
+ this.appArgs = appArgs;
+ }
+
+ private static final String USER_HOME_KEY = "${user.home}";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.jar.JarFile;
+
+import com.threerings.getdown.cache.GarbageCollector;
+import com.threerings.getdown.cache.ResourceCache;
+import com.threerings.getdown.util.FileUtil;
+import static com.threerings.getdown.Log.log;
+
+public class PathBuilder
+{
+ /** Name of directory to store cached code files in. */
+ public static final String CODE_CACHE_DIR = ".cache";
+
+ /** Name of directory to store cached native resources in. */
+ public static final String NATIVE_CACHE_DIR = ".ncache";
+
+ /**
+ * Builds either a default or cached classpath based on {@code app}'s configuration.
+ */
+ public static ClassPath buildClassPath (Application app) throws IOException
+ {
+ return app.useCodeCache() ? buildCachedClassPath(app) : buildDefaultClassPath(app);
+ }
+
+ /**
+ * Builds a {@link ClassPath} instance for {@code app} using the code resources in place in
+ * the app directory.
+ */
+ public static ClassPath buildDefaultClassPath (Application app)
+ {
+ LinkedHashSet<File> classPathEntries = new LinkedHashSet<File>();
+ for (Resource resource: app.getActiveCodeResources()) {
+ classPathEntries.add(resource.getFinalTarget());
+ }
+ return new ClassPath(classPathEntries);
+ }
+
+ /**
+ * Builds a {@link ClassPath} instance for {@code app} by first copying the code resources into
+ * a cache directory and then referencing them from there. This avoids problems with
+ * overwriting in-use classpath elements when the application is later updated. This also
+ * "garbage collects" expired caches if necessary.
+ */
+ public static ClassPath buildCachedClassPath (Application app) throws IOException
+ {
+ File codeCacheDir = new File(app.getAppDir(), CODE_CACHE_DIR);
+
+ // a negative value of code_cache_retention_days allows to clean up the cache forcefully
+ long retainMillis = TimeUnit.DAYS.toMillis(app.getCodeCacheRetentionDays());
+ if (retainMillis != 0L) {
+ GarbageCollector.collect(codeCacheDir, retainMillis);
+ }
+
+ ResourceCache cache = new ResourceCache(codeCacheDir);
+ LinkedHashSet<File> classPathEntries = new LinkedHashSet<>();
+ for (Resource resource: app.getActiveCodeResources()) {
+ String digest = app.getDigest(resource);
+ File entry = cache.cacheFile(resource.getFinalTarget(), digest.substring(0, 2), digest);
+ classPathEntries.add(entry);
+ }
+
+ return new ClassPath(classPathEntries);
+ }
+
+ /**
+ * Builds a {@link ClassPath} instance by first caching all native jars (indicated by
+ * nresource=[native jar]), unpacking them, and referencing the locations of each of the
+ * unpacked files. Also performs garbage collection similar to {@link #buildCachedClassPath}
+ *
+ * @param app used to determine native jars and related information.
+ * @param addCurrentLibraryPath if true, it adds the locations referenced by
+ * {@code System.getProperty("java.library.path")} as well.
+ * @return a classpath instance if at least one native resource was found and unpacked,
+ * {@code null} if no native resources were used by the application.
+ */
+ public static ClassPath buildLibsPath (Application app,
+ boolean addCurrentLibraryPath) throws IOException {
+ List<Resource> resources = app.getNativeResources();
+ if (resources.isEmpty()) {
+ return null;
+ }
+
+ LinkedHashSet<File> nativedirs = new LinkedHashSet<>();
+ File nativeCacheDir = new File(app.getAppDir(), NATIVE_CACHE_DIR);
+ ResourceCache cache = new ResourceCache(nativeCacheDir);
+
+ // negative value forces total garbage collection, 0 avoids garbage collection at all
+ long retainMillis = TimeUnit.DAYS.toMillis(app.getCodeCacheRetentionDays());
+ if (retainMillis != 0L) {
+ GarbageCollector.collectNative(nativeCacheDir, retainMillis);
+ }
+
+ for (Resource resource : resources) {
+ // Use untruncated cache subdirectory names to avoid overwriting issues when unpacking,
+ // in the off chance that two native jars share a directory AND contain files with the
+ // same names
+ String digest = app.getDigest(resource);
+ File cachedFile = cache.cacheFile(resource.getFinalTarget(), digest, digest);
+ File cachedParent = cachedFile.getParentFile();
+ File unpackedIndicator = new File(cachedParent, cachedFile.getName() + ".unpacked");
+
+ if (!unpackedIndicator.exists()) {
+ try {
+ FileUtil.unpackJar(new JarFile(cachedFile), cachedParent, false);
+ unpackedIndicator.createNewFile();
+ } catch (IOException ioe) {
+ log.warning("Failed to unpack native jar",
+ "file", cachedFile.getAbsolutePath(), ioe);
+ // Keep going and unpack the other jars...
+ }
+ }
+
+ nativedirs.add(cachedFile.getParentFile());
+ }
+
+ if (addCurrentLibraryPath) {
+ for (String path : System.getProperty("java.library.path").split(File.pathSeparator)) {
+ nativedirs.add(new File(path));
+ }
+ }
+
+ return new ClassPath(nativedirs);
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+/**
+ * System property constants associated with Getdown.
+ */
+public class Properties
+{
+ /** This property will be set to "true" on the application when it is being run by getdown. */
+ public static final String GETDOWN = "com.threerings.getdown";
+
+ /** If accepting connections from the launched application, this property
+ * will be set to the connection server port. */
+ public static final String CONNECT_PORT = "com.threerings.getdown.connectPort";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.MessageDigest;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+
+import com.threerings.getdown.util.FileUtil;
+import com.threerings.getdown.util.ProgressObserver;
+import com.threerings.getdown.util.StringUtil;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Models a single file resource used by an {@link Application}.
+ */
+public class Resource implements Comparable<Resource>
+{
+ /** Defines special attributes for resources. */
+ public static enum Attr {
+ /** Indicates that the resource should be unpacked. */
+ UNPACK,
+ /** If present, when unpacking a resource, any directories created by the newly
+ * unpacked resource will first be cleared of files before unpacking. */
+ CLEAN,
+ /** Indicates that the resource should be marked executable. */
+ EXEC,
+ /** Indicates that the resource should be downloaded before a UI is displayed. */
+ PRELOAD,
+ /** Indicates that the resource is a jar containing native libs. */
+ NATIVE
+ };
+
+ public static final EnumSet<Attr> NORMAL = EnumSet.noneOf(Attr.class);
+ public static final EnumSet<Attr> UNPACK = EnumSet.of(Attr.UNPACK);
+ public static final EnumSet<Attr> EXEC = EnumSet.of(Attr.EXEC);
+ public static final EnumSet<Attr> PRELOAD = EnumSet.of(Attr.PRELOAD);
+ public static final EnumSet<Attr> NATIVE = EnumSet.of(Attr.NATIVE);
+
+ /**
+ * Computes the MD5 hash of the supplied file.
+ * @param version the version of the digest protocol to use.
+ */
+ public static String computeDigest (int version, File target, MessageDigest md,
+ ProgressObserver obs)
+ throws IOException
+ {
+ md.reset();
+ byte[] buffer = new byte[DIGEST_BUFFER_SIZE];
+ int read;
+
+ boolean isJar = isJar(target.getPath());
+ boolean isPacked200Jar = isPacked200Jar(target.getPath());
+
+ // if this is a jar, we need to compute the digest in a "timestamp and file order" agnostic
+ // manner to properly correlate jardiff patched jars with their unpatched originals
+ if (isJar || isPacked200Jar){
+ File tmpJarFile = null;
+ JarFile jar = null;
+ try {
+ // if this is a compressed jar file, uncompress it to compute the jar file digest
+ if (isPacked200Jar){
+ tmpJarFile = new File(target.getPath() + ".tmp");
+ FileUtil.unpackPacked200Jar(target, tmpJarFile);
+ jar = new JarFile(tmpJarFile);
+ } else{
+ jar = new JarFile(target);
+ }
+
+ List<JarEntry> entries = Collections.list(jar.entries());
+ Collections.sort(entries, ENTRY_COMP);
+
+ int eidx = 0;
+ for (JarEntry entry : entries) {
+ // old versions of the digest code skipped metadata
+ if (version < 2) {
+ if (entry.getName().startsWith("META-INF")) {
+ updateProgress(obs, eidx, entries.size());
+ continue;
+ }
+ }
+
+ try (InputStream in = jar.getInputStream(entry)) {
+ while ((read = in.read(buffer)) != -1) {
+ md.update(buffer, 0, read);
+ }
+ }
+
+ updateProgress(obs, eidx, entries.size());
+ }
+
+ } finally {
+ if (jar != null) {
+ try {
+ jar.close();
+ } catch (IOException ioe) {
+ log.warning("Error closing jar", "path", target, "jar", jar, "error", ioe);
+ }
+ }
+ if (tmpJarFile != null) {
+ FileUtil.deleteHarder(tmpJarFile);
+ }
+ }
+
+ } else {
+ long totalSize = target.length(), position = 0L;
+ try (FileInputStream fin = new FileInputStream(target)) {
+ while ((read = fin.read(buffer)) != -1) {
+ md.update(buffer, 0, read);
+ position += read;
+ updateProgress(obs, position, totalSize);
+ }
+ }
+ }
+ return StringUtil.hexlate(md.digest());
+ }
+
+ /**
+ * Creates a resource with the supplied remote URL and local path.
+ */
+ public Resource (String path, URL remote, File local, EnumSet<Attr> attrs)
+ {
+ _path = path;
+ _remote = remote;
+ _local = local;
+ _localNew = new File(local.toString() + "_new");
+ String lpath = _local.getPath();
+ _marker = new File(lpath + "v");
+
+ _attrs = attrs;
+ _isTgz = isTgz(lpath);
+ _isJar = isJar(lpath);
+ _isPacked200Jar = isPacked200Jar(lpath);
+ boolean unpack = attrs.contains(Attr.UNPACK);
+ if (unpack && _isJar) {
+ _unpacked = _local.getParentFile();
+ } else if(unpack && _isTgz) {
+ _unpacked = _local.getParentFile();
+ } else if(unpack && _isPacked200Jar) {
+ String dotJar = ".jar", lname = _local.getName();
+ String uname = lname.substring(0, lname.lastIndexOf(dotJar) + dotJar.length());
+ _unpacked = new File(_local.getParent(), uname);
+ }
+ }
+
+ /**
+ * Returns the path associated with this resource.
+ */
+ public String getPath ()
+ {
+ return _path;
+ }
+
+ /**
+ * Returns the local location of this resource.
+ */
+ public File getLocal ()
+ {
+ return _local;
+ }
+
+ /**
+ * Returns the location of the to-be-installed new version of this resource.
+ */
+ public File getLocalNew ()
+ {
+ return _localNew;
+ }
+
+ /**
+ * Returns the location of the unpacked resource.
+ */
+ public File getUnpacked ()
+ {
+ return _unpacked;
+ }
+
+ /**
+ * Returns the final target of this resource, whether it has been unpacked or not.
+ */
+ public File getFinalTarget ()
+ {
+ return shouldUnpack() ? getUnpacked() : getLocal();
+ }
+
+ /**
+ * Returns the remote location of this resource.
+ */
+ public URL getRemote ()
+ {
+ return _remote;
+ }
+
+ /**
+ * Returns true if this resource should be unpacked as a part of the validation process.
+ */
+ public boolean shouldUnpack ()
+ {
+ return _attrs.contains(Attr.UNPACK) && !SysProps.noUnpack();
+ }
+
+ /**
+ * Returns true if this resource should be pre-downloaded.
+ */
+ public boolean shouldPredownload ()
+ {
+ return _attrs.contains(Attr.PRELOAD);
+ }
+
+ /**
+ * Returns true if this resource is a native lib jar.
+ */
+ public boolean isNative ()
+ {
+ return _attrs.contains(Attr.NATIVE);
+ }
+
+ /**
+ * Computes the MD5 hash of this resource's underlying file.
+ * <em>Note:</em> This is both CPU and I/O intensive.
+ * @param version the version of the digest protocol to use.
+ */
+ public String computeDigest (int version, MessageDigest md, ProgressObserver obs)
+ throws IOException
+ {
+ File file;
+ if (_local.toString().toLowerCase(Locale.ROOT).endsWith(Application.CONFIG_FILE)) {
+ file = _local;
+ } else {
+ file = _localNew.exists() ? _localNew : _local;
+ }
+ return computeDigest(version, file, md, obs);
+ }
+
+ /**
+ * Returns true if this resource has an associated "validated" marker
+ * file.
+ */
+ public boolean isMarkedValid ()
+ {
+ if (!_local.exists()) {
+ clearMarker();
+ return false;
+ }
+ return _marker.exists();
+ }
+
+ /**
+ * Creates a "validated" marker file for this resource to indicate
+ * that its MD5 hash has been computed and compared with the value in
+ * the digest file.
+ *
+ * @throws IOException if we fail to create the marker file.
+ */
+ public void markAsValid ()
+ throws IOException
+ {
+ _marker.createNewFile();
+ }
+
+ /**
+ * Removes any "validated" marker file associated with this resource.
+ */
+ public void clearMarker ()
+ {
+ if (_marker.exists() && !FileUtil.deleteHarder(_marker)) {
+ log.warning("Failed to erase marker file '" + _marker + "'.");
+ }
+ }
+
+ /**
+ * Installs the {@code getLocalNew} version of this resource to {@code getLocal}.
+ * @param validate whether or not to mark the resource as valid after installing.
+ */
+ public void install (boolean validate) throws IOException {
+ File source = getLocalNew(), dest = getLocal();
+ log.info("- " + source);
+ if (!FileUtil.renameTo(source, dest)) {
+ throw new IOException("Failed to rename " + source + " to " + dest);
+ }
+ applyAttrs();
+ if (validate) {
+ markAsValid();
+ }
+ }
+
+ /**
+ * Unpacks this resource file into the directory that contains it.
+ */
+ public void unpack () throws IOException
+ {
+ // sanity check
+ if (!_isJar && !_isPacked200Jar && !_isTgz) {
+ throw new IOException("Requested to unpack non-jar/tgz file '" + _local + "'.");
+ }
+ if (_isJar) {
+ try (JarFile jar = new JarFile(_local)) {
+ FileUtil.unpackJar(jar, _unpacked, _attrs.contains(Attr.CLEAN));
+ }
+ } else if (_isTgz) {
+ try (InputStream fi = Files.newInputStream(_local.toPath());
+ InputStream bi = new BufferedInputStream(fi);
+ InputStream gzi = new GzipCompressorInputStream(bi);
+ TarArchiveInputStream tgz = new TarArchiveInputStream(gzi)) {
+ FileUtil.unpackTgz(tgz, _unpacked, _attrs.contains(Attr.CLEAN));
+ }
+ } else {
+ FileUtil.unpackPacked200Jar(_local, _unpacked);
+ }
+ }
+
+ /**
+ * Applies this resources special attributes: unpacks this resource if needed, marks it as
+ * executable if needed.
+ */
+ public void applyAttrs () throws IOException {
+ if (shouldUnpack()) {
+ unpack();
+ }
+ if (_attrs.contains(Attr.EXEC)) {
+ FileUtil.makeExecutable(_local);
+ }
+ }
+
+ /**
+ * Wipes this resource file along with any "validated" marker file that may be associated with
+ * it.
+ */
+ public void erase ()
+ {
+ clearMarker();
+ if (_local.exists() && !FileUtil.deleteHarder(_local)) {
+ log.warning("Failed to erase resource '" + _local + "'.");
+ }
+ }
+
+ @Override public int compareTo (Resource other) {
+ return _path.compareTo(other._path);
+ }
+
+ @Override public boolean equals (Object other)
+ {
+ if (other instanceof Resource) {
+ return _path.equals(((Resource)other)._path);
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode ()
+ {
+ return _path.hashCode();
+ }
+
+ @Override public String toString ()
+ {
+ return _path;
+ }
+
+ /** Helper function to simplify the process of reporting progress. */
+ protected static void updateProgress (ProgressObserver obs, long pos, long total)
+ {
+ if (obs != null) {
+ obs.progress((int)(100 * pos / total));
+ }
+ }
+
+ protected static boolean isJar (String path)
+ {
+ return path.endsWith(".jar") || path.endsWith(".jar_new");
+ }
+
+ protected static boolean isTgz (String path)
+ {
+ return path.endsWith(".tgz") || path.endsWith(".tgz_new");
+ }
+
+ protected static boolean isPacked200Jar (String path)
+ {
+ return path.endsWith(".jar.pack") || path.endsWith(".jar.pack_new") ||
+ path.endsWith(".jar.pack.gz")|| path.endsWith(".jar.pack.gz_new");
+ }
+
+ protected String _path;
+ protected URL _remote;
+ protected File _local, _localNew, _marker, _unpacked;
+ protected EnumSet<Attr> _attrs;
+ protected boolean _isJar, _isPacked200Jar, _isTgz;
+
+ /** Used to sort the entries in a jar file. */
+ protected static final Comparator<JarEntry> ENTRY_COMP = new Comparator<JarEntry>() {
+ @Override public int compare (JarEntry e1, JarEntry e2) {
+ return e1.getName().compareTo(e2.getName());
+ }
+ };
+
+ protected static final int DIGEST_BUFFER_SIZE = 5 * 1025;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.threerings.getdown.util.VersionUtil;
+
+/**
+ * This class encapsulates all system properties that are read and processed by Getdown. Don't
+ * stick a call to {@code System.getProperty} randomly into the code, put it in here and give it an
+ * accessor so that it's easy to see all of the secret system property arguments that Getdown makes
+ * use of.
+ */
+public class SysProps
+{
+ /** Configures the appdir (in lieu of passing it in argv). Usage: {@code -Dappdir=foo}. */
+ public static String appDir () {
+ return System.getProperty("appdir");
+ }
+
+ /** Configures the appid (in lieu of passing it in argv). Usage: {@code -Dappid=foo}. */
+ public static String appId () {
+ return System.getProperty("appid");
+ }
+
+ /** Configures the bootstrap appbase (used in lieu of providing a skeleton getdown.txt, and as
+ * a last resort fallback). Usage: {@code -Dappbase=URL}. */
+ public static String appBase () {
+ return System.getProperty("appbase");
+ }
+
+ /** If true, disables redirection of logging into {@code launcher.log}.
+ * Usage: {@code -Dno_log_redir}. */
+ public static boolean noLogRedir () {
+ return System.getProperty("no_log_redir") != null;
+ }
+
+ /** Overrides the domain on {@code appbase}. Usage: {@code -Dappbase_domain=foo}. */
+ public static String appbaseDomain () {
+ return System.getProperty("appbase_domain");
+ }
+
+ /** Overrides enter {@code appbase}. Usage: {@code -Dappbase_override=URL}. */
+ public static String appbaseOverride () {
+ return System.getProperty("appbase_override");
+ }
+
+ /** If true, Getdown installs the app without ever bringing up a UI (except in the event of an
+ * error). NOTE: it does not launch the app. See {@link #launchInSilent}.
+ * Usage: {@code -Dsilent}. */
+ public static boolean silent () {
+ return System.getProperty("silent") != null;
+ }
+
+ /** Instructs Getdown to install/update the app without ever bringing up a UI (except in the
+ * event of an error), and then launch it.
+ * Usage: {@code -Dsilent=launch}. */
+ public static boolean launchInSilent () {
+ return "launch".equals(System.getProperty("silent"));
+ }
+
+ /**
+ * Instructs Getdown to launch the app without updating it, or ever bringing up a UI (except
+ * in the event of an error).
+ * Usage: {@code -Dsilent=noupdate}.
+ */
+ public static boolean noUpdate() {
+ return "noupdate".equals(System.getProperty("silent"));
+ }
+
+ /** If true, Getdown does not automatically install updates after downloading them. It waits
+ * for the application to call `Getdown.install`.
+ * Usage: {@code -Dno_install}. */
+ public static boolean noInstall () {
+ return System.getProperty("no_install") != null;
+ }
+
+ /** Specifies the delay (in minutes) to wait before starting the update and install process.
+ * Minimum delay is 0 minutes, or no delay (negative values are rounded up to 0 minutes).
+ * Maximum delay is 1 day, or 1440 minutes (larger values are rounded down to 1 day).
+ * Usage: {@code -Ddelay=N}. */
+ public static int startDelay () {
+ return Math.min(Math.max(Integer.getInteger("delay", 0), 0), 60 * 24);
+ }
+
+ /** If true, Getdown will not unpack {@code uresource} jars. Usage: {@code -Dno_unpack}. */
+ public static boolean noUnpack () {
+ return Boolean.getBoolean("no_unpack");
+ }
+
+ /** If true, Getdown will run the application in the same VM in which Getdown is running. If
+ * false (the default), Getdown will fork a new VM. Note that reusing the same VM prevents
+ * Getdown from configuring some launch-time-only VM parameters (like -mxN etc.).
+ * Usage: {@code -Ddirect}. */
+ public static boolean direct () {
+ return Boolean.getBoolean("direct");
+ }
+
+ /** Specifies the connection timeout (in seconds) to use when downloading control files from
+ * the server. This is chiefly useful when you are running in versionless mode and want Getdown
+ * to more quickly timeout its startup update check if the server with which it is
+ * communicating is not available. Usage: {@code -Dconnect_timeout=N}. */
+ public static int connectTimeout () {
+ return Integer.getInteger("connect_timeout", 0);
+ }
+
+ /** Specifies the read timeout (in seconds) to use when downloading all files from the server.
+ * The default is 30 seconds, meaning that if a download stalls for more than 30 seconds, the
+ * update process wil fail. Setting the timeout to zero (or a negative value) will disable it.
+ * Usage: {@code -Dread_timeout=N}. */
+ public static int readTimeout () {
+ return Integer.getInteger("read_timeout", 30);
+ }
+
+ /** Returns the number of threads used to perform digesting and verifying operations in
+ * parallel. Usage: {@code -Dthread_pool_size=N} */
+ public static int threadPoolSize () {
+ int defaultSize = Math.max(Runtime.getRuntime().availableProcessors()-1, 1);
+ return Integer.getInteger("thread_pool_size", defaultSize);
+ }
+
+ /** Parses a Java version system property using the supplied regular expression. The numbers
+ * extracted from the regexp will be placed in each consecutive hundreds position in the
+ * returned value.
+ *
+ * <p>For example, {@code java.version} takes the form {@code 1.8.0_31}, and with the regexp
+ * {@code (\d+)\.(\d+)\.(\d+)(_\d+)?} we would parse {@code 1, 8, 0, 31} and combine them into
+ * the final value {@code 1080031}.
+ *
+ * <p>Note that non-numeric characters matched by the regular expression will simply be
+ * ignored, and optional groups which do not match are treated as zero in the final version
+ * calculation.
+ *
+ * <p>One can instead parse {@code java.runtime.version} which takes the form {@code
+ * 1.8.0_31-b13}. Using regexp {@code (\d+)\.(\d+)\.(\d+)_(\d+)-b(\d+)} we would parse
+ * {@code 1, 8, 0, 31, 13} and combine them into a final value {@code 108003113}.
+ *
+ * <p>Other (or future) JVMs may provide different version properties which can be parsed as
+ * desired using this general scheme as long as the numbers appear from left to right in order
+ * of significance.
+ *
+ * @throws IllegalArgumentException if no system named {@code propName} exists, or if
+ * {@code propRegex} does not match the returned version string.
+ */
+ public static long parseJavaVersion (String propName, String propRegex) {
+ String verstr = System.getProperty(propName);
+ if (verstr == null) throw new IllegalArgumentException(
+ "No system property '" + propName + "'.");
+
+ long vers = VersionUtil.parseJavaVersion(propRegex, verstr);
+ if (vers == 0L) throw new IllegalArgumentException(
+ "Regexp '" + propRegex + "' does not match '" + verstr + "' (from " + propName + ")");
+ return vers;
+ }
+
+ /**
+ * Applies {@code appbase_override} or {@code appbase_domain} if they are set.
+ */
+ public static String overrideAppbase (String appbase) {
+ String appbaseOverride = appbaseOverride();
+ if (appbaseOverride != null) {
+ return appbaseOverride;
+ } else {
+ return replaceDomain(appbase);
+ }
+ }
+
+ /**
+ * If appbase_domain property is set, replace the domain on the provided string.
+ */
+ public static String replaceDomain (String appbase)
+ {
+ String appbaseDomain = appbaseDomain();
+ if (appbaseDomain != null) {
+ Matcher m = Pattern.compile("(https?://[^/]+)(.*)").matcher(appbase);
+ appbase = m.replaceAll(appbaseDomain + "$2");
+ }
+ return appbase;
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.net;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import com.threerings.getdown.data.Resource;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Handles the download of a collection of files, first issuing HTTP head requests to obtain size
+ * information and then downloading the files individually, reporting progress back via protected
+ * callback methods. <em>Note:</em> these methods are all called arbitrary download threads, so
+ * implementors must take care to only execute thread-safe code or simply pass a message to the AWT
+ * thread, for example.
+ */
+public abstract class Downloader
+{
+ /**
+ * Start the downloading process.
+ * @param resources the resources to download.
+ * @param maxConcurrent the maximum number of concurrent downloads allowed.
+ * @return true if the download completed, false if it was aborted (via {@link #abort}).
+ */
+ public boolean download (Collection<Resource> resources, int maxConcurrent)
+ {
+ // first compute the total size of our download
+ resolvingDownloads();
+ for (Resource rsrc : resources) {
+ try {
+ _sizes.put(rsrc, Math.max(checkSize(rsrc), 0L));
+ } catch (IOException ioe) {
+ downloadFailed(rsrc, ioe);
+ }
+ }
+
+ long totalSize = sum(_sizes.values());
+ log.info("Downloading " + resources.size() + " resources",
+ "totalBytes", totalSize, "maxConcurrent", maxConcurrent);
+
+ // make a note of the time at which we started the download
+ _start = System.currentTimeMillis();
+
+ // start the downloads
+ ExecutorService exec = Executors.newFixedThreadPool(maxConcurrent);
+ for (final Resource rsrc : resources) {
+ // make sure the resource's target directory exists
+ File parent = new File(rsrc.getLocal().getParent());
+ if (!parent.exists() && !parent.mkdirs()) {
+ log.warning("Failed to create target directory for resource '" + rsrc + "'.");
+ }
+
+ exec.execute(new Runnable() {
+ @Override public void run () {
+ try {
+ if (_state != State.ABORTED) {
+ download(rsrc);
+ }
+ } catch (IOException ioe) {
+ _state = State.FAILED;
+ downloadFailed(rsrc, ioe);
+ }
+ }
+ });
+ }
+ exec.shutdown();
+
+ // wait for the downloads to complete
+ try {
+ exec.awaitTermination(10, TimeUnit.DAYS);
+
+ // report download completion if we did not already do so via our final resource
+ if (_state == State.DOWNLOADING) {
+ downloadProgress(100, 0);
+ }
+
+ } catch (InterruptedException ie) {
+ exec.shutdownNow();
+ downloadFailed(null, ie);
+ }
+
+ return _state != State.ABORTED;
+ }
+
+ /**
+ * Aborts the in-progress download.
+ */
+ public void abort () {
+ _state = State.ABORTED;
+ }
+
+ /**
+ * Called before the downloader begins the series of HTTP head requests to determine the
+ * size of the files it needs to download.
+ */
+ protected void resolvingDownloads () {}
+
+ /**
+ * Reports ongoing progress toward completion of the overall downloading task. One call is
+ * guaranteed to be made reporting 100% completion if the download is not aborted and no
+ * resources fail.
+ *
+ * @param percent the percent completion of the complete download process (based on total bytes
+ * downloaded versus total byte size of all resources).
+ * @param remaining the estimated download time remaining in seconds, or {@code -1} if the time
+ * can not yet be determined.
+ */
+ protected void downloadProgress (int percent, long remaining) {}
+
+ /**
+ * Called if a failure occurs while downloading a resource. No progress will be reported after
+ * a download fails, but additional download failures may be reported.
+ *
+ * @param rsrc the resource that failed to download, or null if the download failed due to
+ * thread interruption.
+ * @param cause the exception detailing the failure.
+ */
+ protected void downloadFailed (Resource rsrc, Exception cause) {}
+
+ /**
+ * Performs the protocol-specific portion of checking download size.
+ */
+ protected abstract long checkSize (Resource rsrc) throws IOException;
+
+ /**
+ * Periodically called by the protocol-specific downloaders to update their progress. This
+ * should be called at least once for each resource to be downloaded, with the total downloaded
+ * size for that resource. It can also be called periodically along the way for each resource
+ * to communicate incremental progress.
+ *
+ * @param rsrc the resource currently being downloaded.
+ * @param currentSize the number of bytes currently downloaded for said resource.
+ * @param actualSize the size reported for this resource now that we're actually downloading
+ * it. Some web servers lie about Content-length when doing a HEAD request, so by reporting
+ * updated sizes here we can recover from receiving bogus information in the earlier
+ * {@link #checkSize} phase.
+ */
+ protected synchronized void reportProgress (Resource rsrc, long currentSize, long actualSize)
+ {
+ // update the actual size for this resource (but don't let it shrink)
+ _sizes.put(rsrc, actualSize = Math.max(actualSize, _sizes.get(rsrc)));
+
+ // update the current downloaded size for said resource; don't allow the downloaded bytes
+ // to exceed the original claimed size of the resource, otherwise our progress will get
+ // booched and we'll end up back on the Daily WTF: http://tinyurl.com/29wt4oq
+ _downloaded.put(rsrc, Math.min(actualSize, currentSize));
+
+ // notify the observer if it's been sufficiently long since our last notification
+ long now = System.currentTimeMillis();
+ if ((now - _lastUpdate) >= UPDATE_DELAY) {
+ _lastUpdate = now;
+
+ // total up our current and total bytes
+ long downloaded = sum(_downloaded.values());
+ long totalSize = sum(_sizes.values());
+
+ // compute our bytes per second
+ long secs = (now - _start) / 1000L;
+ long bps = (secs == 0) ? 0 : (downloaded / secs);
+
+ // compute our percentage completion
+ int pctdone = (totalSize == 0) ? 0 : (int)((downloaded * 100f) / totalSize);
+
+ // estimate our time remaining
+ long remaining = (bps <= 0 || totalSize == 0) ? -1 : (totalSize - downloaded) / bps;
+
+ // if we're complete or failed, when we don't want to report again
+ if (_state == State.DOWNLOADING) {
+ if (pctdone == 100) _state = State.COMPLETE;
+ downloadProgress(pctdone, remaining);
+ }
+ }
+ }
+
+ /**
+ * Sums the supplied values.
+ */
+ protected static long sum (Iterable<Long> values)
+ {
+ long acc = 0L;
+ for (Long value : values) {
+ acc += value;
+ }
+ return acc;
+ }
+
+ protected enum State { DOWNLOADING, COMPLETE, FAILED, ABORTED }
+
+ /**
+ * Accomplishes the copying of the resource from remote location to local location using
+ * protocol-specific code. This method should periodically check whether {@code _state} is set
+ * to aborted and abort any in-progress download if so.
+ */
+ protected abstract void download (Resource rsrc) throws IOException;
+
+ /** The reported sizes of our resources. */
+ protected Map<Resource, Long> _sizes = new HashMap<>();
+
+ /** The bytes downloaded for each resource. */
+ protected Map<Resource, Long> _downloaded = new HashMap<>();
+
+ /** The time at which the file transfer began. */
+ protected long _start;
+
+ /** The current transfer rate in bytes per second. */
+ protected long _bytesPerSecond;
+
+ /** The time at which the last progress update was posted to the progress observer. */
+ protected long _lastUpdate;
+
+ /** A wee state machine to ensure we call our callbacks sanely. */
+ protected volatile State _state = State.DOWNLOADING;
+
+ /** The delay in milliseconds between notifying progress observers of file download
+ * progress. */
+ protected static final long UPDATE_DELAY = 500L;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.net;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+
+import com.threerings.getdown.data.Resource;
+import com.threerings.getdown.util.ConnectionUtil;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Implements downloading files over HTTP
+ */
+public class HTTPDownloader extends Downloader
+{
+ public HTTPDownloader (Proxy proxy)
+ {
+ _proxy = proxy;
+ }
+
+ @Override protected long checkSize (Resource rsrc) throws IOException
+ {
+ URLConnection conn = ConnectionUtil.open(_proxy, rsrc.getRemote(), 0, 0);
+ try {
+ // if we're accessing our data via HTTP, we only need a HEAD request
+ if (conn instanceof HttpURLConnection) {
+ HttpURLConnection hcon = (HttpURLConnection)conn;
+ hcon.setRequestMethod("HEAD");
+ hcon.connect();
+ // make sure we got a satisfactory response code
+ if (hcon.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ throw new IOException("Unable to check up-to-date for " +
+ rsrc.getRemote() + ": " + hcon.getResponseCode());
+ }
+ }
+ return conn.getContentLength();
+
+ } finally {
+ // let it be known that we're done with this connection
+ conn.getInputStream().close();
+ }
+ }
+
+ @Override protected void download (Resource rsrc) throws IOException
+ {
+ // TODO: make FileChannel download impl (below) robust and allow apps to opt-into it via a
+ // system property
+ if (true) {
+ // download the resource from the specified URL
+ URLConnection conn = ConnectionUtil.open(_proxy, rsrc.getRemote(), 0, 0);
+ conn.connect();
+
+ // make sure we got a satisfactory response code
+ if (conn instanceof HttpURLConnection) {
+ HttpURLConnection hcon = (HttpURLConnection)conn;
+ if (hcon.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ throw new IOException("Unable to download resource " + rsrc.getRemote() + ": " +
+ hcon.getResponseCode());
+ }
+ }
+ long actualSize = conn.getContentLength();
+ log.info("Downloading resource", "url", rsrc.getRemote(), "size", actualSize);
+ long currentSize = 0L;
+ byte[] buffer = new byte[4*4096];
+ try (InputStream in = conn.getInputStream();
+ FileOutputStream out = new FileOutputStream(rsrc.getLocalNew())) {
+
+ // TODO: look to see if we have a download info file
+ // containing info on potentially partially downloaded data;
+ // if so, use a "Range: bytes=HAVE-" header.
+
+ // read in the file data
+ int read;
+ while ((read = in.read(buffer)) != -1) {
+ // abort the download if the downloader is aborted
+ if (_state == State.ABORTED) {
+ break;
+ }
+ // write it out to our local copy
+ out.write(buffer, 0, read);
+ // note that we've downloaded some data
+ currentSize += read;
+ reportProgress(rsrc, currentSize, actualSize);
+ }
+ }
+
+ } else {
+ log.info("Downloading resource", "url", rsrc.getRemote(), "size", "unknown");
+ File localNew = rsrc.getLocalNew();
+ try (ReadableByteChannel rbc = Channels.newChannel(rsrc.getRemote().openStream());
+ FileOutputStream fos = new FileOutputStream(localNew)) {
+ // TODO: more work is needed here, transferFrom can fail to transfer the entire
+ // file, in which case it's not clear what we're supposed to do.. call it again?
+ // will it repeatedly fail?
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ reportProgress(rsrc, localNew.length(), localNew.length());
+ }
+ }
+ }
+
+ protected final Proxy _proxy;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.spi;
+
+/**
+ * A service provider interface that handles the storage of proxy credentials.
+ */
+public interface ProxyAuth
+{
+ /** Credentials for a proxy server. */
+ public static class Credentials {
+ public final String username;
+ public final String password;
+ public Credentials (String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+ }
+
+ /**
+ * Loads the credentials for the app installed in {@code appDir}.
+ */
+ public Credentials loadCredentials (String appDir);
+
+ /**
+ * Encrypts and saves the credentials for the app installed in {@code appDir}.
+ */
+ public void saveCredentials (String appDir, String username, String password);
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tools;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+
+import java.security.MessageDigest;
+
+import com.threerings.getdown.data.Application;
+import com.threerings.getdown.data.Digest;
+import com.threerings.getdown.data.EnvConfig;
+import com.threerings.getdown.data.Resource;
+import com.threerings.getdown.util.FileUtil;
+import com.threerings.getdown.util.StreamUtil;
+
+/**
+ * Generates patch files between two particular revisions of an
+ * application. The differences between all the files in the two
+ * revisions are bundled into a single patch file which is placed into the
+ * target version directory.
+ */
+public class Differ
+{
+ /**
+ * Creates a single patch file that contains the differences between
+ * the two specified application directories. The patch file will be
+ * created in the <code>nvdir</code> directory with name
+ * <code>patchV.dat</code> where V is the old application version.
+ */
+ public void createDiff (File nvdir, File ovdir, boolean verbose)
+ throws IOException
+ {
+ // sanity check
+ String nvers = nvdir.getName();
+ String overs = ovdir.getName();
+ try {
+ if (Long.parseLong(nvers) <= Long.parseLong(overs)) {
+ String err = "New version (" + nvers + ") must be greater " +
+ "than old version (" + overs + ").";
+ throw new IOException(err);
+ }
+ } catch (NumberFormatException nfe) {
+ throw new IOException("Non-numeric versions? [nvers=" + nvers +
+ ", overs=" + overs + "].");
+ }
+
+ Application oapp = new Application(new EnvConfig(ovdir));
+ oapp.init(false);
+ ArrayList<Resource> orsrcs = new ArrayList<>();
+ orsrcs.addAll(oapp.getCodeResources());
+ orsrcs.addAll(oapp.getResources());
+
+ Application napp = new Application(new EnvConfig(nvdir));
+ napp.init(false);
+ ArrayList<Resource> nrsrcs = new ArrayList<>();
+ nrsrcs.addAll(napp.getCodeResources());
+ nrsrcs.addAll(napp.getResources());
+
+ // first create a patch for the main application
+ File patch = new File(nvdir, "patch" + overs + ".dat");
+ createPatch(patch, orsrcs, nrsrcs, verbose);
+
+ // next create patches for any auxiliary resource groups
+ for (Application.AuxGroup ag : napp.getAuxGroups()) {
+ orsrcs = new ArrayList<>();
+ Application.AuxGroup oag = oapp.getAuxGroup(ag.name);
+ if (oag != null) {
+ orsrcs.addAll(oag.codes);
+ orsrcs.addAll(oag.rsrcs);
+ }
+ nrsrcs = new ArrayList<>();
+ nrsrcs.addAll(ag.codes);
+ nrsrcs.addAll(ag.rsrcs);
+ patch = new File(nvdir, "patch-" + ag.name + overs + ".dat");
+ createPatch(patch, orsrcs, nrsrcs, verbose);
+ }
+ }
+
+ protected void createPatch (File patch, ArrayList<Resource> orsrcs,
+ ArrayList<Resource> nrsrcs, boolean verbose)
+ throws IOException
+ {
+ int version = Digest.VERSION;
+ MessageDigest md = Digest.getMessageDigest(version);
+ try (FileOutputStream fos = new FileOutputStream(patch);
+ BufferedOutputStream buffered = new BufferedOutputStream(fos);
+ JarOutputStream jout = new JarOutputStream(buffered)) {
+
+ // for each file in the new application, it either already exists
+ // in the old application, or it is new
+ for (Resource rsrc : nrsrcs) {
+ int oidx = orsrcs.indexOf(rsrc);
+ Resource orsrc = (oidx == -1) ? null : orsrcs.remove(oidx);
+ if (orsrc != null) {
+ // first see if they are the same
+ String odig = orsrc.computeDigest(version, md, null);
+ String ndig = rsrc.computeDigest(version, md, null);
+ if (odig.equals(ndig)) {
+ if (verbose) {
+ System.out.println("Unchanged: " + rsrc.getPath());
+ }
+ // by leaving it out, it will be left as is during the
+ // patching process
+ continue;
+ }
+
+ // otherwise potentially create a jar diff
+ if (rsrc.getPath().endsWith(".jar")) {
+ if (verbose) {
+ System.out.println("JarDiff: " + rsrc.getPath());
+ }
+ // here's a juicy one: JarDiff blindly pulls ZipEntry
+ // objects out of one jar file and stuffs them into
+ // another without clearing out things like the
+ // compressed size, so if, for whatever reason (like
+ // different JRE versions or phase of the moon) the
+ // compressed size in the old jar file is different
+ // than the compressed size generated when creating the
+ // jardiff jar file, ZipOutputStream will choke and
+ // we'll be hosed; so we recreate the jar files in
+ // their entirety before running jardiff on 'em
+ File otemp = rebuildJar(orsrc.getLocal());
+ File temp = rebuildJar(rsrc.getLocal());
+ jout.putNextEntry(new ZipEntry(rsrc.getPath() + Patcher.PATCH));
+ jarDiff(otemp, temp, jout);
+ FileUtil.deleteHarder(otemp);
+ FileUtil.deleteHarder(temp);
+ continue;
+ }
+ }
+
+ if (verbose) {
+ System.out.println("Addition: " + rsrc.getPath());
+ }
+ jout.putNextEntry(new ZipEntry(rsrc.getPath() + Patcher.CREATE));
+ pipe(rsrc.getLocal(), jout);
+ }
+
+ // now any file remaining in orsrcs needs to be removed
+ for (Resource rsrc : orsrcs) {
+ // add an entry with the resource name and the deletion suffix
+ if (verbose) {
+ System.out.println("Removal: " + rsrc.getPath());
+ }
+ jout.putNextEntry(new ZipEntry(rsrc.getPath() + Patcher.DELETE));
+ }
+
+ System.out.println("Created patch file: " + patch);
+
+ } catch (IOException ioe) {
+ FileUtil.deleteHarder(patch);
+ throw ioe;
+ }
+ }
+
+ protected File rebuildJar (File target)
+ throws IOException
+ {
+ File temp = File.createTempFile("differ", "jar");
+ try (JarFile jar = new JarFile(target);
+ FileOutputStream tempFos = new FileOutputStream(temp);
+ BufferedOutputStream tempBos = new BufferedOutputStream(tempFos);
+ JarOutputStream jout = new JarOutputStream(tempBos)) {
+ byte[] buffer = new byte[4096];
+ for (Enumeration< JarEntry > iter = jar.entries(); iter.hasMoreElements();) {
+ JarEntry entry = iter.nextElement();
+ entry.setCompressedSize(-1);
+ jout.putNextEntry(entry);
+ try (InputStream in = jar.getInputStream(entry)) {
+ int size = in.read(buffer);
+ while (size != -1) {
+ jout.write(buffer, 0, size);
+ size = in.read(buffer);
+ }
+ }
+ }
+ }
+ return temp;
+ }
+
+ protected void jarDiff (File ofile, File nfile, JarOutputStream jout)
+ throws IOException
+ {
+ JarDiff.createPatch(ofile.getPath(), nfile.getPath(), jout, false);
+ }
+
+ public static void main (String[] args)
+ {
+ if (args.length < 2) {
+ System.err.println(
+ "Usage: Differ [-verbose] new_vers_dir old_vers_dir");
+ System.exit(255);
+ }
+ Differ differ = new Differ();
+ boolean verbose = false;
+ int aidx = 0;
+ if (args[0].equals("-verbose")) {
+ verbose = true;
+ aidx++;
+ }
+ try {
+ differ.createDiff(new File(args[aidx++]),
+ new File(args[aidx++]), verbose);
+ } catch (IOException ioe) {
+ System.err.println("Error: " + ioe.getMessage());
+ System.exit(255);
+ }
+ }
+
+ protected static void pipe (File file, JarOutputStream jout)
+ throws IOException
+ {
+ try (FileInputStream fin = new FileInputStream(file)) {
+ StreamUtil.copy(fin, jout);
+ }
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tools;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Signature;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.threerings.getdown.data.Application;
+import com.threerings.getdown.data.Digest;
+import com.threerings.getdown.data.EnvConfig;
+import com.threerings.getdown.data.Resource;
+import com.threerings.getdown.util.Base64;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Handles the generation of the digest.txt file.
+ */
+public class Digester
+{
+ /**
+ * A command line entry point for the digester.
+ */
+ public static void main (String[] args)
+ throws IOException, GeneralSecurityException
+ {
+ switch (args.length) {
+ case 1:
+ createDigests(new File(args[0]), null, null, null);
+ break;
+ case 4:
+ createDigests(new File(args[0]), new File(args[1]), args[2], args[3]);
+ break;
+ default:
+ System.err.println("Usage: Digester app_dir [keystore_path password alias]");
+ System.exit(255);
+ }
+ }
+
+ /**
+ * Creates digest file(s) and optionally signs them if {@code keystore} is not null.
+ */
+ public static void createDigests (File appdir, File keystore, String password, String alias)
+ throws IOException, GeneralSecurityException
+ {
+ for (int version = 1; version <= Digest.VERSION; version++) {
+ createDigest(version, appdir);
+ if (keystore != null) {
+ signDigest(version, appdir, keystore, password, alias);
+ }
+ }
+ }
+
+ /**
+ * Creates a digest file in the specified application directory.
+ */
+ public static void createDigest (int version, File appdir)
+ throws IOException
+ {
+ File target = new File(appdir, Digest.digestFile(version));
+ System.out.println("Generating digest file '" + target + "'...");
+
+ // create our application and instruct it to parse its business
+ Application app = new Application(new EnvConfig(appdir));
+ app.init(false);
+
+ List<Resource> rsrcs = new ArrayList<>();
+ rsrcs.add(app.getConfigResource());
+ rsrcs.addAll(app.getCodeResources());
+ rsrcs.addAll(app.getResources());
+ for (Application.AuxGroup ag : app.getAuxGroups()) {
+ rsrcs.addAll(ag.codes);
+ rsrcs.addAll(ag.rsrcs);
+ }
+
+ // now generate the digest file
+ Digest.createDigest(version, rsrcs, target);
+ }
+
+ /**
+ * Creates a digest file in the specified application directory.
+ */
+ public static void signDigest (int version, File appdir,
+ File storePath, String storePass, String storeAlias)
+ throws IOException, GeneralSecurityException
+ {
+ String filename = Digest.digestFile(version);
+ File inputFile = new File(appdir, filename);
+ File signatureFile = new File(appdir, filename + Application.SIGNATURE_SUFFIX);
+
+ try (FileInputStream storeInput = new FileInputStream(storePath);
+ FileInputStream dataInput = new FileInputStream(inputFile);
+ FileOutputStream signatureOutput = new FileOutputStream(signatureFile)) {
+
+ // initialize the keystore
+ KeyStore store = KeyStore.getInstance("JKS");
+ store.load(storeInput, storePass.toCharArray());
+ PrivateKey key = (PrivateKey)store.getKey(storeAlias, storePass.toCharArray());
+
+ // sign the digest file
+ String algo = Digest.sigAlgorithm(version);
+ Signature sig = Signature.getInstance(algo);
+ byte[] buffer = new byte[8192];
+ int length;
+
+ sig.initSign(key);
+ while ((length = dataInput.read(buffer)) != -1) {
+ sig.update(buffer, 0, length);
+ }
+
+ // Write out the signature
+ String signed = Base64.encodeToString(sig.sign(), Base64.DEFAULT);
+ signatureOutput.write(signed.getBytes(UTF_8));
+ }
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+/*
+ * @(#)JarDiff.java 1.7 05/11/17
+ *
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * -Redistribution of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * -Redistribution in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
+ * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
+ * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
+ * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
+ * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
+ * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
+ * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or intended
+ * for use in the design, construction, operation or maintenance of any
+ * nuclear facility.
+ */
+
+package com.threerings.getdown.tools;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * JarDiff is able to create a jar file containing the delta between two jar files (old and new).
+ * The delta jar file can then be applied to the old jar file to reconstruct the new jar file.
+ *
+ * <p> Refer to the JNLP spec for details on how this is done.
+ *
+ * @version 1.13, 06/26/03
+ */
+public class JarDiff implements JarDiffCodes
+{
+ private static final int DEFAULT_READ_SIZE = 2048;
+ private static byte[] newBytes = new byte[DEFAULT_READ_SIZE];
+ private static byte[] oldBytes = new byte[DEFAULT_READ_SIZE];
+
+ // The JARDiff.java is the stand-alone jardiff.jar tool. Thus, we do not depend on Globals.java
+ // and other stuff here. Instead, we use an explicit _debug flag.
+ private static boolean _debug;
+
+ /**
+ * Creates a patch from the two passed in files, writing the result to <code>os</code>.
+ */
+ public static void createPatch (String oldPath, String newPath,
+ OutputStream os, boolean minimal) throws IOException
+ {
+ try (JarFile2 oldJar = new JarFile2(oldPath);
+ JarFile2 newJar = new JarFile2(newPath)) {
+
+ HashMap<String,String> moved = new HashMap<>();
+ HashSet<String> implicit = new HashSet<>();
+ HashSet<String> moveSrc = new HashSet<>();
+ HashSet<String> newEntries = new HashSet<>();
+
+ // FIRST PASS
+ // Go through the entries in new jar and
+ // determine which files are candidates for implicit moves
+ // ( files that has the same filename and same content in old.jar
+ // and new.jar )
+ // and for files that cannot be implicitly moved, we will either
+ // find out whether it is moved or new (modified)
+ for (JarEntry newEntry : newJar) {
+ String newname = newEntry.getName();
+
+ // Return best match of contents, will return a name match if possible
+ String oldname = oldJar.getBestMatch(newJar, newEntry);
+ if (oldname == null) {
+ // New or modified entry
+ if (_debug) {
+ System.out.println("NEW: "+ newname);
+ }
+ newEntries.add(newname);
+ } else {
+ // Content already exist - need to do a move
+
+ // Should do implicit move? Yes, if names are the same, and
+ // no move command already exist from oldJar
+ if (oldname.equals(newname) && !moveSrc.contains(oldname)) {
+ if (_debug) {
+ System.out.println(newname + " added to implicit set!");
+ }
+ implicit.add(newname);
+ } else {
+ // The 1.0.1/1.0 JarDiffPatcher cannot handle
+ // multiple MOVE command with same src.
+ // The work around here is if we are going to generate
+ // a MOVE command with duplicate src, we will
+ // instead add the target as a new file. This way
+ // the jardiff can be applied by 1.0.1/1.0
+ // JarDiffPatcher also.
+ if (!minimal && (implicit.contains(oldname) ||
+ moveSrc.contains(oldname) )) {
+
+ // generate non-minimal jardiff
+ // for backward compatibility
+
+ if (_debug) {
+
+ System.out.println("NEW: "+ newname);
+ }
+ newEntries.add(newname);
+ } else {
+ // Use newname as key, since they are unique
+ if (_debug) {
+ System.err.println("moved.put " + newname + " " + oldname);
+ }
+ moved.put(newname, oldname);
+ moveSrc.add(oldname);
+ }
+ // Check if this disables an implicit 'move <oldname> <oldname>'
+ if (implicit.contains(oldname) && minimal) {
+
+ if (_debug) {
+ System.err.println("implicit.remove " + oldname);
+
+ System.err.println("moved.put " + oldname + " " + oldname);
+
+ }
+ implicit.remove(oldname);
+ moved.put(oldname, oldname);
+ moveSrc.add(oldname);
+ }
+ }
+ }
+ }
+
+ // SECOND PASS: <deleted files> = <oldjarnames> - <implicitmoves> -
+ // <source of move commands> - <new or modified entries>
+ ArrayList<String> deleted = new ArrayList<>();
+ for (JarEntry oldEntry : oldJar) {
+ String oldName = oldEntry.getName();
+ if (!implicit.contains(oldName) && !moveSrc.contains(oldName)
+ && !newEntries.contains(oldName)) {
+ if (_debug) {
+ System.err.println("deleted.add " + oldName);
+ }
+ deleted.add(oldName);
+ }
+ }
+
+ //DEBUG
+ if (_debug) {
+ //DEBUG: print out moved map
+ System.out.println("MOVED MAP!!!");
+ for (Map.Entry<String,String> entry : moved.entrySet()) {
+ System.out.println(entry);
+ }
+
+ //DEBUG: print out IMOVE map
+ System.out.println("IMOVE MAP!!!");
+ for (String newName : implicit) {
+ System.out.println("key is " + newName);
+ }
+ }
+
+ JarOutputStream jos = new JarOutputStream(os);
+
+ // Write out all the MOVEs and REMOVEs
+ createIndex(jos, deleted, moved);
+
+ // Put in New and Modified entries
+ for (String newName : newEntries) {
+ if (_debug) {
+ System.out.println("New File: " + newName);
+ }
+ writeEntry(jos, newJar.getEntryByName(newName), newJar);
+ }
+
+ jos.finish();
+// jos.close();
+ }
+ }
+
+ /**
+ * Writes the index file out to <code>jos</code>.
+ * <code>oldEntries</code> gives the names of the files that were removed,
+ * <code>movedMap</code> maps from the new name to the old name.
+ */
+ private static void createIndex (JarOutputStream jos, List<String> oldEntries,
+ Map<String,String> movedMap)
+ throws IOException
+ {
+ StringWriter writer = new StringWriter();
+ writer.write(VERSION_HEADER);
+ writer.write("\r\n");
+
+ // Write out entries that have been removed
+ for (String name : oldEntries) {
+ writer.write(REMOVE_COMMAND);
+ writer.write(" ");
+ writeEscapedString(writer, name);
+ writer.write("\r\n");
+ }
+
+ // And those that have moved
+ for (String newName : movedMap.keySet()) {
+ String oldName = movedMap.get(newName);
+ writer.write(MOVE_COMMAND);
+ writer.write(" ");
+ writeEscapedString(writer, oldName);
+ writer.write(" ");
+ writeEscapedString(writer, newName);
+ writer.write("\r\n");
+ }
+
+ jos.putNextEntry(new JarEntry(INDEX_NAME));
+ byte[] bytes = writer.toString().getBytes(UTF_8);
+ jos.write(bytes, 0, bytes.length);
+ }
+
+ protected static Writer writeEscapedString (Writer writer, String string)
+ throws IOException
+ {
+ int index = 0;
+ int last = 0;
+ char[] chars = null;
+
+ while ((index = string.indexOf(' ', index)) != -1) {
+ if (last != index) {
+ if (chars == null) {
+ chars = string.toCharArray();
+ }
+ writer.write(chars, last, index - last);
+ }
+ last = index;
+ index++;
+ writer.write('\\');
+ }
+ if (last != 0 && chars != null) {
+ writer.write(chars, last, chars.length - last);
+ }
+ else {
+ // no spaces
+ writer.write(string);
+ }
+
+ return writer;
+ }
+
+ private static void writeEntry (JarOutputStream jos, JarEntry entry, JarFile2 file)
+ throws IOException
+ {
+ try (InputStream data = file.getJarFile().getInputStream(entry)) {
+ jos.putNextEntry(entry);
+ int size = data.read(newBytes);
+ while (size != -1) {
+ jos.write(newBytes, 0, size);
+ size = data.read(newBytes);
+ }
+ }
+ }
+
+ /**
+ * JarFile2 wraps a JarFile providing some convenience methods.
+ */
+ private static class JarFile2 implements Iterable<JarEntry>, Closeable
+ {
+ private JarFile _jar;
+ private List<JarEntry> _entries;
+ private HashMap<String,JarEntry> _nameToEntryMap;
+ private HashMap<Long,LinkedList<JarEntry>> _crcToEntryMap;
+
+ public JarFile2 (String path) throws IOException {
+ _jar = new JarFile(new File(path));
+ index();
+ }
+
+ public JarFile getJarFile () {
+ return _jar;
+ }
+
+ // from interface Iterable<JarEntry>
+ @Override
+ public Iterator<JarEntry> iterator () {
+ return _entries.iterator();
+ }
+
+ public JarEntry getEntryByName (String name) {
+ return _nameToEntryMap.get(name);
+ }
+
+ /**
+ * Returns true if the two InputStreams differ.
+ */
+ private static boolean differs (InputStream oldIS, InputStream newIS) throws IOException {
+ int newSize = 0;
+ int oldSize;
+ int total = 0;
+ boolean retVal = false;
+
+ while (newSize != -1) {
+ newSize = newIS.read(newBytes);
+ oldSize = oldIS.read(oldBytes);
+
+ if (newSize != oldSize) {
+ if (_debug) {
+ System.out.println("\tread sizes differ: " + newSize +
+ " " + oldSize + " total " + total);
+ }
+ retVal = true;
+ break;
+ }
+ if (newSize > 0) {
+ while (--newSize >= 0) {
+ total++;
+ if (newBytes[newSize] != oldBytes[newSize]) {
+ if (_debug) {
+ System.out.println("\tbytes differ at " +
+ total);
+ }
+ retVal = true;
+ break;
+ }
+ if ( retVal ) {
+ //Jump out
+ break;
+ }
+ newSize = 0;
+ }
+ }
+ }
+
+ return retVal;
+ }
+
+ public String getBestMatch (JarFile2 file, JarEntry entry) throws IOException {
+ // check for same name and same content, return name if found
+ if (contains(file, entry)) {
+ return (entry.getName());
+ }
+
+ // return name of same content file or null
+ return (hasSameContent(file,entry));
+ }
+
+ public boolean contains (JarFile2 f, JarEntry e) throws IOException {
+
+ JarEntry thisEntry = getEntryByName(e.getName());
+
+ // Look up name in 'this' Jar2File - if not exist return false
+ if (thisEntry == null)
+ return false;
+
+ // Check CRC - if no match - return false
+ if (thisEntry.getCrc() != e.getCrc())
+ return false;
+
+ // Check contents - if no match - return false
+ try (InputStream oldIS = getJarFile().getInputStream(thisEntry);
+ InputStream newIS = f.getJarFile().getInputStream(e)) {
+ return !differs(oldIS, newIS);
+ }
+ }
+
+ public String hasSameContent (JarFile2 file, JarEntry entry) throws IOException {
+ String thisName = null;
+ Long crcL = Long.valueOf(entry.getCrc());
+ // check if this jar contains files with the passed in entry's crc
+ if (_crcToEntryMap.containsKey(crcL)) {
+ // get the Linked List with files with the crc
+ LinkedList<JarEntry> ll = _crcToEntryMap.get(crcL);
+ // go through the list and check for content match
+ ListIterator<JarEntry> li = ll.listIterator(0);
+ while (li.hasNext()) {
+ JarEntry thisEntry = li.next();
+ // check for content match
+ try (InputStream oldIS = getJarFile().getInputStream(thisEntry);
+ InputStream newIS = file.getJarFile().getInputStream(entry)) {
+ if (!differs(oldIS, newIS)) {
+ thisName = thisEntry.getName();
+ return thisName;
+ }
+ }
+ }
+ }
+ return thisName;
+ }
+
+ private void index () throws IOException {
+ Enumeration<JarEntry> entries = _jar.entries();
+
+ _nameToEntryMap = new HashMap<>();
+ _crcToEntryMap = new HashMap<>();
+ _entries = new ArrayList<>();
+ if (_debug) {
+ System.out.println("indexing: " + _jar.getName());
+ }
+ if (entries != null) {
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ long crc = entry.getCrc();
+ Long crcL = Long.valueOf(crc);
+ if (_debug) {
+ System.out.println("\t" + entry.getName() + " CRC " + crc);
+ }
+
+ _nameToEntryMap.put(entry.getName(), entry);
+ _entries.add(entry);
+
+ // generate the CRC to entries map
+ if (_crcToEntryMap.containsKey(crcL)) {
+ // key exist, add the entry to the correcponding linked list
+ LinkedList<JarEntry> ll = _crcToEntryMap.get(crcL);
+ ll.add(entry);
+ _crcToEntryMap.put(crcL, ll);
+
+ } else {
+ // create a new entry in the hashmap for the new key
+ LinkedList<JarEntry> ll = new LinkedList<JarEntry>();
+ ll.add(entry);
+ _crcToEntryMap.put(crcL, ll);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ _jar.close();
+ }
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tools;
+
+/**
+ * Constants shared by {@link JarDiff} and {@link JarDiffPatcher}.
+ */
+public interface JarDiffCodes
+{
+ /** The name of the jardiff control file. */
+ String INDEX_NAME = "META-INF/INDEX.JD";
+
+ /** The version header used in the control file. */
+ String VERSION_HEADER = "version 1.0";
+
+ /** A jardiff command to remove an entry. */
+ String REMOVE_COMMAND = "remove";
+
+ /** A jardiff command to move an entry. */
+ String MOVE_COMMAND = "move";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tools;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+import com.threerings.getdown.util.ProgressObserver;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Applies a jardiff patch to a jar file.
+ */
+public class JarDiffPatcher implements JarDiffCodes
+{
+ /**
+ * Patches the specified jar file using the supplied patch file and writing
+ * the new jar file to the supplied target.
+ *
+ * @param jarPath the path to the original jar file.
+ * @param diffPath the path to the jardiff patch file.
+ * @param target the output stream to which we will write the patched jar.
+ * @param observer an optional observer to be notified of patching progress.
+ *
+ * @throws IOException if any problem occurs during patching.
+ */
+ public void patchJar (String jarPath, String diffPath, File target, ProgressObserver observer)
+ throws IOException
+ {
+ File oldFile = new File(jarPath), diffFile = new File(diffPath);
+
+ try (JarFile oldJar = new JarFile(oldFile);
+ JarFile jarDiff = new JarFile(diffFile);
+ JarOutputStream jos = new JarOutputStream(new FileOutputStream(target))) {
+
+ Set<String> ignoreSet = new HashSet<>();
+ Map<String, String> renameMap = new HashMap<>();
+ determineNameMapping(jarDiff, ignoreSet, renameMap);
+
+ // get all keys in renameMap
+ String[] keys = renameMap.keySet().toArray(new String[renameMap.size()]);
+
+ // Files to implicit move
+ Set<String> oldjarNames = new HashSet<>();
+ Enumeration<JarEntry> oldEntries = oldJar.entries();
+ if (oldEntries != null) {
+ while (oldEntries.hasMoreElements()) {
+ oldjarNames.add(oldEntries.nextElement().getName());
+ }
+ }
+
+ // size depends on the three parameters below, which is basically the
+ // counter for each loop that do the actual writes to the output file
+ // since oldjarNames.size() changes in the first two loop below, we
+ // need to adjust the size accordingly also when oldjarNames.size()
+ // changes
+ double size = oldjarNames.size() + keys.length + jarDiff.size();
+ double currentEntry = 0;
+
+ // Handle all remove commands
+ oldjarNames.removeAll(ignoreSet);
+ size -= ignoreSet.size();
+
+ // Add content from JARDiff
+ Enumeration<JarEntry> entries = jarDiff.entries();
+ if (entries != null) {
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ if (!INDEX_NAME.equals(entry.getName())) {
+ updateObserver(observer, currentEntry, size);
+ currentEntry++;
+ writeEntry(jos, entry, jarDiff);
+
+ // Remove entry from oldjarNames since no implicit move is
+ // needed
+ boolean wasInOld = oldjarNames.remove(entry.getName());
+
+ // Update progress counters. If it was in old, we do not
+ // need an implicit move, so adjust total size.
+ if (wasInOld) {
+ size--;
+ }
+
+ } else {
+ // no write is done, decrement size
+ size--;
+ }
+ }
+ }
+
+ // go through the renameMap and apply move for each entry
+ for (String newName : keys) {
+ // Apply move <oldName> <newName> command
+ String oldName = renameMap.get(newName);
+
+ // Get source JarEntry
+ JarEntry oldEntry = oldJar.getJarEntry(oldName);
+ if (oldEntry == null) {
+ String moveCmd = MOVE_COMMAND + oldName + " " + newName;
+ throw new IOException("error.badmove: " + moveCmd);
+ }
+
+ // Create dest JarEntry
+ JarEntry newEntry = new JarEntry(newName);
+ newEntry.setTime(oldEntry.getTime());
+ newEntry.setSize(oldEntry.getSize());
+ newEntry.setCompressedSize(oldEntry.getCompressedSize());
+ newEntry.setCrc(oldEntry.getCrc());
+ newEntry.setMethod(oldEntry.getMethod());
+ newEntry.setExtra(oldEntry.getExtra());
+ newEntry.setComment(oldEntry.getComment());
+
+ updateObserver(observer, currentEntry, size);
+ currentEntry++;
+
+ try (InputStream data = oldJar.getInputStream(oldEntry)) {
+ writeEntry(jos, newEntry, data);
+ }
+
+ // Remove entry from oldjarNames since no implicit move is needed
+ boolean wasInOld = oldjarNames.remove(oldName);
+
+ // Update progress counters. If it was in old, we do not need an
+ // implicit move, so adjust total size.
+ if (wasInOld) {
+ size--;
+ }
+ }
+
+ // implicit move
+ Iterator<String> iEntries = oldjarNames.iterator();
+ if (iEntries != null) {
+ while (iEntries.hasNext()) {
+ String name = iEntries.next();
+ JarEntry entry = oldJar.getJarEntry(name);
+ if (entry == null) {
+ // names originally retrieved from the JAR, so this should never happen
+ throw new AssertionError("JAR entry not found: " + name);
+ }
+ updateObserver(observer, currentEntry, size);
+ currentEntry++;
+ writeEntry(jos, entry, oldJar);
+ }
+ }
+ updateObserver(observer, currentEntry, size);
+ }
+ }
+
+ protected void updateObserver (ProgressObserver observer, double currentSize, double size)
+ {
+ if (observer != null) {
+ observer.progress((int)(100*currentSize/size));
+ }
+ }
+
+ protected void determineNameMapping (
+ JarFile jarDiff, Set<String> ignoreSet, Map<String, String> renameMap)
+ throws IOException
+ {
+ InputStream is = jarDiff.getInputStream(jarDiff.getEntry(INDEX_NAME));
+ if (is == null) {
+ throw new IOException("error.noindex");
+ }
+
+ LineNumberReader indexReader =
+ new LineNumberReader(new InputStreamReader(is, UTF_8));
+ String line = indexReader.readLine();
+ if (line == null || !line.equals(VERSION_HEADER)) {
+ throw new IOException("jardiff.error.badheader: " + line);
+ }
+
+ while ((line = indexReader.readLine()) != null) {
+ if (line.startsWith(REMOVE_COMMAND)) {
+ List<String> sub = getSubpaths(
+ line.substring(REMOVE_COMMAND.length()));
+
+ if (sub.size() != 1) {
+ throw new IOException("error.badremove: " + line);
+ }
+ ignoreSet.add(sub.get(0));
+
+ } else if (line.startsWith(MOVE_COMMAND)) {
+ List<String> sub = getSubpaths(
+ line.substring(MOVE_COMMAND.length()));
+ if (sub.size() != 2) {
+ throw new IOException("error.badmove: " + line);
+ }
+
+ // target of move should be the key
+ if (renameMap.put(sub.get(1), sub.get(0)) != null) {
+ // invalid move - should not move to same target twice
+ throw new IOException("error.badmove: " + line);
+ }
+
+ } else if (line.length() > 0) {
+ throw new IOException("error.badcommand: " + line);
+ }
+ }
+ }
+
+ protected List<String> getSubpaths (String path)
+ {
+ int index = 0;
+ int length = path.length();
+ ArrayList<String> sub = new ArrayList<>();
+
+ while (index < length) {
+ while (index < length && Character.isWhitespace
+ (path.charAt(index))) {
+ index++;
+ }
+ if (index < length) {
+ int start = index;
+ int last = start;
+ String subString = null;
+
+ while (index < length) {
+ char aChar = path.charAt(index);
+ if (aChar == '\\' && (index + 1) < length &&
+ path.charAt(index + 1) == ' ') {
+
+ if (subString == null) {
+ subString = path.substring(last, index);
+ } else {
+ subString += path.substring(last, index);
+ }
+ last = ++index;
+ } else if (Character.isWhitespace(aChar)) {
+ break;
+ }
+ index++;
+ }
+ if (last != index) {
+ if (subString == null) {
+ subString = path.substring(last, index);
+ } else {
+ subString += path.substring(last, index);
+ }
+ }
+ sub.add(subString);
+ }
+ }
+ return sub;
+ }
+
+ protected void writeEntry (JarOutputStream jos, JarEntry entry, JarFile file)
+ throws IOException
+ {
+ try (InputStream data = file.getInputStream(entry)) {
+ writeEntry(jos, entry, data);
+ }
+ }
+
+ protected void writeEntry (JarOutputStream jos, JarEntry entry, InputStream data)
+ throws IOException
+ {
+ jos.putNextEntry(new JarEntry(entry.getName()));
+
+ // Read the entry
+ int size = data.read(newBytes);
+ while (size != -1) {
+ jos.write(newBytes, 0, size);
+ size = data.read(newBytes);
+ }
+ }
+
+ protected static final int DEFAULT_READ_SIZE = 2048;
+
+ protected static byte[] newBytes = new byte[DEFAULT_READ_SIZE];
+ protected static byte[] oldBytes = new byte[DEFAULT_READ_SIZE];
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.tools;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import com.threerings.getdown.util.FileUtil;
+import com.threerings.getdown.util.ProgressObserver;
+import com.threerings.getdown.util.StreamUtil;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Applies a unified patch file to an application directory, providing
+ * percentage completion feedback along the way. <em>Note:</em> the
+ * patcher is not thread safe. Create a separate patcher instance for each
+ * patching action that is desired.
+ */
+public class Patcher
+{
+ /** A suffix appended to file names to indicate that a file should be newly created. */
+ public static final String CREATE = ".create";
+
+ /** A suffix appended to file names to indicate that a file should be patched. */
+ public static final String PATCH = ".patch";
+
+ /** A suffix appended to file names to indicate that a file should be deleted. */
+ public static final String DELETE = ".delete";
+
+ /**
+ * Applies the specified patch file to the application living in the
+ * specified application directory. The supplied observer, if
+ * non-null, will be notified of progress along the way.
+ *
+ * <p><em>Note:</em> this method runs on the calling thread, thus the
+ * caller may want to make use of a separate thread in conjunction
+ * with the patcher so that the user interface is not blocked for the
+ * duration of the patch.
+ */
+ public void patch (File appdir, File patch, ProgressObserver obs)
+ throws IOException
+ {
+ // save this information for later
+ _obs = obs;
+ _plength = patch.length();
+
+ try (JarFile file = new JarFile(patch)) {
+ Enumeration<JarEntry> entries = file.entries(); // old skool!
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String path = entry.getName();
+ long elength = entry.getCompressedSize();
+
+ // depending on the suffix, we do The Right Thing (tm)
+ if (path.endsWith(CREATE)) {
+ path = strip(path, CREATE);
+ log.info("Creating " + path + "...");
+ createFile(file, entry, new File(appdir, path));
+
+ } else if (path.endsWith(PATCH)) {
+ path = strip(path, PATCH);
+ log.info("Patching " + path + "...");
+ patchFile(file, entry, appdir, path);
+
+ } else if (path.endsWith(DELETE)) {
+ path = strip(path, DELETE);
+ log.info("Removing " + path + "...");
+ File target = new File(appdir, path);
+ if (!FileUtil.deleteHarder(target)) {
+ log.warning("Failure deleting '" + target + "'.");
+ }
+
+ } else {
+ log.warning("Skipping bogus patch file entry: " + path);
+ }
+
+ // note that we've completed this entry
+ _complete += elength;
+ }
+ }
+ }
+
+ protected String strip (String path, String suffix)
+ {
+ return path.substring(0, path.length() - suffix.length());
+ }
+
+ protected void createFile (JarFile file, ZipEntry entry, File target)
+ {
+ // create our copy buffer if necessary
+ if (_buffer == null) {
+ _buffer = new byte[COPY_BUFFER_SIZE];
+ }
+
+ // make sure the file's parent directory exists
+ File pdir = target.getParentFile();
+ if (!pdir.exists() && !pdir.mkdirs()) {
+ log.warning("Failed to create parent for '" + target + "'.");
+ }
+
+ try (InputStream in = file.getInputStream(entry);
+ FileOutputStream fout = new FileOutputStream(target)) {
+
+ int total = 0, read;
+ while ((read = in.read(_buffer)) != -1) {
+ total += read;
+ fout.write(_buffer, 0, read);
+ updateProgress(total);
+ }
+
+ } catch (IOException ioe) {
+ log.warning("Error creating '" + target + "': " + ioe);
+ }
+ }
+
+ protected void patchFile (JarFile file, ZipEntry entry,
+ File appdir, String path)
+ {
+ File target = new File(appdir, path);
+ File patch = new File(appdir, entry.getName());
+ File otarget = new File(appdir, path + ".old");
+ JarDiffPatcher patcher = null;
+
+ // make sure no stale old target is lying around to mess us up
+ FileUtil.deleteHarder(otarget);
+
+ // pipe the contents of the patch into a file
+ try (InputStream in = file.getInputStream(entry);
+ FileOutputStream fout = new FileOutputStream(patch)) {
+
+ StreamUtil.copy(in, fout);
+ StreamUtil.close(fout);
+
+ // move the current version of the jar to .old
+ if (!FileUtil.renameTo(target, otarget)) {
+ log.warning("Failed to .oldify '" + target + "'.");
+ return;
+ }
+
+ // we'll need this to pass progress along to our observer
+ final long elength = entry.getCompressedSize();
+ ProgressObserver obs = new ProgressObserver() {
+ public void progress (int percent) {
+ updateProgress((int)(percent * elength / 100));
+ }
+ };
+
+ // now apply the patch to create the new target file
+ patcher = new JarDiffPatcher();
+ patcher.patchJar(otarget.getPath(), patch.getPath(), target, obs);
+
+ } catch (IOException ioe) {
+ if (patcher == null) {
+ log.warning("Failed to write patch file '" + patch + "': " + ioe);
+ } else {
+ log.warning("Error patching '" + target + "': " + ioe);
+ }
+
+ } finally {
+ // clean up our temporary files
+ FileUtil.deleteHarder(patch);
+ FileUtil.deleteHarder(otarget);
+ }
+ }
+
+ protected void updateProgress (int progress)
+ {
+ if (_obs != null) {
+ _obs.progress((int)(100 * (_complete + progress) / _plength));
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ if (args.length != 2) {
+ System.err.println("Usage: Patcher appdir patch_file");
+ System.exit(-1);
+ }
+
+ Patcher patcher = new Patcher();
+ try {
+ patcher.patch(new File(args[0]), new File(args[1]), null);
+ } catch (IOException ioe) {
+ System.err.println("Error: " + ioe.getMessage());
+ System.exit(-1);
+ }
+ }
+
+ protected ProgressObserver _obs;
+ protected long _complete, _plength;
+ protected byte[] _buffer;
+
+ protected static final int COPY_BUFFER_SIZE = 4096;
+}
--- /dev/null
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.threerings.getdown.util;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+/**
+ * Utilities for encoding and decoding the Base64 representation of
+ * binary data. See RFCs <a
+ * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
+ * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
+ */
+public class Base64 {
+ /**
+ * Default values for encoder/decoder flags.
+ */
+ public static final int DEFAULT = 0;
+
+ /**
+ * Encoder flag bit to omit the padding '=' characters at the end
+ * of the output (if any).
+ */
+ public static final int NO_PADDING = 1;
+
+ /**
+ * Encoder flag bit to omit all line terminators (i.e., the output
+ * will be on one long line).
+ */
+ public static final int NO_WRAP = 2;
+
+ /**
+ * Encoder flag bit to indicate lines should be terminated with a
+ * CRLF pair instead of just an LF. Has no effect if {@code
+ * NO_WRAP} is specified as well.
+ */
+ public static final int CRLF = 4;
+
+ /**
+ * Encoder/decoder flag bit to indicate using the "URL and
+ * filename safe" variant of Base64 (see RFC 3548 section 4) where
+ * {@code -} and {@code _} are used in place of {@code +} and
+ * {@code /}.
+ */
+ public static final int URL_SAFE = 8;
+
+ /**
+ * Flag to pass to {@code Base64OutputStream} to indicate that it
+ * should not close the output stream it is wrapping when it
+ * itself is closed.
+ */
+ public static final int NO_CLOSE = 16;
+
+ // --------------------------------------------------------
+ // shared code
+ // --------------------------------------------------------
+
+ /* package */ static abstract class Coder {
+ public byte[] output;
+ public int op;
+
+ /**
+ * Encode/decode another block of input data. this.output is
+ * provided by the caller, and must be big enough to hold all
+ * the coded data. On exit, this.opwill be set to the length
+ * of the coded data.
+ *
+ * @param finish true if this is the final call to process for
+ * this object. Will finalize the coder state and
+ * include any final bytes in the output.
+ *
+ * @return true if the input so far is good; false if some
+ * error has been detected in the input stream..
+ */
+ public abstract boolean process(byte[] input, int offset, int len, boolean finish);
+
+ /**
+ * @return the maximum number of bytes a call to process()
+ * could produce for the given number of input bytes. This may
+ * be an overestimate.
+ */
+ public abstract int maxOutputSize(int len);
+ }
+
+ // --------------------------------------------------------
+ // decoding
+ // --------------------------------------------------------
+
+ /**
+ * Decode the Base64-encoded data in input and return the data in
+ * a new byte array.
+ *
+ * <p>The padding '=' characters at the end are considered optional, but
+ * if any are present, there must be the correct number of them.
+ *
+ * @param str the input String to decode, which is converted to
+ * bytes using ASCII
+ * @param flags controls certain features of the decoded output.
+ * Pass {@code DEFAULT} to decode standard Base64.
+ *
+ * @throws IllegalArgumentException if the input contains
+ * incorrect padding
+ */
+ public static byte[] decode(String str, int flags) {
+ return decode(str.getBytes(US_ASCII), flags);
+ }
+
+ /**
+ * Decode the Base64-encoded data in input and return the data in
+ * a new byte array.
+ *
+ * <p>The padding '=' characters at the end are considered optional, but
+ * if any are present, there must be the correct number of them.
+ *
+ * @param input the input array to decode
+ * @param flags controls certain features of the decoded output.
+ * Pass {@code DEFAULT} to decode standard Base64.
+ *
+ * @throws IllegalArgumentException if the input contains
+ * incorrect padding
+ */
+ public static byte[] decode(byte[] input, int flags) {
+ return decode(input, 0, input.length, flags);
+ }
+
+ /**
+ * Decode the Base64-encoded data in input and return the data in
+ * a new byte array.
+ *
+ * <p>The padding '=' characters at the end are considered optional, but
+ * if any are present, there must be the correct number of them.
+ *
+ * @param input the data to decode
+ * @param offset the position within the input array at which to start
+ * @param len the number of bytes of input to decode
+ * @param flags controls certain features of the decoded output.
+ * Pass {@code DEFAULT} to decode standard Base64.
+ *
+ * @throws IllegalArgumentException if the input contains
+ * incorrect padding
+ */
+ public static byte[] decode(byte[] input, int offset, int len, int flags) {
+ // Allocate space for the most data the input could represent.
+ // (It could contain less if it contains whitespace, etc.)
+ Decoder decoder = new Decoder(flags, new byte[len*3/4]);
+
+ if (!decoder.process(input, offset, len, true)) {
+ throw new IllegalArgumentException("bad base-64");
+ }
+
+ // Maybe we got lucky and allocated exactly enough output space.
+ if (decoder.op == decoder.output.length) {
+ return decoder.output;
+ }
+
+ // Need to shorten the array, so allocate a new one of the
+ // right size and copy.
+ byte[] temp = new byte[decoder.op];
+ System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
+ return temp;
+ }
+
+ /* package */ static class Decoder extends Coder {
+ /**
+ * Lookup table for turning bytes into their position in the
+ * Base64 alphabet.
+ */
+ private static final int DECODE[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ };
+
+ /**
+ * Decode lookup table for the "web safe" variant (RFC 3548
+ * sec. 4) where - and _ replace + and /.
+ */
+ private static final int DECODE_WEBSAFE[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ };
+
+ /** Non-data values in the DECODE arrays. */
+ private static final int SKIP = -1;
+ private static final int EQUALS = -2;
+
+ /**
+ * States 0-3 are reading through the next input tuple.
+ * State 4 is having read one '=' and expecting exactly
+ * one more.
+ * State 5 is expecting no more data or padding characters
+ * in the input.
+ * State 6 is the error state; an error has been detected
+ * in the input and no future input can "fix" it.
+ */
+ private int state; // state number (0 to 6)
+ private int value;
+
+ final private int[] alphabet;
+
+ public Decoder(int flags, byte[] output) {
+ this.output = output;
+
+ alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
+ state = 0;
+ value = 0;
+ }
+
+ /**
+ * @return an overestimate for the number of bytes {@code
+ * len} bytes could decode to.
+ */
+ public int maxOutputSize(int len) {
+ return len * 3/4 + 10;
+ }
+
+ /**
+ * Decode another block of input data.
+ *
+ * @return true if the state machine is still healthy. false if
+ * bad base-64 data has been detected in the input stream.
+ */
+ public boolean process(byte[] input, int offset, int len, boolean finish) {
+ if (this.state == 6) return false;
+
+ int p = offset;
+ len += offset;
+
+ // Using local variables makes the decoder about 12%
+ // faster than if we manipulate the member variables in
+ // the loop. (Even alphabet makes a measurable
+ // difference, which is somewhat surprising to me since
+ // the member variable is final.)
+ int state = this.state;
+ int value = this.value;
+ int op = 0;
+ final byte[] output = this.output;
+ final int[] alphabet = this.alphabet;
+
+ while (p < len) {
+ // Try the fast path: we're starting a new tuple and the
+ // next four bytes of the input stream are all data
+ // bytes. This corresponds to going through states
+ // 0-1-2-3-0. We expect to use this method for most of
+ // the data.
+ //
+ // If any of the next four bytes of input are non-data
+ // (whitespace, etc.), value will end up negative. (All
+ // the non-data values in decode are small negative
+ // numbers, so shifting any of them up and or'ing them
+ // together will result in a value with its top bit set.)
+ //
+ // You can remove this whole block and the output should
+ // be the same, just slower.
+ if (state == 0) {
+ while (p+4 <= len &&
+ (value = ((alphabet[input[p] & 0xff] << 18) |
+ (alphabet[input[p+1] & 0xff] << 12) |
+ (alphabet[input[p+2] & 0xff] << 6) |
+ (alphabet[input[p+3] & 0xff]))) >= 0) {
+ output[op+2] = (byte) value;
+ output[op+1] = (byte) (value >> 8);
+ output[op] = (byte) (value >> 16);
+ op += 3;
+ p += 4;
+ }
+ if (p >= len) break;
+ }
+
+ // The fast path isn't available -- either we've read a
+ // partial tuple, or the next four input bytes aren't all
+ // data, or whatever. Fall back to the slower state
+ // machine implementation.
+
+ int d = alphabet[input[p++] & 0xff];
+
+ switch (state) {
+ case 0:
+ if (d >= 0) {
+ value = d;
+ ++state;
+ } else if (d != SKIP) {
+ this.state = 6;
+ return false;
+ }
+ break;
+
+ case 1:
+ if (d >= 0) {
+ value = (value << 6) | d;
+ ++state;
+ } else if (d != SKIP) {
+ this.state = 6;
+ return false;
+ }
+ break;
+
+ case 2:
+ if (d >= 0) {
+ value = (value << 6) | d;
+ ++state;
+ } else if (d == EQUALS) {
+ // Emit the last (partial) output tuple;
+ // expect exactly one more padding character.
+ output[op++] = (byte) (value >> 4);
+ state = 4;
+ } else if (d != SKIP) {
+ this.state = 6;
+ return false;
+ }
+ break;
+
+ case 3:
+ if (d >= 0) {
+ // Emit the output triple and return to state 0.
+ value = (value << 6) | d;
+ output[op+2] = (byte) value;
+ output[op+1] = (byte) (value >> 8);
+ output[op] = (byte) (value >> 16);
+ op += 3;
+ state = 0;
+ } else if (d == EQUALS) {
+ // Emit the last (partial) output tuple;
+ // expect no further data or padding characters.
+ output[op+1] = (byte) (value >> 2);
+ output[op] = (byte) (value >> 10);
+ op += 2;
+ state = 5;
+ } else if (d != SKIP) {
+ this.state = 6;
+ return false;
+ }
+ break;
+
+ case 4:
+ if (d == EQUALS) {
+ ++state;
+ } else if (d != SKIP) {
+ this.state = 6;
+ return false;
+ }
+ break;
+
+ case 5:
+ if (d != SKIP) {
+ this.state = 6;
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (!finish) {
+ // We're out of input, but a future call could provide
+ // more.
+ this.state = state;
+ this.value = value;
+ this.op = op;
+ return true;
+ }
+
+ // Done reading input. Now figure out where we are left in
+ // the state machine and finish up.
+
+ switch (state) {
+ case 0:
+ // Output length is a multiple of three. Fine.
+ break;
+ case 1:
+ // Read one extra input byte, which isn't enough to
+ // make another output byte. Illegal.
+ this.state = 6;
+ return false;
+ case 2:
+ // Read two extra input bytes, enough to emit 1 more
+ // output byte. Fine.
+ output[op++] = (byte) (value >> 4);
+ break;
+ case 3:
+ // Read three extra input bytes, enough to emit 2 more
+ // output bytes. Fine.
+ output[op++] = (byte) (value >> 10);
+ output[op++] = (byte) (value >> 2);
+ break;
+ case 4:
+ // Read one padding '=' when we expected 2. Illegal.
+ this.state = 6;
+ return false;
+ case 5:
+ // Read all the padding '='s we expected and no more.
+ // Fine.
+ break;
+ }
+
+ this.state = state;
+ this.op = op;
+ return true;
+ }
+ }
+
+ // --------------------------------------------------------
+ // encoding
+ // --------------------------------------------------------
+
+ /**
+ * Base64-encode the given data and return a newly allocated
+ * String with the result.
+ *
+ * @param input the data to encode
+ * @param flags controls certain features of the encoded output.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
+ */
+ public static String encodeToString(byte[] input, int flags) {
+ return new String(encode(input, flags), US_ASCII);
+ }
+
+ /**
+ * Base64-encode the given data and return a newly allocated
+ * String with the result.
+ *
+ * @param input the data to encode
+ * @param offset the position within the input array at which to
+ * start
+ * @param len the number of bytes of input to encode
+ * @param flags controls certain features of the encoded output.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
+ */
+ public static String encodeToString(byte[] input, int offset, int len, int flags) {
+ return new String(encode(input, offset, len, flags), US_ASCII);
+ }
+
+ /**
+ * Base64-encode the given data and return a newly allocated
+ * byte[] with the result.
+ *
+ * @param input the data to encode
+ * @param flags controls certain features of the encoded output.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
+ */
+ public static byte[] encode(byte[] input, int flags) {
+ return encode(input, 0, input.length, flags);
+ }
+
+ /**
+ * Base64-encode the given data and return a newly allocated
+ * byte[] with the result.
+ *
+ * @param input the data to encode
+ * @param offset the position within the input array at which to
+ * start
+ * @param len the number of bytes of input to encode
+ * @param flags controls certain features of the encoded output.
+ * Passing {@code DEFAULT} results in output that
+ * adheres to RFC 2045.
+ */
+ public static byte[] encode(byte[] input, int offset, int len, int flags) {
+ Encoder encoder = new Encoder(flags, null);
+
+ // Compute the exact length of the array we will produce.
+ int output_len = len / 3 * 4;
+
+ // Account for the tail of the data and the padding bytes, if any.
+ if (encoder.do_padding) {
+ if (len % 3 > 0) {
+ output_len += 4;
+ }
+ } else {
+ switch (len % 3) {
+ case 0: break;
+ case 1: output_len += 2; break;
+ case 2: output_len += 3; break;
+ }
+ }
+
+ // Account for the newlines, if any.
+ if (encoder.do_newline && len > 0) {
+ output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
+ (encoder.do_cr ? 2 : 1);
+ }
+
+ encoder.output = new byte[output_len];
+ encoder.process(input, offset, len, true);
+
+ assert encoder.op == output_len;
+
+ return encoder.output;
+ }
+
+ /* package */ static class Encoder extends Coder {
+ /**
+ * Emit a new line every this many output tuples. Corresponds to
+ * a 76-character line length (the maximum allowable according to
+ * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
+ */
+ public static final int LINE_GROUPS = 19;
+
+ /**
+ * Lookup table for turning Base64 alphabet positions (6 bits)
+ * into output bytes.
+ */
+ private static final byte ENCODE[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
+ };
+
+ /**
+ * Lookup table for turning Base64 alphabet positions (6 bits)
+ * into output bytes.
+ */
+ private static final byte ENCODE_WEBSAFE[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
+ };
+
+ final private byte[] tail;
+ /* package */ int tailLen;
+ private int count;
+
+ final public boolean do_padding;
+ final public boolean do_newline;
+ final public boolean do_cr;
+ final private byte[] alphabet;
+
+ public Encoder(int flags, byte[] output) {
+ this.output = output;
+
+ do_padding = (flags & NO_PADDING) == 0;
+ do_newline = (flags & NO_WRAP) == 0;
+ do_cr = (flags & CRLF) != 0;
+ alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+
+ tail = new byte[2];
+ tailLen = 0;
+
+ count = do_newline ? LINE_GROUPS : -1;
+ }
+
+ /**
+ * @return an overestimate for the number of bytes {@code
+ * len} bytes could encode to.
+ */
+ public int maxOutputSize(int len) {
+ return len * 8/5 + 10;
+ }
+
+ public boolean process(byte[] input, int offset, int len, boolean finish) {
+ // Using local variables makes the encoder about 9% faster.
+ final byte[] alphabet = this.alphabet;
+ final byte[] output = this.output;
+ int op = 0;
+ int count = this.count;
+
+ int p = offset;
+ len += offset;
+ int v = -1;
+
+ // First we need to concatenate the tail of the previous call
+ // with any input bytes available now and see if we can empty
+ // the tail.
+
+ switch (tailLen) {
+ case 0:
+ // There was no tail.
+ break;
+
+ case 1:
+ if (p+2 <= len) {
+ // A 1-byte tail with at least 2 bytes of
+ // input available now.
+ v = ((tail[0] & 0xff) << 16) |
+ ((input[p++] & 0xff) << 8) |
+ (input[p++] & 0xff);
+ tailLen = 0;
+ };
+ break;
+
+ case 2:
+ if (p+1 <= len) {
+ // A 2-byte tail with at least 1 byte of input.
+ v = ((tail[0] & 0xff) << 16) |
+ ((tail[1] & 0xff) << 8) |
+ (input[p++] & 0xff);
+ tailLen = 0;
+ }
+ break;
+ }
+
+ if (v != -1) {
+ output[op++] = alphabet[(v >> 18) & 0x3f];
+ output[op++] = alphabet[(v >> 12) & 0x3f];
+ output[op++] = alphabet[(v >> 6) & 0x3f];
+ output[op++] = alphabet[v & 0x3f];
+ if (--count == 0) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ count = LINE_GROUPS;
+ }
+ }
+
+ // At this point either there is no tail, or there are fewer
+ // than 3 bytes of input available.
+
+ // The main loop, turning 3 input bytes into 4 output bytes on
+ // each iteration.
+ while (p+3 <= len) {
+ v = ((input[p] & 0xff) << 16) |
+ ((input[p+1] & 0xff) << 8) |
+ (input[p+2] & 0xff);
+ output[op] = alphabet[(v >> 18) & 0x3f];
+ output[op+1] = alphabet[(v >> 12) & 0x3f];
+ output[op+2] = alphabet[(v >> 6) & 0x3f];
+ output[op+3] = alphabet[v & 0x3f];
+ p += 3;
+ op += 4;
+ if (--count == 0) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ count = LINE_GROUPS;
+ }
+ }
+
+ if (finish) {
+ // Finish up the tail of the input. Note that we need to
+ // consume any bytes in tail before any bytes
+ // remaining in input; there should be at most two bytes
+ // total.
+
+ if (p-tailLen == len-1) {
+ int t = 0;
+ v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
+ tailLen -= t;
+ output[op++] = alphabet[(v >> 6) & 0x3f];
+ output[op++] = alphabet[v & 0x3f];
+ if (do_padding) {
+ output[op++] = '=';
+ output[op++] = '=';
+ }
+ if (do_newline) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ }
+ } else if (p-tailLen == len-2) {
+ int t = 0;
+ v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
+ (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
+ tailLen -= t;
+ output[op++] = alphabet[(v >> 12) & 0x3f];
+ output[op++] = alphabet[(v >> 6) & 0x3f];
+ output[op++] = alphabet[v & 0x3f];
+ if (do_padding) {
+ output[op++] = '=';
+ }
+ if (do_newline) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ }
+ } else if (do_newline && op > 0 && count != LINE_GROUPS) {
+ if (do_cr) output[op++] = '\r';
+ output[op++] = '\n';
+ }
+
+ assert tailLen == 0;
+ assert p == len;
+ } else {
+ // Save the leftovers in tail to be consumed on the next
+ // call to encodeInternal.
+
+ if (p == len-1) {
+ tail[tailLen++] = input[p];
+ } else if (p == len-2) {
+ tail[tailLen++] = input[p];
+ tail[tailLen++] = input[p+1];
+ }
+ }
+
+ this.op = op;
+ this.count = count;
+
+ return true;
+ }
+ }
+
+ private Base64() { } // don't instantiate
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+/**
+ * Utilities for handling ARGB colors.
+ */
+public class Color
+{
+ public final static int CLEAR = 0x00000000;
+ public final static int WHITE = 0xFFFFFFFF;
+ public final static int BLACK = 0xFF000000;
+
+ public static float brightness (int argb) {
+ // TODO: we're ignoring alpha here...
+ int red = (argb >> 16) & 0xFF;
+ int green = (argb >> 8) & 0xFF;
+ int blue = (argb >> 0) & 0xFF;
+ int max = Math.max(Math.max(red, green), blue);
+ return ((float) max) / 255.0f;
+ }
+
+ private Color () {}
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Handles parsing and runtime access for Getdown's config files (mainly {@code getdown.txt}).
+ * These files contain zero or more mappings for a particular string key. Config values can be
+ * fetched as single strings, lists of strings, or parsed into primitives or compound data types
+ * like colors and rectangles.
+ */
+public class Config
+{
+ /** Empty configuration. */
+ public static final Config EMPTY = new Config(new HashMap<String, Object>());
+
+ /** Options that control the {@link #parsePairs} function. */
+ public static class ParseOpts {
+ // these should be tweaked as desired by the caller
+ public boolean biasToKey = false;
+ public boolean strictComments = false;
+
+ // these are filled in by parseConfig
+ public String osname = null;
+ public String osarch = null;
+ }
+
+ /**
+ * Creates a parse configuration, filling in the platform filters (or not) depending on the
+ * value of {@code checkPlatform}.
+ */
+ public static ParseOpts createOpts (boolean checkPlatform) {
+ ParseOpts opts = new ParseOpts();
+ if (checkPlatform) {
+ opts.osname = StringUtil.deNull(System.getProperty("os.name")).toLowerCase(Locale.ROOT);
+ opts.osarch = StringUtil.deNull(System.getProperty("os.arch")).toLowerCase(Locale.ROOT);
+ }
+ return opts;
+ }
+
+ /**
+ * Parses a configuration file containing key/value pairs. The file must be in the UTF-8
+ * encoding.
+ *
+ * @param opts options that influence the parsing. See {@link #createOpts}.
+ *
+ * @return a list of <code>String[]</code> instances containing the key/value pairs in the
+ * order they were parsed from the file.
+ */
+ public static List<String[]> parsePairs (File source, ParseOpts opts)
+ throws IOException
+ {
+ // annoyingly FileReader does not allow encoding to be specified (uses platform default)
+ try (FileInputStream fis = new FileInputStream(source);
+ InputStreamReader input = new InputStreamReader(fis, StandardCharsets.UTF_8)) {
+ return parsePairs(input, opts);
+ }
+ }
+
+ /**
+ * See {@link #parsePairs(File,ParseOpts)}.
+ */
+ public static List<String[]> parsePairs (Reader source, ParseOpts opts) throws IOException
+ {
+ List<String[]> pairs = new ArrayList<>();
+ for (String line : FileUtil.readLines(source)) {
+ // nix comments
+ int cidx = line.indexOf("#");
+ if (opts.strictComments ? cidx == 0 : cidx != -1) {
+ line = line.substring(0, cidx);
+ }
+
+ // trim whitespace and skip blank lines
+ line = line.trim();
+ if (StringUtil.isBlank(line)) {
+ continue;
+ }
+
+ // parse our key/value pair
+ String[] pair = new String[2];
+ // if we're biasing toward key, put all the extra = in the key rather than the value
+ int eidx = opts.biasToKey ? line.lastIndexOf("=") : line.indexOf("=");
+ if (eidx != -1) {
+ pair[0] = line.substring(0, eidx).trim();
+ pair[1] = line.substring(eidx+1).trim();
+ } else {
+ pair[0] = line;
+ pair[1] = "";
+ }
+
+ // if the pair has an os qualifier, we need to process it
+ if (pair[1].startsWith("[")) {
+ int qidx = pair[1].indexOf("]");
+ if (qidx == -1) {
+ log.warning("Bogus platform specifier", "key", pair[0], "value", pair[1]);
+ continue; // omit the pair entirely
+ }
+ // if we're checking qualifiers and the os doesn't match this qualifier, skip it
+ String quals = pair[1].substring(1, qidx);
+ if (opts.osname != null && !checkQualifiers(quals, opts.osname, opts.osarch)) {
+ log.debug("Skipping", "quals", quals,
+ "osname", opts.osname, "osarch", opts.osarch,
+ "key", pair[0], "value", pair[1]);
+ continue;
+ }
+ // otherwise filter out the qualifier text
+ pair[1] = pair[1].substring(qidx+1).trim();
+ }
+
+ pairs.add(pair);
+ }
+
+ return pairs;
+ }
+
+ /**
+ * Takes a comma-separated String of four integers and returns a rectangle using those ints as
+ * the its x, y, width, and height.
+ */
+ public static Rectangle parseRect (String name, String value)
+ {
+ if (!StringUtil.isBlank(value)) {
+ int[] v = StringUtil.parseIntArray(value);
+ if (v != null && v.length == 4) {
+ return new Rectangle(v[0], v[1], v[2], v[3]);
+ }
+ log.warning("Ignoring invalid rect '" + name + "' config '" + value + "'.");
+ }
+ return null;
+ }
+
+ /**
+ * Parses the given hex color value (e.g. FFCC99) and returns an {@code Integer} with that
+ * value. If the given value is null or not a valid hexadecimal number, this will return null.
+ */
+ public static Integer parseColor (String hexValue)
+ {
+ if (!StringUtil.isBlank(hexValue)) {
+ try {
+ // if no alpha channel is specified, use 255 (full alpha)
+ int alpha = hexValue.length() > 6 ? 0 : 0xFF000000;
+ return Integer.parseInt(hexValue, 16) | alpha;
+ } catch (NumberFormatException e) {
+ log.warning("Ignoring invalid color", "hexValue", hexValue, "exception", e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parses a configuration file containing key/value pairs. The file must be in the UTF-8
+ * encoding.
+ *
+ * @return a map from keys to values, where a value will be an array of strings if more than
+ * one key/value pair in the config file was associated with the same key.
+ */
+ public static Config parseConfig (File source, ParseOpts opts)
+ throws IOException
+ {
+ Map<String, Object> data = new HashMap<>();
+
+ // I thought that we could use HashMap<String, String[]> and put new String[] {pair[1]} for
+ // the null case, but it mysteriously dies on launch, so leaving it as HashMap<String,
+ // Object> for now
+ for (String[] pair : parsePairs(source, opts)) {
+ Object value = data.get(pair[0]);
+ if (value == null) {
+ data.put(pair[0], pair[1]);
+ } else if (value instanceof String) {
+ data.put(pair[0], new String[] { (String)value, pair[1] });
+ } else if (value instanceof String[]) {
+ String[] values = (String[])value;
+ String[] nvalues = new String[values.length+1];
+ System.arraycopy(values, 0, nvalues, 0, values.length);
+ nvalues[values.length] = pair[1];
+ data.put(pair[0], nvalues);
+ }
+ }
+
+ // special magic for the getdown.txt config: if the parsed data contains 'strict_comments =
+ // true' then we reparse the file with strict comments (i.e. # is only assumed to start a
+ // comment in column 0)
+ if (!opts.strictComments && Boolean.parseBoolean((String)data.get("strict_comments"))) {
+ opts.strictComments = true;
+ return parseConfig(source, opts);
+ }
+
+ return new Config(data);
+ }
+
+ public Config (Map<String, Object> data) {
+ _data = data;
+ }
+
+ /**
+ * Returns whether {@code name} has a value in this config.
+ */
+ public boolean hasValue (String name) {
+ return _data.containsKey(name);
+ }
+
+ /**
+ * Returns the raw-value for {@code name}. This may be a {@code String}, {@code String[]}, or
+ * {@code null}.
+ */
+ public Object getRaw (String name) {
+ return _data.get(name);
+ }
+
+ /**
+ * Returns the specified config value as a string, or {@code null}.
+ */
+ public String getString (String name) {
+ return (String)_data.get(name);
+ }
+
+ /**
+ * Returns the specified config value as a string, or {@code def}.
+ */
+ public String getString (String name, String def) {
+ String value = (String)_data.get(name);
+ return value == null ? def : value;
+ }
+
+ /**
+ * Returns the specified config value as a boolean.
+ */
+ public boolean getBoolean (String name) {
+ return Boolean.parseBoolean(getString(name));
+ }
+
+ /**
+ * Massages a single string into an array and leaves existing array values as is. Simplifies
+ * access to parameters that are expected to be arrays.
+ */
+ public String[] getMultiValue (String name)
+ {
+ Object value = _data.get(name);
+ if (value instanceof String) {
+ return new String[] { (String)value };
+ } else {
+ return (String[])value;
+ }
+ }
+
+ /** Used to parse rectangle specifications from the config file. */
+ public Rectangle getRect (String name, Rectangle def)
+ {
+ String value = getString(name);
+ Rectangle rect = parseRect(name, value);
+ return (rect == null) ? def : rect;
+ }
+
+ /**
+ * Parses and returns the config value for {@code name} as an int. If no value is provided,
+ * {@code def} is returned. If the value is invalid, a warning is logged and {@code def} is
+ * returned.
+ */
+ public int getInt (String name, int def) {
+ String value = getString(name);
+ try {
+ return value == null ? def : Integer.parseInt(value);
+ } catch (Exception e) {
+ log.warning("Ignoring invalid int '" + name + "' config '" + value + "',");
+ return def;
+ }
+ }
+
+ /**
+ * Parses and returns the config value for {@code name} as a long. If no value is provided,
+ * {@code def} is returned. If the value is invalid, a warning is logged and {@code def} is
+ * returned.
+ */
+ public long getLong (String name, long def) {
+ String value = getString(name);
+ try {
+ return value == null ? def : Long.parseLong(value);
+ } catch (Exception e) {
+ log.warning("Ignoring invalid long '" + name + "' config '" + value + "',");
+ return def;
+ }
+ }
+
+ /** Used to parse color specifications from the config file. */
+ public int getColor (String name, int def)
+ {
+ String value = getString(name);
+ Integer color = parseColor(value);
+ return (color == null) ? def : color;
+ }
+
+ /** Parses a list of strings from the config file. */
+ public String[] getList (String name)
+ {
+ String value = getString(name);
+ return (value == null) ? new String[0] : StringUtil.parseStringArray(value);
+ }
+
+ /**
+ * Parses a URL from the config file, checking first for a localized version.
+ */
+ public String getUrl (String name, String def)
+ {
+ String value = getString(name + "." + Locale.getDefault().getLanguage());
+ if (StringUtil.isBlank(value)) {
+ value = getString(name);
+ }
+ if (StringUtil.isBlank(value)) {
+ value = def;
+ }
+ if (!StringUtil.isBlank(value)) {
+ try {
+ HostWhitelist.verify(new URL(value));
+ } catch (MalformedURLException e) {
+ log.warning("Invalid URL.", "url", value, e);
+ value = null;
+ }
+ }
+ return value;
+ }
+
+ /**
+ * A helper function for {@link #parsePairs(Reader,ParseOpts)}. Qualifiers have the following
+ * form:
+ * <pre>
+ * id = os[-arch]
+ * ids = id | id,ids
+ * quals = !id | ids
+ * </pre>
+ * Examples: [linux-amd64,linux-x86_64], [windows], [mac os x], [!windows]. Negative qualifiers
+ * must appear alone, they cannot be used with other qualifiers (positive or negative).
+ */
+ protected static boolean checkQualifiers (String quals, String osname, String osarch)
+ {
+ if (quals.startsWith("!")) {
+ if (quals.indexOf(",") != -1) { // sanity check
+ log.warning("Multiple qualifiers cannot be used when one of the qualifiers " +
+ "is negative", "quals", quals);
+ return false;
+ }
+ return !checkQualifier(quals.substring(1), osname, osarch);
+ }
+ for (String qual : quals.split(",")) {
+ if (checkQualifier(qual, osname, osarch)) {
+ return true; // if we have a positive match, we can immediately return true
+ }
+ }
+ return false; // we had no positive matches, so return false
+ }
+
+ /** A helper function for {@link #checkQualifiers}. */
+ protected static boolean checkQualifier (String qual, String osname, String osarch)
+ {
+ String[] bits = qual.trim().toLowerCase(Locale.ROOT).split("-");
+ String os = bits[0], arch = (bits.length > 1) ? bits[1] : "";
+ return (osname.indexOf(os) != -1) && (osarch.indexOf(arch) != -1);
+ }
+
+ private final Map<String, Object> _data;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+
+import com.threerings.getdown.data.SysProps;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+public class ConnectionUtil
+{
+ /**
+ * Opens a connection to a URL, setting the authentication header if user info is present.
+ * @param proxy the proxy via which to perform HTTP connections.
+ * @param url the URL to which to open a connection.
+ * @param connectTimeout if {@code > 0} then a timeout, in seconds, to use when opening the
+ * connection. If {@code 0} is supplied, the connection timeout specified via system properties
+ * will be used instead.
+ * @param readTimeout if {@code > 0} then a timeout, in seconds, to use while reading data from
+ * the connection. If {@code 0} is supplied, the read timeout specified via system properties
+ * will be used instead.
+ */
+ public static URLConnection open (Proxy proxy, URL url, int connectTimeout, int readTimeout)
+ throws IOException
+ {
+ URLConnection conn = url.openConnection(proxy);
+
+ // configure a connect timeout, if requested
+ int ctimeout = connectTimeout > 0 ? connectTimeout : SysProps.connectTimeout();
+ if (ctimeout > 0) {
+ conn.setConnectTimeout(ctimeout * 1000);
+ }
+
+ // configure a read timeout, if requested
+ int rtimeout = readTimeout > 0 ? readTimeout : SysProps.readTimeout();
+ if (rtimeout > 0) {
+ conn.setReadTimeout(rtimeout * 1000);
+ }
+
+ // If URL has a username:password@ before hostname, use HTTP basic auth
+ String userInfo = url.getUserInfo();
+ if (userInfo != null) {
+ // Remove any percent-encoding in the username/password
+ userInfo = URLDecoder.decode(userInfo, "UTF-8");
+ // Now base64 encode the auth info and make it a single line
+ String encoded = Base64.encodeToString(userInfo.getBytes(UTF_8), Base64.DEFAULT).
+ replaceAll("\\n","").replaceAll("\\r", "");
+ conn.setRequestProperty("Authorization", "Basic " + encoded);
+ }
+
+ return conn;
+ }
+
+ /**
+ * Opens a connection to a http or https URL, setting the authentication header if user info is
+ * present. Throws a class cast exception if the connection returned is not the right type. See
+ * {@link #open} for parameter documentation.
+ */
+ public static HttpURLConnection openHttp (
+ Proxy proxy, URL url, int connectTimeout, int readTimeout) throws IOException
+ {
+ return (HttpURLConnection)open(proxy, url, connectTimeout, readTimeout);
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.jar.*;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+
+import com.threerings.getdown.util.StreamUtil;
+import com.threerings.getdown.Log;
+import static com.threerings.getdown.Log.log;
+
+/**
+ * File related utilities.
+ */
+public class FileUtil
+{
+ /**
+ * Gets the specified source file to the specified destination file by hook or crook. Windows
+ * has all sorts of problems which we work around in this method.
+ *
+ * @return true if we managed to get the job done, false otherwise.
+ */
+ public static boolean renameTo (File source, File dest)
+ {
+ // if we're on a civilized operating system we may be able to simple rename it
+ if (source.renameTo(dest)) {
+ return true;
+ }
+
+ // fall back to trying to rename the old file out of the way, rename the new file into
+ // place and then delete the old file
+ if (dest.exists()) {
+ File temp = new File(dest.getPath() + "_old");
+ if (temp.exists() && !deleteHarder(temp)) {
+ log.warning("Failed to delete old intermediate file " + temp + ".");
+ // the subsequent code will probably fail
+ }
+ if (dest.renameTo(temp) && source.renameTo(dest)) {
+ if (!deleteHarder(temp)) {
+ log.warning("Failed to delete intermediate file " + temp + ".");
+ }
+ return true;
+ }
+ }
+
+ // as a last resort, try copying the old data over the new
+ try {
+ copy(source, dest);
+ } catch (IOException ioe) {
+ log.warning("Failed to copy " + source + " to " + dest + ": " + ioe);
+ return false;
+ }
+
+ if (!deleteHarder(source)) {
+ log.warning("Failed to delete " + source + " after brute force copy to " + dest + ".");
+ }
+ return true;
+ }
+
+ /**
+ * "Tries harder" to delete {@code file} than just calling {@code delete} on it. Presently this
+ * just means "try a second time if the first time fails, and if that fails then try to delete
+ * when the virtual machine terminates." On Windows Vista, sometimes deletes fail but then
+ * succeed if you just try again. Given that delete failure is a rare occurrence, we can
+ * implement this hacky workaround without any negative consequences for normal behavior.
+ */
+ public static boolean deleteHarder (File file) {
+ // if at first you don't succeed... try, try again
+ boolean deleted = (file.delete() || file.delete());
+ if (!deleted) {
+ file.deleteOnExit();
+ }
+ return deleted;
+ }
+
+ /**
+ * Force deletes {@code file} and all of its children recursively using {@link #deleteHarder}.
+ * Note that some children may still be deleted even if {@code false} is returned. Also, since
+ * {@link #deleteHarder} is used, the {@code file} could be deleted once the jvm exits even if
+ * {@code false} is returned.
+ *
+ * @param file file to delete.
+ * @return true iff {@code file} was successfully deleted.
+ */
+ public static boolean deleteDirHarder (File file) {
+ if (file.isDirectory()) {
+ for (File child : file.listFiles()) {
+ deleteDirHarder(child);
+ }
+ }
+ return deleteHarder(file);
+ }
+
+ /**
+ * Reads the contents of the supplied input stream into a list of lines. Closes the reader on
+ * successful or failed completion.
+ */
+ public static List<String> readLines (Reader in)
+ throws IOException
+ {
+ List<String> lines = new ArrayList<>();
+ try (BufferedReader bin = new BufferedReader(in)) {
+ for (String line = null; (line = bin.readLine()) != null; lines.add(line)) {}
+ }
+ return lines;
+ }
+
+ /**
+ * Unpacks the specified jar file into the specified target directory.
+ * @param cleanExistingDirs if true, all files in all directories contained in {@code jar} will
+ * be deleted prior to unpacking the jar.
+ */
+ public static void unpackJar (JarFile jar, File target, boolean cleanExistingDirs)
+ throws IOException
+ {
+ if (cleanExistingDirs) {
+ Enumeration<?> entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = (JarEntry)entries.nextElement();
+ if (entry.isDirectory()) {
+ File efile = new File(target, entry.getName());
+ if (efile.exists()) {
+ for (File f : efile.listFiles()) {
+ if (!f.isDirectory())
+ f.delete();
+ }
+ }
+ }
+ }
+ }
+
+ Enumeration<?> entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = (JarEntry)entries.nextElement();
+ File efile = new File(target, entry.getName());
+
+ // if we're unpacking a normal jar file, it will have special path
+ // entries that allow us to create our directories first
+ if (entry.isDirectory()) {
+ if (!efile.exists() && !efile.mkdir()) {
+ log.warning("Failed to create jar entry path", "jar", jar, "entry", entry);
+ }
+ continue;
+ }
+
+ // but some do not, so we want to ensure that our directories exist
+ // prior to getting down and funky
+ File parent = new File(efile.getParent());
+ if (!parent.exists() && !parent.mkdirs()) {
+ log.warning("Failed to create jar entry parent", "jar", jar, "parent", parent);
+ continue;
+ }
+
+ try (BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(efile));
+ InputStream jin = jar.getInputStream(entry)) {
+ StreamUtil.copy(jin, fout);
+ } catch (Exception e) {
+ throw new IOException(
+ Log.format("Failure unpacking", "jar", jar, "entry", efile), e);
+ }
+ }
+ }
+
+ /**
+ * Unpacks the specified tgz file into the specified target directory.
+ * @param cleanExistingDirs if true, all files in all directories contained in {@code tgz} will
+ * be deleted prior to unpacking the tgz.
+ */
+ public static void unpackTgz (TarArchiveInputStream tgz, File target, boolean cleanExistingDirs)
+ throws IOException
+ {
+ TarArchiveEntry entry;
+ while ((entry = tgz.getNextTarEntry()) != null) {
+ // sanitize the entry name
+ String entryName = entry.getName();
+ if (entryName.startsWith(File.separator))
+ {
+ entryName = entryName.substring(File.separator.length());
+ }
+ File efile = new File(target, entryName);
+
+ // if we're unpacking a normal tgz file, it will have special path
+ // entries that allow us to create our directories first
+ if (entry.isDirectory()) {
+
+ if (cleanExistingDirs) {
+ if (efile.exists()) {
+ for (File f : efile.listFiles()) {
+ if (!f.isDirectory())
+ f.delete();
+ }
+ }
+ }
+
+ if (!efile.exists() && !efile.mkdir()) {
+ log.warning("Failed to create tgz entry path", "tgz", tgz, "entry", entry);
+ }
+ continue;
+ }
+
+ // but some do not, so we want to ensure that our directories exist
+ // prior to getting down and funky
+ File parent = new File(efile.getParent());
+ if (!parent.exists() && !parent.mkdirs()) {
+ log.warning("Failed to create tgz entry parent", "tgz", tgz, "parent", parent);
+ continue;
+ }
+
+ if (entry.isLink())
+ {
+ System.out.println("Creating hard link "+efile.getName()+" -> "+entry.getLinkName());
+ Files.createLink(efile.toPath(), Paths.get(entry.getLinkName()));
+ continue;
+ }
+
+ if (entry.isSymbolicLink())
+ {
+ System.out.println("Creating symbolic link "+efile.getName()+" -> "+entry.getLinkName());
+ Files.createSymbolicLink(efile.toPath(), Paths.get(entry.getLinkName()));
+ continue;
+ }
+
+ try (BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(efile));
+ InputStream tin = tgz;) {
+ StreamUtil.copy(tin, fout);
+ } catch (Exception e) {
+ throw new IOException(
+ Log.format("Failure unpacking", "tgz", tgz, "entry", efile), e);
+ }
+ }
+ }
+
+ /**
+ * Unpacks a pack200 packed jar file from {@code packedJar} into {@code target}. If {@code
+ * packedJar} has a {@code .gz} extension, it will be gunzipped first.
+ */
+ public static void unpackPacked200Jar (File packedJar, File target) throws IOException
+ {
+ try (InputStream packJarIn = new FileInputStream(packedJar);
+ JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(target))) {
+ boolean gz = (packedJar.getName().endsWith(".gz") ||
+ packedJar.getName().endsWith(".gz_new"));
+ try (InputStream packJarIn2 = (gz ? new GZIPInputStream(packJarIn) : packJarIn)) {
+ Pack200.Unpacker unpacker = Pack200.newUnpacker();
+ unpacker.unpack(packJarIn2, jarOut);
+ }
+ }
+ }
+
+ /**
+ * Copies the given {@code source} file to the given {@code target}.
+ */
+ public static void copy (File source, File target) throws IOException {
+ try (FileInputStream in = new FileInputStream(source);
+ FileOutputStream out = new FileOutputStream(target)) {
+ StreamUtil.copy(in, out);
+ }
+ }
+
+ /**
+ * Marks {@code file} as executable, if it exists. Catches and logs any errors that occur.
+ */
+ public static void makeExecutable (File file) {
+ try {
+ if (file.exists()) {
+ if (!file.setExecutable(true, false)) {
+ log.warning("Failed to mark as executable", "file", file);
+ }
+ }
+ } catch (Exception e) {
+ log.warning("Failed to mark as executable", "file", file, "error", e);
+ }
+ }
+
+ /**
+ * Used by {@link #walkTree}.
+ */
+ public interface Visitor
+ {
+ void visit (File file);
+ }
+
+ /**
+ * Walks all files in {@code root}, calling {@code visitor} on each file in the tree.
+ */
+ public static void walkTree (File root, Visitor visitor)
+ {
+ File[] children = root.listFiles();
+ if (children == null) return;
+ Deque<File> stack = new ArrayDeque<>(Arrays.asList(children));
+ while (!stack.isEmpty()) {
+ File currentFile = stack.pop();
+ if (currentFile.exists()) {
+ visitor.visit(currentFile);
+ File[] currentChildren = currentFile.listFiles();
+ if (currentChildren != null) {
+ for (File file : currentChildren) {
+ stack.push(file);
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import com.threerings.getdown.data.Build;
+
+/**
+ * Optional support for compiling a URL host whitelist into the Getdown JAR.
+ * Useful if you're on the paranoid end of the security spectrum.
+ *
+ * @see Build#hostWhitelist()
+ */
+public final class HostWhitelist
+{
+ /**
+ * Verifies that the specified URL should be accessible, per the built-in host whitelist.
+ * See {@link Build#hostWhitelist()} and {@link #verify(List,URL)}.
+ */
+ public static URL verify (URL url) throws MalformedURLException
+ {
+ return verify(Build.hostWhitelist(), url);
+ }
+
+ /**
+ * Verifies that the specified URL should be accessible, per the supplied host whitelist.
+ * If the URL should not be accessible, this method throws a {@link MalformedURLException}.
+ * If the URL should be accessible, this method simply returns the {@link URL} passed in.
+ */
+ public static URL verify (List<String> hosts, URL url) throws MalformedURLException
+ {
+ if (url == null || hosts.isEmpty()) {
+ // either there is no URL to validate or no whitelist was configured
+ return url;
+ }
+
+ String urlHost = url.getHost();
+ for (String host : hosts) {
+ String regex = host.replace(".", "\\.").replace("*", ".*");
+ if (urlHost.matches(regex)) {
+ return url;
+ }
+ }
+
+ throw new MalformedURLException(
+ "The host for the specified URL (" + url + ") is not in the host whitelist: " + hosts);
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Locale;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Useful routines for launching Java applications from within other Java
+ * applications.
+ */
+public class LaunchUtil
+{
+ /** The directory into which a local VM installation should be unpacked. */
+ public static final String LOCAL_JAVA_DIR = "java_vm";
+
+ /**
+ * Writes a <code>version.txt</code> file into the specified application directory and
+ * attempts to relaunch Getdown in that directory which will cause it to upgrade to the newly
+ * specified version and relaunch the application.
+ *
+ * @param appdir the directory in which the application is installed.
+ * @param getdownJarName the name of the getdown jar file in the application directory. This is
+ * probably <code>getdown-pro.jar</code> or <code>getdown-retro-pro.jar</code> if you are using
+ * the results of the standard build.
+ * @param newVersion the new version to which Getdown will update when it is executed.
+ *
+ * @return true if the relaunch succeeded, false if we were unable to relaunch due to being on
+ * Windows 9x where we cannot launch subprocesses without waiting around for them to exit,
+ * reading their stdout and stderr all the while. If true is returned, the application may exit
+ * after making this call as it will be upgraded and restarted. If false is returned, the
+ * application should tell the user that they must restart the application manually.
+ *
+ * @exception IOException thrown if we were unable to create the <code>version.txt</code> file
+ * in the supplied application directory. If the version.txt file cannot be created, restarting
+ * Getdown will not cause the application to be upgraded, so the application will have to
+ * resort to telling the user that it is in a bad way.
+ */
+ public static boolean updateVersionAndRelaunch (
+ File appdir, String getdownJarName, String newVersion)
+ throws IOException
+ {
+ // create the file that instructs Getdown to upgrade
+ File vfile = new File(appdir, "version.txt");
+ try (PrintStream ps = new PrintStream(new FileOutputStream(vfile))) {
+ ps.println(newVersion);
+ }
+
+ // make sure that we can find our getdown.jar file and can safely launch children
+ File pro = new File(appdir, getdownJarName);
+ if (mustMonitorChildren() || !pro.exists()) {
+ return false;
+ }
+
+ // do the deed
+ String[] args = new String[] {
+ getJVMPath(appdir), "-jar", pro.toString(), appdir.getPath()
+ };
+ log.info("Running " + StringUtil.join(args, "\n "));
+ try {
+ Runtime.getRuntime().exec(args, null);
+ return true;
+ } catch (IOException ioe) {
+ log.warning("Failed to run getdown", ioe);
+ return false;
+ }
+ }
+
+ /**
+ * Reconstructs the path to the JVM used to launch this process.
+ */
+ public static String getJVMPath (File appdir)
+ {
+ return getJVMPath(appdir, false);
+ }
+
+ /**
+ * Reconstructs the path to the JVM used to launch this process.
+ *
+ * @param windebug if true we will use java.exe instead of javaw.exe on Windows.
+ */
+ public static String getJVMPath (File appdir, boolean windebug)
+ {
+ // first look in our application directory for an installed VM
+ String vmpath = checkJVMPath(new File(appdir, LOCAL_JAVA_DIR).getAbsolutePath(), windebug);
+ if (vmpath == null && isMacOS()) {
+ vmpath = checkJVMPath(new File(appdir, LOCAL_JAVA_DIR + "/Contents/Home").getAbsolutePath(), windebug);
+ }
+
+ // then fall back to the VM in which we're already running
+ if (vmpath == null) {
+ vmpath = checkJVMPath(System.getProperty("java.home"), windebug);
+ }
+
+ // then throw up our hands and hope for the best
+ if (vmpath == null) {
+ log.warning("Unable to find java [appdir=" + appdir +
+ ", java.home=" + System.getProperty("java.home") + "]!");
+ vmpath = "java";
+ }
+
+ // Oddly, the Mac OS X specific java flag -Xdock:name will only work if java is launched
+ // from /usr/bin/java, and not if launched by directly referring to <java.home>/bin/java,
+ // even though the former is a symlink to the latter! To work around this, see if the
+ // desired jvm is in fact pointed to by /usr/bin/java and, if so, use that instead.
+ if (isMacOS()) {
+ try {
+ File localVM = new File("/usr/bin/java").getCanonicalFile();
+ if (localVM.equals(new File(vmpath).getCanonicalFile())) {
+ vmpath = "/usr/bin/java";
+ }
+ } catch (IOException ioe) {
+ log.warning("Failed to check Mac OS canonical VM path.", ioe);
+ }
+ }
+
+ return vmpath;
+ }
+
+ /**
+ * Upgrades Getdown by moving an installation managed copy of the Getdown jar file over the
+ * non-managed copy (which would be used to run Getdown itself).
+ *
+ * <p> If the upgrade fails for a variety of reasons, warnings are logged but no other actions
+ * are taken. There's not much else one can do other than try again next time around.
+ */
+ public static void upgradeGetdown (File oldgd, File curgd, File newgd)
+ {
+ // we assume getdown's jar file size changes with every upgrade, this is not guaranteed,
+ // but in reality it will, and it allows us to avoid pointlessly upgrading getdown every
+ // time the client is updated which is unnecessarily flirting with danger
+ if (!newgd.exists() || newgd.length() == curgd.length()) {
+ return;
+ }
+
+ log.info("Updating Getdown with " + newgd + "...");
+
+ // clear out any old getdown
+ if (oldgd.exists()) {
+ FileUtil.deleteHarder(oldgd);
+ }
+
+ // now try updating using renames
+ if (!curgd.exists() || curgd.renameTo(oldgd)) {
+ if (newgd.renameTo(curgd)) {
+ FileUtil.deleteHarder(oldgd); // yay!
+ try {
+ // copy the moved file back to getdown-dop-new.jar so that we don't end up
+ // downloading another copy next time
+ FileUtil.copy(curgd, newgd);
+ } catch (IOException e) {
+ log.warning("Error copying updated Getdown back: " + e);
+ }
+ return;
+ }
+
+ log.warning("Unable to renameTo(" + oldgd + ").");
+ // try to unfuck ourselves
+ if (!oldgd.renameTo(curgd)) {
+ log.warning("Oh God, why dost thee scorn me so.");
+ }
+ }
+
+ // that didn't work, let's try copying it
+ log.info("Attempting to upgrade by copying over " + curgd + "...");
+ try {
+ FileUtil.copy(newgd, curgd);
+ } catch (IOException ioe) {
+ log.warning("Mayday! Brute force copy method also failed.", ioe);
+ }
+ }
+
+ /**
+ * Returns true if, on this operating system, we have to stick around and read the stderr from
+ * our children processes to prevent them from filling their output buffers and hanging.
+ */
+ public static boolean mustMonitorChildren ()
+ {
+ String osname = System.getProperty("os.name", "").toLowerCase(Locale.ROOT);
+ return (osname.indexOf("windows 98") != -1 || osname.indexOf("windows me") != -1);
+ }
+
+ /**
+ * Returns true if we're running in a JVM that identifies its operating system as Windows.
+ */
+ public static final boolean isWindows () { return _isWindows; }
+
+ /**
+ * Returns true if we're running in a JVM that identifies its operating system as MacOS.
+ */
+ public static final boolean isMacOS () { return _isMacOS; }
+
+ /**
+ * Returns true if we're running in a JVM that identifies its operating system as Linux.
+ */
+ public static final boolean isLinux () { return _isLinux; }
+
+ /**
+ * Checks whether a Java Virtual Machine can be located in the supplied path.
+ */
+ protected static String checkJVMPath (String vmhome, boolean windebug)
+ {
+ String vmbase = vmhome + File.separator + "bin" + File.separator;
+ String vmpath = vmbase + "java";
+ if (new File(vmpath).exists()) {
+ return vmpath;
+ }
+
+ if (!windebug) {
+ vmpath = vmbase + "javaw.exe";
+ if (new File(vmpath).exists()) {
+ return vmpath;
+ }
+ }
+
+ vmpath = vmbase + "java.exe";
+ if (new File(vmpath).exists()) {
+ return vmpath;
+ }
+
+ return null;
+ }
+
+ /** Flag indicating that we're on Windows; initialized when this class is first loaded. */
+ protected static boolean _isWindows;
+ /** Flag indicating that we're on MacOS; initialized when this class is first loaded. */
+ protected static boolean _isMacOS;
+ /** Flag indicating that we're on Linux; initialized when this class is first loaded. */
+ protected static boolean _isLinux;
+
+ static {
+ try {
+ String osname = System.getProperty("os.name");
+ osname = (osname == null) ? "" : osname;
+ _isWindows = (osname.indexOf("Windows") != -1);
+ _isMacOS = (osname.indexOf("Mac OS") != -1 ||
+ osname.indexOf("MacOS") != -1);
+ _isLinux = (osname.indexOf("Linux") != -1);
+ } catch (Exception e) {
+ // can't grab system properties; we'll just pretend we're not on any of these OSes
+ }
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+public class MessageUtil {
+
+ /**
+ * Returns whether or not the provided string is tainted. See {@link #taint}. Null strings
+ * are considered untainted.
+ */
+ public static boolean isTainted (String text)
+ {
+ return text != null && text.startsWith(TAINT_CHAR);
+ }
+
+ /**
+ * Call this to "taint" any string that has been entered by an entity outside the application
+ * so that the translation code knows not to attempt to translate this string when doing
+ * recursive translations.
+ */
+ public static String taint (Object text)
+ {
+ return TAINT_CHAR + text;
+ }
+
+ /**
+ * Removes the tainting character added to a string by {@link #taint}. If the provided string
+ * is not tainted, this silently returns the originally provided string.
+ */
+ public static String untaint (String text)
+ {
+ return isTainted(text) ? text.substring(TAINT_CHAR.length()) : text;
+ }
+
+ /**
+ * Composes a message key with an array of arguments. The message can subsequently be
+ * decomposed and translated without prior knowledge of how many arguments were provided.
+ */
+ public static String compose (String key, Object... args)
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append(key);
+ buf.append('|');
+ for (int i = 0; i < args.length; i++) {
+ if (i > 0) {
+ buf.append('|');
+ }
+ // escape the string while adding to the buffer
+ String arg = (args[i] == null) ? "" : String.valueOf(args[i]);
+ int alength = arg.length();
+ for (int p = 0; p < alength; p++) {
+ char ch = arg.charAt(p);
+ if (ch == '|') {
+ buf.append("\\!");
+ } else if (ch == '\\') {
+ buf.append("\\\\");
+ } else {
+ buf.append(ch);
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Compose a message with String args. This is just a convenience so callers do not have to
+ * cast their String[] to an Object[].
+ */
+ public static String compose (String key, String... args)
+ {
+ return compose(key, (Object[]) args);
+ }
+
+ /**
+ * A convenience method for calling {@link #compose(String,Object[])} with an array of
+ * arguments that will be automatically tainted (see {@link #taint}).
+ */
+ public static String tcompose (String key, Object... args)
+ {
+ int acount = args.length;
+ String[] targs = new String[acount];
+ for (int ii = 0; ii < acount; ii++) {
+ targs[ii] = taint(args[ii]);
+ }
+ return compose(key, (Object[]) targs);
+ }
+
+ /**
+ * A convenience method for calling {@link #compose(String,String[])} with an array of argument
+ * that will be automatically tainted.
+ */
+ public static String tcompose (String key, String... args)
+ {
+ for (int ii = 0, nn = args.length; ii < nn; ii++) {
+ args[ii] = taint(args[ii]);
+ }
+ return compose(key, args);
+ }
+
+ /**
+ * Used to escape single quotes so that they are not interpreted by <code>MessageFormat</code>.
+ * As we assume all single quotes are to be escaped, we cannot use the characters
+ * <code>{</code> and <code>}</code> in our translation strings, but this is a small price to
+ * pay to have to differentiate between messages that will and won't eventually be parsed by a
+ * <code>MessageFormat</code> instance.
+ */
+ public static String escape (String message)
+ {
+ return message.replace("'", "''");
+ }
+
+ /**
+ * Unescapes characters that are escaped in a call to compose.
+ */
+ public static String unescape (String value)
+ {
+ int bsidx = value.indexOf('\\');
+ if (bsidx == -1) {
+ return value;
+ }
+
+ StringBuilder buf = new StringBuilder();
+ int vlength = value.length();
+ for (int ii = 0; ii < vlength; ii++) {
+ char ch = value.charAt(ii);
+ if (ch != '\\' || ii == vlength-1) {
+ buf.append(ch);
+ } else {
+ // look at the next character
+ ch = value.charAt(++ii);
+ buf.append((ch == '!') ? '|' : ch);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ /** Text prefixed by this character will be considered tainted when doing recursive
+ * translations and won't be translated. */
+ protected static final String TAINT_CHAR = "~";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+/**
+ * Accumulates the progress from a number of (potentially parallel) elements into a single smoothly
+ * progressing progress.
+ */
+public class ProgressAggregator
+{
+ public ProgressAggregator (ProgressObserver target, long[] sizes) {
+ _target = target;
+ _sizes = sizes;
+ _progress = new int[sizes.length];
+ }
+
+ public ProgressObserver startElement (final int index) {
+ return new ProgressObserver() {
+ public void progress (int percent) {
+ _progress[index] = percent;
+ updateAggProgress();
+ }
+ };
+ }
+
+ protected void updateAggProgress () {
+ long totalSize = 0L, currentSize = 0L;
+ synchronized (this) {
+ for (int ii = 0, ll = _sizes.length; ii < ll; ii++) {
+ long size = _sizes[ii];
+ totalSize += size;
+ currentSize += (int)((size * _progress[ii])/100.0);
+ }
+ }
+ _target.progress((int)(100.0*currentSize / totalSize));
+ }
+
+ protected static long sum (long[] sizes) {
+ long totalSize = 0L;
+ for (long size : sizes) totalSize += size;
+ return totalSize;
+ }
+
+ protected ProgressObserver _target;
+ protected long[] _sizes;
+ protected int[] _progress;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+/**
+ * Used to communicate progress.
+ */
+public interface ProgressObserver
+{
+ /**
+ * Informs the observer that we have completed the specified
+ * percentage of the process.
+ */
+ public void progress (int percent);
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+/**
+ * An immutable rectangle.
+ */
+public class Rectangle
+{
+ public final int x;
+ public final int y;
+ public final int width;
+ public final int height;
+
+ public Rectangle (int x, int y, int width, int height)
+ {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ public Rectangle union (Rectangle other) {
+ int x1 = Math.min(x, other.x);
+ int x2 = Math.max(x + width, other.x + other.width);
+ int y1 = Math.min(y, other.y);
+ int y2 = Math.max(y + height, other.y + other.height);
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /** {@inheritDoc} */
+ public String toString ()
+ {
+ return getClass().getName() + "[x=" + x + ", y=" + y +
+ ", width=" + width + ", height=" + height + "]";
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+
+import static com.threerings.getdown.Log.log;
+
+public class StreamUtil {
+ /**
+ * Convenient close for a stream. Use in a finally clause and love life.
+ */
+ public static void close (InputStream in)
+ {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ioe) {
+ log.warning("Error closing input stream", "stream", in, "cause", ioe);
+ }
+ }
+ }
+
+ /**
+ * Convenient close for a stream. Use in a finally clause and love life.
+ */
+ public static void close (OutputStream out)
+ {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException ioe) {
+ log.warning("Error closing output stream", "stream", out, "cause", ioe);
+ }
+ }
+ }
+
+ /**
+ * Convenient close for a Reader. Use in a finally clause and love life.
+ */
+ public static void close (Reader in)
+ {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ioe) {
+ log.warning("Error closing reader", "reader", in, "cause", ioe);
+ }
+ }
+ }
+
+ /**
+ * Convenient close for a Writer. Use in a finally clause and love life.
+ */
+ public static void close (Writer out)
+ {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException ioe) {
+ log.warning("Error closing writer", "writer", out, "cause", ioe);
+ }
+ }
+ }
+
+ /**
+ * Copies the contents of the supplied input stream to the supplied output stream.
+ */
+ public static <T extends OutputStream> T copy (InputStream in, T out)
+ throws IOException
+ {
+ byte[] buffer = new byte[4096];
+ for (int read = 0; (read = in.read(buffer)) > 0; ) {
+ out.write(buffer, 0, read);
+ }
+ return out;
+ }
+
+ /**
+ * Reads the contents of the supplied stream into a byte array.
+ */
+ public static byte[] toByteArray (InputStream stream)
+ throws IOException
+ {
+ return copy(stream, new ByteArrayOutputStream()).toByteArray();
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.util.StringTokenizer;
+
+public class StringUtil {
+
+ /**
+ * @return true if the specified string could be a valid URL (contains no illegal characters)
+ */
+ public static boolean couldBeValidUrl (String url)
+ {
+ return url.matches("[A-Za-z0-9\\-\\._~:/\\?#\\[\\]@!$&'\\(\\)\\*\\+,;=%]+");
+ }
+
+ /**
+ * @return true if the string is null or consists only of whitespace, false otherwise.
+ */
+ public static boolean isBlank (String value)
+ {
+ for (int ii = 0, ll = (value == null) ? 0 : value.length(); ii < ll; ii++) {
+ if (!Character.isWhitespace(value.charAt(ii))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Parses an array of integers from it's string representation. The array should be represented
+ * as a bare list of numbers separated by commas, for example:
+ *
+ * <pre>25, 17, 21, 99</pre>
+ *
+ * Any inability to parse the int array will result in the function returning null.
+ */
+ public static int[] parseIntArray (String source)
+ {
+ StringTokenizer tok = new StringTokenizer(source, ",");
+ int[] vals = new int[tok.countTokens()];
+ for (int i = 0; tok.hasMoreTokens(); i++) {
+ try {
+ // trim the whitespace from the token
+ vals[i] = Integer.parseInt(tok.nextToken().trim());
+ } catch (NumberFormatException nfe) {
+ return null;
+ }
+ }
+ return vals;
+ }
+
+ /**
+ * Parses an array of strings from a single string. The array should be represented as a bare
+ * list of strings separated by commas, for example:
+ *
+ * <pre>mary, had, a, little, lamb, and, an, escaped, comma,,</pre>
+ *
+ * If a comma is desired in one of the strings, it should be escaped by putting two commas in a
+ * row. Any inability to parse the string array will result in the function returning null.
+ */
+ public static String[] parseStringArray (String source)
+ {
+ return parseStringArray(source, false);
+ }
+
+ /**
+ * Like {@link #parseStringArray(String)} but can be instructed to invoke {@link String#intern}
+ * on the strings being parsed into the array.
+ */
+ public static String[] parseStringArray (String source, boolean intern)
+ {
+ int tcount = 0, tpos = -1, tstart = 0;
+
+ // empty strings result in zero length arrays
+ if (source.length() == 0) {
+ return new String[0];
+ }
+
+ // sort out escaped commas
+ source = source.replace(",,", "%COMMA%");
+
+ // count up the number of tokens
+ while ((tpos = source.indexOf(",", tpos+1)) != -1) {
+ tcount++;
+ }
+
+ String[] tokens = new String[tcount+1];
+ tpos = -1; tcount = 0;
+
+ // do the split
+ while ((tpos = source.indexOf(",", tpos+1)) != -1) {
+ tokens[tcount] = source.substring(tstart, tpos);
+ tokens[tcount] = tokens[tcount].trim().replace("%COMMA%", ",");
+ if (intern) {
+ tokens[tcount] = tokens[tcount].intern();
+ }
+ tstart = tpos+1;
+ tcount++;
+ }
+
+ // grab the last token
+ tokens[tcount] = source.substring(tstart);
+ tokens[tcount] = tokens[tcount].trim().replace("%COMMA%", ",");
+
+ return tokens;
+ }
+
+ /**
+ * @return the supplied string if it is non-null, "" if it is null.
+ */
+ public static String deNull (String value)
+ {
+ return (value == null) ? "" : value;
+ }
+
+ /**
+ * Generates a string from the supplied bytes that is the HEX encoded representation of those
+ * bytes. Returns the empty string for a <code>null</code> or empty byte array.
+ *
+ * @param bytes the bytes for which we want a string representation.
+ * @param count the number of bytes to stop at (which will be coerced into being {@code <=} the
+ * length of the array).
+ */
+ public static String hexlate (byte[] bytes, int count)
+ {
+ if (bytes == null) {
+ return "";
+ }
+
+ count = Math.min(count, bytes.length);
+ char[] chars = new char[count*2];
+
+ for (int i = 0; i < count; i++) {
+ int val = bytes[i];
+ if (val < 0) {
+ val += 256;
+ }
+ chars[2*i] = XLATE.charAt(val/16);
+ chars[2*i+1] = XLATE.charAt(val%16);
+ }
+
+ return new String(chars);
+ }
+
+ /**
+ * Generates a string from the supplied bytes that is the HEX encoded representation of those
+ * bytes.
+ */
+ public static String hexlate (byte[] bytes)
+ {
+ return (bytes == null) ? "" : hexlate(bytes, bytes.length);
+ }
+
+ /**
+ * Joins an array of strings (or objects which will be converted to strings) into a single
+ * string separated by commas.
+ */
+ public static String join (Object[] values)
+ {
+ return join(values, false);
+ }
+
+ /**
+ * Joins an array of strings into a single string, separated by commas, and optionally escaping
+ * commas that occur in the individual string values such that a subsequent call to {@link
+ * #parseStringArray} would recreate the string array properly. Any elements in the values
+ * array that are null will be treated as an empty string.
+ */
+ public static String join (Object[] values, boolean escape)
+ {
+ return join(values, ", ", escape);
+ }
+
+ /**
+ * Joins the supplied array of strings into a single string separated by the supplied
+ * separator.
+ */
+ public static String join (Object[] values, String separator)
+ {
+ return join(values, separator, false);
+ }
+
+ /**
+ * Helper function for the various <code>join</code> methods.
+ */
+ protected static String join (Object[] values, String separator, boolean escape)
+ {
+ StringBuilder buf = new StringBuilder();
+ int vlength = values.length;
+ for (int i = 0; i < vlength; i++) {
+ if (i > 0) {
+ buf.append(separator);
+ }
+ String value = (values[i] == null) ? "" : values[i].toString();
+ buf.append((escape) ? value.replace(",", ",,") : value);
+ }
+ return buf.toString();
+ }
+
+ /** Used by {@link #hexlate} and {@link #unhexlate}. */
+ protected static final String XLATE = "0123456789abcdef";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.threerings.getdown.data.SysProps;
+import static com.threerings.getdown.Log.log;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Version related utilities.
+ */
+public class VersionUtil
+{
+ /**
+ * Reads a version number from a file.
+ */
+ public static long readVersion (File vfile)
+ {
+ long fileVersion = -1;
+ try (BufferedReader bin =
+ new BufferedReader(new InputStreamReader(new FileInputStream(vfile), UTF_8))) {
+ String vstr = bin.readLine();
+ if (!StringUtil.isBlank(vstr)) {
+ fileVersion = Long.parseLong(vstr);
+ }
+ } catch (Exception e) {
+ log.info("Unable to read version file: " + e.getMessage());
+ }
+
+ return fileVersion;
+ }
+
+ /**
+ * Writes a version number to a file.
+ */
+ public static void writeVersion (File vfile, long version) throws IOException
+ {
+ try (PrintStream out = new PrintStream(new FileOutputStream(vfile))) {
+ out.println(version);
+ } catch (Exception e) {
+ log.warning("Unable to write version file: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Parses {@code versStr} using {@code versRegex} into a (long) integer version number.
+ * @see SysProps#parseJavaVersion
+ */
+ public static long parseJavaVersion (String versRegex, String versStr)
+ {
+ Matcher m = Pattern.compile(versRegex).matcher(versStr);
+ if (!m.matches()) return 0L;
+
+ long vers = 0L;
+ for (int ii = 1; ii <= m.groupCount(); ii++) {
+ String valstr = m.group(ii);
+ int value = (valstr == null) ? 0 : parseInt(valstr);
+ vers *= 100;
+ vers += value;
+ }
+ return vers;
+ }
+
+ /**
+ * Reads and parses the version from the {@code release} file bundled with a JVM.
+ */
+ public static long readReleaseVersion (File relfile, String versRegex)
+ {
+ try (BufferedReader in =
+ new BufferedReader(new InputStreamReader(new FileInputStream(relfile), UTF_8))) {
+ String line = null, relvers = null;
+ while ((line = in.readLine()) != null) {
+ if (line.startsWith("JAVA_VERSION=")) {
+ relvers = line.substring("JAVA_VERSION=".length()).replace('"', ' ').trim();
+ }
+ }
+
+ if (relvers == null) {
+ log.warning("No JAVA_VERSION line in 'release' file", "file", relfile);
+ return 0L;
+ }
+ return parseJavaVersion(versRegex, relvers);
+
+ } catch (Exception e) {
+ log.warning("Failed to read version from 'release' file", "file", relfile, e);
+ return 0L;
+ }
+ }
+
+ private static int parseInt (String str) {
+ int value = 0;
+ for (int ii = 0, ll = str.length(); ii < ll; ii++) {
+ char c = str.charAt(ii);
+ if (c >= '0' && c <= '9') {
+ value *= 10;
+ value += (c - '0');
+ }
+ }
+ return value;
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Validates that cache garbage is collected and deleted correctly.
+ */
+public class GarbageCollectorTest
+{
+ @Before public void setupFiles () throws IOException
+ {
+ _cachedFile = _folder.newFile("abc123.jar");
+ _lastAccessedFile = _folder.newFile("abc123.jar" + ResourceCache.LAST_ACCESSED_FILE_SUFFIX);
+ }
+
+ @Test public void shouldDeleteCacheEntryIfRetentionPeriodIsReached ()
+ {
+ gcNow();
+ assertFalse(_cachedFile.exists());
+ assertFalse(_lastAccessedFile.exists());
+ }
+
+ @Test public void shouldDeleteCacheFolderIfFolderIsEmpty ()
+ {
+ gcNow();
+ assertFalse(_folder.getRoot().exists());
+ }
+
+ private void gcNow() {
+ GarbageCollector.collect(_folder.getRoot(), -1);
+ }
+
+ @Test public void shouldKeepFilesInCacheIfRententionPeriodIsNotReached ()
+ {
+ GarbageCollector.collect(_folder.getRoot(), TimeUnit.DAYS.toMillis(1));
+ assertTrue(_cachedFile.exists());
+ assertTrue(_lastAccessedFile.exists());
+ }
+
+ @Test public void shouldDeleteCachedFileIfLastAccessedFileIsMissing ()
+ {
+ assumeTrue(_lastAccessedFile.delete());
+ gcNow();
+ assertFalse(_cachedFile.exists());
+ }
+
+ @Test public void shouldDeleteLastAccessedFileIfCachedFileIsMissing ()
+ {
+ assumeTrue(_cachedFile.delete());
+ gcNow();
+ assertFalse(_lastAccessedFile.exists());
+ }
+
+ @Rule public TemporaryFolder _folder = new TemporaryFolder();
+
+ private File _cachedFile;
+ private File _lastAccessedFile;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.*;
+
+/**
+ * Asserts the correct functionality of the {@link ResourceCache}.
+ */
+public class ResourceCacheTest
+{
+ @Before public void setupCache () throws IOException {
+ _fileToCache = _folder.newFile("filetocache.jar");
+ _cache = new ResourceCache(_folder.newFolder(".cache"));
+ }
+
+ @Test public void shouldCacheFile () throws IOException
+ {
+ assertEquals("abc123.jar", cacheFile().getName());
+ }
+
+ private File cacheFile() throws IOException
+ {
+ return _cache.cacheFile(_fileToCache, "abc123", "abc123");
+ }
+
+ @Test public void shouldTrackFileUsage () throws IOException
+ {
+ String name = "abc123.jar" + ResourceCache.LAST_ACCESSED_FILE_SUFFIX;
+ File lastAccessedFile = new File(cacheFile().getParentFile(), name);
+ assertTrue(lastAccessedFile.exists());
+ }
+
+ @Test public void shouldNotCacheTheSameFile () throws Exception
+ {
+ File cachedFile = cacheFile();
+ cachedFile.setLastModified(YESTERDAY);
+ long expectedLastModified = cachedFile.lastModified();
+ // caching it another time
+ File sameCachedFile = cacheFile();
+ assertEquals(expectedLastModified, sameCachedFile.lastModified());
+ }
+
+ @Test public void shouldRememberWhenFileWasRequested () throws Exception
+ {
+ File cachedFile = cacheFile();
+ String name = cachedFile.getName() + ResourceCache.LAST_ACCESSED_FILE_SUFFIX;
+ File lastAccessedFile = new File(cachedFile.getParentFile(), name);
+ lastAccessedFile.setLastModified(YESTERDAY);
+ long lastAccessed = lastAccessedFile.lastModified();
+ // caching it another time
+ cacheFile();
+ assertTrue(lastAccessedFile.lastModified() > lastAccessed);
+ }
+
+ @Rule public TemporaryFolder _folder = new TemporaryFolder();
+
+ private File _fileToCache;
+ private ResourceCache _cache;
+
+ private static final long YESTERDAY = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.LinkedHashSet;
+
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for {@link ClassPath}.
+ */
+public class ClassPathTest
+{
+ @Before public void createJarsAndSetupClassPath () throws IOException
+ {
+ _firstJar = _folder.newFile("a.jar");
+ _secondJar = _folder.newFile("b.jar");
+
+ LinkedHashSet<File> classPathEntries = new LinkedHashSet<File>();
+ classPathEntries.add(_firstJar);
+ classPathEntries.add(_secondJar);
+ _classPath = new ClassPath(classPathEntries);
+ }
+
+ @Test public void shouldCreateValidArgumentString ()
+ {
+ assertEquals(
+ _firstJar.getAbsolutePath() + File.pathSeparator + _secondJar.getAbsolutePath(),
+ _classPath.asArgumentString());
+ }
+
+ @Test public void shouldProvideJarUrls () throws MalformedURLException, URISyntaxException
+ {
+ URL[] actualUrls = _classPath.asUrls();
+ assertEquals(_firstJar, new File(actualUrls[0].toURI()));
+ assertEquals(_secondJar, new File(actualUrls[1].toURI()));
+ }
+
+ @Rule public TemporaryFolder _folder = new TemporaryFolder();
+
+ private File _firstJar, _secondJar;
+ private ClassPath _classPath;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.io.File;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+public class EnvConfigTest {
+
+ static String CWD = System.getProperty("user.dir");
+ static String TESTID = "testid";
+ static String TESTBASE = "https://test.com/test";
+
+ private void debugNotes(List<EnvConfig.Note> notes) {
+ for (EnvConfig.Note note : notes) {
+ System.out.println(note.message);
+ }
+ }
+
+ private void checkNoNotes (List<EnvConfig.Note> notes) {
+ StringBuilder msg = new StringBuilder();
+ for (EnvConfig.Note note : notes) {
+ if (note.level != EnvConfig.Note.Level.INFO) {
+ msg.append("\n").append(note.message);
+ }
+ }
+ if (msg.length() > 0) {
+ fail("Unexpected notes:" + msg.toString());
+ }
+ }
+ private void checkDir (EnvConfig cfg) {
+ assertTrue(cfg != null);
+ assertEquals(new File(CWD), cfg.appDir);
+ }
+ private void checkNoAppId (EnvConfig cfg) {
+ assertNull(cfg.appId);
+ }
+ private void checkAppId (EnvConfig cfg, String appId) {
+ assertEquals(appId, cfg.appId);
+ }
+ private void checkAppBase (EnvConfig cfg, String appBase) {
+ assertEquals(appBase, cfg.appBase);
+ }
+ private void checkNoAppBase (EnvConfig cfg) {
+ assertNull(cfg.appBase);
+ }
+ private void checkNoAppArgs (EnvConfig cfg) {
+ assertTrue(cfg.appArgs.isEmpty());
+ }
+ private void checkAppArgs (EnvConfig cfg, String... args) {
+ assertEquals(Arrays.asList(args), cfg.appArgs);
+ }
+
+ @Test public void testArgvDir () {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ String[] args = { CWD };
+ EnvConfig cfg = EnvConfig.create(args, notes);
+ // debugNotes(notes);
+ checkNoNotes(notes);
+ checkDir(cfg);
+ checkNoAppId(cfg);
+ checkNoAppBase(cfg);
+ checkNoAppArgs(cfg);
+ }
+
+ @Test public void testArgvDirId () {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ String[] args = { CWD, TESTID };
+ EnvConfig cfg = EnvConfig.create(args, notes);
+ // debugNotes(notes);
+ checkNoNotes(notes);
+ checkDir(cfg);
+ checkAppId(cfg, TESTID);
+ checkNoAppBase(cfg);
+ checkNoAppArgs(cfg);
+ }
+
+ @Test public void testArgvDirArgs () {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ String[] args = { CWD, "", "one", "two" };
+ EnvConfig cfg = EnvConfig.create(args, notes);
+ // debugNotes(notes);
+ checkNoNotes(notes);
+ checkDir(cfg);
+ checkNoAppId(cfg);
+ checkNoAppBase(cfg);
+ checkAppArgs(cfg, "one", "two");
+ }
+
+ @Test public void testArgvDirIdArgs () {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ String[] args = { CWD, TESTID, "one", "two" };
+ EnvConfig cfg = EnvConfig.create(args, notes);
+ // debugNotes(notes);
+ checkNoNotes(notes);
+ checkDir(cfg);
+ checkAppId(cfg, TESTID);
+ checkNoAppBase(cfg);
+ checkAppArgs(cfg, "one", "two");
+ }
+
+ private EnvConfig sysPropsConfig (List<EnvConfig.Note> notes, String... keyVals) {
+ for (int ii = 0; ii < keyVals.length; ii += 2) {
+ System.setProperty(keyVals[ii], keyVals[ii+1]);
+ }
+ EnvConfig cfg = EnvConfig.create(new String[0], notes);
+ for (int ii = 0; ii < keyVals.length; ii += 2) {
+ System.clearProperty(keyVals[ii]);
+ }
+ return cfg;
+ }
+
+ @Test public void testSysPropsDir () {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ EnvConfig cfg = sysPropsConfig(notes, "appdir", CWD);
+ // debugNotes(notes);
+ checkNoNotes(notes);
+ checkDir(cfg);
+ checkNoAppId(cfg);
+ checkNoAppBase(cfg);
+ checkNoAppArgs(cfg);
+ }
+
+ @Test public void testSysPropsDirIdBase () {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ EnvConfig cfg = sysPropsConfig(notes, "appdir", CWD, "appid", TESTID, "appbase", TESTBASE);
+ // debugNotes(notes);
+ checkNoNotes(notes);
+ checkDir(cfg);
+ checkAppId(cfg, TESTID);
+ checkAppBase(cfg, TESTBASE);
+ checkNoAppArgs(cfg);
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import static org.junit.Assert.assertEquals;
+
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PathBuilderTest
+{
+ @Before public void setupFilesAndResources () throws IOException
+ {
+ _firstJarFile = _appdir.newFile("a.jar");
+ _secondJarFile = _appdir.newFile("b.jar");
+
+ when(_firstJar.getFinalTarget()).thenReturn(_firstJarFile);
+ when(_secondJar.getFinalTarget()).thenReturn(_secondJarFile);
+ when(_application.getActiveCodeResources()).thenReturn(Arrays.asList(_firstJar, _secondJar));
+ when(_application.getAppDir()).thenReturn(_appdir.getRoot());
+ }
+
+ @Test public void shouldBuildDefaultClassPath () throws IOException
+ {
+ ClassPath classPath = PathBuilder.buildDefaultClassPath(_application);
+ String expectedClassPath = _firstJarFile.getAbsolutePath() + File.pathSeparator +
+ _secondJarFile.getAbsolutePath();
+ assertEquals(expectedClassPath, classPath.asArgumentString());
+ }
+
+ @Test public void shouldBuildCachedClassPath () throws IOException
+ {
+ when(_application.getDigest(_firstJar)).thenReturn("first");
+ when(_application.getDigest(_secondJar)).thenReturn("second");
+ when(_application.getCodeCacheRetentionDays()).thenReturn(1);
+
+ Path firstCachedJarFile = _appdir.getRoot().toPath().
+ resolve(PathBuilder.CODE_CACHE_DIR).resolve("fi").resolve("first.jar");
+
+ Path secondCachedJarFile = _appdir.getRoot().toPath().
+ resolve(PathBuilder.CODE_CACHE_DIR).resolve("se").resolve("second.jar");
+
+ String expectedClassPath = firstCachedJarFile.toAbsolutePath() + File.pathSeparator +
+ secondCachedJarFile.toAbsolutePath();
+
+ ClassPath classPath = PathBuilder.buildCachedClassPath(_application);
+ assertEquals(expectedClassPath, classPath.asArgumentString());
+ }
+
+ @Mock protected Application _application;
+ @Mock protected Resource _firstJar;
+ @Mock protected Resource _secondJar;
+
+ protected File _firstJarFile, _secondJarFile;
+
+ @Rule public TemporaryFolder _appdir = new TemporaryFolder();
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.data;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+public class SysPropsTest {
+
+ @After public void clearProps () {
+ System.clearProperty("delay");
+ System.clearProperty("appbase_domain");
+ System.clearProperty("appbase_override");
+ }
+
+ private static final String[] APPBASES = {
+ "http://foobar.com/myapp",
+ "https://foobar.com/myapp",
+ "http://foobar.com:8080/myapp",
+ "https://foobar.com:8080/myapp"
+ };
+
+ @Test public void testStartDelay () {
+
+ assertEquals(0, SysProps.startDelay());
+
+ System.setProperty("delay", "x");
+ assertEquals(0, SysProps.startDelay());
+
+ System.setProperty("delay", "-7");
+ assertEquals(0, SysProps.startDelay());
+
+ System.setProperty("delay", "7");
+ assertEquals(7, SysProps.startDelay());
+
+ System.setProperty("delay", "1440");
+ assertEquals(1440, SysProps.startDelay());
+
+ System.setProperty("delay", "1441");
+ assertEquals(1440, SysProps.startDelay());
+ }
+
+ @Test public void testAppbaseDomain () {
+ System.setProperty("appbase_domain", "https://barbaz.com");
+ for (String appbase : APPBASES) {
+ assertEquals("https://barbaz.com/myapp", SysProps.overrideAppbase(appbase));
+ }
+ System.setProperty("appbase_domain", "http://barbaz.com");
+ for (String appbase : APPBASES) {
+ assertEquals("http://barbaz.com/myapp", SysProps.overrideAppbase(appbase));
+ }
+ }
+
+ @Test public void testAppbaseOverride () {
+ System.setProperty("appbase_override", "https://barbaz.com/newapp");
+ for (String appbase : APPBASES) {
+ assertEquals("https://barbaz.com/newapp", SysProps.overrideAppbase(appbase));
+ }
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link Color}.
+ */
+public class ColorTest
+{
+ @Test
+ public void testBrightness() {
+ assertEquals(0, Color.brightness(0xFF000000), 0.0000001);
+ assertEquals(1, Color.brightness(0xFFFFFFFF), 0.0000001);
+ assertEquals(0.0117647, Color.brightness(0xFF010203), 0.0000001);
+ assertEquals(1, Color.brightness(0xFF00FFC8), 0.0000001);
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.*;
+import static org.junit.Assert.*;
+
+/**
+ * Tests {@link Config}.
+ */
+public class ConfigTest
+{
+ public static class Pair {
+ public final String key;
+ public final String value;
+ public Pair (String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+ }
+
+ public static final Pair[] SIMPLE_PAIRS = {
+ new Pair("one", "two"),
+ new Pair("three", "four"),
+ new Pair("five", "six"),
+ new Pair("seven", "eight"),
+ new Pair("nine", "ten"),
+ };
+
+ @Test public void testSimplePairs () throws IOException
+ {
+ List<String[]> pairs = Config.parsePairs(
+ toReader(SIMPLE_PAIRS), Config.createOpts(true));
+ for (int ii = 0; ii < SIMPLE_PAIRS.length; ii++) {
+ assertEquals(SIMPLE_PAIRS[ii].key, pairs.get(ii)[0]);
+ assertEquals(SIMPLE_PAIRS[ii].value, pairs.get(ii)[1]);
+ }
+ }
+
+ @Test public void testQualifiedPairs () throws IOException
+ {
+ Pair linux = new Pair("one", "[linux] two");
+ Pair mac = new Pair("three", "[mac os x] four");
+ Pair linuxAndMac = new Pair("five", "[linux, mac os x] six");
+ Pair linux64 = new Pair("seven", "[linux-x86_64] eight");
+ Pair linux64s = new Pair("nine", "[linux-x86_64, linux-amd64] ten");
+ Pair mac64 = new Pair("eleven", "[mac os x-x86_64] twelve");
+ Pair win64 = new Pair("thirteen", "[windows-x86_64] fourteen");
+ Pair notWin = new Pair("fifteen", "[!windows] sixteen");
+ Pair[] pairs = { linux, mac, linuxAndMac, linux64, linux64s, mac64, win64, notWin };
+
+ Config.ParseOpts opts = Config.createOpts(false);
+ opts.osname = "linux";
+ opts.osarch = "i386";
+ List<String[]> parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ assertTrue(exists(parsed, notWin.key));
+
+ opts.osarch = "x86_64";
+ parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(exists(parsed, linux64.key));
+ assertTrue(exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ assertTrue(exists(parsed, notWin.key));
+
+ opts.osarch = "amd64";
+ parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ assertTrue(exists(parsed, notWin.key));
+
+ opts.osname = "mac os x";
+ opts.osarch = "x86_64";
+ parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(exists(parsed, mac.key));
+ assertTrue(exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ assertTrue(exists(parsed, notWin.key));
+
+ opts.osname = "windows";
+ opts.osarch = "i386";
+ parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(!exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ assertTrue(!exists(parsed, notWin.key));
+
+ opts.osarch = "x86_64";
+ parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(!exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(exists(parsed, win64.key));
+ assertTrue(!exists(parsed, notWin.key));
+
+ opts.osarch = "amd64";
+ parsed = Config.parsePairs(toReader(pairs), opts);
+ assertTrue(!exists(parsed, linux.key));
+ assertTrue(!exists(parsed, mac.key));
+ assertTrue(!exists(parsed, linuxAndMac.key));
+ assertTrue(!exists(parsed, linux64.key));
+ assertTrue(!exists(parsed, linux64s.key));
+ assertTrue(!exists(parsed, mac64.key));
+ assertTrue(!exists(parsed, win64.key));
+ assertTrue(!exists(parsed, notWin.key));
+ }
+
+ protected static boolean exists (List<String[]> pairs, String key)
+ {
+ for (String[] pair : pairs) {
+ if (pair[0].equals(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected static StringReader toReader (Pair[] pairs)
+ {
+ StringBuilder builder = new StringBuilder();
+ for (Pair pair : pairs) {
+ // throw some whitespace in to ensure it's trimmed
+ builder.append(whitespace()).append(pair.key).
+ append(whitespace()).append("=").
+ append(whitespace()).append(pair.value).
+ append(whitespace()).append("\n");
+ }
+ return new StringReader(builder.toString());
+ }
+
+ protected static String whitespace ()
+ {
+ return _rando.nextBoolean() ? " " : "";
+ }
+
+ protected static Random _rando = new Random();
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests {@link FileUtil}.
+ */
+public class FileUtilTest
+{
+ @Test public void testReadLines () throws IOException
+ {
+ String data = "This is a test\nof a file with\na few lines\n";
+ List<String> lines = FileUtil.readLines(new StringReader(data));
+ String[] linesBySplit = data.split("\n");
+ assertEquals(linesBySplit.length, lines.size());
+ for (int ii = 0; ii < lines.size(); ii++) {
+ assertEquals(linesBySplit[ii], lines.get(ii));
+ }
+ }
+
+ @Test public void shouldCopyFile () throws IOException
+ {
+ File source = _folder.newFile("source.txt");
+ File target = new File(_folder.getRoot(), "target.txt");
+ assertFalse(target.exists());
+ FileUtil.copy(source, target);
+ assertTrue(target.exists());
+ }
+
+ @Test public void shouldRecursivelyWalkOverFilesAndFolders () throws IOException
+ {
+ _folder.newFile("a.txt");
+ new File(_folder.newFolder("b"), "b.txt").createNewFile();
+
+ class CountingVisitor implements FileUtil.Visitor {
+ int fileCount = 0;
+ @Override public void visit(File file) {
+ fileCount++;
+ }
+ }
+ CountingVisitor visitor = new CountingVisitor();
+ FileUtil.walkTree(_folder.getRoot(), visitor);
+ assertEquals(3, visitor.fileCount);
+ }
+
+ @Rule public TemporaryFolder _folder = new TemporaryFolder();
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+/**
+ * Tests {@link HostWhitelist}.
+ */
+public class HostWhitelistTest
+{
+ @Test
+ public void testVerify () throws MalformedURLException
+ {
+ checkCanVerify("foo.com", "http://foo.com", true);
+ checkCanVerify("foo.com", "http://foo.com/", true);
+ checkCanVerify("foo.com", "http://foo.com/x/y/z", true);
+ checkCanVerify("foo.com", "http://www.foo.com", false);
+ checkCanVerify("foo.com", "http://www.foo.com/", false);
+ checkCanVerify("foo.com", "http://www.foo.com/x/y/z", false);
+ checkCanVerify("foo.com", "http://a.b.foo.com", false);
+ checkCanVerify("foo.com", "http://a.b.foo.com/", false);
+ checkCanVerify("foo.com", "http://a.b.foo.com/x/y/z", false);
+ checkCanVerify("foo.com", "http://oo.com", false);
+ checkCanVerify("foo.com", "http://f.oo.com", false);
+ checkCanVerify("foo.com", "http://a.f.oo.com", false);
+
+ checkCanVerify("*.foo.com", "http://foo.com", false);
+ checkCanVerify("*.foo.com", "http://foo.com/", false);
+ checkCanVerify("*.foo.com", "http://foo.com/x/y/z", false);
+ checkCanVerify("*.foo.com", "http://www.foo.com", true);
+ checkCanVerify("*.foo.com", "http://www.foo.com/", true);
+ checkCanVerify("*.foo.com", "http://www.foo.com/x/y/z", true);
+ checkCanVerify("*.foo.com", "http://a.b.foo.com", true);
+ checkCanVerify("*.foo.com", "http://a.b.foo.com/", true);
+ checkCanVerify("*.foo.com", "http://a.b.foo.com/x/y/z", true);
+ checkCanVerify("*.foo.com", "http://oo.com", false);
+ checkCanVerify("*.foo.com", "http://f.oo.com", false);
+ checkCanVerify("*.foo.com", "http://a.f.oo.com", false);
+
+ checkCanVerify("*.com", "http://foo.com", true);
+ checkCanVerify("*.com", "http://foo.com/", true);
+ checkCanVerify("*.com", "http://foo.com/x/y/z", true);
+ checkCanVerify("*.com", "http://www.foo.com", true);
+ checkCanVerify("*.com", "http://www.foo.com/", true);
+ checkCanVerify("*.com", "http://www.foo.com/x/y/z", true);
+ checkCanVerify("*.com", "http://a.b.foo.com", true);
+ checkCanVerify("*.com", "http://a.b.foo.com/", true);
+ checkCanVerify("*.com", "http://a.b.foo.com/x/y/z", true);
+ checkCanVerify("*.com", "http://oo.com", true);
+ checkCanVerify("*.com", "http://f.oo.com", true);
+ checkCanVerify("*.com", "http://a.f.oo.com", true);
+
+ checkCanVerify("*.net", "http://foo.com", false);
+ checkCanVerify("*.net", "http://foo.com/", false);
+ checkCanVerify("*.net", "http://foo.com/x/y/z", false);
+ checkCanVerify("*.net", "http://www.foo.com", false);
+ checkCanVerify("*.net", "http://www.foo.com/", false);
+ checkCanVerify("*.net", "http://www.foo.com/x/y/z", false);
+ checkCanVerify("*.net", "http://a.b.foo.com", false);
+ checkCanVerify("*.net", "http://a.b.foo.com/", false);
+ checkCanVerify("*.net", "http://a.b.foo.com/x/y/z", false);
+ checkCanVerify("*.net", "http://oo.com", false);
+ checkCanVerify("*.net", "http://f.oo.com", false);
+ checkCanVerify("*.net", "http://a.f.oo.com", false);
+
+ checkCanVerify("www.*.com", "http://foo.com", false);
+ checkCanVerify("www.*.com", "http://foo.com/", false);
+ checkCanVerify("www.*.com", "http://foo.com/x/y/z", false);
+ checkCanVerify("www.*.com", "http://www.foo.com", true);
+ checkCanVerify("www.*.com", "http://www.foo.com/", true);
+ checkCanVerify("www.*.com", "http://www.foo.com/x/y/z", true);
+ checkCanVerify("www.*.com", "http://a.b.foo.com", false);
+ checkCanVerify("www.*.com", "http://a.b.foo.com/", false);
+ checkCanVerify("www.*.com", "http://a.b.foo.com/x/y/z", false);
+ checkCanVerify("www.*.com", "http://oo.com", false);
+ checkCanVerify("www.*.com", "http://f.oo.com", false);
+ checkCanVerify("www.*.com", "http://a.f.oo.com", false);
+ checkCanVerify("www.*.com", "http://www.a.f.oo.com", true);
+
+ checkCanVerify("foo.*", "http://foo.com", true);
+ checkCanVerify("foo.*", "http://foo.com/", true);
+ checkCanVerify("foo.*", "http://foo.com/x/y/z", true);
+ checkCanVerify("foo.*", "http://www.foo.com", false);
+ checkCanVerify("foo.*", "http://www.foo.com/", false);
+ checkCanVerify("foo.*", "http://www.foo.com/x/y/z", false);
+ checkCanVerify("foo.*", "http://a.b.foo.com", false);
+ checkCanVerify("foo.*", "http://a.b.foo.com/", false);
+ checkCanVerify("foo.*", "http://a.b.foo.com/x/y/z", false);
+ checkCanVerify("foo.*", "http://oo.com", false);
+ checkCanVerify("foo.*", "http://f.oo.com", false);
+ checkCanVerify("foo.*", "http://a.f.oo.com", false);
+
+ checkCanVerify("*.foo.*", "http://foo.com", false);
+ checkCanVerify("*.foo.*", "http://foo.com/", false);
+ checkCanVerify("*.foo.*", "http://foo.com/x/y/z", false);
+ checkCanVerify("*.foo.*", "http://www.foo.com", true);
+ checkCanVerify("*.foo.*", "http://www.foo.com/", true);
+ checkCanVerify("*.foo.*", "http://www.foo.com/x/y/z", true);
+ checkCanVerify("*.foo.*", "http://a.b.foo.com", true);
+ checkCanVerify("*.foo.*", "http://a.b.foo.com/", true);
+ checkCanVerify("*.foo.*", "http://a.b.foo.com/x/y/z", true);
+ checkCanVerify("*.foo.*", "http://oo.com", false);
+ checkCanVerify("*.foo.*", "http://f.oo.com", false);
+ checkCanVerify("*.foo.*", "http://a.f.oo.com", false);
+
+ checkCanVerify("127.0.0.1", "http://127.0.0.1", true);
+ checkCanVerify("127.0.0.1", "http://127.0.0.1/", true);
+ checkCanVerify("127.0.0.1", "http://127.0.0.1/x/y/z", true);
+ checkCanVerify("*.0.0.1", "http://127.0.0.1/abc", true);
+ checkCanVerify("127.*.0.1", "http://127.0.0.1/abc", true);
+ checkCanVerify("127.0.*.1", "http://127.0.0.1/abc", true);
+ checkCanVerify("127.0.0.*", "http://127.0.0.1/abc", true);
+ checkCanVerify("127.*.1", "http://127.0.0.1/abc", true);
+ checkCanVerify("*.0.1", "http://127.0.0.1/abc", true);
+ checkCanVerify("127.0.*", "http://127.0.0.1/abc", true);
+ checkCanVerify("*", "http://127.0.0.1/abc", true);
+ checkCanVerify("127.0.0.2", "http://127.0.0.1", false);
+ checkCanVerify("127.0.2.1", "http://127.0.0.1", false);
+ checkCanVerify("127.2.0.1", "http://127.0.0.1", false);
+ checkCanVerify("222.0.0.1", "http://127.0.0.1", false);
+
+ checkCanVerify("", "http://foo.com", true);
+ checkCanVerify("", "http://aaa.bbb.net/xyz", true);
+ checkCanVerify("", "https://127.0.0.1/abc", true);
+
+ checkCanVerify("aaa.bbb.com,xxx.yyy.com, *.jjj.net", "http://aaa.bbb.com/m", true);
+ checkCanVerify("aaa.bbb.com, xxx.yyy.com,*.jjj.net", "http://xxx.yyy.com/n", true);
+ checkCanVerify("aaa.bbb.com,xxx.yyy.com, *.jjj.net", "http://www.jjj.net/o", true);
+ }
+
+ private static void checkCanVerify (String whitelist, String url, boolean expectedToPass)
+ throws MalformedURLException
+ {
+ List<String> w = Arrays.asList(StringUtil.parseStringArray(whitelist));
+ URL u = new URL(url);
+ boolean passed;
+
+ try {
+ HostWhitelist.verify(w, u);
+ passed = true;
+ } catch (MalformedURLException e) {
+ passed = false;
+ }
+
+ assertEquals("with whitelist '" + whitelist + "' and URL '" + url + "'",
+ expectedToPass, passed);
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import org.junit.Test;
+
+import static com.threerings.getdown.util.StringUtil.couldBeValidUrl;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link StringUtil}.
+ */
+public class StringUtilTest
+{
+ @Test public void testCouldBeValidUrl ()
+ {
+ assertTrue(couldBeValidUrl("http://www.foo.com/"));
+ assertTrue(couldBeValidUrl("http://www.foo.com/A-B-C/1_2_3/~bar/q.jsp?x=u+i&y=2;3;4#baz%20baz"));
+ assertTrue(couldBeValidUrl("https://user:secret@www.foo.com/"));
+
+ assertFalse(couldBeValidUrl("http://www.foo.com & echo hello"));
+ assertFalse(couldBeValidUrl("http://www.foo.com\""));
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class VersionUtilTest {
+
+ @Test
+ public void shouldParseJavaVersion ()
+ {
+ long version = VersionUtil.parseJavaVersion(
+ "(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(_\\d+)?)?)?", "1.8.0_152");
+ assertEquals(1_080_152, version);
+ }
+
+ @Test
+ public void shouldParseJavaVersion8 ()
+ {
+ long version = VersionUtil.parseJavaVersion(
+ "(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(_\\d+)?)?)?", "1.8");
+ assertEquals(1_080_000, version);
+ }
+
+ @Test
+ public void shouldParseJavaVersion9 ()
+ {
+ long version = VersionUtil.parseJavaVersion(
+ "(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(_\\d+)?)?)?", "9");
+ assertEquals(9_000_000, version);
+ }
+
+ @Test
+ public void shouldParseJavaVersion10 ()
+ {
+ long version = VersionUtil.parseJavaVersion(
+ "(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(_\\d+)?)?)?", "10");
+ assertEquals(10_000_000, version);
+ }
+
+ @Test
+ public void shouldParseJavaRuntimeVersion ()
+ {
+ long version = VersionUtil.parseJavaVersion(
+ "(\\d+)\\.(\\d+)\\.(\\d+)(_\\d+)?(-b\\d+)?", "1.8.0_131-b11");
+ assertEquals(108_013_111, version);
+ }
+}
--- /dev/null
+mock-maker-inline
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>getdown-launcher</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/<project>=UTF-8
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.7
--- /dev/null
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown</artifactId>
+ <version>1.8.3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>getdown-launcher</artifactId>
+ <packaging>jar</packaging>
+ <name>Getdown Launcher</name>
+ <description>The Getdown app updater/launcher</description>
+
+ <repositories>
+ <repository>
+ <id>lib-repo</id>
+ <url>file://${basedir}/../lib</url>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.samskivert</groupId>
+ <artifactId>samskivert</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>jregistrykey</groupId>
+ <artifactId>jregistrykey</artifactId>
+ <version>1.0</version>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.wvengen</groupId>
+ <artifactId>proguard-maven-plugin</artifactId>
+ <version>2.0.14</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals><goal>proguard</goal></goals>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>net.sf.proguard</groupId>
+ <artifactId>proguard-base</artifactId>
+ <version>6.0.3</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <proguardVersion>6.0.3</proguardVersion>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ <outjar>${project.build.finalName}.jar</outjar>
+ <injar>${project.build.finalName}.jar</injar>
+ <assembly>
+ <inclusions>
+ <inclusion>
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown-core</artifactId>
+ </inclusion>
+ <inclusion>
+ <groupId>com.samskivert</groupId>
+ <artifactId>samskivert</artifactId>
+ <filter>
+ !**/*.java,
+ !**/swing/RuntimeAdjust*,
+ !**/swing/util/ButtonUtil*,
+ !**/util/CalendarUtil*,
+ !**/util/Calendars*,
+ !**/util/Log4JLogger*,
+ !**/util/PrefsConfig*,
+ !**/util/SignalUtil*,
+ com/samskivert/Log.class,
+ **/samskivert/io/**,
+ **/samskivert/swing/**,
+ **/samskivert/text/**,
+ **/samskivert/util/**
+ </filter>
+ </inclusion>
+ <inclusion>
+ <groupId>jregistrykey</groupId>
+ <artifactId>jregistrykey</artifactId>
+ </inclusion>
+ </inclusions>
+ </assembly>
+ <obfuscate>true</obfuscate>
+ <options>
+ <option>-keep public class com.threerings.getdown.** { *; }</option>
+ <option>-keep public class ca.beq.util.win32.registry.** { *; }</option>
+ <option>-keepattributes Exceptions, InnerClasses, Signature</option>
+ </options>
+ <libs>
+ <lib>${rt.jar.path}</lib>
+ </libs>
+ <addMavenDescriptor>false</addMavenDescriptor>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>com.threerings.getdown.launcher.GetdownApp</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Permissions>all-permissions</Permissions>
+ <Application-Name>Getdown</Application-Name>
+ <Codebase>*</Codebase>
+ <Application-Library-Allowable-Codebase>*</Application-Library-Allowable-Codebase>
+ <Caller-Allowable-Codebase>*</Caller-Allowable-Codebase>
+ <Trusted-Library>true</Trusted-Library>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <!-- finagling to find rt.jar -->
+ <profile>
+ <id>non-mac-jre</id>
+ <activation>
+ <file><exists>${java.home}/../lib/rt.jar</exists></file>
+ </activation>
+ <properties>
+ <rt.jar.path>${java.home}/../lib/rt.jar</rt.jar.path>
+ </properties>
+ </profile>
+ <profile>
+ <id>non-mac-jdk</id>
+ <activation>
+ <file><exists>${java.home}/lib/rt.jar</exists></file>
+ </activation>
+ <properties>
+ <rt.jar.path>${java.home}/lib/rt.jar</rt.jar.path>
+ </properties>
+ </profile>
+ <profile>
+ <id>java-9-jdk</id>
+ <activation>
+ <file><exists>${java.home}/jmods/java.base.jmod</exists></file>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.wvengen</groupId>
+ <artifactId>proguard-maven-plugin</artifactId>
+ <configuration>
+ <libs>
+ <lib>${java.home}/jmods/java.base.jmod</lib>
+ <lib>${java.home}/jmods/java.desktop.jmod</lib>
+ <lib>${java.home}/jmods/java.logging.jmod</lib>
+ <lib>${java.home}/jmods/jdk.jsobject.jmod</lib>
+ </libs>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import com.samskivert.swing.GroupLayout;
+import com.samskivert.swing.Spacer;
+import com.samskivert.swing.VGroupLayout;
+
+import com.threerings.getdown.util.MessageUtil;
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Displays a confirmation that the user wants to abort installation.
+ */
+public final class AbortPanel extends JFrame
+ implements ActionListener
+{
+ public AbortPanel (Getdown getdown, ResourceBundle msgs)
+ {
+ _getdown = getdown;
+ _msgs = msgs;
+
+ setLayout(new VGroupLayout());
+ setResizable(false);
+ setTitle(get("m.abort_title"));
+
+ JLabel message = new JLabel(get("m.abort_confirm"));
+ message.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ add(message);
+ add(new Spacer(5, 5));
+
+ JPanel row = GroupLayout.makeButtonBox(GroupLayout.CENTER);
+ JButton button;
+ row.add(button = new JButton(get("m.abort_ok")));
+ button.setActionCommand("ok");
+ button.addActionListener(this);
+ row.add(button = new JButton(get("m.abort_cancel")));
+ button.setActionCommand("cancel");
+ button.addActionListener(this);
+ getRootPane().setDefaultButton(button);
+ add(row);
+ }
+
+ // documentation inherited
+ @Override
+ public Dimension getPreferredSize ()
+ {
+ // this is annoyingly hardcoded, but we can't just force the width
+ // or the JLabel will claim a bogus height thinking it can lay its
+ // text out all on one line which will booch the whole UI's
+ // preferred size
+ return new Dimension(300, 200);
+ }
+
+ // documentation inherited from interface
+ public void actionPerformed (ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("ok")) {
+ System.exit(0);
+ } else {
+ setVisible(false);
+ }
+ }
+
+ /** Used to look up localized messages. */
+ protected String get (String key)
+ {
+ // if this string is tainted, we don't translate it, instead we
+ // simply remove the taint character and return it to the caller
+ if (MessageUtil.isTainted(key)) {
+ return MessageUtil.untaint(key);
+ }
+ try {
+ return _msgs.getString(key);
+ } catch (MissingResourceException mre) {
+ log.warning("Missing translation message '" + key + "'.");
+ return key;
+ }
+ }
+
+ protected Getdown _getdown;
+ protected ResourceBundle _msgs;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+
+import javax.imageio.ImageIO;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLayeredPane;
+
+import com.samskivert.swing.util.SwingUtil;
+import com.threerings.getdown.data.*;
+import com.threerings.getdown.data.Application.UpdateInterface.Step;
+import com.threerings.getdown.net.Downloader;
+import com.threerings.getdown.net.HTTPDownloader;
+import com.threerings.getdown.tools.Patcher;
+import com.threerings.getdown.util.*;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Manages the main control for the Getdown application updater and deployment system.
+ */
+public abstract class Getdown extends Thread
+ implements Application.StatusDisplay, RotatingBackgrounds.ImageLoader
+{
+ public Getdown (EnvConfig envc)
+ {
+ super("Getdown");
+ try {
+ // If the silent property exists, install without bringing up any gui. If it equals
+ // launch, start the application after installing. Otherwise, just install and exit.
+ _silent = SysProps.silent();
+ if (_silent) {
+ _launchInSilent = SysProps.launchInSilent();
+ _noUpdate = SysProps.noUpdate();
+ }
+ // If we're running in a headless environment and have not otherwise customized
+ // silence, operate without a UI and do launch the app.
+ if (!_silent && GraphicsEnvironment.isHeadless()) {
+ log.info("Running in headless JVM, will attempt to operate without UI.");
+ _silent = true;
+ _launchInSilent = true;
+ }
+ _delay = SysProps.startDelay();
+ } catch (SecurityException se) {
+ // don't freak out, just assume non-silent and no delay; we're probably already
+ // recovering from a security failure
+ }
+ try {
+ _msgs = ResourceBundle.getBundle("com.threerings.getdown.messages");
+ } catch (Exception e) {
+ // welcome to hell, where java can't cope with a classpath that contains jars that live
+ // in a directory that contains a !, at least the same bug happens on all platforms
+ String dir = envc.appDir.toString();
+ if (dir.equals(".")) {
+ dir = System.getProperty("user.dir");
+ }
+ String errmsg = "The directory in which this application is installed:\n" + dir +
+ "\nis invalid (" + e.getMessage() + "). If the full path to the app directory " +
+ "contains the '!' character, this will trigger this error.";
+ fail(errmsg);
+ }
+ _app = new Application(envc);
+ _startup = System.currentTimeMillis();
+ }
+
+ /**
+ * Returns true if there are pending new resources, waiting to be installed.
+ */
+ public boolean isUpdateAvailable ()
+ {
+ return _readyToInstall && !_toInstallResources.isEmpty();
+ }
+
+ /**
+ * Installs the currently pending new resources.
+ */
+ public void install () throws IOException
+ {
+ if (SysProps.noInstall()) {
+ log.info("Skipping install due to 'no_install' sysprop.");
+ } else if (_readyToInstall) {
+ log.info("Installing " + _toInstallResources.size() + " downloaded resources:");
+ for (Resource resource : _toInstallResources) {
+ resource.install(true);
+ }
+ _toInstallResources.clear();
+ _readyToInstall = false;
+ log.info("Install completed.");
+ } else {
+ log.info("Nothing to install.");
+ }
+ }
+
+ @Override
+ public void run ()
+ {
+ // if we have no messages, just bail because we're hosed; the error message will be
+ // displayed to the user already
+ if (_msgs == null) {
+ return;
+ }
+
+ log.info("Getdown starting", "version", Build.version(), "built", Build.time());
+
+ // determine whether or not we can write to our install directory
+ File instdir = _app.getLocalPath("");
+ if (!instdir.canWrite()) {
+ String path = instdir.getPath();
+ if (path.equals(".")) {
+ path = System.getProperty("user.dir");
+ }
+ fail(MessageUtil.tcompose("m.readonly_error", path));
+ return;
+ }
+
+ try {
+ _dead = false;
+ // if we fail to detect a proxy, but we're allowed to run offline, then go ahead and
+ // run the app anyway because we're prepared to cope with not being able to update
+ if (detectProxy() || _app.allowOffline()) {
+ getdown();
+ } else if (_silent) {
+ log.warning("Need a proxy, but we don't want to bother anyone. Exiting.");
+ } else {
+ // create a panel they can use to configure the proxy settings
+ _container = createContainer();
+ // allow them to close the window to abort the proxy configuration
+ _dead = true;
+ configureContainer();
+ ProxyPanel panel = new ProxyPanel(this, _msgs);
+ // set up any existing configured proxy
+ String[] hostPort = ProxyUtil.loadProxy(_app);
+ panel.setProxy(hostPort[0], hostPort[1]);
+ _container.add(panel, BorderLayout.CENTER);
+ showContainer();
+ }
+
+ } catch (Exception e) {
+ log.warning("run() failed.", e);
+ String msg = e.getMessage();
+ if (msg == null) {
+ msg = MessageUtil.compose("m.unknown_error", _ifc.installError);
+ } else if (!msg.startsWith("m.")) {
+ // try to do something sensible based on the type of error
+ if (e instanceof FileNotFoundException) {
+ msg = MessageUtil.compose(
+ "m.missing_resource", MessageUtil.taint(msg), _ifc.installError);
+ } else {
+ msg = MessageUtil.compose(
+ "m.init_error", MessageUtil.taint(msg), _ifc.installError);
+ }
+ }
+ fail(msg);
+ }
+ }
+
+ /**
+ * Configures our proxy settings (called by {@link ProxyPanel}) and fires up the launcher.
+ */
+ public void configProxy (String host, String port, String username, String password)
+ {
+ log.info("User configured proxy", "host", host, "port", port);
+
+ if (!StringUtil.isBlank(host)) {
+ ProxyUtil.configProxy(_app, host, port, username, password);
+ }
+
+ // clear out our UI
+ disposeContainer();
+ _container = null;
+
+ // fire up a new thread
+ new Thread(this).start();
+ }
+
+ protected boolean detectProxy () {
+ if (ProxyUtil.autoDetectProxy(_app)) {
+ return true;
+ }
+
+ // otherwise see if we actually need a proxy; first we have to initialize our application
+ // to get some sort of interface configuration and the appbase URL
+ log.info("Checking whether we need to use a proxy...");
+ try {
+ readConfig(true);
+ } catch (IOException ioe) {
+ // no worries
+ }
+ updateStatus("m.detecting_proxy");
+ if (!ProxyUtil.canLoadWithoutProxy(_app.getConfigResource().getRemote())) {
+ return false;
+ }
+
+ // we got through, so we appear not to require a proxy; make a blank proxy config so that
+ // we don't go through this whole detection process again next time
+ log.info("No proxy appears to be needed.");
+ ProxyUtil.saveProxy(_app, null, null);
+ return true;
+ }
+
+ protected void readConfig (boolean preloads) throws IOException {
+ Config config = _app.init(true);
+ if (preloads) doPredownloads(_app.getResources());
+ _ifc = new Application.UpdateInterface(config);
+ }
+
+ /**
+ * Downloads and installs (without verifying) any resources that are marked with a
+ * {@code PRELOAD} attribute.
+ * @param resources the full set of resources from the application (the predownloads will be
+ * extracted from it).
+ */
+ protected void doPredownloads (Collection<Resource> resources) {
+ List<Resource> predownloads = new ArrayList<>();
+ for (Resource rsrc : resources) {
+ if (rsrc.shouldPredownload() && !rsrc.getLocal().exists()) {
+ predownloads.add(rsrc);
+ }
+ }
+
+ try {
+ download(predownloads);
+ for (Resource rsrc : predownloads) {
+ rsrc.install(false); // install but don't validate yet
+ }
+ } catch (IOException ioe) {
+ log.warning("Failed to predownload resources. Continuing...", ioe);
+ }
+ }
+
+ /**
+ * Does the actual application validation, update and launching business.
+ */
+ protected void getdown ()
+ {
+ try {
+ // first parses our application deployment file
+ try {
+ readConfig(true);
+ } catch (IOException ioe) {
+ log.warning("Failed to initialize: " + ioe);
+ _app.attemptRecovery(this);
+ // and re-initalize
+ readConfig(true);
+ // and force our UI to be recreated with the updated info
+ createInterfaceAsync(true);
+ }
+ if (!_noUpdate && !_app.lockForUpdates()) {
+ throw new MultipleGetdownRunning();
+ }
+
+ // Update the config modtime so a sleeping getdown will notice the change.
+ File config = _app.getLocalPath(Application.CONFIG_FILE);
+ if (!config.setLastModified(System.currentTimeMillis())) {
+ log.warning("Unable to set modtime on config file, will be unable to check for " +
+ "another instance of getdown running while this one waits.");
+ }
+ if (_delay > 0) {
+ // don't hold the lock while waiting, let another getdown proceed if it starts.
+ _app.releaseLock();
+ // Store the config modtime before waiting the delay amount of time
+ long lastConfigModtime = config.lastModified();
+ log.info("Waiting " + _delay + " minutes before beginning actual work.");
+ Thread.sleep(_delay * 60 * 1000);
+ if (lastConfigModtime < config.lastModified()) {
+ log.warning("getdown.txt was modified while getdown was waiting.");
+ throw new MultipleGetdownRunning();
+ }
+ }
+
+ // if no_update was specified, directly start the app without updating
+ if (_noUpdate) {
+ log.info("Launching without update!");
+ launch();
+ return;
+ }
+
+ // we create this tracking counter here so that we properly note the first time through
+ // the update process whether we previously had validated resources (which means this
+ // is not a first time install); we may, in the course of updating, wipe out our
+ // validation markers and revalidate which would make us think we were doing a fresh
+ // install if we didn't specifically remember that we had validated resources the first
+ // time through
+ int[] alreadyValid = new int[1];
+
+ // we'll keep track of all the resources we unpack
+ Set<Resource> unpacked = new HashSet<>();
+
+ _toInstallResources = new HashSet<>();
+ _readyToInstall = false;
+
+ // setStep(Step.START);
+ for (int ii = 0; ii < MAX_LOOPS; ii++) {
+ // make sure we have the desired version and that the metadata files are valid...
+ setStep(Step.VERIFY_METADATA);
+ setStatusAsync("m.validating", -1, -1L, false);
+ if (_app.verifyMetadata(this)) {
+ log.info("Application requires update.");
+ update();
+ // loop back again and reverify the metadata
+ continue;
+ }
+
+ // now verify (and download) our resources...
+ setStep(Step.VERIFY_RESOURCES);
+ setStatusAsync("m.validating", -1, -1L, false);
+ Set<Resource> toDownload = new HashSet<>();
+ _app.verifyResources(_progobs, alreadyValid, unpacked,
+ _toInstallResources, toDownload);
+
+ if (toDownload.size() > 0) {
+ // we have resources to download, also note them as to-be-installed
+ for (Resource r : toDownload) {
+ if (!_toInstallResources.contains(r)) {
+ _toInstallResources.add(r);
+ }
+ }
+
+ try {
+ // if any of our resources have already been marked valid this is not a
+ // first time install and we don't want to enable tracking
+ _enableTracking = (alreadyValid[0] == 0);
+ reportTrackingEvent("app_start", -1);
+
+ // redownload any that are corrupt or invalid...
+ log.info(toDownload.size() + " of " + _app.getAllActiveResources().size() +
+ " rsrcs require update (" + alreadyValid[0] + " assumed valid).");
+ setStep(Step.REDOWNLOAD_RESOURCES);
+ download(toDownload);
+
+ reportTrackingEvent("app_complete", -1);
+
+ } finally {
+ _enableTracking = false;
+ }
+
+ // now we'll loop back and try it all again
+ continue;
+ }
+
+ // if we aren't running in a JVM that meets our version requirements, either
+ // complain or attempt to download and install the appropriate version
+ if (!_app.haveValidJavaVersion()) {
+ // download and install the necessary version of java, then loop back again and
+ // reverify everything; if we can't download java; we'll throw an exception
+ log.info("Attempting to update Java VM...");
+ setStep(Step.UPDATE_JAVA);
+ _enableTracking = true; // always track JVM downloads
+ try {
+ updateJava();
+ } finally {
+ _enableTracking = false;
+ }
+ continue;
+ }
+
+ // if we were downloaded in full from another service (say, Steam), we may
+ // not have unpacked all of our resources yet
+ if (Boolean.getBoolean("check_unpacked")) {
+ File ufile = _app.getLocalPath("unpacked.dat");
+ long version = -1;
+ long aversion = _app.getVersion();
+ if (!ufile.exists()) {
+ ufile.createNewFile();
+ } else {
+ version = VersionUtil.readVersion(ufile);
+ }
+
+ if (version < aversion) {
+ log.info("Performing unpack", "version", version, "aversion", aversion);
+ setStep(Step.UNPACK);
+ updateStatus("m.validating");
+ _app.unpackResources(_progobs, unpacked);
+ try {
+ VersionUtil.writeVersion(ufile, aversion);
+ } catch (IOException ioe) {
+ log.warning("Failed to update unpacked version", ioe);
+ }
+ }
+ }
+
+ // assuming we're not doing anything funny, install the update
+ _readyToInstall = true;
+ install();
+
+ // Only launch if we aren't in silent mode. Some mystery program starting out
+ // of the blue would be disconcerting.
+ if (!_silent || _launchInSilent) {
+ // And another final check for the lock. It'll already be held unless
+ // we're in silent mode.
+ _app.lockForUpdates();
+ launch();
+ }
+ return;
+ }
+
+ log.warning("Pants! We couldn't get the job done.");
+ throw new IOException("m.unable_to_repair");
+
+ } catch (Exception e) {
+ log.warning("getdown() failed.", e);
+ String msg = e.getMessage();
+ if (msg == null) {
+ msg = MessageUtil.compose("m.unknown_error", _ifc.installError);
+ } else if (!msg.startsWith("m.")) {
+ // try to do something sensible based on the type of error
+ if (e instanceof FileNotFoundException) {
+ msg = MessageUtil.compose(
+ "m.missing_resource", MessageUtil.taint(msg), _ifc.installError);
+ } else {
+ msg = MessageUtil.compose(
+ "m.init_error", MessageUtil.taint(msg), _ifc.installError);
+ }
+ }
+ // Since we're dead, clear off the 'time remaining' label along with displaying the
+ // error message
+ fail(msg);
+ _app.releaseLock();
+ }
+ }
+
+ // documentation inherited from interface
+ @Override
+ public void updateStatus (String message)
+ {
+ setStatusAsync(message, -1, -1L, true);
+ }
+
+ /**
+ * Load the image at the path. Before trying the exact path/file specified we will look to see
+ * if we can find a localized version by sticking a {@code _<language>} in front of the "." in
+ * the filename.
+ */
+ @Override
+ public BufferedImage loadImage (String path)
+ {
+ if (StringUtil.isBlank(path)) {
+ return null;
+ }
+
+ File imgpath = null;
+ try {
+ // First try for a localized image.
+ String localeStr = Locale.getDefault().getLanguage();
+ imgpath = _app.getLocalPath(path.replace(".", "_" + localeStr + "."));
+ return ImageIO.read(imgpath);
+ } catch (IOException ioe) {
+ // No biggie, we'll try the generic one.
+ }
+
+ // If that didn't work, try a generic one.
+ try {
+ imgpath = _app.getLocalPath(path);
+ return ImageIO.read(imgpath);
+ } catch (IOException ioe2) {
+ log.warning("Failed to load image", "path", imgpath, "error", ioe2);
+ return null;
+ }
+ }
+
+ /**
+ * Downloads and installs an Java VM bundled with the application. This is called if we are not
+ * running with the necessary Java version.
+ */
+ protected void updateJava ()
+ throws IOException
+ {
+ Resource vmjar = _app.getJavaVMResource();
+ if (vmjar == null) {
+ throw new IOException("m.java_download_failed");
+ }
+
+ reportTrackingEvent("jvm_start", -1);
+
+ updateStatus("m.downloading_java");
+ List<Resource> list = new ArrayList<>();
+ list.add(vmjar);
+ download(list);
+
+ reportTrackingEvent("jvm_unpack", -1);
+
+ updateStatus("m.unpacking_java");
+ vmjar.install(true);
+
+ // these only run on non-Windows platforms, so we use Unix file separators
+ String localJavaDir = LaunchUtil.LOCAL_JAVA_DIR + "/";
+ FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "bin/java"));
+ FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "lib/jspawnhelper"));
+ FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "lib/amd64/jspawnhelper"));
+
+ // lastly regenerate the .jsa dump file that helps Java to start up faster
+ String vmpath = LaunchUtil.getJVMPath(_app.getLocalPath(""));
+ try {
+ log.info("Regenerating classes.jsa for " + vmpath + "...");
+ Runtime.getRuntime().exec(vmpath + " -Xshare:dump");
+ } catch (Exception e) {
+ log.warning("Failed to regenerate .jsa dump file", "error", e);
+ }
+
+ reportTrackingEvent("jvm_complete", -1);
+ }
+
+ /**
+ * Called if the application is determined to be of an old version.
+ */
+ protected void update ()
+ throws IOException
+ {
+ // first clear all validation markers
+ _app.clearValidationMarkers();
+
+ // attempt to download the patch files
+ Resource patch = _app.getPatchResource(null);
+ if (patch != null) {
+ List<Resource> list = new ArrayList<>();
+ list.add(patch);
+
+ // add the auxiliary group patch files for activated groups
+ for (Application.AuxGroup aux : _app.getAuxGroups()) {
+ if (_app.isAuxGroupActive(aux.name)) {
+ patch = _app.getPatchResource(aux.name);
+ if (patch != null) {
+ list.add(patch);
+ }
+ }
+ }
+
+ // show the patch notes button, if applicable
+ if (!StringUtil.isBlank(_ifc.patchNotesUrl)) {
+ createInterfaceAsync(false);
+ EventQueue.invokeLater(new Runnable() {
+ public void run () {
+ _patchNotes.setVisible(true);
+ }
+ });
+ }
+
+ // download the patch files...
+ setStep(Step.DOWNLOAD);
+ download(list);
+
+ // and apply them...
+ setStep(Step.PATCH);
+ updateStatus("m.patching");
+
+ long[] sizes = new long[list.size()];
+ Arrays.fill(sizes, 1L);
+ ProgressAggregator pragg = new ProgressAggregator(_progobs, sizes);
+ int ii = 0; for (Resource prsrc : list) {
+ ProgressObserver pobs = pragg.startElement(ii++);
+ try {
+ // install the patch file (renaming them from _new)
+ prsrc.install(false);
+ // now apply the patch
+ Patcher patcher = new Patcher();
+ patcher.patch(prsrc.getLocal().getParentFile(), prsrc.getLocal(), pobs);
+ } catch (Exception e) {
+ log.warning("Failed to apply patch", "prsrc", prsrc, e);
+ }
+
+ // clean up the patch file
+ if (!FileUtil.deleteHarder(prsrc.getLocal())) {
+ log.warning("Failed to delete '" + prsrc + "'.");
+ }
+ }
+ }
+
+ // if the patch resource is null, that means something was booched in the application, so
+ // we skip the patching process but update the metadata which will result in a "brute
+ // force" upgrade
+
+ // finally update our metadata files...
+ _app.updateMetadata();
+ // ...and reinitialize the application
+ readConfig(false);
+ }
+
+ /**
+ * Called if the application is determined to require resource downloads.
+ */
+ protected void download (Collection<Resource> resources)
+ throws IOException
+ {
+ // create our user interface
+ createInterfaceAsync(false);
+
+ Downloader dl = new HTTPDownloader(_app.proxy) {
+ @Override protected void resolvingDownloads () {
+ updateStatus("m.resolving");
+ }
+
+ @Override protected void downloadProgress (int percent, long remaining) {
+ // check for another getdown running at 0 and every 10% after that
+ if (_lastCheck == -1 || percent >= _lastCheck + 10) {
+ if (_delay > 0) {
+ // stop the presses if something else is holding the lock
+ boolean locked = _app.lockForUpdates();
+ _app.releaseLock();
+ if (locked) abort();
+ }
+ _lastCheck = percent;
+ }
+ setStatusAsync("m.downloading", stepToGlobalPercent(percent), remaining, true);
+ if (percent > 0) {
+ reportTrackingEvent("progress", percent);
+ }
+ }
+
+ @Override protected void downloadFailed (Resource rsrc, Exception e) {
+ updateStatus(MessageUtil.tcompose("m.failure", e.getMessage()));
+ log.warning("Download failed", "rsrc", rsrc, e);
+ }
+
+ /** The last percentage at which we checked for another getdown running, or -1 for not
+ * having checked at all. */
+ protected int _lastCheck = -1;
+ };
+ if (!dl.download(resources, _app.maxConcurrentDownloads())) {
+ // if we aborted due to detecting another getdown running, we want to report here
+ throw new MultipleGetdownRunning();
+ }
+ }
+
+ /**
+ * Called to launch the application if everything is determined to be ready to go.
+ */
+ protected void launch ()
+ {
+ setStep(Step.LAUNCH);
+ setStatusAsync("m.launching", stepToGlobalPercent(100), -1L, false);
+
+ try {
+ if (invokeDirect()) {
+ // we want to close the Getdown window, as the app is launching
+ disposeContainer();
+ _app.releaseLock();
+ _app.invokeDirect();
+
+ } else {
+ Process proc;
+ if (_app.hasOptimumJvmArgs()) {
+ // if we have "optimum" arguments, we want to try launching with them first
+ proc = _app.createProcess(true);
+
+ long fallback = System.currentTimeMillis() + FALLBACK_CHECK_TIME;
+ boolean error = false;
+ while (fallback > System.currentTimeMillis()) {
+ try {
+ error = proc.exitValue() != 0;
+ break;
+ } catch (IllegalThreadStateException e) {
+ Thread.yield();
+ }
+ }
+
+ if (error) {
+ log.info("Failed to launch with optimum arguments; falling back.");
+ proc = _app.createProcess(false);
+ }
+ } else {
+ proc = _app.createProcess(false);
+ }
+
+ // close standard in to avoid choking standard out of the launched process
+ proc.getInputStream().close();
+ // close standard out, since we're not going to write to anything to it anyway
+ proc.getOutputStream().close();
+
+ // on Windows 98 and ME we need to stick around and read the output of stderr lest
+ // the process fill its output buffer and choke, yay!
+ final InputStream stderr = proc.getErrorStream();
+ if (LaunchUtil.mustMonitorChildren()) {
+ // close our window if it's around
+ disposeContainer();
+ _container = null;
+ copyStream(stderr, System.err);
+ log.info("Process exited: " + proc.waitFor());
+
+ } else {
+ // spawn a daemon thread that will catch the early bits of stderr in case the
+ // launch fails
+ Thread t = new Thread() {
+ @Override public void run () {
+ copyStream(stderr, System.err);
+ }
+ };
+ t.setDaemon(true);
+ t.start();
+ }
+ }
+
+ // if we have a UI open and we haven't been around for at least 5 seconds (the default
+ // for min_show_seconds), don't stick a fork in ourselves straight away but give our
+ // lovely user a chance to see what we're doing
+ long uptime = System.currentTimeMillis() - _startup;
+ long minshow = _ifc.minShowSeconds * 1000L;
+ if (_container != null && uptime < minshow) {
+ try {
+ Thread.sleep(minshow - uptime);
+ } catch (Exception e) {
+ }
+ }
+
+ // pump the percent up to 100%
+ setStatusAsync(null, 100, -1L, false);
+ exit(0);
+
+ } catch (Exception e) {
+ log.warning("launch() failed.", e);
+ }
+ }
+
+ /**
+ * Creates our user interface, which we avoid doing unless we actually have to update
+ * something. NOTE: this happens on the next UI tick, not immediately.
+ *
+ * @param reinit - if the interface should be reinitialized if it already exists.
+ */
+ protected void createInterfaceAsync (final boolean reinit)
+ {
+ if (_silent || (_container != null && !reinit)) {
+ return;
+ }
+
+ EventQueue.invokeLater(new Runnable() {
+ public void run () {
+ if (_container == null || reinit) {
+ if (_container == null) {
+ _container = createContainer();
+ } else {
+ _container.removeAll();
+ }
+ configureContainer();
+ _layers = new JLayeredPane();
+ _container.add(_layers, BorderLayout.CENTER);
+ _patchNotes = new JButton(new AbstractAction(_msgs.getString("m.patch_notes")) {
+ @Override public void actionPerformed (ActionEvent event) {
+ showDocument(_ifc.patchNotesUrl);
+ }
+ });
+ _patchNotes.setFont(StatusPanel.FONT);
+ _layers.add(_patchNotes);
+ _status = new StatusPanel(_msgs);
+ _layers.add(_status);
+ initInterface();
+ }
+ showContainer();
+ }
+ });
+ }
+
+ /**
+ * Initializes the interface with the current UpdateInterface and backgrounds.
+ */
+ protected void initInterface ()
+ {
+ RotatingBackgrounds newBackgrounds = getBackground();
+ if (_background == null || newBackgrounds.getNumImages() > 0) {
+ // Leave the old _background in place if there is an old one to leave in place
+ // and the new getdown.txt didn't yield any images.
+ _background = newBackgrounds;
+ }
+ _status.init(_ifc, _background, getProgressImage());
+ Dimension size = _status.getPreferredSize();
+ _status.setSize(size);
+ _layers.setPreferredSize(size);
+
+ _patchNotes.setBounds(_ifc.patchNotes.x, _ifc.patchNotes.y,
+ _ifc.patchNotes.width, _ifc.patchNotes.height);
+ _patchNotes.setVisible(false);
+
+ // we were displaying progress while the UI wasn't up. Now that it is, whatever progress
+ // is left is scaled into a 0-100 DISPLAYED progress.
+ _uiDisplayPercent = _lastGlobalPercent;
+ _stepMinPercent = _lastGlobalPercent = 0;
+ }
+
+ protected RotatingBackgrounds getBackground ()
+ {
+ if (_ifc.rotatingBackgrounds != null) {
+ if (_ifc.backgroundImage != null) {
+ log.warning("ui.background_image and ui.rotating_background were both specified. " +
+ "The rotating images are being used.");
+ }
+ return new RotatingBackgrounds(_ifc.rotatingBackgrounds, _ifc.errorBackground,
+ Getdown.this);
+ } else if (_ifc.backgroundImage != null) {
+ return new RotatingBackgrounds(loadImage(_ifc.backgroundImage));
+ } else {
+ return new RotatingBackgrounds();
+ }
+ }
+
+ protected Image getProgressImage ()
+ {
+ return loadImage(_ifc.progressImage);
+ }
+
+ protected void handleWindowClose ()
+ {
+ if (_dead) {
+ exit(0);
+ } else {
+ if (_abort == null) {
+ _abort = new AbortPanel(Getdown.this, _msgs);
+ }
+ _abort.pack();
+ SwingUtil.centerWindow(_abort);
+ _abort.setVisible(true);
+ _abort.setState(JFrame.NORMAL);
+ _abort.requestFocus();
+ }
+ }
+
+ /**
+ * Update the status to indicate getdown has failed for the reason in <code>message</code>.
+ */
+ protected void fail (String message)
+ {
+ _dead = true;
+ setStatusAsync(message, stepToGlobalPercent(0), -1L, true);
+ }
+
+ /**
+ * Set the current step, which will be used to globalize per-step percentages.
+ */
+ protected void setStep (Step step)
+ {
+ int finalPercent = -1;
+ for (Integer perc : _ifc.stepPercentages.get(step)) {
+ if (perc > _stepMaxPercent) {
+ finalPercent = perc;
+ break;
+ }
+ }
+ if (finalPercent == -1) {
+ // we've gone backwards and this step will be ignored
+ return;
+ }
+
+ _stepMaxPercent = finalPercent;
+ _stepMinPercent = _lastGlobalPercent;
+ }
+
+ /**
+ * Convert a step percentage to the global percentage.
+ */
+ protected int stepToGlobalPercent (int percent)
+ {
+ int adjustedMaxPercent =
+ ((_stepMaxPercent - _uiDisplayPercent) * 100) / (100 - _uiDisplayPercent);
+ _lastGlobalPercent = Math.max(_lastGlobalPercent,
+ _stepMinPercent + (percent * (adjustedMaxPercent - _stepMinPercent)) / 100);
+ return _lastGlobalPercent;
+ }
+
+ /**
+ * Updates the status. NOTE: this happens on the next UI tick, not immediately.
+ */
+ protected void setStatusAsync (final String message, final int percent, final long remaining,
+ boolean createUI)
+ {
+ if (_status == null && createUI) {
+ createInterfaceAsync(false);
+ }
+
+ EventQueue.invokeLater(new Runnable() {
+ public void run () {
+ if (_status == null) {
+ if (message != null) {
+ log.info("Dropping status '" + message + "'.");
+ }
+ return;
+ }
+ if (message != null) {
+ _status.setStatus(message, _dead);
+ }
+ if (_dead) {
+ _status.setProgress(0, -1L);
+ } else if (percent >= 0) {
+ _status.setProgress(percent, remaining);
+ }
+ }
+ });
+ }
+
+ protected void reportTrackingEvent (String event, int progress)
+ {
+ if (!_enableTracking) {
+ return;
+
+ } else if (progress > 0) {
+ // we need to make sure we do the right thing if we skip over progress levels
+ do {
+ URL url = _app.getTrackingProgressURL(++_reportedProgress);
+ if (url != null) {
+ new ProgressReporter(url).start();
+ }
+ } while (_reportedProgress <= progress);
+
+ } else {
+ URL url = _app.getTrackingURL(event);
+ if (url != null) {
+ new ProgressReporter(url).start();
+ }
+ }
+ }
+
+ /**
+ * Creates the container in which our user interface will be displayed.
+ */
+ protected abstract Container createContainer ();
+
+ /**
+ * Configures the interface container based on the latest UI config.
+ */
+ protected abstract void configureContainer ();
+
+ /**
+ * Shows the container in which our user interface will be displayed.
+ */
+ protected abstract void showContainer ();
+
+ /**
+ * Disposes the container in which we have our user interface.
+ */
+ protected abstract void disposeContainer ();
+
+ /**
+ * If this method returns true we will run the application in the same JVM, otherwise we will
+ * fork off a new JVM. Some options are not supported if we do not fork off a new JVM.
+ */
+ protected boolean invokeDirect ()
+ {
+ return SysProps.direct();
+ }
+
+ /**
+ * Requests to show the document at the specified URL in a new window.
+ */
+ protected abstract void showDocument (String url);
+
+ /**
+ * Requests that Getdown exit.
+ */
+ protected abstract void exit (int exitCode);
+
+ /**
+ * Copies the supplied stream from the specified input to the specified output. Used to copy
+ * our child processes stderr and stdout to our own stderr and stdout.
+ */
+ protected static void copyStream (InputStream in, PrintStream out)
+ {
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ out.print(line);
+ out.flush();
+ }
+ } catch (IOException ioe) {
+ log.warning("Failure copying", "in", in, "out", out, "error", ioe);
+ }
+ }
+
+ /** Used to fetch a progress report URL. */
+ protected class ProgressReporter extends Thread
+ {
+ public ProgressReporter (URL url) {
+ setDaemon(true);
+ _url = url;
+ }
+
+ @Override
+ public void run () {
+ try {
+ HttpURLConnection ucon = ConnectionUtil.openHttp(_app.proxy, _url, 0, 0);
+
+ // if we have a tracking cookie configured, configure the request with it
+ if (_app.getTrackingCookieName() != null &&
+ _app.getTrackingCookieProperty() != null) {
+ String val = System.getProperty(_app.getTrackingCookieProperty());
+ if (val != null) {
+ ucon.setRequestProperty("Cookie", _app.getTrackingCookieName() + "=" + val);
+ }
+ }
+
+ // now request our tracking URL and ensure that we get a non-error response
+ ucon.connect();
+ try {
+ if (ucon.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ log.warning("Failed to report tracking event",
+ "url", _url, "rcode", ucon.getResponseCode());
+ }
+ } finally {
+ ucon.disconnect();
+ }
+
+ } catch (IOException ioe) {
+ log.warning("Failed to report tracking event", "url", _url, "error", ioe);
+ }
+ }
+
+ protected URL _url;
+ }
+
+ /** Used to pass progress on to our user interface. */
+ protected ProgressObserver _progobs = new ProgressObserver() {
+ public void progress (int percent) {
+ setStatusAsync(null, stepToGlobalPercent(percent), -1L, false);
+ }
+ };
+
+ protected Application _app;
+ protected Application.UpdateInterface _ifc = new Application.UpdateInterface(Config.EMPTY);
+
+ protected ResourceBundle _msgs;
+ protected Container _container;
+ protected JLayeredPane _layers;
+ protected StatusPanel _status;
+ protected JButton _patchNotes;
+ protected AbortPanel _abort;
+ protected RotatingBackgrounds _background;
+
+ protected boolean _dead;
+ protected boolean _silent;
+ protected boolean _launchInSilent;
+ protected boolean _noUpdate;
+ protected long _startup;
+
+ protected Set<Resource> _toInstallResources;
+ protected boolean _readyToInstall;
+
+ protected boolean _enableTracking = true;
+ protected int _reportedProgress = 0;
+
+ /** Number of minutes to wait after startup before beginning any real heavy lifting. */
+ protected int _delay;
+
+ protected int _stepMaxPercent;
+ protected int _stepMinPercent;
+ protected int _lastGlobalPercent;
+ protected int _uiDisplayPercent;
+
+ protected static final int MAX_LOOPS = 5;
+ protected static final long FALLBACK_CHECK_TIME = 1000L;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.EventQueue;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.KeyStroke;
+import javax.swing.WindowConstants;
+
+import com.samskivert.swing.util.SwingUtil;
+import com.threerings.getdown.data.EnvConfig;
+import com.threerings.getdown.data.SysProps;
+import com.threerings.getdown.util.LaunchUtil;
+import com.threerings.getdown.util.StringUtil;
+import static com.threerings.getdown.Log.log;
+
+/**
+ * The main application entry point for Getdown.
+ */
+public class GetdownApp
+{
+ /**
+ * The main entry point of the Getdown launcher application.
+ */
+ public static void main (String[] argv) {
+ try {
+ start(argv);
+ } catch (Exception e) {
+ log.warning("main() failed.", e);
+ }
+ }
+
+ /**
+ * Runs Getdown as an application, using the arguments supplie as {@code argv}.
+ * @return the {@code Getdown} instance that is running. {@link Getdown#start} will have been
+ * called on it.
+ * @throws Exception if anything goes wrong starting Getdown.
+ */
+ public static Getdown start (String[] argv) throws Exception {
+ List<EnvConfig.Note> notes = new ArrayList<>();
+ EnvConfig envc = EnvConfig.create(argv, notes);
+ if (envc == null) {
+ if (!notes.isEmpty()) for (EnvConfig.Note n : notes) System.err.println(n.message);
+ else System.err.println("Usage: java -jar getdown.jar [app_dir] [app_id] [app args]");
+ System.exit(-1);
+ }
+
+ // pipe our output into a file in the application directory
+ if (!SysProps.noLogRedir()) {
+ File logFile = new File(envc.appDir, "launcher.log");
+ try {
+ PrintStream logOut = new PrintStream(
+ new BufferedOutputStream(new FileOutputStream(logFile)), true);
+ System.setOut(logOut);
+ System.setErr(logOut);
+ } catch (IOException ioe) {
+ log.warning("Unable to redirect output to '" + logFile + "': " + ioe);
+ }
+ }
+
+ // report any notes from reading our env config, and abort if necessary
+ boolean abort = false;
+ for (EnvConfig.Note note : notes) {
+ switch (note.level) {
+ case INFO: log.info(note.message); break;
+ case WARN: log.warning(note.message); break;
+ case ERROR: log.error(note.message); abort = true; break;
+ }
+ }
+ if (abort) System.exit(-1);
+
+ // record a few things for posterity
+ log.info("------------------ VM Info ------------------");
+ log.info("-- OS Name: " + System.getProperty("os.name"));
+ log.info("-- OS Arch: " + System.getProperty("os.arch"));
+ log.info("-- OS Vers: " + System.getProperty("os.version"));
+ log.info("-- Java Vers: " + System.getProperty("java.version"));
+ log.info("-- Java Home: " + System.getProperty("java.home"));
+ log.info("-- User Name: " + System.getProperty("user.name"));
+ log.info("-- User Home: " + System.getProperty("user.home"));
+ log.info("-- Cur dir: " + System.getProperty("user.dir"));
+ log.info("---------------------------------------------");
+
+ Getdown app = new Getdown(envc) {
+ @Override
+ protected Container createContainer () {
+ // create our user interface, and display it
+ if (_frame == null) {
+ _frame = new JFrame("");
+ _frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing (WindowEvent evt) {
+ handleWindowClose();
+ }
+ });
+ // handle close on ESC
+ String cancelId = "Cancel"; // $NON-NLS-1$
+ _frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelId);
+ _frame.getRootPane().getActionMap().put(cancelId, new AbstractAction() {
+ public void actionPerformed (ActionEvent e) {
+ handleWindowClose();
+ }
+ });
+ // this cannot be called in configureContainer as it is only allowed before the
+ // frame has been displayed for the first time
+ _frame.setUndecorated(_ifc.hideDecorations);
+ _frame.setResizable(false);
+ } else {
+ _frame.getContentPane().removeAll();
+ }
+ _frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ return _frame.getContentPane();
+ }
+
+ @Override
+ protected void configureContainer () {
+ if (_frame == null) return;
+
+ _frame.setTitle(_ifc.name);
+
+ try {
+ _frame.setBackground(new Color(_ifc.background, true));
+ } catch (Exception e) {
+ log.warning("Failed to set background", "bg", _ifc.background, e);
+ }
+
+ if (_ifc.iconImages != null) {
+ ArrayList<Image> icons = new ArrayList<>();
+ for (String path : _ifc.iconImages) {
+ Image img = loadImage(path);
+ if (img == null) {
+ log.warning("Error loading icon image", "path", path);
+ } else {
+ icons.add(img);
+ }
+ }
+ if (icons.isEmpty()) {
+ log.warning("Failed to load any icons", "iconImages", _ifc.iconImages);
+ } else {
+ _frame.setIconImages(icons);
+ }
+ }
+ }
+
+ @Override
+ protected void showContainer () {
+ if (_frame != null) {
+ _frame.pack();
+ SwingUtil.centerWindow(_frame);
+ _frame.setVisible(true);
+ }
+ }
+
+ @Override
+ protected void disposeContainer () {
+ if (_frame != null) {
+ _frame.dispose();
+ _frame = null;
+ }
+ }
+
+ @Override
+ protected void showDocument (String url) {
+ if (!StringUtil.couldBeValidUrl(url)) {
+ // command injection would be possible if we allowed e.g. spaces and double quotes
+ log.warning("Invalid document URL.", "url", url);
+ return;
+ }
+ String[] cmdarray;
+ if (LaunchUtil.isWindows()) {
+ String osName = System.getProperty("os.name", "");
+ if (osName.indexOf("9") != -1 || osName.indexOf("Me") != -1) {
+ cmdarray = new String[] {
+ "command.com", "/c", "start", "\"" + url + "\"" };
+ } else {
+ cmdarray = new String[] {
+ "cmd.exe", "/c", "start", "\"\"", "\"" + url + "\"" };
+ }
+ } else if (LaunchUtil.isMacOS()) {
+ cmdarray = new String[] { "open", url };
+ } else { // Linux, Solaris, etc.
+ cmdarray = new String[] { "firefox", url };
+ }
+ try {
+ Runtime.getRuntime().exec(cmdarray);
+ } catch (Exception e) {
+ log.warning("Failed to open browser.", "cmdarray", cmdarray, e);
+ }
+ }
+
+ @Override
+ protected void exit (int exitCode) {
+ // if we're running the app in the same JVM, don't call System.exit, but do
+ // make double sure that the download window is closed.
+ if (invokeDirect()) {
+ disposeContainer();
+ } else {
+ System.exit(exitCode);
+ }
+ }
+
+ @Override
+ protected void fail (String message) {
+ super.fail(message);
+ // super.fail causes the UI to be created (if needed) on the next UI tick, so we
+ // want to wait until that happens before we attempt to redecorate the window
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ // if the frame was set to be undecorated, make window decoration available
+ // to allow the user to close the window
+ if (_frame != null && _frame.isUndecorated()) {
+ _frame.dispose();
+ Color bg = _frame.getBackground();
+ if (bg != null && bg.getAlpha() < 255) {
+ // decorated windows do not allow alpha backgrounds
+ _frame.setBackground(
+ new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));
+ }
+ _frame.setUndecorated(false);
+ showContainer();
+ }
+ }
+ });
+ }
+
+ protected JFrame _frame;
+ };
+ app.start();
+ return app;
+ }
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.io.IOException;
+
+/**
+ * Thrown when it's detected that multiple instances of the same getdown installer are running.
+ */
+public class MultipleGetdownRunning extends IOException
+{
+ public MultipleGetdownRunning ()
+ {
+ super("m.another_getdown_running");
+ }
+
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+
+import com.samskivert.swing.GroupLayout;
+import com.samskivert.swing.Spacer;
+import com.samskivert.swing.VGroupLayout;
+import com.threerings.getdown.util.MessageUtil;
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Displays an interface with which the user can configure their proxy
+ * settings.
+ */
+public final class ProxyPanel extends JPanel implements ActionListener
+{
+ public ProxyPanel (Getdown getdown, ResourceBundle msgs)
+ {
+ _getdown = getdown;
+ _msgs = msgs;
+
+ setLayout(new VGroupLayout());
+ setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ add(new SaneLabelField(get("m.configure_proxy")));
+ add(new Spacer(5, 5));
+
+ JPanel row = new JPanel(new GridLayout());
+ row.add(new SaneLabelField(get("m.proxy_host")), BorderLayout.WEST);
+ row.add(_host = new SaneTextField());
+ add(row);
+
+ row = new JPanel(new GridLayout());
+ row.add(new SaneLabelField(get("m.proxy_port")), BorderLayout.WEST);
+ row.add(_port = new SaneTextField());
+ add(row);
+
+ add(new Spacer(5, 5));
+
+ row = new JPanel(new GridLayout());
+ row.add(new SaneLabelField(get("m.proxy_auth_required")), BorderLayout.WEST);
+ _useAuth = new JCheckBox();
+ row.add(_useAuth);
+ add(row);
+
+ row = new JPanel(new GridLayout());
+ row.add(new SaneLabelField(get("m.proxy_username")), BorderLayout.WEST);
+ _username = new SaneTextField();
+ _username.setEnabled(false);
+ row.add(_username);
+ add(row);
+
+ row = new JPanel(new GridLayout());
+ row.add(new SaneLabelField(get("m.proxy_password")), BorderLayout.WEST);
+ _password = new SanePasswordField();
+ _password.setEnabled(false);
+ row.add(_password);
+ add(row);
+
+ _useAuth.addItemListener(new ItemListener() {
+ @Override public void itemStateChanged (ItemEvent event) {
+ boolean selected = (event.getStateChange() == ItemEvent.SELECTED);
+ _username.setEnabled(selected);
+ _password.setEnabled(selected);
+ }
+ });
+
+ add(new Spacer(5, 5));
+
+ row = GroupLayout.makeButtonBox(GroupLayout.CENTER);
+ JButton button;
+ row.add(button = new JButton(get("m.proxy_ok")));
+ button.setActionCommand("ok");
+ button.addActionListener(this);
+ row.add(button = new JButton(get("m.proxy_cancel")));
+ button.setActionCommand("cancel");
+ button.addActionListener(this);
+ add(row);
+ }
+
+ public void setProxy (String host, String port) {
+ if (host != null) {
+ _host.setText(host);
+ }
+ if (port != null) {
+ _port.setText(port);
+ }
+ }
+
+ // documentation inherited
+ @Override
+ public void addNotify ()
+ {
+ super.addNotify();
+ _host.requestFocusInWindow();
+ }
+
+ // documentation inherited
+ @Override
+ public Dimension getPreferredSize ()
+ {
+ // this is annoyingly hardcoded, but we can't just force the width
+ // or the JLabel will claim a bogus height thinking it can lay its
+ // text out all on one line which will booch the whole UI's
+ // preferred size
+ return new Dimension(500, 320);
+ }
+
+ // documentation inherited from interface
+ @Override
+ public void actionPerformed (ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("ok")) {
+ String user = null, pass = null;
+ if (_useAuth.isSelected()) {
+ user = _username.getText();
+ // we have to keep the proxy password around for every HTTP request, so having it
+ // in a char[] that gets zeroed out after use is not viable for this use case
+ pass = new String(_password.getPassword());
+ }
+ _getdown.configProxy(_host.getText(), _port.getText(), user, pass);
+ } else {
+ // they canceled, we're outta here
+ System.exit(0);
+ }
+ }
+
+ /** Used to look up localized messages. */
+ protected String get (String key)
+ {
+ // if this string is tainted, we don't translate it, instead we
+ // simply remove the taint character and return it to the caller
+ if (MessageUtil.isTainted(key)) {
+ return MessageUtil.untaint(key);
+ }
+ try {
+ return _msgs.getString(key);
+ } catch (MissingResourceException mre) {
+ log.warning("Missing translation message '" + key + "'.");
+ return key;
+ }
+ }
+
+ protected static class SaneLabelField extends JLabel {
+ public SaneLabelField(String message) { super(message); }
+ @Override public Dimension getPreferredSize () {
+ return clampWidth(super.getPreferredSize(), 200);
+ }
+ }
+ protected static class SaneTextField extends JTextField {
+ @Override public Dimension getPreferredSize () {
+ return clampWidth(super.getPreferredSize(), 150);
+ }
+ }
+ protected static class SanePasswordField extends JPasswordField {
+ @Override public Dimension getPreferredSize () {
+ return clampWidth(super.getPreferredSize(), 150);
+ }
+ }
+
+ protected static Dimension clampWidth (Dimension dim, int minWidth) {
+ dim.width = Math.max(dim.width, minWidth);
+ return dim;
+ }
+
+ protected Getdown _getdown;
+ protected ResourceBundle _msgs;
+
+ protected JTextField _host;
+ protected JTextField _port;
+ protected JCheckBox _useAuth;
+ protected JTextField _username;
+ protected JPasswordField _password;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.Authenticator;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import ca.beq.util.win32.registry.RegistryKey;
+import ca.beq.util.win32.registry.RegistryValue;
+import ca.beq.util.win32.registry.RootKey;
+
+import com.threerings.getdown.data.Application;
+import com.threerings.getdown.spi.ProxyAuth;
+import com.threerings.getdown.util.Config;
+import com.threerings.getdown.util.ConnectionUtil;
+import com.threerings.getdown.util.LaunchUtil;
+import com.threerings.getdown.util.StringUtil;
+
+import static com.threerings.getdown.Log.log;
+
+public class ProxyUtil {
+
+ public static boolean autoDetectProxy (Application app)
+ {
+ String host = null, port = null;
+
+ // check for a proxy configured via system properties
+ if (System.getProperty("https.proxyHost") != null) {
+ host = System.getProperty("https.proxyHost");
+ port = System.getProperty("https.proxyPort");
+ }
+ if (StringUtil.isBlank(host) && System.getProperty("http.proxyHost") != null) {
+ host = System.getProperty("http.proxyHost");
+ port = System.getProperty("http.proxyPort");
+ }
+
+ // check the Windows registry
+ if (StringUtil.isBlank(host) && LaunchUtil.isWindows()) {
+ try {
+ String rhost = null, rport = null;
+ boolean enabled = false;
+ RegistryKey.initialize();
+ RegistryKey r = new RegistryKey(RootKey.HKEY_CURRENT_USER, PROXY_REGISTRY);
+ for (Iterator<?> iter = r.values(); iter.hasNext(); ) {
+ RegistryValue value = (RegistryValue)iter.next();
+ if (value.getName().equals("ProxyEnable")) {
+ enabled = value.getStringValue().equals("1");
+ }
+ if (value.getName().equals("ProxyServer")) {
+ String strval = value.getStringValue();
+ int cidx = strval.indexOf(":");
+ if (cidx != -1) {
+ rport = strval.substring(cidx+1);
+ strval = strval.substring(0, cidx);
+ }
+ rhost = strval;
+ }
+ }
+ if (enabled) {
+ host = rhost;
+ port = rport;
+ } else {
+ log.info("Detected no proxy settings in the registry.");
+ }
+ } catch (Throwable t) {
+ log.info("Failed to find proxy settings in Windows registry", "error", t);
+ }
+ }
+
+ // look for a proxy.txt file
+ if (StringUtil.isBlank(host)) {
+ String[] hostPort = loadProxy(app);
+ host = hostPort[0];
+ port = hostPort[1];
+ }
+
+ if (StringUtil.isBlank(host)) {
+ return false;
+ }
+
+ // yay, we found a proxy configuration, configure it in the app
+ initProxy(app, host, port, null, null);
+ return true;
+ }
+
+ public static boolean canLoadWithoutProxy (URL rurl)
+ {
+ log.info("Testing whether proxy is needed, via: " + rurl);
+ try {
+ // try to make a HEAD request for this URL (use short connect and read timeouts)
+ URLConnection conn = ConnectionUtil.open(Proxy.NO_PROXY, rurl, 5, 5);
+ if (conn instanceof HttpURLConnection) {
+ HttpURLConnection hcon = (HttpURLConnection)conn;
+ try {
+ hcon.setRequestMethod("HEAD");
+ hcon.connect();
+ // make sure we got a satisfactory response code
+ int rcode = hcon.getResponseCode();
+ if (rcode == HttpURLConnection.HTTP_PROXY_AUTH ||
+ rcode == HttpURLConnection.HTTP_FORBIDDEN) {
+ log.warning("Got an 'HTTP credentials needed' response", "code", rcode);
+ } else {
+ return true;
+ }
+ } finally {
+ hcon.disconnect();
+ }
+ } else {
+ // if the appbase is not an HTTP/S URL (like file:), then we don't need a proxy
+ return true;
+ }
+ } catch (IOException ioe) {
+ log.info("Failed to HEAD " + rurl + ": " + ioe);
+ log.info("We probably need a proxy, but auto-detection failed.");
+ }
+ return false;
+ }
+
+ public static void configProxy (Application app, String host, String port,
+ String username, String password) {
+ // save our proxy host and port in a local file
+ saveProxy(app, host, port);
+
+ // save our credentials via the SPI
+ if (!StringUtil.isBlank(username) && !StringUtil.isBlank(password)) {
+ ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
+ Iterator<ProxyAuth> iterator = loader.iterator();
+ String appDir = app.getAppDir().getAbsolutePath();
+ while (iterator.hasNext()) {
+ iterator.next().saveCredentials(appDir, username, password);
+ }
+ }
+
+ // also configure them in the app
+ initProxy(app, host, port, username, password);
+ }
+
+ public static String[] loadProxy (Application app) {
+ File pfile = app.getLocalPath("proxy.txt");
+ if (pfile.exists()) {
+ try {
+ Config pconf = Config.parseConfig(pfile, Config.createOpts(false));
+ return new String[] { pconf.getString("host"), pconf.getString("port") };
+ } catch (IOException ioe) {
+ log.warning("Failed to read '" + pfile + "': " + ioe);
+ }
+ }
+ return new String[] { null, null};
+ }
+
+ public static void saveProxy (Application app, String host, String port) {
+ File pfile = app.getLocalPath("proxy.txt");
+ try (PrintStream pout = new PrintStream(new FileOutputStream(pfile))) {
+ if (!StringUtil.isBlank(host)) {
+ pout.println("host = " + host);
+ }
+ if (!StringUtil.isBlank(port)) {
+ pout.println("port = " + port);
+ }
+ } catch (IOException ioe) {
+ log.warning("Error creating proxy file '" + pfile + "': " + ioe);
+ }
+ }
+
+ public static void initProxy (Application app, String host, String port,
+ String username, String password)
+ {
+ // check whether we have saved proxy credentials
+ String appDir = app.getAppDir().getAbsolutePath();
+ ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
+ Iterator<ProxyAuth> iter = loader.iterator();
+ ProxyAuth.Credentials creds = iter.hasNext() ? iter.next().loadCredentials(appDir) : null;
+ if (creds != null) {
+ username = creds.username;
+ password = creds.password;
+ }
+ boolean haveCreds = !StringUtil.isBlank(username) && !StringUtil.isBlank(password);
+
+ int pport = StringUtil.isBlank(port) ? 80 : Integer.valueOf(port);
+ log.info("Using proxy", "host", host, "port", pport, "haveCreds", haveCreds);
+ app.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, pport));
+
+ if (haveCreds) {
+ final String fuser = username;
+ final char[] fpass = password.toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override protected PasswordAuthentication getPasswordAuthentication () {
+ return new PasswordAuthentication(fuser, fpass);
+ }
+ });
+ }
+ }
+
+ protected static final String PROXY_REGISTRY =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.awt.Image;
+import java.util.List;
+
+import static com.threerings.getdown.Log.log;
+
+public final class RotatingBackgrounds
+{
+ public interface ImageLoader {
+ /** Loads and returns the image with the supplied path. */
+ public Image loadImage (String path);
+ }
+
+ /**
+ * Creates a placeholder if there are no images. Just returns null from getImage every time.
+ */
+ public RotatingBackgrounds ()
+ {
+ makeEmpty();
+ }
+
+ /** Creates a single image background. */
+ public RotatingBackgrounds (Image background)
+ {
+ percentages = new int[] { 0 };
+ minDisplayTime = new int[] { 0 };
+ images = new Image[] { background };
+ errorImage = images[0];
+ }
+
+ /**
+ * Create a sequence of images to be rotated through from <code>backgrounds</code>.
+ *
+ * Each String in backgrounds should be the path to the image, a semicolon, and the minimum
+ * amount of time to display the image in seconds. Each image will be active for an equal
+ * percentage of the download process, unless one hasn't been active for its minimum display
+ * time when the next should be shown. In that case, it's left up until its been there for its
+ * minimum display time and then the next one gets to come up.
+ */
+ public RotatingBackgrounds (List<String> backgrounds, String errorBackground, ImageLoader loader)
+ {
+ percentages = new int[backgrounds.size()];
+ minDisplayTime = new int[backgrounds.size()];
+ images = new Image[backgrounds.size()];
+ for (int ii = 0; ii < backgrounds.size(); ii++) {
+ String background = backgrounds.get(ii);
+ String[] pieces = background.split(";");
+ if (pieces.length != 2) {
+ log.warning("Unable to parse background image '" + background + "'");
+ makeEmpty();
+ return;
+ }
+ images[ii] = loader.loadImage(pieces[0]);
+ try {
+ minDisplayTime[ii] = Integer.parseInt(pieces[1]);
+ } catch (NumberFormatException e) {
+ log.warning("Unable to parse background image display time '" + background + "'");
+ makeEmpty();
+ return;
+ }
+ percentages[ii] = (int)((ii/(float)backgrounds.size()) * 100);
+ }
+ if (errorBackground == null) {
+ errorImage = images[0];
+ } else {
+ errorImage = loader.loadImage(errorBackground);
+ }
+ }
+
+ /**
+ * @return the image to display at the given progress or null if there aren't any.
+ */
+ public Image getImage (int progress)
+ {
+ if (images.length == 0) {
+ return null;
+ }
+ long now = System.currentTimeMillis();
+ if (current != images.length - 1
+ && (current == -1 || (progress >= percentages[current + 1] &&
+ (now - currentDisplayStart) / 1000 > minDisplayTime[current]))) {
+ current++;
+ currentDisplayStart = now;
+ }
+ return images[current];
+ }
+
+ /**
+ * Returns the image to display if an error has caused getdown to fail.
+ */
+ public Image getErrorImage ()
+ {
+ return errorImage;
+ }
+
+ /**
+ * @return the number of images in this RotatingBackgrounds
+ */
+ public int getNumImages() {
+ return images.length;
+ }
+
+ protected void makeEmpty ()
+ {
+ percentages = new int[] {};
+ minDisplayTime = new int[] {};
+ images = new Image[] {};
+ }
+
+ /** Time at which the currently displayed image was first displayed in millis. */
+ protected long currentDisplayStart;
+
+ /** The index of the currently displayed image or -1 if we haven't displayed any. */
+ protected int current = -1;
+
+ protected Image[] images;
+
+ /** The image to display if getdown has failed due to an error. */
+ protected Image errorImage;
+
+ /** Percentage at which each image should be displayed. */
+ protected int[] percentages;
+
+ /** Time to show each image in seconds. */
+ protected int[] minDisplayTime;
+}
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
+package com.threerings.getdown.launcher;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.ImageObserver;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.swing.JComponent;
+import javax.swing.Timer;
+
+import com.samskivert.swing.Label;
+import com.samskivert.swing.LabelStyleConstants;
+import com.samskivert.swing.util.SwingUtil;
+import com.samskivert.util.Throttle;
+
+import com.threerings.getdown.data.Application.UpdateInterface;
+import com.threerings.getdown.util.MessageUtil;
+import com.threerings.getdown.util.Rectangle;
+import com.threerings.getdown.util.StringUtil;
+
+import static com.threerings.getdown.Log.log;
+
+/**
+ * Displays download and patching status.
+ */
+public final class StatusPanel extends JComponent
+ implements ImageObserver
+{
+ public StatusPanel (ResourceBundle msgs)
+ {
+ _msgs = msgs;
+
+ // Add a bit of "throbbing" to the display by updating the number of dots displayed after
+ // our status. This lets users know things are still working.
+ _timer = new Timer(1000,
+ new ActionListener() {
+ public void actionPerformed (ActionEvent event) {
+ if (_status != null && !_displayError) {
+ _statusDots = (_statusDots % 3) + 1; // 1, 2, 3, 1, 2, 3, etc.
+ updateStatusLabel();
+ }
+ }
+ });
+ }
+
+ public void init (UpdateInterface ifc, RotatingBackgrounds bg, Image barimg)
+ {
+ _ifc = ifc;
+ _bg = bg;
+ Image img = _bg.getImage(_progress);
+ int width = img == null ? -1 : img.getWidth(this);
+ int height = img == null ? -1 : img.getHeight(this);
+ if (width == -1 || height == -1) {
+ Rectangle bounds = ifc.progress.union(ifc.status);
+ // assume the x inset defines the frame padding; add it on the left, right, and bottom
+ _psize = new Dimension(bounds.x + bounds.width + bounds.x,
+ bounds.y + bounds.height + bounds.x);
+ } else {
+ _psize = new Dimension(width, height);
+ }
+ _barimg = barimg;
+ invalidate();
+ }
+
+ @Override
+ public boolean imageUpdate (Image img, int infoflags, int x, int y, int width, int height)
+ {
+ boolean updated = false;
+ if ((infoflags & WIDTH) != 0) {
+ _psize.width = width;
+ updated = true;
+ }
+ if ((infoflags & HEIGHT) != 0) {
+ _psize.height = height;
+ updated = true;
+ }
+ if (updated) {
+ invalidate();
+ setSize(_psize);
+ getParent().setSize(_psize);
+ }
+ return (infoflags & ALLBITS) == 0;
+ }
+
+ /**
+ * Adjusts the progress display to the specified percentage.
+ */
+ public void setProgress (int percent, long remaining)
+ {
+ boolean needsRepaint = false;
+
+ // maybe update the progress label
+ if (_progress != percent) {
+ _progress = percent;
+ if (!_ifc.hideProgressText) {
+ String msg = MessageFormat.format(get("m.complete"), percent);
+ _newplab = createLabel(msg, new Color(_ifc.progressText, true));
+ }
+ needsRepaint = true;
+ }
+
+ // maybe update the remaining label
+ if (remaining > 1) {
+ // skip this estimate if it's been less than a second since our last one came in
+ if (!_rthrottle.throttleOp()) {
+ _remain[_ridx++%_remain.length] = remaining;
+ }
+
+ // smooth the remaining time by taking the trailing average of the last four values
+ remaining = 0;
+ int values = Math.min(_ridx, _remain.length);
+ for (int ii = 0; ii < values; ii++) {
+ remaining += _remain[ii];
+ }
+ remaining /= values;
+
+ if (!_ifc.hideProgressText) {
+ // now compute our display value
+ int minutes = (int)(remaining / 60), seconds = (int)(remaining % 60);
+ String remstr = minutes + ":" + ((seconds < 10) ? "0" : "") + seconds;
+ String msg = MessageFormat.format(get("m.remain"), remstr);
+ _newrlab = createLabel(msg, new Color(_ifc.statusText, true));
+ }
+ needsRepaint = true;
+
+ } else if (_rlabel != null || _newrlab != null) {
+ _rthrottle = new Throttle(1, 1000);
+ _ridx = 0;
+ _newrlab = _rlabel = null;
+ needsRepaint = true;
+ }
+
+ if (needsRepaint) {
+ repaint();
+ }
+ }
+
+ /**
+ * Displays the specified status string.
+ */
+ public void setStatus (String status, boolean displayError)
+ {
+ _status = xlate(status);
+ _displayError = displayError;
+ updateStatusLabel();
+ }
+
+ /**
+ * Stop the throbbing.
+ */
+ public void stopThrob ()
+ {
+ _timer.stop();
+ _statusDots = 3;
+ updateStatusLabel();
+ }
+
+ @Override
+ public void addNotify ()
+ {
+ super.addNotify();
+ _timer.start();
+ }
+
+ @Override
+ public void removeNotify ()
+ {
+ _timer.stop();
+ super.removeNotify();
+ }
+
+ // documentation inherited
+ @Override
+ public void paintComponent (Graphics g)
+ {
+ super.paintComponent(g);
+ Graphics2D gfx = (Graphics2D)g;
+
+ // attempt to draw a background image...
+ Image img;
+ if (_displayError) {
+ img = _bg.getErrorImage();
+ } else {
+ img = _bg.getImage(_progress);
+ }
+ if (img != null) {
+ gfx.drawImage(img, 0, 0, this);
+ }
+
+ Object oalias = SwingUtil.activateAntiAliasing(gfx);
+
+ // if we have new labels; lay them out
+ if (_newlab != null) {
+ _newlab.layout(gfx);
+ _label = _newlab;
+ _newlab = null;
+ }
+ if (_newplab != null) {
+ _newplab.layout(gfx);
+ _plabel = _newplab;
+ _newplab = null;
+ }
+ if (_newrlab != null) {
+ _newrlab.layout(gfx);
+ _rlabel = _newrlab;
+ _newrlab = null;
+ }
+
+ if (_barimg != null) {
+ gfx.setClip(_ifc.progress.x, _ifc.progress.y,
+ _progress * _ifc.progress.width / 100,
+ _ifc.progress.height);
+ gfx.drawImage(_barimg, _ifc.progress.x, _ifc.progress.y, null);
+ gfx.setClip(null);
+ } else {
+ gfx.setColor(new Color(_ifc.progressBar, true));
+ gfx.fillRect(_ifc.progress.x, _ifc.progress.y,
+ _progress * _ifc.progress.width / 100,
+ _ifc.progress.height);
+ }
+
+ if (_plabel != null) {
+ int xmarg = (_ifc.progress.width - _plabel.getSize().width)/2;
+ int ymarg = (_ifc.progress.height - _plabel.getSize().height)/2;
+ _plabel.render(gfx, _ifc.progress.x + xmarg, _ifc.progress.y + ymarg);
+ }
+
+ if (_label != null) {
+ _label.render(gfx, _ifc.status.x, getStatusY(_label));
+ }
+
+ if (_rlabel != null) {
+ // put the remaining label at the end of the status area. This could be dangerous
+ // but I think the only time we would display it is with small statuses.
+ int x = _ifc.status.x + _ifc.status.width - _rlabel.getSize().width;
+ _rlabel.render(gfx, x, getStatusY(_rlabel));
+ }
+
+ SwingUtil.restoreAntiAliasing(gfx, oalias);
+ }
+
+ // documentation inherited
+ @Override
+ public Dimension getPreferredSize ()
+ {
+ return _psize;
+ }
+
+ /**
+ * Update the status label.
+ */
+ protected void updateStatusLabel ()
+ {
+ String status = _status;
+ if (!_displayError) {
+ for (int ii = 0; ii < _statusDots; ii++) {
+ status += " .";
+ }
+ }
+ _newlab = createLabel(status, new Color(_ifc.statusText, true));
+ // set the width of the label to the width specified
+ int width = _ifc.status.width;
+ if (width == 0) {
+ // unless we had trouble reading that width, in which case use the entire window
+ width = getWidth();
+ }
+ // but the window itself might not be initialized and have a width of 0
+ if (width > 0) {
+ _newlab.setTargetWidth(width);
+ }
+ repaint();
+ }
+
+ /**
+ * Get the y coordinate of a label in the status area.
+ */
+ protected int getStatusY (Label label)
+ {
+ // if the status region is higher than the progress region, we
+ // want to align the label with the bottom of its region
+ // rather than the top
+ if (_ifc.status.y > _ifc.progress.y) {
+ return _ifc.status.y;
+ }
+ return _ifc.status.y + (_ifc.status.height - label.getSize().height);
+ }
+
+ /**
+ * Create a label, taking care of adding the shadow if needed.
+ */
+ protected Label createLabel (String text, Color color)
+ {
+ Label label = new Label(text, color, FONT);
+ if (_ifc.textShadow != 0) {
+ label.setAlternateColor(new Color(_ifc.textShadow, true));
+ label.setStyle(LabelStyleConstants.SHADOW);
+ }
+ return label;
+ }
+
+ /** Used by {@link #setStatus}. */
+ protected String xlate (String compoundKey)
+ {
+ // to be more efficient about creating unnecessary objects, we
+ // do some checking before splitting
+ int tidx = compoundKey.indexOf('|');
+ if (tidx == -1) {
+ return get(compoundKey);
+
+ } else {
+ String key = compoundKey.substring(0, tidx);
+ String argstr = compoundKey.substring(tidx+1);
+ String[] args = argstr.split("\\|");
+ // unescape and translate the arguments
+ for (int i = 0; i < args.length; i++) {
+ // if the argument is tainted, do no further translation
+ // (it might contain |s or other fun stuff)
+ if (MessageUtil.isTainted(args[i])) {
+ args[i] = MessageUtil.unescape(MessageUtil.untaint(args[i]));
+ } else {
+ args[i] = xlate(MessageUtil.unescape(args[i]));
+ }
+ }
+ return get(key, args);
+ }
+ }
+
+ /** Used by {@link #setStatus}. */
+ protected String get (String key, String[] args)
+ {
+ String msg = get(key);
+ if (msg != null) return MessageFormat.format(MessageUtil.escape(msg), (Object[])args);
+ return key + String.valueOf(Arrays.asList(args));
+ }
+
+ /** Used by {@link #setStatus}, and {@link #setProgress}. */
+ protected String get (String key)
+ {
+ // if we have no _msgs that means we're probably recovering from a
+ // failure to load the translation messages in the first place, so
+ // just give them their key back because it's probably an english
+ // string; whee!
+ if (_msgs == null) {
+ return key;
+ }
+
+ // if this string is tainted, we don't translate it, instead we
+ // simply remove the taint character and return it to the caller
+ if (MessageUtil.isTainted(key)) {
+ return MessageUtil.untaint(key);
+ }
+ try {
+ return _msgs.getString(key);
+ } catch (MissingResourceException mre) {
+ log.warning("Missing translation message '" + key + "'.");
+ return key;
+ }
+ }
+
+ protected Image _barimg;
+ protected RotatingBackgrounds _bg;
+ protected Dimension _psize;
+
+ protected ResourceBundle _msgs;
+
+ protected int _progress = -1;
+ protected String _status;
+ protected int _statusDots = 1;
+ protected boolean _displayError;
+ protected Label _label, _newlab;
+ protected Label _plabel, _newplab;
+ protected Label _rlabel, _newrlab;
+
+ protected UpdateInterface _ifc;
+ protected Timer _timer;
+
+ protected long[] _remain = new long[4];
+ protected int _ridx;
+ protected Throttle _rthrottle = new Throttle(1, 1000L);
+
+ protected static final Font FONT = new Font("SansSerif", Font.BOLD, 12);
+}
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = Abort installation?
+m.abort_confirm = <html>Are you sure you want to stop installation? \
+ You can resume at a later time by running the application again.</html>
+m.abort_ok = Quit
+m.abort_cancel = Continue installation
+
+m.detecting_proxy = Trying to auto-detect proxy settings
+
+m.configure_proxy = <html>We were unable to connect to the application server to download data. \
+ <p> Please make sure that no virus scanner or firewall is blocking network communicaton with \
+ the server. \
+ <p> Your computer may access the Internet through a proxy and we were unable to automatically \
+ detect your proxy settings. If you know your proxy settings, you can enter them below.</html>
+
+m.proxy_extra = <html>If you are sure that you don't use a proxy then \
+ perhaps there is a temporary Internet outage that is preventing us from \
+ communicating with the servers. In this case, you can cancel and try \
+ installing again later.</html>
+
+m.proxy_host = Proxy IP
+m.proxy_port = Proxy port
+m.proxy_username = Username
+m.proxy_password = Password
+m.proxy_auth_required = Authentication required
+m.proxy_ok = OK
+m.proxy_cancel = Cancel
+
+m.downloading_java = Downloading Java Virtual Machine
+m.unpacking_java = Unpacking Java Virtual Machine
+
+m.resolving = Resolving downloads
+m.downloading = Downloading data
+m.failure = Download failed: {0}
+
+m.checking = Checking for update
+m.validating = Validating
+m.patching = Patching
+m.launching = Launching
+
+m.patch_notes = Patch Notes
+m.play_again = Play Again
+
+m.complete = {0}% complete
+m.remain = {0} remaining
+
+m.updating_metadata = Downloading control files
+
+m.init_failed = Our configuration file is missing or corrupt. Attempting \
+ to download a new copy...
+
+m.java_download_failed = We were unable to automatically download the \
+ necessary version of Java for your computer.\n\n\
+ Please go to www.java.com and download the latest version of \
+ Java, then try running the application again.
+
+m.java_unpack_failed = We were unable to unpack an updated version of \
+ Java. Please make sure you have at least 100 MB of free space on your \
+ harddrive and try running the application again.\n\n\
+ If that does not solve the problem, go to www.java.com and download and \
+ install the latest version of Java and try again.
+
+m.unable_to_repair = We were unable to download the necessary files after \
+ five attempts. You can try running the application again, but if it \
+ fails you may need to uninstall and reinstall.
+
+m.unknown_error = The application has failed to launch due to some strange \
+ error from which we could not recover. Please visit\n{0} for information on \
+ how to recover.
+m.init_error = The application has failed to launch due to the following \
+ error:\n{0}\n\nPlease visit\n{1} for \
+ information on how to handle such problems.
+
+m.readonly_error = The directory in which this application is installed: \
+ \n{0}\nis read-only. Please install the application into a directory where \
+ you have write access.
+
+m.missing_resource = The application has failed to launch due to a missing \
+ resource:\n{0}\n\nPlease visit\n{1} for information on how to handle such \
+ problems.
+
+m.insufficient_permissions_error = You did not accept this application's \
+ digital signature. If you want to run the application, you will need to accept \
+ its digital signature.\n\nTo do so, you will need to quit your web browser, \
+ restart it, and return to this web page to relaunch the application. When the \
+ security dialog is shown, click the button to accept the digital signature \
+ and grant this application the privileges it needs to run.
+
+m.corrupt_digest_signature_error = We couldn't verify the application's digital \
+ signature.\nPlease check that you are launching the application from\nthe \
+ correct website.
+
+m.default_install_error = the support section of the website
+
+m.another_getdown_running = Multiple instances of this application's \
+ installer are running. This one will stop and let another complete.
+
+m.applet_stopped = Getdown's applet was told to stop working.
+
+# application/digest errors
+m.missing_appbase = The configuration file is missing the 'appbase'.
+m.invalid_version = The configuration file specifies an invalid version.
+m.invalid_appbase = The configuration file specifies an invalid 'appbase'.
+m.missing_class = The configuration file is missing the application class.
+m.missing_code = The configuration file specifies no code resources.
+m.invalid_digest_file = The digest file is invalid.
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = Installation abbrechen?
+m.abort_confirm = <html>Bist du sicher, dass du die Installation abbrechen \
+m\u00f6chtest? \
+ Du kannst sp\u00e4ter fortfahren, indem du die Anwendung erneut \
+ausf\u00fchrst.</html>
+m.abort_ok = Beenden
+m.abort_cancel = Installation fortsetzen
+
+m.detecting_proxy = Versuche Proxy-Einstellungen automatisch zu ermitteln
+
+m.configure_proxy = <html>Es konnte keine Verbindung zum Applikations-Server aufgebaut werden. \
+ <p>Bitte kontrollieren Sie die Proxyeinstellungen und stellen Sie sicher, dass keine lokal oder \
+ im Netzwerk betriebene Sicherheitsanwendung (Virenscanner, Firewall, etc.) die Kommunikation \
+ mit dem Server blockiert.<br> \
+ Wenn kein Proxy verwendet werden soll, l\u00f6schen Sie bitte alle Eintr\u00e4ge in den unten \
+ stehenden Feldern und klicken sie auf OK.</html>
+
+m.proxy_extra = <html>Sollten Sie keine Proxyeinstellungen gesetzt haben wenden Sie sich bitte \
+ an Ihren Administrator.</html>
+
+m.proxy_host = Proxy-Adresse
+m.proxy_port = Proxy-Port
+m.proxy_username = Benutzername
+m.proxy_password = Passwort
+m.proxy_auth_required = Authentisierung erforderlich
+m.proxy_ok = OK
+m.proxy_cancel = Abbrechen
+
+m.downloading_java = Lade Java Virtual Machine herunter
+m.unpacking_java = Entpacke Java Virtual Machine
+
+m.resolving = Bereite Download vor
+m.downloading = Lade Daten herunter
+m.failure = Download fehlgeschlagen: {0}
+
+m.checking = Suche nach Updates
+m.validating = Validiere Download
+m.patching = Patche
+m.launching = Starte
+
+m.patch_notes = Patchnotes
+
+m.complete = {0}% abgeschlossen
+m.remain = {0} \u00fcbrig
+
+m.updating_metadata = Lade Steuerungsdateien herunter
+
+m.init_failed = Unsere Konfigurationsdatei fehlt oder ist besch\u00e4digt. \
+Versuche, eine neue Kopie herunterzuladen...
+
+m.java_download_failed = Wir konnten die notwendige Javaversion f\u00fcr deinen \
+Computer nicht automatisch herunterladen. \n\n \
+Bitte auf www.java.com die aktuelle Javaversion herunterladen und dann die \
+Anwendung erneut starten.
+
+m.java_unpack_failed = Wir konnten die aktualisierte Javaversion nicht \
+entpacken. Bitte stelle sicher, dass wenigstens 100MB Platz auf der \
+Festplatte frei sind und versuche dann die Anwendung erneut zu \
+starten.\n\n\ \
+Falls das das Problem nicht beseitigt, bitte auf www.java.com die aktuelle \
+Javaversion herunterladen und installieren und dann erneut versuchen.
+
+m.unable_to_repair = Wir konnten die notwendigen Dateien nach 5 Versuchen \
+nicht herunterladen. Du kannst versuchen, die Anwendung erneut zu starten, \
+aber wenn dies erneut fehlschl\u00e4gt, musst du die Anwendung deinstallieren \
+und erneut installieren.
+
+m.unknown_error = Die Anwendung konnte wegen eines unbekannten Fehlers \
+nicht gestartet werden. Bitte auf \n{0} weiterlesen.
+
+m.init_error = Die Anwendung konnte wegen folgendem Fehler nicht gestartet \
+werden:\n{0}\n\n Bitte auf \n{1} weiterlesen, um zu erfahren, wie bei \
+solchen Problemen vorzugehen ist.
+
+m.readonly_error = Das Verzeichnis, in dem die Anwendung installiert ist: \
+ \n{0}\nist nicht schreibberechtigt. Bitte in ein Verzeichnis mit \
+Schreibzugriff installieren.
+
+m.missing_resource = Die Anwendung konnte nicht gestartet werden, da die \
+folgende Quelle nicht gefunden wurde:\n{0}\n\n\ Bitte auf \n{1} \
+weiterlesen, um zu erfahren, wie bei solchen Problemen vorzugehen ist.
+
+m.insufficient_permissions_error = Du hast die digitale Signatur dieser \
+Anwendung nicht akzeptiert. Falls du diese Anwendung benutzen willst, \
+musst du ihre digitale Signatur akzeptieren. \n\Um das zu tun, musst du \
+deinen Browser beenden, neu starten und erneut die Anwendung von dieser \
+Webseite aus starten. Wenn die Sicherheitsabfrage erscheint, bitte die \
+digitale Signatur akzeptieren, um der Anwendung die n\u00f6tigen Rechte zu \
+geben, die sie braucht, um zu laufen.
+
+m.corrupt_digest_signature_error = Wir konnten die digitale Signatur \
+dieser Anwendung nicht \u00fcberpr\u00fcfen.\nBitte \u00fcberpr\u00fcfe, ob du die Anwendung \
+von der richtigen Webseite aus startest.
+
+m.default_install_error = der Support-Webseite
+
+m.another_getdown_running = Diese Installationsanwendung l\u00e4uft in mehreren \
+Instanzen. Diese Instanz wird sich beenden und eine andere Instanz den \
+Vorgang erledigen lassen.
+
+m.applet_stopped = Die Anwendung wurde beendet.
+
+
+# application/digest errors
+m.missing_appbase = In der Konfigurationsdatei fehlt die 'appbase'.
+m.invalid_version = In der Konfigurationsdatei steht die falsche Version.
+m.invalid_appbase = In der Konfigurationsdatei steht die falsche 'appbase'.
+m.missing_class = In der Konfigurationsdatei fehlt die Anwendungsklasse.
+m.missing_code = Die Konfigurationsdatei enth\u00e4lt keine Codequellen.
+m.invalid_digest_file = Die Hashwertedatei ist ung\u00fcltig.
+
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = \u00bfCancelar la instalaci\u00f3n?
+m.abort_confirm = <html>\u00bfEst\u00e1s seguro de querer cancelar la instalaci\u00f3n? \
+ Puedes continuarla despu\u00e9s si corres de nuevo la aplicaci\u00f3n.</html>
+m.abort_ok = Cancelar
+m.abort_cancel = Continuar la instalaci\u00f3n
+
+m.detecting_proxy = Detectando autom\u00e1ticamente la configuraci\u00f3n proxy
+
+m.configure_proxy = <html>No ha sido posible conectar con nuestros servidores para \
+ descargar los datos del juego. \
+ <ul><li> Si el cortafuegos de Windows o Norton Internet Security tiene instrucciones \
+ de bloquear <code>javaw.exe</code> no podemos descargar el juego. Necesitar\u00e1s \
+ permitir que <code>javaw.exe</code> tenga acceso al Internet. Puedes intentar \
+ correr el juego de nuevo, pero es posible que debas dar permisos a javaw.exe en la \
+ configuraci\u00f3n de tu cortafuegos ( Inicio -> Panel de control -> Firewall de Windows ).</ul> \
+ <p> Es posible que tu computadora tenga acceso al Internet por medio de un proxy por lo que \
+ no ha sido posible detectar autom\u00e1ticamente tu configuraci\u00f3n. Si conoces tu \
+ configuraci\u00f3n proxy, puedes anotarla abajo.</html>
+
+m.proxy_extra = <html>Si est\u00e1s seguro de que no tienes un proxy entonces \
+ tal vez exista un falla temporal en el Internet que est\u00e1 evitando que podamos \
+ comunicarnos con los servidores. En este caso, puedes cancelar e intentar \
+ instalarla de nuevo m\u00e1s tarde.</html>
+
+m.proxy_host = IP proxy
+m.proxy_port = Puerto proxy
+m.proxy_username = Nombre de usuario
+m.proxy_password = Contrase\u00f1a
+m.proxy_auth_required = Autenticacion requerida
+m.proxy_ok = OK
+m.proxy_cancel = Cancelar
+
+m.downloading_java = Descargando Java Virtual Machine
+m.unpacking_java = Desempacando Java Virtual Machine
+
+m.resolving = Resolviendo descarga
+m.downloading = Descargando datos
+m.failure = Descarga fallida: {0}
+
+m.checking = Buscando actualizaciones
+m.validating = Validando
+m.patching = Parchando
+m.launching = Lanzando
+
+m.patch_notes = Notas del parche
+
+m.complete = {0}% completado
+m.remain = {0} restante
+
+m.updating_metadata = Descargando los archivos de control
+
+m.init_failed = Un archivo de configuraci\u00f3n est\u00e1 faltante o est\u00e1 corrupto. Intentando \
+ descargar una nueva copia...
+
+m.java_download_failed = No ha sido posible descargar autom\u00e1ticamente la \
+ versi\u00f3n de Java necesaria para tu computadora.\n\n\
+ Por favor ve a www.java.com y descarga la \u00faltima versi\u00f3n de \
+ Java, despu\u00e9s intenta correr de nuevo la aplicaci\u00f3n.
+
+m.java_unpack_failed = No ha sido posible desempacar una versi\u00f3n actualizada de \
+ Java. Por favor aseg\u00farate de tener al menos 100 MB de espacio libre en tu \
+ disco duro e intenta correr de nuevo la aplicaci\u00f3n.\n\n\
+ Si eso no soluciona el problema, ve a www.java.com y descarga e \
+ instala la \u00faltima versi\u00f3n de Java e intenta de nuevo.
+
+m.unable_to_repair = No ha sido posible descargar los archivos necesarios despu\u00e9s de \
+ cinco intentos. Puedes intentar correr de nuevo la aplicaci\u00f3n, pero si falla \
+ de nuevo podr\u00edas necesitar desinstalar y reinstalar.
+
+m.unknown_error = La aplicaci\u00f3n no ha podido iniciar debido a un extra\u00f1o \
+ error del que no se pudo recobrar. Por favor visita\n{0} para ver informaci\u00f3n acerca \
+ de como recuperarla.
+m.init_error = La aplicaci\u00f3n no ha podido iniciar debido al siguiente \
+ error:\n{0}\n\nPor favor visita\n{1} para \
+ ver informaci\u00f3n acerca de como manejar ese tipo de problemas.
+
+m.readonly_error = El directorio en el que esta aplicaci\u00f3n est\u00e1 instalada: \
+ \n{0}\nes solo lectura. Por favor instala la aplicaci\u00f3n en un directorio en el cual \
+ tengas acceso de escritura.
+
+m.missing_resource = La aplicaci\u00f3n no ha podido iniciar debido a un recurso \
+ faltante:\n{0}\n\nPor favor visita\n{1} para informaci\u00f3n acerca de como solucionar \
+ estos problemas.
+
+m.insufficient_permissions_error = No aceptaste la firma digital de \
+ esta aplicaci\u00f3n. Si quieres correr la aplicaci\u00f3n, necesitas aceptar \
+ su firma digital.\n\nPara hacerlo, necesitas cerrar tu navegador, \
+ reiniciarlo, y regresar a esta p\u00e1gina web para reiniciar la aplicaci\u00f3n. Cuando se muestre \
+ el di\u00e1logo de seguridad, haz clic en el bot\u00f3n para aceptar la firmar digital \
+ y otorgar a esta aplicaci\u00f3n los privilegios que necesita para correr.
+
+m.corrupt_digest_signature_error = No pudimos verificar la firma digital \
+ de la aplicaci\u00f3n.\nPor favor revisa que est\u00e9s lanzando la aplicaci\u00f3n desde\nel \
+ sitio web correcto.
+
+m.default_install_error = la secci\u00f3n de asistencia de este sitio web
+
+m.another_getdown_running = Est\u00e1n corriendo m\u00faltiples instancias de \
+ este instalador. Este se detendr\u00e1 para permitir que otra contin\u00fae.
+
+m.applet_stopped = Se le dijo al applet de Getdown que dejara de trabajar.
+
+# application/digest errors
+m.missing_appbase = Al archivo de configuraci\u00f3n le falta el 'appbase'.
+m.invalid_version = El archivo de configuraci\u00f3n especifica una versi\u00f3n no v\u00e1lida.
+m.invalid_appbase = El archivo de configuraci\u00f3n especifica un 'appbase' no v\u00e1lido.
+m.missing_class = Al archivo de configuraci\u00f3n le falta la clase de aplicaci\u00f3n.
+m.missing_code = El archivo de configuraci\u00f3n especifica que no hay recursos de c\u00f3digo.
+m.invalid_digest_file = El archivo digest no es v\u00e1lido.
+
--- /dev/null
+#
+# $Id: messages.properties 485 2012-03-08 22:05:30Z ray.j.greenwell $
+#
+# Getdown translation messages
+
+m.abort_title = Annuler l'installation?
+m.abort_confirm =<html>\u00cates-vous s\u00fbr de vouloir annuler l'installation? \
+ Vous pourrez reprendre l'installation en ex\u00e9cutant l'application de nouveau.</html>
+m.abort_ok = Quitter
+m.abort_cancel = Continuer l'installation
+
+m.detecting_proxy = D\u00e9tection automatique des r\u00e9glages proxy
+
+m.configure_proxy =<html>Connexion au serveur impossible. \
+ <ul><li> Veuillez v\u00e9rifier que <code>javaw.exe</code> n'est bloqu\u00e9 \
+ par aucun pare-feu ou antivirus. \
+ Vous pouvez vous rendre sur la configuration du pare-feu windows via \
+ (D\u00e9marrer -> Panneau de Configuration -> Pare-feu Windows ).</ul> \
+ <p> Il est \u00e9galement possible que vous soyez derri\u00e8re un proxy que l'application \
+ est incapable de d\u00e9tecter automatiquement. \
+ Si tel est le cas, veuillez saisir les r\u00e9glages proxy ci-dessous.</html>
+
+m.proxy_extra =<html>Si vous \u00eates certain de ne pas utiliser de proxy, il est \
+ possible qu'une interruption temporaire de la connexion internet emp\u00fbche la \
+ communication avec les serveurs. Dans ce cas, vous pouvez relancer \
+ l'installation ult\u00e9rieurement.</html>
+
+m.proxy_host = Proxy IP
+m.proxy_port = Proxy port
+m.proxy_username = Nom d'utilisateur
+m.proxy_password = Mot de passe
+m.proxy_auth_required = Identification requise
+m.proxy_ok = OK
+m.proxy_cancel = Annuler
+
+m.downloading_java = T\u00e9l\u00e9chargement en cours de la Machine Virtuelle Java
+m.unpacking_java = D\u00e9compression en cours de la Machine Virtuelle Java
+
+m.resolving = R\u00e9solution des t\u00e9l\u00e9chargements en cours
+m.downloading = T\u00e9l\u00e9chargement des donn\u00e9es en cours
+m.failure = \u00c9chec du t\u00e9l\u00e9chargement: {0}
+
+m.checking = V\u00e9rification de la mise-\u00e0-jour en cours
+m.validating = Validation en cours
+m.patching = Modification en cours
+m.launching = Lancement en cours
+
+m.patch_notes = Notes de mise-\u00e0-jour
+
+m.complete = Complet \u00e0 {0}%
+m.remain = {0} restant
+
+m.updating_metadata = T\u00e9l\u00e9chargement des fichiers de contr\u00f4les en cours
+
+m.init_failed = Notre fichier de configuration est perdu ou corrompu. T\u00e9l\u00e9chargement \
+ d'une nouvelle copie en cours ...
+
+m.java_download_failed = Impossible de t\u00e9l\u00e9charger automatiquement la \
+ version de Java n\u00e9cessaire.\n\n\
+ Veuillez vous rendre sur www.java.com et t\u00e9l\u00e9charger et installer la version \
+ la plus r\u00e9cente de Java, avant d'ex\u00e9cuter l'application \u00e0 nouveau.
+
+m.java_unpack_failed = Impossible de d\u00e9compresser la version de \
+ Java n\u00e9cessaire. Veuillez v\u00e9rifier que vous avez au moins 100 MB d'espace libre \
+ sur votre disque dur puis tenter d'ex\u00e9cuter l'application \u00e0 nouveau.\n\n\
+ Si le probl\u00e8me persiste, rendez vous www.java.com et t\u00e9l\u00e9chargez et \
+ installez la version plus r\u00e9cente de Java puis essayez de nouveau.
+
+m.unable_to_repair = Impossible de t\u00e9l\u00e9charger les fichiers n\u00e9cessaires apr\u00e8s \
+ cinq tentatives. Vous pouvez tenter d'ex\u00e9cuter l'application \u00e0 nouveau, mais il est \
+ possible qu'une d\u00e9sinstallation / r\u00e9installation soit n\u00e9cessaire.
+
+m.unknown_error = Une erreur inconnue a fait \u00e9chouer le lancement de l'application. \
+ Veuillez visiter\n{0} pour plus d'informations.
+m.init_error = Le lancement de l'application a \u00e9chou\u00e9 \u00e0 cause de l'erreur \
+ suivante:\n{0}\n\nVeuillez visiter\n{1} pour plus d'informations.
+
+m.readonly_error = Le r\u00e9pertoire d'installation de cette application: \
+ \n{0}\nest en lecture seule. Veuillez installer l'application dans un r\u00e9pertoire avec \
+ un acc\u00e8s en \u00e9criture.
+
+m.missing_resource = Le lancement de l'application a \u00e9chou\u00e9 \u00e0 cause d'une \
+ ressource manquante:\n{0}\n\nVeuillez visiter\n{1} pour plus d'informations.
+
+m.insufficient_permissions_error = Vous n'avez pas accepter la signature \
+ num\u00e9rique de cette application. Si vous souhaitez ex\u00e9cuter cette application, vous \
+ devez accepter sa signature num\u00e9rique.\n\nAfin de le faire, vous devez quitter votre \
+ navigateur, le red\u00e9marrer, retourner \u00e0 cette page puis relancer l'application. \
+ Une fois la bo\u00eete de dialogue de s\u00e9curit\u00e9 affich\u00e9e, cliquez sur le bouton \
+ pour accepter la signature num\u00e9rique et accorder les permissions n\u00e9cessaires au bon \
+ fonctionnement de l'application.
+
+m.corrupt_digest_signature_error = Nous ne pouvons pas v\u00e9rifier la signature num\u00e9rique \
+ de l'application.\nVeuillez v\u00e9rifier que vous lancez l'application \ndepuis \
+ la bonne adresse internet.
+
+m.default_install_error = la section de support du site
+
+m.another_getdown_running = Plusieurs instances d'installation de cette \
+ application sont d\u00e9j\u00e0 en cours d'ex\u00e9cution. Cette instance va s'arr\u00eater \
+ afin de permettre aux autres d'aboutir.
+
+m.applet_stopped = L'appelet Getdown a \u00e9t\u00e9 stopp\u00e9e.
+
+# application/digest errors
+m.missing_appbase = Le fichier de configuration ne contient pas 'appbase'.
+m.invalid_version = Le fichier de configuration sp\u00e9cifie une version invalide.
+m.invalid_appbase = Le fichier de configuration sp\u00e9cifie un 'appbase' invalide.
+m.missing_class = Le fichier de configuration ne contient pas la classe de l'application.
+m.missing_code = Le fichier de configuration ne sp\u00e9cifie aucune ressource de code.
+m.invalid_digest_file = Le fichier digest est invalide.
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = Annullare l'installazione?
+m.abort_confirm = <html>Sei sicuro di voler annullare l'installazione? \
+ Potrai riprenderla in seguito, riavviando nuovamente l'applicazione.</html>
+m.abort_ok = Chiudi
+m.abort_cancel = Continua l'installazione
+
+m.detecting_proxy = Provo a recuperare le configurazioni del proxy
+
+m.configure_proxy = <html>Impossibile collegarsi al server per \
+ recuperare i dati. \
+ <ul><li> Se il Firewall di Windows o Norton Internet Security bloccano \
+ <code>javaw.exe</code> non si possono scaricare i dati. Devi \
+ permettere a <code>javaw.exe</code> di accedere a internet. Puoi provare \
+ di nuovo, ma dovresti abilitare javaw.exe nella tua configurazione \
+ del firewall ( Start -> Pannello di Controllo -> Windows Firewall ).</ul> \
+ <p> Il tuo computer potrebbe accedere a internet attraverso un proxy e \
+ questo potrebbe non essere stato riconosciuto automaticamente. Se conosci le \
+ tue impostazioni del proxy, puoi inserirle di seguito.</html>
+
+m.proxy_extra = <html>Se sei sicuro di non usare proxy \
+ potrebbe essere un problema di internet o di collegamento con il server. \
+ In questo caso puoi annullare e ripetere l'installazione più tardi.</html>
+
+m.proxy_host = IP Proxy
+m.proxy_port = Porta Proxy
+m.proxy_username = Nome utente
+m.proxy_password = Parola d'ordine
+m.proxy_auth_required = Autenticazione richiesta
+m.proxy_ok = OK
+m.proxy_cancel = Annulla
+
+m.downloading_java = Scaricando la Java Virtual Machine
+m.unpacking_java = Scompattando la Java Virtual Machine
+
+m.resolving = Recuperando i file da scaricare
+m.downloading = Download dei dati
+m.failure = Download fallito: {0}
+
+m.checking = Sto controllando gli aggiornamenti
+m.validating = Validazione
+m.patching = Applico le patch
+m.launching = Avvio
+
+m.patch_notes = Note delle Patch
+m.play_again = Avvia Nuovamente
+
+m.complete = {0}% completato
+m.remain = {0} rimasto
+
+m.updating_metadata = Scarico i file di controllo
+
+m.init_failed = La configurazione è corrotta o mancante. Provo a \
+ scaricarne una nuova copia...
+
+m.java_download_failed = Impossibile scaricare la versione corretta \
+ di Java per il tuo computer.\n\n\
+ Visita www.java.com e scarica l'ultima versione di \
+ Java, poi lancia di nuovo l'applicazione.
+
+m.java_unpack_failed = Impossibile scompattare l'aggiornamento di \
+ Java. Verifica di avere almeno 100 MB di spazio libero nel tuo \
+ hard disk e prova a rilanciare l'applicazione.\n\n\
+ Se l'errore persiste, vistia www.java.com, scarica e \
+ installa l'ultima versione di Java e riprova.
+
+m.unable_to_repair = Impossibile scaricare i file necessari dopo 5 \
+ tentativi. Puoi provare a rilanciare l'applicazione, ma se fallisce \
+ di nuovo potresti dover reinstallarla.
+
+m.unknown_error = L'applicazione non è stata avviata a causa di uno strano \
+ errore che non conosco. Visita\n{0} per avere informazioni \
+ in merito.
+m.init_error = L'applicazione non è stata avviata a causa del seguente \
+ errore:\n{0}\n\nVistita\n{1} per avere \
+ informazioni su come risolvere il problema.
+
+m.readonly_error = La directory dove l'applicazione è installata: \
+ \n{0}\nè in sola lettura. Installa l'applicazione dove hai i diritti \
+ di scrittura.
+
+m.missing_resource = L'applicazione non è stata avviata a causa di mancanza \
+ di risorse:\n{0}\n\nVisita\n{1} per avere informazioni su come risolvere \
+ questi problemi.
+
+m.insufficient_permissions_error = Non hai accettato la \
+ firma digitale. Se vuoi eseguire l'applicazione devi accettare la \
+ firma digitale.\n\nPer farlo, riavvia il tuo browser \
+ e ritorna in questa pagina per rilanciare l'applicazione. Quando l'avviso \
+ di sicurezza viene mostrato, clicca per accettare la firma digitale \
+ ed eseguire l'applicazione con i privilegi necessari.
+
+m.corrupt_digest_signature_error = Impossibile verificare la firma digitale dell'applicazione \
+ .\nControlla di aver lanciato l'applicazione dal\n\
+ sito web corretto.
+
+m.default_install_error = la sezione di supporto del sito
+
+m.another_getdown_running = E' già in esecuzione un'istanza del programma. \
+ Questa verrà chiusa.
+
+m.applet_stopped = L'applet di Getdown è stata interrotta.
+
+# application/digest errors
+m.missing_appbase = Il tag "appbase" è mancante.
+m.invalid_version = Il file di configurazione non contiene una versione valida (tag "version").
+m.invalid_appbase = Il tag "appbase" non è valido.
+m.missing_class = Il file di configurazione non contiene la classe da eseguire (tag "class").
+m.missing_code = Il file di configurazione non contiene alcuna risorsa (tag "code").
+m.invalid_digest_file = Il file di digest non è valido.
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u4e2d\u6b62\u3057\u307e\u3059\u304b\uff1f
+m.abort_confirm = <html>\u672c\u5f53\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u4e2d\u6b62\u3057\u307e\u3059\u304b\uff1f \
+ \u5f8c\u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u305f\u969b\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u518d\u958b\u3067\u304d\u307e\u3059\u3002</html>
+m.abort_ok = \u4e2d\u6b62
+m.abort_cancel = \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u306e\u7d9a\u884c
+
+m.detecting_proxy = \u81ea\u52d5\u30d7\u30ed\u30ad\u30b7\u8a2d\u5b9a\u5b9f\u884c\u4e2d
+
+m.configure_proxy = <html>\u30b5\u30fc\u30d0\u306b\u63a5\u7d9a\u3067\u304d\u306a\u3044\u305f\u3081\u3001\u30b2\u30fc\u30e0\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306b \
+ \u5931\u6557\u3057\u307e\u3057\u305f\u3002 \
+ <ul><li>\u30a6\u30a3\u30f3\u30c9\u30a6\u30ba\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u307e\u305f\u306f\u30ce\u30fc\u30c8\u30f3\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u304c \
+ <code>javaw.exe</code>\u3092\u30d6\u30ed\u30c3\u30af\u3059\u308b\u3088\u3046\u8a2d\u5b9a\u3057\u3066\u3042\u308b\u5834\u5408\u306f\u3001\u30b2\u30fc\u30e0\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093\u3002 \u8a2d\u5b9a\u3092 \
+ <code>javaw.exe</code>\u7d4c\u7531\u3067\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u308b\u3088\u3046\u306b\u5909\u66f4\u3057\u3066\u304f\u3060\u3055\u3044\u3002 \u30b2\u30fc\u30e0\u3092\u518d\u8d77\u52d5 \
+ \u3057\u305f\u5f8c\u3001\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u306e\u8a2d\u5b9a\u304b\u3089javaw.exe \u3092\u524a\u9664 \
+ \u3057\u3066\u304f\u3060\u3055\u3044\uff08\u30b9\u30bf\u30fc\u30c8\u2192\u30b3\u30f3\u30c8\u30ed\u30fc\u30eb\u30d1\u30cd\u30eb\u2192\u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\uff09\u3002</ul> \
+ <p>\u30d7\u30ed\u30ad\u30b7\u8a2d\u5b9a\u306e\u81ea\u52d5\u691c\u51fa\u304c\u3067\u304d\u307e\u305b\u3093\u3002\u304a\u4f7f\u3044\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u306f \
+ \u30d7\u30ed\u30ad\u30b7\u3092\u4f7f\u7528\u3057\u3066\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u3078\u30a2\u30af\u30bb\u30b9\u3057\u3066\u3044\u307e\u3059\u3002 \u30d7\u30ed\u30ad\u30b7\u8a2d\u5b9a\u306e\u8a73\u7d30\u304c \
+ \u308f\u304b\u3063\u3066\u3044\u308b\u5834\u5408\u306f\u3001\u4e0b\u306b\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002</html>
+
+m.proxy_extra = <html>\u30d7\u30ed\u30ad\u30b7\u3092\u4f7f\u7528\u3057\u3066\u3044\u306a\u3044\u5834\u5408\u306f\u3001\u4e00\u6642\u7684\u306a \
+ \u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u306e\u4e0d\u5177\u5408\u306b\u3088\u308a\u3001\u30b5\u30fc\u30d0\u3068\u4ea4\u4fe1\u3067\u304d\u306a\u3044\u72b6\u614b\u306b\u3042\u308b \
+ \u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002 \u305d\u306e\u5834\u5408\u306f\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u3066\u3001 \
+ \u5f8c\u307b\u3069\u6539\u3081\u3066\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002</html>
+
+m.proxy_host = \u30d7\u30ed\u30ad\u30b7IP
+m.proxy_port = \u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8
+m.proxy_username = Username
+m.proxy_password = Password
+m.proxy_auth_required = Authentication required
+m.proxy_ok = OK
+m.proxy_cancel = \u30ad\u30e3\u30f3\u30bb\u30eb
+
+m.downloading_java = Java\u30d0\u30fc\u30c1\u30e3\u30eb\u30de\u30b7\u30f3\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u4e2d
+m.unpacking_java = Java\u30d0\u30fc\u30c1\u30e3\u30eb\u30de\u30b7\u30f3\u306e\u89e3\u51cd\u4e2d
+
+m.resolving = \u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u306e\u8a2d\u5b9a\u4e2d
+m.downloading = \u30c7\u30fc\u30bf\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u4e2d
+m.failure = \u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u5931\u6557\uff1a {0}
+
+m.checking = \u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u306e\u78ba\u8a8d\u4e2d
+m.validating = \u8a8d\u8a3c\u4e2d
+m.patching = \u4fee\u6b63\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5b9f\u884c\u4e2d
+m.launching = \u5b9f\u884c\u4e2d
+
+m.complete = {0}\uff05\u5b8c\u4e86
+m.remain = \u3000\u6b8b\u308a{0}
+
+m.updating_metadata = \u30b3\u30f3\u30c8\u30ed\u30fc\u30eb\u30d5\u30a1\u30a4\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u4e2d
+
+m.init_failed = \u74b0\u5883\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3001\u307e\u305f\u306f\u58ca\u308c\u3066\u3044\u307e\u3059\u3002 \u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u3092 \
+ \u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u4e2d\u2026
+
+m.java_download_failed = \u304a\u4f7f\u3044\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u306b\u3001Java\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u6700\u65b0 \
+ \u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u81ea\u52d5\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n\n \
+ www.java.com \u304b\u3089\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u624b\u52d5\u3067\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u3001 \
+ \u518d\u5ea6\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.java_unpack_failed = Java\u306e\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u89e3\u51cd \
+ \u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 \u30cf\u30fc\u30c9\u30c9\u30e9\u30a4\u30d6\u306e\u30e1\u30e2\u30ea\u304c100MB\u4ee5\u4e0a\u3042\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304b\u3089 \
+ \u518d\u5ea6\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002\n\n \
+ \u554f\u984c\u304c\u89e3\u6c7a\u3057\u306a\u3044\u5834\u5408\u306f\u3001www.java.com \u304b\u3089Java\u306e\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u3092 \
+ \u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3066\u304b\u3089\u3001\u518d\u5ea6\u304a\u8a66\u3057\u304f\u3060\u3055\u3044\u3002
+
+m.unable_to_repair = 5\u56de\u8a66\u884c\u3057\u307e\u3057\u305f\u304c\u3001\u5fc5\u8981\u306a\u30d5\u30a1\u30a4\u30eb\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9 \
+ \u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 \u5f8c\u307b\u3069\u6539\u3081\u3066\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002 \
+ \u518d\u5ea6\u5931\u6557\u3057\u305f\u5834\u5408\u306f\u3001\u30a2\u30f3\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u5f8c\u306b\u518d\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.unknown_error = \u539f\u56e0\u4e0d\u660e\u306e\u30a8\u30e9\u30fc\u306b\u3088\u308a\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c \
+ \u5b9f\u884c\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 \u89e3\u6c7a\u65b9\u6cd5\u3092\n{0}\u3067 \
+ \u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+m.init_error = \u6b21\u306e\u30a8\u30e9\u30fc\u306b\u3088\u308a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 \
+ \u3067\u3057\u305f\u3002\n{0}\n\n\u5bfe\u51e6\u65b9\u6cd5\u3092\n{1}\u3067 \
+ \u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.readonly_error = \u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3055\u308c\u305f\u30d5\u30a9\u30eb\u30c0\u306f \
+ \n{0}\n\u8aad\u307f\u53d6\u308a\u5c02\u7528\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059\u3002 \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u66f8\u304d\u8fbc\u307f\u304c\u3067\u304d\u308b\u30d5\u30a9\u30eb\u30c0\u306b \
+ \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.missing_resource = \u30ea\u30bd\u30fc\u30b9\u4e0d\u660e\u306e\u305f\u3081\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 \
+ \u3067\u3057\u305f\u3002\n{0}\n\n\u5bfe\u51e6\u65b9\u6cd5\u3092\n{1}\u3067\u78ba\u8a8d \
+ \u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.insufficient_permissions_error = \u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30c7\u30b8\u30bf\u30eb\u7f72\u540d\u304c\u62d2\u5426 \
+ \u3055\u308c\u307e\u3057\u305f\u3002 \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3059\u308b\u5834\u5408\u306f\u3001\u30c7\u30b8\u30bf\u30eb\u7f72\u540d\u306e\u627f\u8a8d\u304c \
+ \u5fc5\u8981\u3067\u3059\u3002\n\n\u627f\u8a8d\u306b\u306f\u3001\u30d6\u30e9\u30a6\u30b6\u3092\u9589\u3058\u3066\u304b\u3089\u518d\u5ea6\u958b\u304d\u3001 \
+ \u672c\u30db\u30fc\u30e0\u30da\u30fc\u30b8\u3092\u518d\u8868\u793a\u3057\u3066\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u518d\u5ea6\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044 \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e \
+ \u8b66\u544a\u304c\u8868\u793a\u3055\u308c\u305f\u6642\u306f\u3001\u5b9f\u884c\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u30c7\u30b8\u30bf\u30eb\u7f72\u540d\u3092\u627f\u8a8d\u3057\u3001 \
+ \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.corrupt_digest_signature_error = \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30c7\u30b8\u30bf\u30eb\u7f72\u540d\u304c\u8a8d\u8a3c \
+ \u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n\u6307\u5b9a\u30db\u30fc\u30e0\u30da\u30fc\u30b8\u304b\u3089\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\u3057\u3066\u3044\u308b\u304b\n \
+ \u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+m.default_install_error = \u30db\u30fc\u30e0\u30da\u30fc\u30b8\u3067\u306e\u30b5\u30dd\u30fc\u30c8\u8868\u793a
+
+# application/digest errors
+m.missing_appbase = \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eappbase\u304c\u4e0d\u660e\u3067\u3059\u3002
+m.invalid_version = \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u52b9\u306a\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059\u3002
+m.invalid_appbase = \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u304c\u7121\u52b9\u306aappbase\u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059\u3002
+m.missing_class = \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30af\u30e9\u30b9\u304c\u4e0d\u660e\u3067\u3059\u3002
+m.missing_code = \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3067\u30b3\u30fc\u30c9\u30ea\u30bd\u30fc\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+m.invalid_digest_file = \u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb\u304c\u7121\u52b9\u3067\u3059\u3002
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = \uC124\uCE58\uB97C \uCDE8\uC18C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?
+m.abort_confirm = <html>\uC815\uB9D0\uB85C \uC124\uCE58\uB97C \uCDE8\uC18C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? \
+ \uB098\uC911\uC5D0 \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uC2E4\uD589\uD558\uC5EC \uC124\uCE58\uB97C \uC7AC\uAC1C\uD558\uC5EC \uC8FC\uC2ED\uC2DC\uC624.</html>
+m.abort_ok = \uC911\uC9C0
+m.abort_cancel = \uACC4\uC18D\uD558\uC5EC \uC124\uCE58
+
+m.detecting_proxy = \uC790\uB3D9 \uD504\uB85D\uC2DC\uB97C \uC124\uC815\uC744 \uC2DC\uB3C4
+
+m.configure_proxy = <html>\uAC8C\uC784 \uB370\uC774\uD130\uB97C \uBC1B\uAE30 \uC704\uD55C \uC11C\uBC84 \uC811\uC18D\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4.\
+ <ul><li>\uC708\uB3C4\uC6B0 \uBC29\uD654\uBCBD \uB610\uB294 \uB178\uD134 \uC778\uD130\uB137 \uC2DC\uD050\uB9AC\uD2F0\uAC00 <code>javaw.exe</code>\uC774 \uC124\uC815\uC5D0\uC11C \uCC28\uB2E8\uB418\uC5B4 \uC788\uC744 \uACBD\uC6B0, \
+ \uAC8C\uC784 \uB370\uC774\uD130\uB97C \uB2E4\uC6B4\uB85C\uB4DC \uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \
+ <code>javaw.exe</code>\uAC00 \uC778\uD130\uB137 \uC5F0\uACB0\uC744 \uD560 \uC218 \uC788\uB3C4\uB85D \uC124\uC815\uC744 \uBCC0\uACBD\uD558\uC5EC \uC8FC\uC2ED\uC2DC\uC624. \
+ \uAC8C\uC784\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD55C \uD6C4, \uBC29\uD654\uBCBD \uC124\uC815\uC5D0\uC11C javaw.exe\uB97C \uC0AD\uC81C\uD558\uC5EC \uC8FC\uC2ED\uC2DC\uC624. \
+ ( \uC2DC\uC791 -> \uC81C\uC5B4\uD310 -> \uC708\uB3C4\uC6B0 \uBC29\uD654\uBCBD )</ul> \
+ <p> \uCEF4\uD4E8\uD130\uAC00 \uD504\uB85D\uC2DC \uC11C\uBC84\uB97C \uD1B5\uD574 \uC778\uD130\uB137\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uB2E4\uBA74, \uD504\uB85D\uC2DC \uC124\uC815\uC758 \uC790\uB3D9 \uAD6C\uC131\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC73C\uBBC0\uB85C, \
+ \uC0AC\uC6A9\uD558\uB294 \uD504\uB85D\uC2DC \uC124\uC815\uC744 \uC54C\uACE0 \uC788\uC744 \uACBD\uC6B0 \uC544\uB798\uC5D0 \uC785\uB825\uD558\uC5EC \uC8FC\uC2DC\uAE38 \uBC14\uB78D\uB2C8\uB2E4.</html>
+
+m.proxy_extra = \uC790\uB3D9 \uD504\uB85D\uC2DC\uB97C \uC124\uC815\uC744 \uC2DC\uB3C4
+
+m.proxy_host = \uD504\uB85D\uC2DC IP
+m.proxy_port = \uD504\uB85D\uC2DC \uD3EC\uD2B8
+m.proxy_username = Username
+m.proxy_password = Password
+m.proxy_auth_required = Authentication required
+m.proxy_ok = OK
+m.proxy_cancel = \uCDE8\uC18C
+
+m.downloading_java = \uC790\uBC14 \uAC00\uC0C1 \uBA38\uC2E0(JVM) \uB2E4\uC6B4\uB85C\uB4DC \uC911
+m.unpacking_java = \uC790\uBC14 \uAC00\uC0C1 \uBA38\uC2E0(JVM) \uC555\uCD95\uC744 \uD574\uC81C\uD558\uB294 \uC911
+
+m.resolving = \uB2E4\uC6B4\uB85C\uB4DC \uBD84\uC11D \uC911
+m.downloading = \uB370\uC774\uD130 \uB2E4\uC6B4\uB85C\uB4DC \uC911
+m.failure = \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328: {0}
+
+m.checking = \uC5C5\uB370\uC774\uD2B8 \uCCB4\uD06C
+m.validating = \uC720\uD6A8\uC131 \uAC80\uC0AC \uC911
+m.patching = \uD328\uCE58 \uC911
+m.launching = \uC2E4\uD589 \uC911
+
+m.patch_notes = \uD328\uCE58 \uB178\uD2B8
+m.play_again = \uB2E4\uC2DC \uC2E4\uD589
+
+m.complete = {0}% \uC644\uB8CC
+m.remain = {0} \uB0A8\uC74C
+
+m.updating_metadata = \uCEE8\uD2B8\uB864 \uD30C\uC77C\uC744 \uB2E4\uC6B4\uB85C\uB4DC \uC911
+
+m.init_failed = \uC124\uC815 \uD30C\uC77C\uC774 \uB204\uB77D\uB418\uC5C8\uAC70\uB098 \uBCC0\uD615\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \
+ \uC0C8\uB85C\uC6B4 \uBCF5\uC0AC\uBCF8\uC744 \uB2E4\uC6B4\uB85C\uB4DC \uC911\uC785\uB2C8\uB2E4...
+
+m.java_download_failed = \uC774 \uCEF4\uD4E8\uD130\uC5D0 \uD544\uC694\uD55C \uC0C8\uB85C\uC6B4 \uBC84\uC804\uC758 \uC790\uBC14\uB97C \uC790\uB3D9\uC73C\uB85C \uB2E4\uC6B4\uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n\n\
+ \uC790\uBC14 \uC6F9\uC0AC\uC774\uD2B8(www.java.com)\uB85C \uAC00\uC11C \uCD5C\uC2E0\uC758 \uC790\uBC14\uB97C \uB2E4\uC6B4\uB85C\uB4DC \uBC1B\uC73C\uC2E0 \uD6C4, \
+ \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC8FC\uC2ED\uC2DC\uC624.
+
+m.java_unpack_failed = \uC5C5\uB370\uC774\uD2B8\uB41C \uBC84\uC804\uC758 \uC790\uBC14\uC758 \uC555\uCD95\uC744 \uD480 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \
+ \uD558\uB4DC\uB4DC\uB77C\uC774\uBE0C\uC5D0 \uCD5C\uC18C\uD55C 100MB\uC758 \uC6A9\uB7C9\uC744 \uD655\uBCF4\uD55C \uC774\uD6C4, \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC8FC\uC2ED\uC2DC\uC624.\n\n\
+ \uB9CC\uC57D \uBB38\uC81C\uAC00 \uD574\uACB0\uB418\uC9C0 \uC54A\uB294\uB2E4\uBA74, \uC790\uBC14 \uC6F9\uC0AC\uC774\uD2B8(www.java.com)\uB85C \uAC00\uC11C \uCD5C\uC2E0\uC758 \uC790\uBC14\uB97C \uB2E4\uC6B4\uB85C\uB4DC \uBC1B\uC73C\uC2E0 \uD6C4, \
+ \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC8FC\uC2ED\uC2DC\uC624.
+
+m.unable_to_repair = \uB2E4\uC12F\uBC88\uC758 \uC2DC\uB3C4\uC5D0\uB3C4 \uD544\uC694\uD55C \uD30C\uC77C\uC744 \uB2E4\uC6B4\uB85C\uB4DC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \
+ \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uB2E4\uC2DC \uC2DC\uC791\uD574\uBCF4\uC2DC\uACE0, \uADF8\uB798\uB3C4 \uB2E4\uC6B4\uB85C\uB4DC\uC5D0 \uC2E4\uD328\uD55C\uB2E4\uBA74, \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uC81C\uAC70\uD55C \uD6C4, \uB2E4\uC2DC \uC2E4\uD589\uD574\uBCF4\uC2DC\uAE30 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.unknown_error = \uBCF5\uAD6C\uB420 \uC218 \uC5C6\uB294 \uC624\uB958\uB85C \uC778\uD558\uC5EC \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC758 \uC2E4\uD589\uC774 \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \
+ \n{0}\uC5D0 \uB300\uD55C \uBCF5\uAD6C \uBC29\uBC95\uC744 \uCC3E\uAE30 \uC704\uD574\uC11C \uBC29\uBB38\uD558\uC2DC\uAE38 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.init_error = \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC774 \uC544\uB798\uC640 \uAC19\uC740 \uC5D0\uB7EC\uB85C \uC2E4\uD589\uC774 \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC5D0\uB7EC:\
+ \n{0}\n\n{1}\uC5D0 \uB300\uD55C \uBB38\uC81C \uD574\uACB0 \uBC29\uBC95\uC744 \uCC3E\uAE30 \uC704\uD574\uC11C \uBC29\uBB38\uD558\uC2DC\uAE38 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.readonly_error = \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC774 \uC124\uCE58\uB41C \uB514\uB809\uD1A0\uB9AC: \
+ \n{0}\n\uAC00 \uC77D\uAE30 \uC804\uC6A9\uC785\uB2C8\uB2E4. \uC77D\uAE30 \uAD8C\uD55C\uC774 \uC2B9\uC778\uB41C \uB809\uD1A0\uB9AC\uC5D0 \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uC124\uCE58\uD558\uC2DC\uAE38 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.missing_resource = \uB9AC\uC18C\uC2A4\uC758 \uC190\uC2E4\uB85C \uC778\uD558\uC5EC \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC758 \uC2E4\uD589\uC774 \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4. : \
+ \n{0}\n\n{1}\uC5D0 \uB300\uD55C \uBB38\uC81C \uD574\uACB0 \uBC29\uBC95\uC744 \uCC3E\uAE30 \uC704\uD574\uC11C \uBC29\uBB38\uD558\uC2DC\uAE38 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.insufficient_permissions_error = \uC774 \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC758 \uB514\uC9C0\uD0C8 \uC11C\uBA85\uC744 \uD655\uC778\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \
+ \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uC2E4\uD589\uD558\uAE30 \uC704\uD574\uC11C \uB514\uC9C0\uD0C8 \uC11C\uBA85\uC744 \uD655\uC778\uD558\uC5EC \uC8FC\uC2ED\uC2DC\uC624. \
+ \n\n\uADF8\uB9AC\uACE0 \uB098\uC11C \uC6F9 \uBE0C\uB77C\uC6B0\uC800\uB97C \uB2EB\uACE0 \uB2E4\uC2DC \uC2DC\uC791\uD558\uC5EC \uC6F9\uD398\uC774\uC9C0\uB85C \uB3CC\uC544\uC640 \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC744 \uC7AC\uC2DC\uC791\uD574\uC8FC\uC2DC\uAE30 \uBC14\uB78D\uB2C8\uB2E4. \
+ \uBCF4\uC548\uC5D0 \uB300\uD55C \uB300\uD654\uC0C1\uC790\uAC00 \uBCF4\uC774\uBA74, \uB514\uC9C0\uD0C8 \uC11C\uBA85\uC5D0 \uB300\uD55C \uD655\uC778 \uBC84\uD2BC\uC744 \uD074\uB9AD\uD558\uACE0, \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC774 \uC2E4\uD589\uB418\uAE30 \uC704\uD55C \
+ \uAD8C\uD55C\uC744 \uBD80\uC5EC\uD574\uC8FC\uC2DC\uAE30 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.corrupt_digest_signature_error = \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC758 \uB514\uC9C0\uD0C8 \uC11C\uBA85\uC744 \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n \
+ \uC62C\uBC14\uB978 \uC6F9\uC0AC\uC774\uD2B8\uC5D0\uC11C \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158\uC774 \uC2E4\uD589\uB418\uACE0 \uC788\uB294 \uC9C0 \uD655\uC778\uBC14\uB78D\uB2C8\uB2E4.
+
+m.default_install_error = \uC6F9\uC0AC\uC774\uD2B8\uC758 \uC9C0\uC6D0 \uBA54\uB274(support section)\uB97C \uD655\uC778\uD558\uC2DC\uAE30 \uBC14\uB78D\uB2C8\uB2E4.
+
+m.another_getdown_running = \uC774 \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158 \uC778\uC2A4\uD1A8\uB7EC\uC758 \uB2E4\uC911 \uC778\uC2A4\uD134\uC2A4\uAC00 \uC2E4\uD589\uC911\uC785\uB2C8\uB2E4. \
+ \uD558\uB098\uAC00 \uC644\uB8CC\uB420 \uB54C\uAE4C\uC9C0 \uC911\uB2E8\uB429\uB2C8\uB2E4.
+
+m.applet_stopped = Getdown \uC560\uD50C\uB9BF \uC2E4\uD589\uC774 \uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
+
+# application/digest errors
+m.missing_appbase = \uC124\uC815 \uD30C\uC77C\uC5D0 'appbase' \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
+m.invalid_version = \uC124\uC815 \uD30C\uC77C\uC5D0 \uC798\uBABB\uB41C \uBC84\uC804\uC774 \uBA85\uC2DC\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.
+m.invalid_appbase = \uC124\uC815 \uD30C\uC77C\uC5D0 \uC798\uBABB\uB41C 'appbase'\uAC00 \uBA85\uC2DC\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.
+m.missing_class = \uC124\uC815 \uD30C\uC77C\uC5D0 \uC5B4\uD50C\uB9AC\uCF00\uC774\uC158 \uD074\uB798\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
+m.missing_code = \uC124\uC815 \uD30C\uC77C\uC5D0 \uB9AC\uC18C\uC2A4\uC5D0 \uB300\uD55C \uCF54\uB4DC\uAC00 \uBA85\uC2DC\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.
+m.invalid_digest_file = \uB2E4\uC774\uC81C\uC2A4\uD2B8 \uD30C\uC77C\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.abort_title = Cancelar a instala\u00E7\u00E3o?
+m.abort_confirm = <html>Tem certeza que deseja cancelar a instala\u00E7\u00E3o? \
+ Voc\u00EA pode continuar a instala\u00E7\u00E3o mais tarde, \
+ basta executar a aplica\u00E7\u00E3o novamente.</html>
+m.abort_ok = Sair
+m.abort_cancel = Continuar a instala\u00E7\u00E3o
+
+m.detecting_proxy = Tentando detectar automaticamente as configura\u00E7\u00F5es de proxy
+
+m.configure_proxy = <html>N\u00E3o foi poss\u00EDvel conectar aos nossos servidores para \
+ fazer o download dos dados. \
+ <ul><li> Se o Firewall do Windows ou o Norton Internet Security est\u00E1 configurado \
+ para bloquear o programa <code>javaw.exe</code> n\u00E3o ser\u00E1 poss\u00EDvel realizar \
+ o download. Voc\u00EA ter\u00E1 que permitir que o programa <code>javaw.exe</code> acesse \
+ a internet. Voc\u00EA pode tentar executar o programa novamente, mas voc\u00EA precisa \
+ remover o programa javaw.exe das configura\u00E7\u00F5es do firewall (Iniciar -> Painel \
+ de controle -> Firewall do Windows).</ul> \
+ <p> Seu computador pode estar acessando a internet atrav\u00E9s de um proxy e n\u00E3o foi \
+ capaz de detectar automaticamente as configura\u00E7\u00F5es de proxy. \
+ Voc\u00EA pode informar esses dados abaixo.</html>
+
+m.proxy_extra = <html>Se voc\u00EA tem certeza que n\u00E3o usa um proxy, ent\u00E3o pode ser \
+ que exista um problema tempor\u00E1rio que est\u00E1 impedindo a comunica\u00E7\u00E3o \
+ com os nossos servidores. Neste caso voc\u00EA pode cancelar e tentar instalar novamente \
+ mais tarde.</html>
+
+m.proxy_host = IP do Proxy
+m.proxy_port = Porta do Proxy
+m.proxy_username = Nome de usu\u00e1rio
+m.proxy_password = Senha
+m.proxy_auth_required = Autentifica\u00e7\u00e3o requerida
+m.proxy_ok = OK
+m.proxy_cancel = Cancelar
+
+m.downloading_java = Fazendo o download da m\u00E1quina virtual Java
+m.unpacking_java = Descompactando a m\u00E1quina virtual Java
+
+m.resolving = Resolvendo downloads
+m.downloading = Transferindo dados
+m.failure = Download falhou: {0}
+
+m.checking = Verificando atualiza\u00E7\u00F5es
+m.validating = Validando
+m.patching = Atualizando
+m.launching = Executando
+
+m.patch_notes = Corrigir notas
+m.play_again = Jogar de novo
+
+m.complete = {0}% completo
+m.remain = {0} Permanecer
+
+m.updating_metadata = Transferindo arquivos de controle
+
+m.init_failed = Nosso arquivo de configura\u00E7\u00E3o est\u00E1 ausente ou corrompido. Tente \
+ baixar uma nova c\u00F3pia...
+
+m.java_download_failed = N\u00E3o conseguimos baixar automaticamente a\
+ vers\u00E3o necess\u00E1ria do Java para o seu computador.\n\n\
+ Por favor, acesse www.java.com, baixe e instale a \u00FAltima vers\u00E3o do \
+ Java, em seguida, tente executar o aplicativo novamente.
+
+m.java_unpack_failed = N\u00E3o conseguimos descompactar uma vers\u00E3o atualizada do \
+ Java. Por favor, certifique-se de ter pelo menos 100 MB de espa\u00E7o livre em seu \
+ disco r\u00EDgido e tente executar o aplicativo novamente. \n\n\
+ Se isso n\u00E3o resolver o problema, acesse www.java.com,baixe e \
+ instale a \u00FAltima vers\u00E3o do Java e tente novamente.
+
+m.unable_to_repair = N\u00E3o conseguimos baixar os arquivos necess\u00E1rios depois de \
+ cinco tentativas. Voc\u00EA pode tentar executar o aplicativo novamente, mas se ele \
+ falhar pode ser necess\u00E1rio desinstalar e reinstalar.
+
+m.unknown_error = A aplica\u00E7\u00E3o falhou ao iniciar devido a algum erro estranho \
+ do qual n\u00E3o conseguimos recuperar. Por favor, visite \n{0} para obter \
+ informa\u00E7\u00F5es sobre como recuperar.
+m.init_error = A aplica\u00E7\u00E3o falhou ao iniciar devido ao seguinte \
+ erro:\n{0}\n\nPor favor visite \n{1} para \
+ informa\u00E7\u00F5es sobre como lidar com esse problema.
+
+m.readonly_error =O diret\u00F3rio no qual este aplicativo est\u00E1 instalado: \
+ \n{0}\n \u00E9 somente leitura. Por favor, instale o aplicativo em um diret\u00F3rio onde \
+ voc\u00EA tem acesso de grava\u00E7\u00E3o.
+
+m.missing_resource = A aplica\u00E7\u00E3o falhou ao iniciar devido a uma falta \
+ de recurso:\n{0}\n\n Por favor, visite\n{1} para obter informa\u00E7\u00F5es sobre \
+ como lidar com tal problema.
+
+m.insufficient_permissions_error = Voc\u00EA n\u00E3o aceitou a assinatura digital \
+ do aplicativo. Se voc\u00EA quiser executar o aplicativo, voc\u00EA ter\u00E1 que aceitar \
+ a assinatura digital. \n\nPara fazer isso, voc\u00EA ter\u00E1 que sair do seu navegador, \
+ reinici\u00E1-lo, e retornar a esta p\u00E1gina web para executar a aplica\u00E7\u00E3o. \
+ Quando o di\u00E1logo de seguran\u00E7a aparecer, clique no bot\u00E3o para aceitar a \
+ assinatura digital e conceder a este aplicativo os privil\u00E9gios necess\u00E1rios \
+ para executar.
+
+m.corrupt_digest_signature_error = N\u00E3o conseguimos verificar a assinatura digital \
+ do aplicativo.\nPor favor, verifique se voc\u00EA est\u00E1 utilizando o aplicativo \nde um \
+ site correto.
+
+m.default_install_error = a se\u00E7\u00E3o de suporte do site
+
+m.another_getdown_running = V\u00E1rias inst\u00E2ncias desta aplica\u00E7\u00E3o \
+ est\u00E3o em execu\u00E7\u00E3o. Esta ir\u00E1 parar e deixar outra completar suas atividades.
+
+m.applet_stopped = Foi solicitado ao miniaplicativo GetDow que parasse de trabalhar.
+
+# application/digest errors
+m.missing_appbase = O arquivo de configura\u00E7\u00E3o n\u00E3o possui o 'AppBase'.
+m.invalid_version = O arquivo de configura\u00E7\u00E3o especifica uma vers\u00E3o inv\u00E1lida.
+m.invalid_appbase = O arquivo de configura\u00E7\u00E3o especifica um 'AppBase' inv\u00E1lido.
+m.missing_class = O arquivo de configura\u00E7\u00E3o n\u00E3o possui a classe de aplicativo.
+m.missing_code = O arquivo de configura\u00E7\u00E3o n\u00E3o especifica um recurso de c\u00F3digo.
+m.invalid_digest_file = O arquivo digest \u00E9 inv\u00E1lido.
--- /dev/null
+#
+# $Id$
+#
+# Getdown translation messages
+
+m.detecting_proxy = \u641c\u5bfb\u4ee3\u7406\u670d\u52a1\u5668
+
+m.configure_proxy = <html>\u6211\u4eec\u65e0\u6cd5\u8fde\u63a5\u5230\u670d\u52a1\u5668\u4e0b\u8f7d\u6e38\u620f\u6570\u636e\u3002\u8fd9\u53ef\u80fd\u662f\u7531\u4e8e \
+ \u60a8\u7684\u8ba1\u7b97\u673a\u662f\u901a\u8fc7\u4ee3\u7406\u670d\u52a1\u5668\u8fde\u63a5\u4e92\u8054\u7f51\u7684\uff0c\u5e76\u4e14\u6211\u4eec\u65e0\u6cd5\u81ea\u52a8\u83b7\u5f97\u4ee3\u7406\u670d\u52a1\u5668\u7684 \
+ \u8bbe\u7f6e\u3002\u5982\u679c\u60a8\u77e5\u9053\u60a8\u4ee3\u7406\u670d\u52a1\u5668\u7684\u8bbe\u7f6e\uff0c\u60a8\u53ef\u4ee5\u5728\u4e0b\u9762\u8f93\u5165\u3002</html>
+
+m.proxy_extra = <html>\u5982\u679c\u60a8\u786e\u5b9a\u60a8\u6ca1\u6709\u4f7f\u7528\u4ee3\u7406\u670d\u52a1\u5668\uff0c\u8fd9\u53ef\u80fd\u662f\u7531\u4e8e\u6682\u65f6\u65e0\u6cd5 \
+ \u8fde\u63a5\u5230\u4e92\u8054\u7f51\uff0c\u5bfc\u81f4\u65e0\u6cd5\u548c\u670d\u52a1\u5668\u901a\u8baf\u3002\u8fd9\u79cd\u60c5\u51b5\uff0c\u60a8\u53ef\u4ee5\u53d6\u6d88\uff0c\u7a0d\u5019\u518d\u91cd\u65b0\u5b89\u88c5\u3002<br><br> \
+ \u5982\u679c\u60a8\u65e0\u6cd5\u786e\u5b9a\u60a8\u662f\u5426\u4f7f\u7528\u4e86\u4ee3\u7406\u670d\u52a1\u5668\uff0c\u8bf7\u8bbf\u95ee\u6211\u4eec\u7f51\u7ad9\u4e2d\u7684\u6280\u672f\u652f\u6301\u90e8\u4efd\uff0c \
+ \u4e86\u89e3\u5982\u4f55\u68c0\u6d4b\u60a8\u7684\u4ee3\u7406\u670d\u52a1\u5668\u8bbe\u7f6e\u3002</html>
+
+m.proxy_host = \u4ee3\u7406\u670d\u52a1\u5668\u7684IP\u5730\u5740
+m.proxy_port = \u4ee3\u7406\u670d\u52a1\u5668\u7684\u7aef\u53e3\u53f7
+m.proxy_username = Username
+m.proxy_password = Password
+m.proxy_auth_required = Authentication required
+m.proxy_ok = \u786e\u5b9a
+m.proxy_cancel = \u53d6\u6d88
+
+m.resolving = \u5206\u6790\u9700\u4e0b\u8f7d\u5185\u5bb9
+m.downloading = \u4e0b\u8f7d\u6570\u636e
+m.failure = \u4e0b\u8f7d\u5931\u8d25: {0}
+
+m.checking = \u68c0\u67e5\u66f4\u65b0\u5185\u5bb9
+m.validating = \u786e\u8ba4
+m.patching = \u5347\u7ea7
+m.launching = \u542f\u52a8
+
+m.complete = {0}% \u5b8c\u6210
+m.remain = {0} \u5269\u4f59\u65f6\u95f4
+
+m.updating_metadata = \u4e0b\u8f7d\u63a7\u5236\u6587\u4ef6
+
+m.init_failed = \u65e0\u6cd5\u627e\u5230\u914d\u7f6e\u6587\u4ef6\u6216\u5df2\u635f\u574f\u3002\u5c1d\u8bd5\u91cd\u65b0\u4e0b\u8f7d...
+
+m.unable_to_repair = \u7ecf\u8fc75\u6b21\u5c1d\u8bd5\uff0c\u4f9d\u7136\u65e0\u6cd5\u4e0b\u8f7d\u6240\u9700\u7684\u6587\u4ef6\u3002\
+\u60a8\u53ef\u4ee5\u91cd\u65b0\u8fd0\u884c\u7a0b\u5e8f\uff0c\u4f46\u662f\u5982\u679c\u4f9d\u7136\u5931\u8d25\uff0c\u60a8\u53ef\u80fd\u9700\u8981\u53cd\u5b89\u88c5\u5e76\u91cd\u65b0\u5b89\u88c5\u3002
+
+
+m.unknown_error = \u7531\u4e8e\u4e00\u4e9b\u65e0\u6cd5\u56de\u590d\u7684\u4e25\u91cd\u9519\u8bef\uff0c\u7a0b\u5e8f\u542f\u52a8\u5931\u8d25\u3002\
+\u8bf7\u8bbf\u95ee\u6211\u4eec\u7684\u7f51\u7ad9\u7684\u6280\u672f\u652f\u6301\u90e8\u4efd\uff0c\u4e86\u89e3\u5982\u4f55\u89e3\u51b3\u95ee\u9898\u3002
+
+m.init_error = \u7531\u4e8e\u4e0b\u5217\u9519\u8bef\uff0c\u7a0b\u5e8f\u542f\u52a8\u5931\u8d25\uff1a\n{0}\n\n \
+\u8bf7\u8bbf\u95ee\u6211\u4eec\u7684\u7f51\u7ad9\u7684\u6280\u672f\u652f\u6301\u90e8\u4efd\uff0c\u4e86\u89e3\u5982\u4f55\u5904\u7406\u8fd9\u4e9b\u9519\u8bef\u3002
+
+
+m.missing_resource = \u7531\u4e8e\u65e0\u6cd5\u627e\u5230\u4e0b\u5217\u8d44\u6e90\uff0c\u7a0b\u5e8f\u542f\u52a8\u5931\u8d25\uff1a\n{0}\n\n \
+\u8bf7\u8bbf\u95ee\u6211\u4eec\u7684\u7f51\u7ad9\u7684\u6280\u672f\u652f\u6301\u90e8\u4efd\uff0c\u4e86\u89e3\u5982\u4f55\u5904\u7406\u8fd9\u4e9b\u95ee\u9898\u3002
+
+# application/digest errors
+m.missing_appbase = \u914d\u7f6e\u6587\u4ef6\u4e2d\u65e0\u6cd5\u627e\u5230 'appbase'\u3002
+m.invalid_version = \u914d\u7f6e\u6587\u4ef6\u6307\u5b9a\u4e86\u65e0\u6548\u7684\u7248\u672c\u3002
+m.invalid_appbase = \u914d\u7f6e\u6587\u4ef6\u6307\u5b9a\u4e86\u65e0\u6548\u7684 'appbase'\u3002
+m.missing_class = \u914d\u7f6e\u6587\u4ef6\u4e2d\u65e0\u6cd5\u627e\u5230\u7a0b\u5e8f\u6587\u4ef6\u3002
+m.missing_code = \u914d\u7f6e\u6587\u4ef6\u4e2d\u65e0\u6cd5\u627e\u5230\u6307\u5b9a\u7684\u8d44\u6e90\u3002
+m.invalid_digest_file = \u65e0\u6548\u7684\u914d\u7f6e\u6587\u4ef6\u3002
--- /dev/null
+//
+// Getdown - application installer, patcher and launcher
+// Copyright (C) 2004-2018 Getdown authors
+// https://github.com/threerings/getdown/blob/master/LICENSE
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>jregistrykey</groupId>
+ <artifactId>jregistrykey</artifactId>
+ <version>1.0</version>
+ <description>POM was created from install:install-file</description>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata>
+ <groupId>jregistrykey</groupId>
+ <artifactId>jregistrykey</artifactId>
+ <version>1.0</version>
+ <versioning>
+ <versions>
+ <version>1.0</version>
+ </versions>
+ <lastUpdated>20101118155146</lastUpdated>
+ </versioning>
+</metadata>
--- /dev/null
+Main-Class: com.threerings.getdown.launcher.Getdown
+Permissions: all-permissions
+Application-Name: Getdown
+Codebase: *
+Application-Library-Allowable-Codebase: *
+Caller-Allowable-Codebase: *
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.sonatype.oss</groupId>
+ <artifactId>oss-parent</artifactId>
+ <version>7</version>
+ </parent>
+
+ <groupId>com.threerings.getdown</groupId>
+ <artifactId>getdown</artifactId>
+ <packaging>pom</packaging>
+ <version>1.8.3-SNAPSHOT</version>
+
+ <name>getdown</name>
+ <description>An application installer and updater.</description>
+ <url>https://github.com/threerings/getdown</url>
+ <issueManagement>
+ <url>https://github.com/threerings/getdown/issues</url>
+ </issueManagement>
+
+ <licenses>
+ <license>
+ <name>The (New) BSD License</name>
+ <url>http://www.opensource.org/licenses/bsd-license.php</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
+ <developers>
+ <developer>
+ <id>samskivert</id>
+ <name>Michael Bayne</name>
+ <email>mdb@samskivert.com</email>
+ </developer>
+ </developers>
+
+ <scm>
+ <connection>scm:git:git://github.com/threerings/getdown.git</connection>
+ <developerConnection>scm:git:git@github.com:threerings/getdown.git</developerConnection>
+ <url>https://github.com/threerings/getdown</url>
+ </scm>
+
+ <modules>
+ <module>core</module>
+ <module>launcher</module>
+ <module>ant</module>
+ </modules>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.18</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.8</version>
+ <extensions>true</extensions>
+ <inherited>false</inherited>
+ <configuration>
+ <serverId>ossrh-releases</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <stagingProfileId>aa555c46fc37d0</stagingProfileId>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ <!-- Common plugin configuration for all children -->
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.7.0</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ <fork>true</fork>
+ <showDeprecation>true</showDeprecation>
+ <showWarnings>true</showWarnings>
+ <compilerArgs>
+ <arg>-Xlint</arg>
+ <arg>-Xlint:-serial</arg>
+ <arg>-Xlint:-path</arg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.0.2</version>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>3.0.0-M1</version>
+ <configuration>
+ <quiet>true</quiet>
+ <show>public</show>
+ <additionalparam>-Xdoclint:all -Xdoclint:-missing</additionalparam>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>eclipse</id>
+ <activation>
+ <property>
+ <name>m2e.version</name>
+ </property>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <!-- Tell m2eclipse to ignore the enforcer plugin from our parent. Otherwise it warns
+ about not being able to run it. -->
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <versionRange>[1.0,)</versionRange>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>release-sign-artifacts</id>
+ <activation>
+ <property><name>performRelease</name><value>true</value></property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.6</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <keyname>mdb@samskivert.com</keyname>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
--- /dev/null
+#org.gradle.java.home = /Users/bsoares/Java/installs/OpenJDK8U-jdk_x64_mac_hotspot_8u192b12/jdk8u192-b12/Contents/Home
+jalviewDir = .
+
+JAVA_VERSION = 11
+JALVIEW_VERSION = DEVELOPMENT
+INSTALLATION = Source
+jalview_keystore = keys/.keystore
+jalview_keystore.pass = alignmentisfun
+jalview_key = jalview
+jalview_key.pass = alignmentisfun
+jalview_tsaurl =
+proxyPort = 80
+proxyHost = sqid
+jalview_keyalg = SHA1withRSA
+jalview_keydig = SHA1
+
+testngGroups = Functional
+
+javac_source = 11
+javac_target = 11
+
+j8libDir = j8lib
+j11libDir = j11lib
+resourceDir = resources
+helpParentDir = help
+helpDir = help
+docDir = doc
+sourceDir = src
+schemaDir = schemas
+classesDir = classes
+clover = false
+use_clover = false
+cloverClassesDir = clover-classes
+cloverSourcesInstrDir = sources-instr
+packageDir = dist
+outputJar = jalview.jar
+
+testSourceDir = test
+testOutputDir = tests
+utilsDir = utils
+
+buildPropertiesFile = .build_properties
+application_codebase = *.jalview.org
+mainClass = jalview.bin.Jalview
+shadowJarMainClass = jalview.bin.Launcher
+launcherClass = jalview.bin.Jalview
+
+gradlePluginsDir = gradle/plugins
+
+getdown_website_dir = getdown/website
+getdown_resource_dir = resource
+getdown_app_dir = dist
+getdown_j11lib_dir = j11lib
+getdown_files_dir = getdown/files
+getdown_launcher = getdown/lib/getdown-launcher.jar
+getdown_core = getdown/lib/getdown-core-1.8.3-SNAPSHOT.jar
+getdown_lib1 = getdown/lib/commons-compress-1.18.jar
+getdown_base_txt = getdown/files/getdown.txt
+getdown_txt_title = Jalview
+getdown_channel_base = http://www.jalview.org/getdown/jalview
+getdown_channel_name = TEST
+getdown_txt_allow_offline = true
+getdown_txt_jvmmempc = 95
+getdown_txt_multi_jvmarg = -Dgetdownappdir="%APPDIR%"
+getdown_txt_strict_comments = true
+getdown_txt_title = Jalview
+getdown_txt_ui.name = Jalview
+getdown_txt_ui.background = FFFFFF
+getdown_txt_ui.background_image = resources/images/jalview_logo_background_getdown-640x480.png
+getdown_txt_ui.error_background = resources/images/jetset_jalview_splash.png
+getdown_txt_ui.progress_image = resources/images/jalview_logo_background_getdown-progress.png
+getdown_txt_ui.icon = resources/images/JalviewLogo_Huge.png
+getdown_txt_ui.progress = 20, 440, 600, 22
+getdown_txt_ui.progress_bar = AAAAFF
+getdown_txt_ui.progress_text = 000000
+getdown_txt_ui.status = 20, 380, 600, 58
+getdown_txt_ui.status_text = 000066
+getdown_txt_ui.text_shadow = EEEEFF
+getdown_txt_ui.install_error = http://www.jalview.org/download/error
+getdown_txt_ui.mac_dock_icon = resources/images/jalview_logos.ico
+getdown_alt_java8_min_version = 01080000
+getdown_alt_java11_min_version = 11000000
+getdown_alt_java11_txt_multi_java_location = [windows-amd64] /getdown/jre/windows-jre11.tgz,[linux-amd64] /getdown/jre/linux-jre11.tgz,[mac os x] /getdown/jre/macos-jre11.tgz
+getdown_alt_java8_txt_multi_java_location = [windows-amd64] /getdown/jre/windows-jre1.8.tgz,[linux-amd64] /getdown/jre/linux-jre1.8.tgz,[mac os x] /getdown/jre/macos-jre1.8.tgz
+JRE_installs = /Users/bsoares/Java/installs
+Windows_JRE8 = OpenJDK8U-jdk_x64_windows_hotspot_8u202b08/jdk8u202-b08
+Mac_JRE8 = OpenJDK8U-jre_x64_mac_hotspot_8u202b08/jdk8u202-b08-jre/Contents/Home
+Linux_JRE8 = OpenJDK8U-jre_x64_linux_hotspot_8u202b08/jdk8u202-b08-jre
+Windows_JRE11 = OpenJDK11-jre_x64_windows_hotspot_11_28/jdk-11+28-jre
+Mac_JRE11 = OpenJDK11-jre_x64_mac_hotspot_11_28/jdk-11+28-jre/Contents/Home
+Linux_JRE11 = OpenJDK11-jre_x64_linux_hotspot_11_28/jdk-11+28-jre
+
+j8libDir = j8lib
+j11libDir = j11lib
+j11modDir = j11mod
+j11modules = com.sun.istack.runtime,com.sun.xml.bind,com.sun.xml.fastinfoset,com.sun.xml.streambuffer,com.sun.xml.txw2,com.sun.xml.ws.policy,java.activation,java.annotation,java.base,java.compiler,java.datatransfer,java.desktop,java.logging,java.management,java.management.rmi,java.naming,java.prefs,java.rmi,java.scripting,java.security.sasl,java.sql,java.xml,java.xml.bind,java.xml.soap,java.xml.ws,javax.jws,jdk.httpserver,jdk.jsobject,jdk.unsupported,jdk.xml.dom,org.jvnet.mimepull,org.jvnet.staxex,javax.servlet.api,java.ws.rs
+
+install4jResourceDir = utils/install4j
+install4jTemplate = install4j_template.install4j
+install4jBuildDir = build/install4j
+install4jMediaTypes = windows,macosArchive,linuxRPM,linuxDeb
+
+eclipse_extra_jdt_prefs_file = .settings/org.eclipse.jdt.core.jalview.prefs
--- /dev/null
+com.sun.istack.runtime,com.sun.xml.bind,com.sun.xml.fastinfoset,com.sun.xml.streambuffer,com.sun.xml.txw2,com.sun.xml.ws.policy,java.activation,java.annotation,java.base,java.compiler,java.datatransfer,java.desktop,java.logging,java.management,java.management.rmi,java.naming,java.prefs,java.rmi,java.scripting,java.security.sasl,java.sql,java.xml,java.xml.bind,java.xml.soap,java.xml.ws,javax.jws,jdk.httpserver,jdk.jsobject,jdk.unsupported,jdk.xml.dom,org.jvnet.mimepull,org.jvnet.staxex,javax.servlet.api,java.ws.rs
action.save_project = Save Project
action.save_project_as = Save Project as...
action.quit = Quit
+label.quit_jalview = Quit Jalview?
action.expand_views = Expand Views
action.gather_views = Gather Views
action.page_setup = Page Setup...
action.save_project = Guardar proyecto
action.save_project_as = Guardar proyecto como...
action.quit = Salir
+label.quit_jalview = Salir Javliew?
action.expand_views = Expandir vistas
action.gather_views = Capturar vistas
action.page_setup = Configuración de la página
import java.awt.Color;
import java.awt.Dimension;
-import java.awt.Event;
-import java.awt.Font;
+import java.awt.event.InputEvent;import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
// JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
MCMatrix objmat = new MCMatrix(3, 3);
objmat.setIdentity();
- if ((evt.getModifiers() & Event.META_MASK) != 0)
+ if ((evt.getModifiersEx() & InputEvent.META_DOWN_MASK) != 0)
{
objmat.rotatez(((mx - omx)));
}
resNumber = Integer.parseInt(str.substring(22, 26).trim());
resNumIns = str.substring(22, 27).trim();
insCode = str.substring(26, 27).charAt(0);
- this.x = (new Float(str.substring(30, 38).trim()).floatValue());
- this.y = (new Float(str.substring(38, 46).trim()).floatValue());
- this.z = (new Float(str.substring(47, 55).trim()).floatValue());
+ this.x = (Float.valueOf(str.substring(30, 38).trim()).floatValue());
+ this.y = (Float.valueOf(str.substring(38, 46).trim()).floatValue());
+ this.z = (Float.valueOf(str.substring(47, 55).trim()).floatValue());
// optional entries - see JAL-730
String tm = str.substring(54, 60).trim();
if (tm.length() > 0)
{
- occupancy = (new Float(tm)).floatValue();
+ occupancy = (Float.valueOf(tm)).floatValue();
}
else
{
tm = str.substring(60, 66).trim();
if (tm.length() > 0)
{
- tfactor = (new Float(tm).floatValue());
+ tfactor = (Float.valueOf(tm).floatValue());
}
else
{
import java.awt.Color;
import java.awt.Dimension;
-import java.awt.Event;
-import java.awt.Font;
+import java.awt.event.InputEvent;import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
// JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
MCMatrix objmat = new MCMatrix(3, 3);
objmat.setIdentity();
- if ((evt.getModifiers() & Event.META_MASK) != 0)
+ if ((evt.getModifiersEx() & InputEvent.META_DOWN_MASK) != 0)
{
objmat.rotatez(((mx - omx)));
}
n = RegOpt.opt(n, ignoreCase, dontMinQ);
}
n.setParent(this);
- set(new Character(o.c), n, ignoreCase, dontMinQ);
+ set(Character.valueOf(o.c), n, ignoreCase, dontMinQ);
if (ignoreCase)
{
if (o.c != o.altc)
{
- set(new Character(o.altc), n, ignoreCase, dontMinQ);
+ set(Character.valueOf(o.altc), n, ignoreCase, dontMinQ);
}
if (o.c != o.altc2 && o.altc != o.altc2)
{
- set(new Character(o.altc2), n, ignoreCase, dontMinQ);
+ set(Character.valueOf(o.altc2), n, ignoreCase, dontMinQ);
}
}
}
{
return -1;
}
- Pattern n = (Pattern) h.get(new Character(pt.src.charAt(pos)));
+ Pattern n = (Pattern) h.get(Character.valueOf(pt.src.charAt(pos)));
if (n == null)
{
return -1;
/** Matches a Unicode punctuation character. */
class UnicodePunct extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && Prop.isPunct(s.charAt(from)) ? to : -1;
/** Matches a Unicode white space character. */
class UnicodeWhite extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && Prop.isWhite(s.charAt(from)) ? to : -1;
*/
class NUnicodePunct extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && !Prop.isPunct(s.charAt(from)) ? to : -1;
*/
class NUnicodeWhite extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && !Prop.isWhite(s.charAt(from)) ? to : -1;
/** Matches a Unicode word character: an alphanumeric or underscore. */
class UnicodeW extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
if (from >= s.length())
/** Matches a character that is not a Unicode alphanumeric or underscore. */
class NUnicodeW extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
if (from >= s.length())
/** Matches a Unicode decimal digit. */
class UnicodeDigit extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && Prop.isDecimalDigit(s.charAt(from)) ? to
/** Matches a character that is not a Unicode digit. */
class NUnicodeDigit extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && !Prop.isDecimalDigit(s.charAt(from)) ? to
/** Matches a Unicode math character. */
class UnicodeMath extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && Prop.isMath(s.charAt(from)) ? to : -1;
/** Matches a non-math Unicode character. */
class NUnicodeMath extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && !Prop.isMath(s.charAt(from)) ? to : -1;
/** Matches a Unicode currency symbol. */
class UnicodeCurrency extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && Prop.isCurrency(s.charAt(from)) ? to : -1;
/** Matches a non-currency symbol Unicode character. */
class NUnicodeCurrency extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && !Prop.isCurrency(s.charAt(from)) ? to : -1;
/** Matches a Unicode alphabetic character. */
class UnicodeAlpha extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && Prop.isAlphabetic(s.charAt(from)) ? to : -1;
/** Matches a non-alphabetic Unicode character. */
class NUnicodeAlpha extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && !Prop.isAlphabetic(s.charAt(from)) ? to
/** Matches an upper case Unicode character. */
class UnicodeUpper extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && isUpper(s.charAt(from)) ? to : -1;
/** Matches an upper case Unicode character. */
class UnicodeLower extends UniValidator
{
+ @Override
public int validate(StringLike s, int from, int to)
{
return from < s.length() && isLower(s.charAt(from)) ? to : -1;
/** Essentially clones the Regex object */
public Regex(Regex r)
{
- super((RegRes) r);
+ super(r);
dontMatchInQuotes = r.dontMatchInQuotes;
esc = r.esc;
ignoreCase = r.ignoreCase;
* patterns are equal as well as the most recent match. If a Regex is compare
* with a RegRes, only the result of the most recent match is compared.
*/
+ @Override
public boolean equals(Object o)
{
if (o instanceof Regex)
}
/** A clone by any other name would smell as sweet. */
+ @Override
public Object clone()
{
return new Regex(this);
{
try
{
- return (Regex) getClass().newInstance();
+ return getClass().getDeclaredConstructor().newInstance();
} catch (InstantiationException ie)
{
return null;
} catch (IllegalAccessException iae)
{
return null;
+ } catch (ReflectiveOperationException roe)
+ {
+ return null;
}
}
{
if (p instanceof Any && p.next == null)
{
- return (Pattern) new DotMulti(lo, hi);
+ return new DotMulti(lo, hi);
}
return RegOpt.safe4fm(p) ? (Pattern) new FastMulti(lo, hi, p)
: (Pattern) new Multi(lo, hi, p);
* representations. Also be prepared to see some strange output if your
* characters are not printable.
*/
+ @Override
public String toString()
{
if (false && thePattern == null)
*
* @see com.stevesoft.pat.FileRegex
*/
+ @Override
public boolean accept(File dir, String s)
{
return search(s);
*
* @deprecated
*/
+ @Deprecated
public int getMaxLines()
{
return max_lines;
*
* @deprecated
*/
+ @Deprecated
public void setMaxLines(int ml)
{
max_lines = ml;
*
* @deprecated
*/
+ @Deprecated
public char getEOLchar()
{
return EOLchar;
*
* @deprecated
*/
+ @Deprecated
public void setEOLchar(char c)
{
EOLchar = c;
if (r.searchFrom(toParse, pos))
{
v.addElement(r.left().substring(pos));
- vi.addElement(new Integer(r.matchFrom() + r.charsMatched()));
+ vi.addElement(Integer.valueOf(r.matchFrom() + r.charsMatched()));
for (int i = 0; i < r.numSubs(); i++)
{
if (r.substring() != null)
{
v.addElement(r.substring(i + offset));
- vi.addElement(new Integer(r.matchFrom(i + offset)
+ vi.addElement(Integer.valueOf(r.matchFrom(i + offset)
+ r.charsMatched(i + offset)));
}
}
float[] rgbValues = new float[4];
for (int i = 0; i < rgbStrings.length; i++)
{
- Float f = new Float(rgbStrings[i]);
+ Float f = Float.valueOf(rgbStrings[i]);
rgbValues[i] = f.floatValue();
}
if (rgbStrings.length == 4)
*/
public static Integer makeModelKey(int model, int subModel)
{
- return new Integer(model * MAX_SUB_MODELS + subModel);
+ return Integer.valueOf(model * MAX_SUB_MODELS + subModel);
}
// invoked by the getResdiue (parseConnectivityReplies in
*/
public ChimeraResidue getResidue(String index)
{
- // Integer index = new Integer(residueIndex);
+ // Integer index = Integer.valueOf(residueIndex);
if (residueMap.containsKey(index))
return residueMap.get(index);
return null;
for (String chimObjName : names)
{
// get or open the corresponding models if they already exist
- List<ChimeraModel> currentModels = chimeraManager.getChimeraModels(
- chimObjName, type);
+ List<ChimeraModel> currentModels = chimeraManager
+ .getChimeraModels(chimObjName, type);
if (currentModels.size() == 0)
{
// open and return models
// Get the corresponding "real" model
if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
{
- ChimeraModel dataModel = chimeraManager.getChimeraModel(
- modelNumber, subModelNumber);
- if (dataModel.getResidueCount() == selectedModel
- .getResidueCount()
- || dataModel.getModelType() == StructureManager.ModelType.SMILES)
+ ChimeraModel dataModel = chimeraManager
+ .getChimeraModel(modelNumber, subModelNumber);
+ if (dataModel.getResidueCount() == selectedModel.getResidueCount()
+ || dataModel
+ .getModelType() == StructureManager.ModelType.SMILES)
{
// Select the entire model
addChimSelection(dataModel);
{
for (ChimeraChain selectedChain : selectedModel.getChains())
{
- ChimeraChain dataChain = dataModel.getChain(selectedChain
- .getChainId());
+ ChimeraChain dataChain = dataModel
+ .getChain(selectedChain.getChainId());
if (selectedChain.getResidueCount() == dataChain
.getResidueCount())
{
pathList.add("/usr/local/chimera/bin/chimera");
pathList.add("/usr/local/bin/chimera");
pathList.add("/usr/bin/chimera");
+ pathList.add(System.getProperty("user.home") + "/opt/bin/chimera");
}
else if (os.startsWith("Windows"))
{
for (int i = 0; i < alignment.length; i++)
{
- ids[i] = (new Float(alignment[i].getName().substring(8)))
+ ids[i] = (Float.valueOf(alignment[i].getName().substring(8)))
.floatValue();
}
max = Math.max(max, bigtot);
- quality.addElement(new Double(bigtot));
+ quality.addElement(Double.valueOf(bigtot));
}
double newmax = -Double.MAX_VALUE;
tmp = ((max - tmp) * (size - cons2GapCounts[j])) / size;
// System.out.println(tmp+ " " + j);
- quality.setElementAt(new Double(tmp), j);
+ quality.setElementAt(Double.valueOf(tmp), j);
if (tmp > newmax)
{
double score = Double.NaN;
try
{
- score = new Double(sstring).doubleValue();
+ score = Double.valueOf(sstring).doubleValue();
} catch (Exception e)
{
// don't try very hard to parse if regex was wrong.
{
Hashtable sqinfo = new Hashtable();
sqinfo.put("Name", seq.getName());
- sqinfo.put("Start", new Integer(seq.getStart()));
- sqinfo.put("End", new Integer(seq.getEnd()));
+ sqinfo.put("Start", Integer.valueOf(seq.getStart()));
+ sqinfo.put("End", Integer.valueOf(seq.getEnd()));
if (seq.getDescription() != null)
{
sqinfo.put("Description", seq.getDescription());
maxResidue = "{";
}
}
- residueHash.put(MAXCOUNT, new Integer(count));
+ residueHash.put(MAXCOUNT, Integer.valueOf(count));
residueHash.put(MAXRESIDUE, maxResidue);
percentage = ((float) count * 100) / jSize;
- residueHash.put(PID_GAPS, new Float(percentage));
+ residueHash.put(PID_GAPS, Float.valueOf(percentage));
percentage = ((float) count * 100) / nongap;
- residueHash.put(PID_NOGAPS, new Float(percentage));
+ residueHash.put(PID_NOGAPS, Float.valueOf(percentage));
if (result[i] == null)
{
residueHash.put(PAIRPROFILE, pairs);
}
- residueHash.put(MAXCOUNT, new Integer(count));
+ residueHash.put(MAXCOUNT, Integer.valueOf(count));
residueHash.put(MAXRESIDUE, maxResidue);
percentage = ((float) count * 100) / jSize;
- residueHash.put(PID_GAPS, new Float(percentage));
+ residueHash.put(PID_GAPS, Float.valueOf(percentage));
percentage = ((float) count * 100) / nongap;
- residueHash.put(PID_NOGAPS, new Float(percentage));
+ residueHash.put(PID_NOGAPS, Float.valueOf(percentage));
result[bpEnd] = residueHash;
}
FeatureDistanceModel instance;
try
{
- instance = this.getClass().newInstance();
+ instance = this.getClass().getDeclaredConstructor().newInstance();
instance.configureFromAlignmentView(view);
return instance;
} catch (InstantiationException | IllegalAccessException e)
System.err.println("Error in " + getClass().getName()
+ ".getInstance(): " + e.getMessage());
return null;
+ } catch (ReflectiveOperationException roe)
+ {
+ return null;
}
}
protected Map<SeqCigar, Set<String>> findFeatureTypesAtColumn(
SeqCigar[] seqs, int columnPosition)
{
- Map<SeqCigar, Set<String>> sfap = new HashMap<SeqCigar, Set<String>>();
+ Map<SeqCigar, Set<String>> sfap = new HashMap<>();
for (SeqCigar seq : seqs)
{
int spos = seq.findPosition(columnPosition);
/*
* position is not a gap
*/
- Set<String> types = new HashSet<String>();
+ Set<String> types = new HashSet<>();
List<SequenceFeature> sfs = fr.findFeaturesAtResidue(
seq.getRefSeq(), spos);
for (SequenceFeature sf : sfs)
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Arrays;
try
{
new URL(url);
- url = URLEncoder.encode(url);
+ url = URLEncoder.encode(url, "UTF-8");
}
/*
* When we finally deprecate 1.1 compatibility, we can start to use
{
url = viewport.applet.getCodeBase() + url;
}
+ catch (UnsupportedEncodingException ex)
+ {
+ System.err.println(
+ "WARNING = IMPLEMENTATION ERROR - UNSUPPORTED ENCODING EXCEPTION FOR "
+ + url);
+ ex.printStackTrace();
+ }
return url;
}
{
try
{
- widthScale = new Float(param).floatValue();
+ widthScale = Float.valueOf(param).floatValue();
} catch (Exception e)
{
}
{
try
{
- heightScale = new Float(param).floatValue();
+ heightScale = Float.valueOf(param).floatValue();
} catch (Exception e)
{
}
{
try
{
- float f = new Float(thresholdValue.getText()).floatValue();
+ float f = Float.valueOf(thresholdValue.getText()).floatValue();
slider.setValue((int) (f * 1000));
adjustmentValueChanged(null);
} catch (NumberFormatException ex)
.getAlignmentAnnotation();
// DETECT RIGHT MOUSE BUTTON IN AWT
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
PopupMenu popup = new PopupMenu(
}
}
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK
&& activeRow != -1)
{
if (av.getColumnSelection() == null
* @author Jim Procter and Andrew Waterhouse
*
*/
-public class EmbmenuFrame extends Frame implements MouseListener
+public class EmbmenuFrame extends Frame
+ implements MouseListener, AutoCloseable
{
protected static final Font FONT_ARIAL_PLAIN_11 = new Font("Arial",
Font.PLAIN, 11);
/**
* map from labels to popup menus for the embedded menubar
*/
- protected Map<Label, PopupMenu> embeddedPopup = new HashMap<Label, PopupMenu>();
+ protected Map<Label, PopupMenu> embeddedPopup = new HashMap<>();
/**
* the embedded menu is built on this and should be added to the frame at the
return embeddedMenu;
}
+ @Override
public void mousePressed(MouseEvent evt)
{
PopupMenu popup = null;
return embeddedPopup.get(source);
}
+ @Override
public void mouseClicked(MouseEvent evt)
{
}
+ @Override
public void mouseReleased(MouseEvent evt)
{
}
+ @Override
public void mouseEntered(MouseEvent evt)
{
}
+ @Override
public void mouseExited(MouseEvent evt)
{
}
/**
* calls destroyMenus()
*/
- public void finalize() throws Throwable
+ @Override
+ public void close()
{
destroyMenus();
embeddedPopup = null;
embeddedMenu = null;
- super.finalize();
+ // no close for Frame
+ // super.finalize();
}
}
{
try
{
- float f = new Float(thresholdValue.getText()).floatValue();
+ float f = Float.valueOf(thresholdValue.getText()).floatValue();
slider.setValue((int) (f * SCALE_FACTOR_1K));
adjustmentValueChanged(null);
public void mouseClicked(MouseEvent evt)
{
MyCheckbox check = (MyCheckbox) evt.getSource();
- if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0)
+ if ((evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0)
{
this.popupSort(check, fr.getMinMax(), evt.getX(), evt.getY());
}
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
import java.awt.Label;
import java.awt.Panel;
-import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
*/
void init()
{
- String fonts[] = Toolkit.getDefaultToolkit().getFontList();
+ // String fonts[] = Toolkit.getDefaultToolkit().getFontList();
+ String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getAvailableFontFamilyNames();
for (int i = 0; i < fonts.length; i++)
{
fontName.addItem(fonts[i]);
int seq = alignPanel.seqPanel.findSeq(e);
- if ((e.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((e.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
SequenceI sq = av.getAlignment().getSequenceAt(seq);
@Override
public void mouseClicked(MouseEvent evt)
{
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
showPopupMenu(evt);
}
@Override
public void mousePressed(MouseEvent evt)
{
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
if (!Platform.isAMac())
{
@Override
public void mouseDragged(MouseEvent evt)
{
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
if (!Platform.isAMac())
{
min = res;
max = res;
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
rightMouseButtonPressed(evt, res);
}
// For now, ignore the mouseWheel font resizing on Macs
// As the Button2_mask always seems to be true
- if ((evt.getModifiers()
- & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON2_DOWN_MASK) == InputEvent.BUTTON2_DOWN_MASK
&& !av.MAC)
{
mouseWheelPressed = true;
}
// DETECT RIGHT MOUSE BUTTON IN AWT
- if ((evt.getModifiers()
- & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
+ if ((evt.getModifiersEx()
+ & InputEvent.BUTTON3_DOWN_MASK) == InputEvent.BUTTON3_DOWN_MASK)
{
List<SequenceFeature> allFeatures = findFeaturesAtColumn(sequence,
sequence.findPosition(column + 1));
import java.awt.event.ItemListener;
public class TreePanel extends EmbmenuFrame
- implements ActionListener, ItemListener
+ implements ActionListener, ItemListener, AutoCloseable
{
SequenceI[] seq;
}
@Override
- public void finalize() throws Throwable
+ public void close()
{
ap = null;
av = null;
- super.finalize();
+ super.close();
}
/**
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
+import com.threerings.getdown.util.LaunchUtil;
+
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
perms.add(new AllPermission());
return (perms);
}
-
+
@Override
public void refresh()
{
+ System.getProperty("os.name") + " "
+ System.getProperty("os.version"));
+ String appdirString = System.getProperty("getdownappdir");
+ if (appdirString != null && appdirString.length() > 0)
+ {
+ final File appdir = new File(appdirString);
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ LaunchUtil.upgradeGetdown(
+ new File(appdir, "getdown-launcher-old.jar"),
+ new File(appdir, "getdown-launcher.jar"),
+ new File(appdir, "getdown-launcher-new.jar"));
+ }
+ }.start();
+
+ }
ArgsParser aparser = new ArgsParser(args);
boolean headless = false;
{
desktop = new Desktop();
desktop.setInBatchMode(true); // indicate we are starting up
+
+ try
+ {
+ JalviewTaskbar.setTaskbar(this);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ } catch (Throwable t)
+ {
+ t.printStackTrace();
+ }
+
desktop.setVisible(true);
desktop.startServiceDiscovery();
if (!aparser.contains("nousagestats"))
}
try
{
- Map<String, Object> vbinding = new HashMap<>();
+ Map<String, java.lang.Object> vbinding = new HashMap<>();
vbinding.put("Jalview", this);
if (af != null)
{
int apos = -1;
try
{
- apos = new Integer(position).intValue();
+ apos = Integer.valueOf(position).intValue();
apos--;
} catch (NumberFormatException ex)
{
int from = -1, to = -1;
try
{
- from = new Integer(cl.substring(0, p)).intValue();
+ from = Integer.valueOf(cl.substring(0, p)).intValue();
from--;
} catch (NumberFormatException ex)
{
}
try
{
- to = new Integer(cl.substring(p + 1)).intValue();
+ to = Integer.valueOf(cl.substring(p + 1)).intValue();
to--;
} catch (NumberFormatException ex)
{
int r = -1;
try
{
- r = new Integer(cl).intValue();
+ r = Integer.valueOf(cl).intValue();
r--;
} catch (NumberFormatException ex)
{
try
{
StructureSelectionManager.getStructureSelectionManager(me)
- .mouseOverStructure(new Integer(pdbResNum).intValue(),
+ .mouseOverStructure(Integer.valueOf(pdbResNum).intValue(),
chain, pdbfile);
if (debug)
{
{
try
{
- alf.scrollTo(new Integer(topRow).intValue(),
- new Integer(leftHandColumn).intValue());
+ alf.scrollTo(Integer.valueOf(topRow).intValue(),
+ Integer.valueOf(leftHandColumn).intValue());
} catch (Exception ex)
{
{
try
{
- alf.scrollToRow(new Integer(topRow).intValue());
+ alf.scrollToRow(Integer.valueOf(topRow).intValue());
} catch (Exception ex)
{
{
try
{
- alf.scrollToColumn(new Integer(leftHandColumn).intValue());
+ alf.scrollToColumn(Integer.valueOf(leftHandColumn).intValue());
} catch (Exception ex)
{
--- /dev/null
+package jalview.bin;
+
+import java.awt.Image;
+import java.awt.Taskbar;
+
+public class JalviewTaskbar
+{
+ public JalviewTaskbar()
+ {
+ }
+
+ protected static void setTaskbar(Jalview jalview)
+ {
+
+ if (Taskbar.isTaskbarSupported())
+ {
+ Taskbar tb = Taskbar.getTaskbar();
+ if (tb.isSupported(Taskbar.Feature.ICON_IMAGE))
+ {
+ try
+ {
+ java.net.URL url = jalview.getClass()
+ .getResource("/images/JalviewLogo_Huge.png");
+ if (url != null)
+ {
+ Image image = java.awt.Toolkit.getDefaultToolkit()
+ .createImage(url);
+ tb.setIconImage(image);
+ }
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ }
+
+}
--- /dev/null
+package jalview.bin;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.util.ArrayList;
+
+public class Launcher
+{
+
+ private final static String startClass = "jalview.bin.Jalview";
+
+ private final static int maxHeapSizePerCent = 95;
+
+ private final static String dockIconPath = "JalviewLogo_Huge.png";
+
+ public static void main(String[] args)
+ {
+ final String javaBin = System.getProperty("java.home") + File.separator
+ + "bin" + File.separator + "java";
+
+ ArrayList<String> command = new ArrayList<>();
+ command.add(javaBin);
+
+ boolean isAMac = System.getProperty("os.name").indexOf("Mac") > -1;
+
+ for (String jvmArg : ManagementFactory.getRuntimeMXBean()
+ .getInputArguments())
+ {
+ command.add(jvmArg);
+ }
+ command.add("-cp");
+ command.add(ManagementFactory.getRuntimeMXBean().getClassPath());
+ ArrayList<String> arguments = new ArrayList<>();
+ for (String arg : args)
+ {
+ arguments.add(arg);
+ }
+
+ // add memory setting if not specified
+ boolean memSet = false;
+ boolean dockIcon = false;
+ ARG: for (int i = 0; i < command.size(); i++)
+ {
+ String arg = command.get(i);
+ if (arg.startsWith("-Xmx"))
+ {
+ memSet = true;
+ }
+ else if (arg.startsWith("-Xdock:icon"))
+ {
+ dockIcon = true;
+ }
+ }
+
+ if (!memSet)
+ {
+ long maxMemLong = -1;
+ long physicalMem = getPhysicalMemory();
+ if (physicalMem > 0)
+ {
+ maxMemLong = physicalMem * maxHeapSizePerCent / 100;
+ }
+ if (maxMemLong > 0)
+ {
+ command.add("-Xmx" + Long.toString(maxMemLong));
+ }
+ }
+
+ if (!dockIcon)
+ {
+ command.add("-Xdock:icon=" + dockIconPath);
+ // -Xdock:name=... doesn't actually work :(
+ // Leaving it in in case it gets fixed
+ command.add("-Xdock:name=" + "Jalview");
+ }
+
+ command.add(startClass);
+ command.addAll(arguments);
+
+ final ProcessBuilder builder = new ProcessBuilder(command);
+
+ System.out.println("COMMAND: " + String.join(" ", builder.command()));
+
+ try
+ {
+ builder.inheritIO();
+ builder.start();
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ // System.exit(0);
+
+ }
+
+ public static long getPhysicalMemory()
+ {
+ final OperatingSystemMXBean o = ManagementFactory
+ .getOperatingSystemMXBean();
+
+ try
+ {
+ if (o instanceof com.sun.management.OperatingSystemMXBean)
+ {
+ final com.sun.management.OperatingSystemMXBean osb = (com.sun.management.OperatingSystemMXBean) o;
+ return osb.getTotalPhysicalMemorySize();
+ }
+ } catch (NoClassDefFoundError e)
+ {
+ // com.sun.management.OperatingSystemMXBean doesn't exist in this JVM
+ System.out.println("No com.sun.management.OperatingSystemMXBean");
+ }
+
+ // We didn't get a com.sun.management.OperatingSystemMXBean.
+ return -1;
+ }
+
+}
* @author JimP
*
*/
-public class Alignment implements AlignmentI
+public class Alignment implements AlignmentI, AutoCloseable
{
private Alignment dataset;
}
@Override
- public void finalize() throws Throwable
+ public void close()
{
if (getDataset() != null)
{
- getDataset().removeAlignmentRef();
+ try
+ {
+ getDataset().removeAlignmentRef();
+ } catch (Throwable e)
+ {
+ e.printStackTrace();
+ }
}
nullReferences();
- super.finalize();
}
/**
seqPos = i + startRes;
}
- sequenceMapping.put(new Integer(seqPos), annotations[i]);
+ sequenceMapping.put(Integer.valueOf(seqPos), annotations[i]);
}
}
{
for (a = sequenceRef.getStart(); a <= sequenceRef.getEnd(); a++)
{
- index = new Integer(a);
+ index = Integer.valueOf(a);
Annotation annot = sequenceMapping.get(index);
if (annot != null)
{
for (int i = 0; i < binary.length; i++)
{
- out += (new Integer(binary[i])).toString();
+ out += (Integer.valueOf(binary[i])).toString();
if (i < (binary.length - 1))
{
void remove(int col)
{
- Integer colInt = new Integer(col);
+ Integer colInt = Integer.valueOf(col);
if (selected.get(col))
{
// clear shifted bits and update List of selected columns
selected.clear(temp);
mask.set(temp - change);
- order.set(i, new Integer(temp - change));
+ order.set(i, Integer.valueOf(temp - change));
}
}
// lastly update the bitfield all at once
Integer colInt;
for (int i = start; i < end; i++)
{
- colInt = new Integer(i);
+ colInt = Integer.valueOf(i);
if (selection.contains(colInt))
{
selection.remove(colInt);
package jalview.ext.htsjdk;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+
import htsjdk.samtools.util.CloseableIterator;
import htsjdk.variant.variantcontext.VariantContext;
import htsjdk.variant.vcf.VCFFileReader;
import htsjdk.variant.vcf.VCFHeader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.IOException;
-
/**
* A thin wrapper for htsjdk classes to read either plain, or compressed, or
* compressed and indexed VCF files
{
final CloseableIterator<VariantContext> it = reader.iterator();
- return new CloseableIterator<VariantContext>()
+ return new CloseableIterator()
{
boolean atEnd = false;
int vend = variant.getEnd();
// todo what is the undeprecated way to get
// the chromosome for the variant?
- if (chrom.equals(variant.getChr()) && (vstart <= end)
+ if (chrom.equals(variant.getContig()) && (vstart <= end)
&& (vend >= start))
{
return variant;
try
{
// recover PDB filename for the model hovered over.
- int mnumber = new Integer(mdlId).intValue() - 1;
+ int mnumber = Integer.valueOf(mdlId).intValue() - 1;
if (_modelFileNameMap != null)
{
int _mp = _modelFileNameMap.length - 1;
public static Iterator<Reader> getRNAMLForPDBFileAsString(String pdbfile)
throws Exception
{
- List<NameValuePair> vals = new ArrayList<NameValuePair>();
+ List<NameValuePair> vals = new ArrayList<>();
vals.add(new BasicNameValuePair("tool", "rnaview"));
vals.add(new BasicNameValuePair("data", pdbfile));
vals.add(new BasicNameValuePair("output", "rnaml"));
// return processJsonResponseFor(HttpClientUtils.doHttpUrlPost(twoDtoolsURL,
// vals));
- ArrayList<Reader> readers = new ArrayList<Reader>();
+ ArrayList<Reader> readers = new ArrayList<>();
final BufferedReader postResponse = HttpClientUtils
.doHttpUrlPost(twoDtoolsURL, vals, 0, 0);
readers.add(postResponse);
try
{
final JSONArray responses = (JSONArray) jp.parse(respons);
- final Iterator rvals = responses.iterator();
- return new Iterator<Reader>()
- {
- @Override
- public boolean hasNext()
- {
- return rvals.hasNext();
- }
-
- @Override
- public Reader next()
- {
- JSONObject val = (JSONObject) rvals.next();
-
- Object sval = null;
- try
- {
- sval = val.get("2D");
- } catch (Exception x)
- {
- x.printStackTrace();
- }
- ;
- if (sval == null)
- {
- System.err.println(
- "DEVELOPER WARNING: Annotate3d didn't return a '2D' tag in its response. Consider checking output of server. Response was :"
- + val.toString());
-
- sval = "";
- }
- return new StringReader((sval instanceof JSONObject)
- ? ((JSONObject) sval).toString()
- : sval.toString());
-
- }
-
- @Override
- public void remove()
- {
- throw new Error(
- MessageManager.getString("error.not_implemented_remove"));
-
- }
-
- @Override
- protected Object clone() throws CloneNotSupportedException
- {
- throw new CloneNotSupportedException(
- MessageManager.getString("error.not_implemented_clone"));
- }
-
- @Override
- public boolean equals(Object obj)
- {
- return super.equals(obj);
- }
-
- @Override
- protected void finalize() throws Throwable
- {
- while (rvals.hasNext())
- {
- rvals.next();
- }
- super.finalize();
- }
- };
+ final RvalsIterator rvals = new RvalsIterator(responses);
+ return rvals;
} catch (Exception foo)
{
throw new Exception(MessageManager.getString(
public static Iterator<Reader> getRNAMLForPDBId(String pdbid)
throws Exception
{
- List<NameValuePair> vals = new ArrayList<NameValuePair>();
+ List<NameValuePair> vals = new ArrayList<>();
vals.add(new BasicNameValuePair("tool", "rnaview"));
vals.add(new BasicNameValuePair("pdbid", pdbid));
vals.add(new BasicNameValuePair("output", "rnaml"));
+ pdbid + "&output=rnaml");
// return processJsonResponseFor(new
// InputStreamReader(geturl.openStream()));
- ArrayList<Reader> readers = new ArrayList<Reader>();
+ ArrayList<Reader> readers = new ArrayList<>();
readers.add(new InputStreamReader(geturl.openStream()));
return readers.iterator();
}
}
+
+class RvalsIterator implements Iterator, AutoCloseable
+{
+ private Iterator rvals;
+
+ protected RvalsIterator(JSONArray responses)
+ {
+ this.rvals = responses.iterator();
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return rvals.hasNext();
+ }
+
+ @Override
+ public Reader next()
+ {
+ JSONObject val = (JSONObject) rvals.next();
+
+ Object sval = null;
+ try
+ {
+ sval = val.get("2D");
+ } catch (Exception x)
+ {
+ x.printStackTrace();
+ }
+ ;
+ if (sval == null)
+ {
+ System.err.println(
+ "DEVELOPER WARNING: Annotate3d didn't return a '2D' tag in its response. Consider checking output of server. Response was :"
+ + val.toString());
+
+ sval = "";
+ }
+ return new StringReader(
+ (sval instanceof JSONObject) ? ((JSONObject) sval).toString()
+ : sval.toString());
+
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new Error(
+ MessageManager.getString("error.not_implemented_remove"));
+
+ }
+
+ @Override
+ protected Object clone() throws CloneNotSupportedException
+ {
+ throw new CloneNotSupportedException(
+ MessageManager.getString("error.not_implemented_clone"));
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return super.equals(obj);
+ }
+
+ @Override
+ public void close()
+ {
+ while (rvals.hasNext())
+ {
+ rvals.next();
+ }
+ }
+}
--- /dev/null
+package jalview.gui;
+
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
+import java.awt.Desktop;
+import java.awt.desktop.AboutEvent;
+import java.awt.desktop.AboutHandler;
+import java.awt.desktop.PreferencesEvent;
+import java.awt.desktop.PreferencesHandler;
+import java.awt.desktop.QuitEvent;
+import java.awt.desktop.QuitHandler;
+import java.awt.desktop.QuitResponse;
+import java.awt.desktop.QuitStrategy;
+
+import javax.swing.JOptionPane;
+
+public class APQHandlers
+{
+ private static boolean setAPQHandlers = false;
+
+ public APQHandlers() {
+ }
+
+ protected static boolean setAPQHandlers(jalview.gui.Desktop jalviewDesktop)
+ {
+ // flagging this test to avoid unnecessary reflection
+ if (!setAPQHandlers)
+ {
+ // see if the Quit, About and Preferences handlers are available
+ Class desktopClass = Desktop.class;
+ Desktop hdesktop = Desktop.getDesktop();
+
+ try
+ {
+ Float specversion = Float.parseFloat(
+ System.getProperty("java.specification.version"));
+
+ if (specversion >= 9)
+ {
+ if (Platform.isAMac())
+ {
+ if (desktopClass.getDeclaredMethod("setAboutHandler",
+ new Class[]
+ { AboutHandler.class }) != null)
+ {
+
+ hdesktop.setAboutHandler(new AboutHandler()
+ {
+ @Override
+ public void handleAbout(AboutEvent e)
+ {
+ jalviewDesktop.aboutMenuItem_actionPerformed(null);
+ }
+ });
+
+ }
+
+ if (desktopClass.getDeclaredMethod("setPreferencesHandler",
+ new Class[]
+ { PreferencesHandler.class }) != null)
+ {
+
+ hdesktop.setPreferencesHandler(
+ new PreferencesHandler()
+ {
+ @Override
+ public void handlePreferences(
+ PreferencesEvent e)
+ {
+ jalviewDesktop.preferences_actionPerformed(null);
+ }
+ });
+
+ }
+
+ if (desktopClass.getDeclaredMethod("setQuitHandler",
+ new Class[]
+ { QuitHandler.class }) != null)
+ {
+
+ hdesktop.setQuitHandler(new QuitHandler()
+ {
+ @Override
+ public void handleQuitRequestWith(
+ QuitEvent e, QuitResponse r)
+ {
+ boolean confirmQuit = jalview.bin.Cache
+ .getDefault(jalviewDesktop.CONFIRM_KEYBOARD_QUIT,
+ true);
+ int n;
+ if (confirmQuit)
+ {
+ n = JOptionPane.showConfirmDialog(null,
+ MessageManager.getString("label.quit_jalview"),
+ MessageManager.getString("action.quit"),
+ JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.PLAIN_MESSAGE, null);
+ }
+ else
+ {
+ n = JOptionPane.OK_OPTION;
+ }
+ if (n == JOptionPane.OK_OPTION)
+ {
+ System.out.println("Shortcut Quit confirmed by user");
+ jalviewDesktop.quit();
+ r.performQuit(); // probably won't reach this line, but just
+ // in
+ // case
+ }
+ else
+ {
+ r.cancelQuit();
+ System.out.println("Shortcut Quit cancelled by user");
+ }
+ }
+ });
+ hdesktop.setQuitStrategy(
+ QuitStrategy.CLOSE_ALL_WINDOWS);
+
+ }
+ }
+ setAPQHandlers = true;
+ }
+ else
+ {
+ System.out.println(
+ "Not going to try setting APQ Handlers as java.spec.version is "
+ + specversion);
+ }
+
+ } catch (Exception e)
+ {
+ System.out.println(
+ "Exception when looking for About, Preferences, Quit Handlers");
+ e.printStackTrace();
+ } catch (Throwable t)
+ {
+ System.out.println(
+ "Throwable when looking for About, Preferences, Quit Handlers");
+ t.printStackTrace();
+ }
+
+ }
+
+ return setAPQHandlers;
+ }
+
+}
PrintWriter out = new PrintWriter(
new FileWriter(backupfiles.getTempFilePath()));
+ // TESTING code here
+ boolean TESTING = true;
+ if (TESTING)
+ {
+ out.print("; TESTSTART\n");
+ int count = 20;
+ for (int i = 0; i < count; i++)
+ {
+ // Thread.sleep(1000);
+ out.println("; TEST: " + (count - 1 - i));
+ }
+ }
out.print(output);
+ if (TESTING)
+ {
+ out.print("; TESTEND\n");
+ }
out.close();
this.setTitle(file);
statusBar.setText(MessageManager.formatMessage(
newGraphGroups.add(q, null);
}
newGraphGroups.set(newann.graphGroup,
- new Integer(++fgroup));
+ Integer.valueOf(++fgroup));
}
newann.graphGroup = newGraphGroups.get(newann.graphGroup)
.intValue();
newGraphGroups.add(q, null);
}
newGraphGroups.set(newann.graphGroup,
- new Integer(++fgroup));
+ Integer.valueOf(++fgroup));
}
newann.graphGroup = newGraphGroups.get(newann.graphGroup)
.intValue();
int assocfiles = 0;
if (filesmatched.size() > 0)
{
- boolean autoAssociate = Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
+ boolean autoAssociate = Cache
+ .getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
if (!autoAssociate)
{
String msg = MessageManager.formatMessage(
public LaunchJvBrowserOnItem(JList listItems)
{
super("Open in Browser");
- this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
+ this.putValue(MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_O));
this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
_listItems = listItems;
}
*/
package jalview.gui;
-import static jalview.util.UrlConstants.SEQUENCE_ID;
-
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
-import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
+ protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
+
+ public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
+
private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
/**
doConfigureStructurePrefs();
setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ /*
+ if (!Platform.isAMac())
+ {
+ // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ }
+ else
+ {
+ this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ }
+ */
+
+ try
+ {
+ APQHandlers.setAPQHandlers(this);
+ } catch (Exception e)
+ {
+ System.out.println("Exception when trying to set APQHandlers");
+ e.printStackTrace();
+ } catch (Throwable t)
+ {
+ System.out.println("Throwable when trying to set APQHandlers");
+ t.printStackTrace();
+ }
+
+
+ addWindowListener(new WindowAdapter()
+ {
+
+ @Override
+ public void windowClosing(WindowEvent ev)
+ {
+ quit();
+ }
+ });
+
boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
false);
+
boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
false);
desktop = new MyDesktopPane(selmemusage);
showMemusage.setSelected(selmemusage);
desktop.setBackground(Color.white);
+
getContentPane().setLayout(new BorderLayout());
// alternate config - have scrollbars - see notes in JAL-153
// JScrollPane sp = new JScrollPane();
+ System.getProperty("java.version") + "\n"
+ System.getProperty("os.arch") + " "
+ System.getProperty("os.name") + " "
- + System.getProperty("os.version"));
+ + System.getProperty("os.version")
+ + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT")
+ ? "\nJava path:"
+ + System.getProperty(
+ "java.home")
+ + File.separator + "bin"
+ + File.separator + "java"
+ : "")
+ );
showConsole(showjconsole);
KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
InputEvent.CTRL_DOWN_MASK);
KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
InputMap inputMap = frame
.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
@Override
public void quit()
{
+ //System.out.println("********** Desktop.quit()");
+ //System.out.println(savingFiles.toString());
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
screen.width + "");
while (li.hasNext())
{
String link = li.next();
- if (link.contains(SEQUENCE_ID)
+ if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
&& !UrlConstants.isDefaultString(link))
{
check = true;
{
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
"Quit");
getRootPane().getActionMap().put("Quit", new AbstractAction()
{
progressBarHandlers = new Hashtable<>();
}
- if (progressBars.get(new Long(id)) != null)
+ if (progressBars.get(Long.valueOf(id)) != null)
{
- JPanel panel = progressBars.remove(new Long(id));
- if (progressBarHandlers.contains(new Long(id)))
+ JPanel panel = progressBars.remove(Long.valueOf(id));
+ if (progressBarHandlers.contains(Long.valueOf(id)))
{
- progressBarHandlers.remove(new Long(id));
+ progressBarHandlers.remove(Long.valueOf(id));
}
removeProgressPanel(panel);
}
else
{
- progressBars.put(new Long(id), addProgressPanel(message));
+ progressBars.put(Long.valueOf(id), addProgressPanel(message));
}
}
final IProgressIndicatorHandler handler)
{
if (progressBarHandlers == null
- || !progressBars.containsKey(new Long(id)))
+ || !progressBars.containsKey(Long.valueOf(id)))
{
throw new Error(MessageManager.getString(
"error.call_setprogressbar_before_registering_handler"));
}
- progressBarHandlers.put(new Long(id), handler);
- final JPanel progressPanel = progressBars.get(new Long(id));
+ progressBarHandlers.put(Long.valueOf(id), handler);
+ final JPanel progressPanel = progressBars.get(Long.valueOf(id));
if (handler.canCancel())
{
JButton cancel = new JButton(
name.setText(sf.getType());
description.setText(sf.getDescription());
group.setText(sf.getFeatureGroup());
- start.setValue(new Integer(sf.getBegin()));
- end.setValue(new Integer(sf.getEnd()));
+ start.setValue(Integer.valueOf(sf.getBegin()));
+ end.setValue(Integer.valueOf(sf.getEnd()));
SearchResultsI highlight = new SearchResults();
highlight.addResult(sequences.get(0), sf.getBegin(),
name.setText(featureType);
group.setText(featureGroup);
- start.setValue(new Integer(firstFeature.getBegin()));
- end.setValue(new Integer(firstFeature.getEnd()));
+ start.setValue(Integer.valueOf(firstFeature.getBegin()));
+ end.setValue(Integer.valueOf(firstFeature.getEnd()));
description.setText(firstFeature.getDescription());
updateColourButton(mainPanel, colour,
(oldcol = fcol = getFeatureStyle(featureType)));
data[dataIndex][FILTER_COLUMN] = featureFilter == null
? new FeatureMatcherSet()
: featureFilter;
- data[dataIndex][SHOW_COLUMN] = new Boolean(
+ data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
af.getViewport().getFeaturesDisplayed().isVisible(type));
dataIndex++;
displayableTypes.remove(type);
data[dataIndex][FILTER_COLUMN] = featureFilter == null
? new FeatureMatcherSet()
: featureFilter;
- data[dataIndex][SHOW_COLUMN] = new Boolean(true);
+ data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
dataIndex++;
displayableTypes.remove(type);
}
// }
//
// JPanel progressPanel;
- // Long lId = new Long(id);
+ // Long lId = Long.valueOf(id);
// GridLayout layout = (GridLayout) statusPanel.getLayout();
// if (progressBars.get(lId) != null)
// {
- // progressPanel = (JPanel) progressBars.get(new Long(id));
+ // progressPanel = (JPanel) progressBars.get(Long.valueOf(id));
// statusPanel.remove(progressPanel);
// progressBars.remove(lId);
// progressPanel = null;
final IProgressIndicatorHandler handler)
{
progressBar.registerHandler(id, handler);
- // if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
+ // if (progressBarHandlers == null || !progressBars.contains(Long.valueOf(id)))
// {
// throw new
// Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
// }
- // progressBarHandlers.put(new Long(id), handler);
- // final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
+ // progressBarHandlers.put(Long.valueOf(id), handler);
+ // final JPanel progressPanel = (JPanel) progressBars.get(Long.valueOf(id));
// if (handler.canCancel())
// {
// JButton cancel = new JButton(
int yDelta = yPos - mouseY;
// Check if this is a rectangle drawing drag
- if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
+ if ((evt.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0)
{
// rectx2 = evt.getX();
// recty2 = evt.getY();
* Ctrl-W / Cmd-W - close view or window
*/
KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
action = new AbstractAction()
{
@Override
* Ctrl-T / Cmd-T open new view
*/
KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
AbstractAction action = new AbstractAction()
{
@Override
* Ctrl-F / Cmd-F open Finder dialog, 'focused' on the right alignment
*/
KeyStroke key_cmdF = KeyStroke.getKeyStroke(KeyEvent.VK_F,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
AbstractAction action = new AbstractAction()
{
@Override
for (String url : wsUrls)
{
int status = Jws2Discoverer.getDiscoverer().getServerStatusFor(url);
- tdat[r][1] = new Integer(status);
+ tdat[r][1] = Integer.valueOf(status);
tdat[r++][0] = url;
}
if (row.graphGroup > -1)
{
graphGroupSeen.set(row.graphGroup);
- Integer key = new Integer(row.graphGroup);
+ Integer key = Integer.valueOf(row.graphGroup);
if (graphGroup.containsKey(key))
{
graphGroup.put(key, graphGroup.get(key) + "\t" + row.label);
autoAnnotsKey(aa[aai], aa[aai].sequenceRef,
(aa[aai].groupRef == null ? null
: aa[aai].groupRef.getName())),
- new Integer(1));
+ Integer.valueOf(1));
}
}
}
{
displayChar = token;
// foo
- value = new Float(token).floatValue();
+ value = Float.valueOf(token).floatValue();
parsedValue = true;
continue;
} catch (NumberFormatException ex)
float score = Float.NaN;
try
{
- score = new Float(gffColumns[6]).floatValue();
+ score = Float.valueOf(gffColumns[6]).floatValue();
} catch (NumberFormatException ex)
{
sf = new SequenceFeature(ft, desc, startPos, endPos, featureGroup);
Thread.sleep(500);
} catch (Exception ex)
{
+ System.out.println(
+ "Exception caught while waiting for FileLoader thread");
+ ex.printStackTrace();
}
}
{
ascore = symbols.nextToken();
- Float score = new Float(ascore);
+ Float score = Float.valueOf(ascore);
scores.addElement(score);
}
seq_entries.addElement(newseq.toString());
ids.addElement(id);
- Symscores.put(id, new Integer(ids.size() - 1));
+ Symscores.put(id, Integer.valueOf(ids.size() - 1));
}
}
}
{
for (int j = 0; j < width; j++)
{
- float value = new Float(preds[i].getCharAt(j) + "")
+ float value = Float.valueOf(preds[i].getCharAt(j) + "")
.floatValue();
annotations[gapmap[j]] = new Annotation(
preds[i].getCharAt(j) + "", "",
{
for (int j = 0; j < width; j++)
{
- float value = new Float(preds[i].getCharAt(j) + "")
+ float value = Float.valueOf(preds[i].getCharAt(j) + "")
.floatValue();
annotations[gapmap[delMap[j]]] = new Annotation(
preds[i].getCharAt(j) + "", "",
resCode(int v)
{
- val = new Integer(v);
+ val = Integer.valueOf(v);
field = val.toString();
}
};
{
try
{
- bootstrap = (new Integer(nbootstrap.stringMatched(1)))
+ bootstrap = (Integer.valueOf(nbootstrap.stringMatched(1)))
.intValue();
HasBootstrap = true;
} catch (Exception e)
{
try
{
- distance = (new Float(ndist.stringMatched(1))).floatValue();
+ distance = (Float.valueOf(ndist.stringMatched(1))).floatValue();
HasDistances = true;
nodehasdistance = true;
} catch (Exception e)
if (code.toLowerCase().equals("b"))
{
int v = -1;
- Float iv = new Float(value);
+ Float iv = Float.valueOf(value);
v = iv.intValue(); // jalview only does integer bootstraps
// currently
c.setBootstrap(v);
Float val = null;
try
{
- val = new Float(props[p].getContent());
+ val = Float.valueOf(props[p].getContent());
} catch (Exception e)
{
Cache.log.warn("Failed to parse threshold property");
int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);
for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)
{
- posList.add(new Integer(p));
+ posList.add(Integer.valueOf(p));
}
}
}
for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
{
pos = dseta.getPos(p).getI();
- posList.add(new Integer(pos));
+ posList.add(Integer.valueOf(pos));
}
}
}
import java.util.Iterator;
import java.util.Map;
-public class DatastoreRegistry
+public class DatastoreRegistry implements AutoCloseable
{
protected static org.apache.log4j.Logger log = org.apache.log4j.Logger
.getLogger(DatastoreRegistry.class);
}
@Override
- protected void finalize() throws Throwable
+ public void close()
{
if (dsObjReg != null)
{
{
dsItemReg.clear();
}
- super.finalize();
+ // super.finalize();
}
}
int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);
for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)
{
- posList.add(new Integer(p));
+ posList.add(Integer.valueOf(p));
}
}
}
for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)
{
pos = dseta.getPos(p).getI();
- posList.add(new Integer(pos));
+ posList.add(Integer.valueOf(pos));
}
}
}
for (int s = 0, sSize = range.getSegCount(); s < sSize; s++)
{
se = getSegRange(range.getSeg(s), false);
- posList.addElement(new Integer(se[0]));
- posList.addElement(new Integer(se[1]));
+ posList.addElement(Integer.valueOf(se[0]));
+ posList.addElement(Integer.valueOf(se[1]));
}
}
else if (range.getPosCount() > 0)
for (int p = 0, pSize = range.getPosCount(); p < pSize; p++)
{
pos = range.getPos(p).getI();
- posList.add(new Integer(pos));
- posList.add(new Integer(pos));
+ posList.add(Integer.valueOf(pos));
+ posList.add(Integer.valueOf(pos));
}
}
}
{
try
{
- val = new Boolean(p.getContent());
+ val = Boolean.valueOf(p.getContent());
} catch (Exception e)
{
}
{
try
{
- val = new Float(p.getContent());
+ val = Float.valueOf(p.getContent());
} catch (Exception e)
{
{
try
{
- val = new Integer(p.getContent());
+ val = Integer.valueOf(p.getContent());
} catch (Exception e)
{
}
Integer nindx = (Integer) nodespecs.get(nname);
if (nindx == null)
{
- nindx = new Integer(1);
+ nindx = Integer.valueOf(1);
}
nname = nindx.toString() + " " + nname;
return nname;
String oval = nodespec.substring(0, nodespec.indexOf(' '));
try
{
- occurence = new Integer(oval).intValue();
+ occurence = Integer.valueOf(oval).intValue();
} catch (Exception e)
{
System.err.println("Invalid nodespec '" + nodespec + "'");
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
-import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
// FIXME getDefaultToolkit throws an exception in Headless mode
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
- | KeyEvent.SHIFT_MASK,
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+ | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
false);
addMenuActionAndAccelerator(keyStroke, saveAs, al);
closeMenuItem.setText(MessageManager.getString("action.close"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem selectAllSequenceMenuItem = new JMenuItem(
MessageManager.getString("action.select_all"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem invertSequenceMenuItem = new JMenuItem(
MessageManager.getString("action.invert_sequence_selection"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem remove2LeftMenuItem = new JMenuItem(
MessageManager.getString("action.remove_left"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_L,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem remove2RightMenuItem = new JMenuItem(
MessageManager.getString("action.remove_right"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem removeGappedColumnMenuItem = new JMenuItem(
MessageManager.getString("action.remove_empty_columns"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem removeAllGapsMenuItem = new JMenuItem(
MessageManager.getString("action.remove_all_gaps"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
- | KeyEvent.SHIFT_MASK,
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+ | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
false);
al = new ActionListener()
{
JMenuItem removeRedundancyMenuItem = new JMenuItem(
MessageManager.getString("action.remove_redundancy"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
undoMenuItem.setEnabled(false);
undoMenuItem.setText(MessageManager.getString("action.undo"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
redoMenuItem.setEnabled(false);
redoMenuItem.setText(MessageManager.getString("action.redo"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem printMenuItem = new JMenuItem(
MessageManager.getString("action.print"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem findMenuItem = new JMenuItem(
MessageManager.getString("action.find"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
findMenuItem.setToolTipText(JvSwingUtils.wrapTooltip(true,
MessageManager.getString("label.find_tip")));
al = new ActionListener()
JMenuItem deleteGroups = new JMenuItem(
MessageManager.getString("action.undefine_groups"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_U,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem createGroup = new JMenuItem(
MessageManager.getString("action.create_group"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem unGroup = new JMenuItem(
MessageManager.getString("action.remove_group"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
- | KeyEvent.SHIFT_MASK,
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+ | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
false);
al = new ActionListener()
{
copy.setText(MessageManager.getString("action.copy"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
cut.setText(MessageManager.getString("action.cut"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem pasteNew = new JMenuItem(
MessageManager.getString("label.to_new_alignment"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
- | KeyEvent.SHIFT_MASK,
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+ | jalview.util.ShortcutKeyMaskExWrapper.SHIFT_DOWN_MASK,
false);
al = new ActionListener()
{
JMenuItem pasteThis = new JMenuItem(
MessageManager.getString("label.to_this_alignment"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem invertColSel = new JMenuItem(
MessageManager.getString("action.invert_column_selection"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
- | KeyEvent.ALT_MASK,
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()
+ | jalview.util.ShortcutKeyMaskExWrapper.ALT_DOWN_MASK,
false);
al = new ActionListener()
{
JMenuItem save = new JMenuItem(MessageManager.getString("action.save"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
JMenuItem newView = new JMenuItem(
MessageManager.getString("action.new_view"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_T,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
al = new ActionListener()
{
@Override
import jalview.gui.JvSwingUtils;
import jalview.util.MessageManager;
+import jalview.util.ShortcutKeyMaskExWrapper;
import java.awt.BorderLayout;
import java.awt.Font;
-import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
});
close.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_W,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
selectAll.setText(MessageManager.getString("action.select_all"));
selectAll.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_A,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
selectAll.addActionListener(new ActionListener()
{
@Override
save.setText(MessageManager.getString("action.save"));
save.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_S,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
save.addActionListener(new ActionListener()
{
@Override
});
copyItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_C,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
editMenubar.add(jMenu1);
editMenubar.add(editMenu);
selectAll.setText(MessageManager.getString("action.select_all"));
selectAll.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_A,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
selectAll.addActionListener(new ActionListener()
{
@Override
save.setText(MessageManager.getString("action.save"));
save.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_S,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
save.addActionListener(new ActionListener()
{
@Override
});
copyItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_C,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
pasteMenu.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
java.awt.event.KeyEvent.VK_V,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false));
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false));
editMenubar.add(jMenu1);
editMenubar.add(editMenu);
textarea.setFont(new java.awt.Font("Monospaced", Font.PLAIN, 12));
import jalview.util.Platform;
import java.awt.FlowLayout;
-import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
.setText(MessageManager.getString("label.load_tree_from_file"));
inputLocalFileMenuItem.setAccelerator(
javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O,
- Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(),
+ jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(),
false));
inputLocalFileMenuItem
.addActionListener(new java.awt.event.ActionListener()
}
});
+ Float specversion = Float.parseFloat(System.getProperty("java.specification.version"));
+
desktopMenubar.add(FileMenu);
desktopMenubar.add(toolsMenu);
VamsasMenu.setVisible(false);
VamsasMenu.add(vamsasImport);
VamsasMenu.add(vamsasSave);
VamsasMenu.add(vamsasStop);
- toolsMenu.add(preferences);
+ if (!Platform.isAMac() || specversion < 11)
+ {
+ toolsMenu.add(preferences);
+ }
toolsMenu.add(showMemusage);
toolsMenu.add(showConsole);
toolsMenu.add(showNews);
*/
protected void quit()
{
+ //System.out.println("********** GDesktop.quit()");
}
/**
}
else
{
- featureOrder.put(featureType, new Float(
+ featureOrder.put(featureType, Float.valueOf(
fs / jm.getFeatureSettings().getSetting().size()));
}
if (safeBoolean(setting.isDisplay()))
for (int gs = 0; gs < jm.getFeatureSettings().getGroup().size(); gs++)
{
Group grp = jm.getFeatureSettings().getGroup().get(gs);
- fgtable.put(grp.getName(), new Boolean(grp.isDisplay()));
+ fgtable.put(grp.getName(), Boolean.valueOf(grp.isDisplay()));
}
// FeatureRendererSettings frs = new FeatureRendererSettings(renderOrder,
// fgtable, featureColours, jms.getFeatureSettings().hasTransparency() ?
{
try
{
- registerColourScheme(cs.getSchemeClass().newInstance());
+ registerColourScheme(
+ cs.getSchemeClass().getDeclaredConstructor().newInstance());
} catch (InstantiationException | IllegalAccessException e)
{
System.err.println("Error instantiating colour scheme for "
+ cs.toString() + " " + e.getMessage());
e.printStackTrace();
+ } catch (ReflectiveOperationException roe)
+ {
+ roe.printStackTrace();
}
}
}
/**
* @deprecated Use {@link #isConserved(int[][],int,int,boolean)} instead
*/
+ @Deprecated
public boolean isConserved(int[][] cons2, int col, int size)
{
+ System.out.println("DEPRECATED!!!!");
return isConserved(cons2, col, size, true);
}
tot += cons2[col][mask[i]];
}
- if ((double) tot > ((threshold * size) / 100))
+ if (tot > ((threshold * size) / 100))
{
// System.out.println("True conserved "+tot+" from "+threshold+" out of
// "+size+" : "+maskstr);
{
if (minval.length() > 0)
{
- min = new Float(minval).floatValue();
+ min = Float.valueOf(minval).floatValue();
}
} catch (Exception e)
{
{
if (maxval.length() > 0)
{
- max = new Float(maxval).floatValue();
+ max = Float.valueOf(maxval).floatValue();
}
} catch (Exception e)
{
{
gcol.nextToken();
tval = gcol.nextToken();
- featureColour.setThreshold(new Float(tval).floatValue());
+ featureColour.setThreshold(Float.valueOf(tval).floatValue());
} catch (Exception e)
{
System.err.println("Couldn't parse threshold value as a float: ("
instances.remove(jalviewLite);
try
{
- mnger.finalize();
+ /* bsoares 2019-03-20 finalize deprecated, no apparent external
+ * resources to close
+ */
+ // mnger.finalize();
} catch (Throwable x)
{
}
{
return false;
}
- return (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
- & e.getModifiers()) != 0;
- // could we use e.isMetaDown() here?
+ return (jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() // .getMenuShortcutKeyMaskEx()
+ & e.getModifiersEx()) != 0; // getModifiers()) != 0;
}
return e.isControlDown();
}
--- /dev/null
+package jalview.util;
+
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+
+public class ShortcutKeyMaskExWrapper
+{
+
+ private static boolean init = false;
+
+ private static final Float specversion = Float
+ .parseFloat(System.getProperty("java.specification.version"));
+
+ private static final float modern = 11;
+
+ public static int SHIFT_DOWN_MASK = KeyEvent.SHIFT_DOWN_MASK;
+
+ public static int ALT_DOWN_MASK = KeyEvent.ALT_DOWN_MASK;
+
+ public ShortcutKeyMaskExWrapper()
+ {
+ }
+
+ private static void init()
+ {
+ if (init)
+ {
+ return;
+ }
+ if (specversion < modern)
+ {
+ SHIFT_DOWN_MASK = KeyEvent.SHIFT_MASK;
+ ALT_DOWN_MASK = KeyEvent.ALT_MASK;
+ }
+ else
+ {
+ SHIFT_DOWN_MASK = KeyEvent.SHIFT_DOWN_MASK;
+ ALT_DOWN_MASK = KeyEvent.ALT_DOWN_MASK;
+ }
+
+ init = true;
+ }
+
+ public static int getMenuShortcutKeyMaskEx()
+ {
+ init();
+ if (specversion < modern)
+ {
+ return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ }
+ else
+ {
+ return Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
+ }
+ }
+
+}
{
featureOrder = new Hashtable<>();
}
- featureOrder.put(type, new Float(position));
+ featureOrder.put(type, Float.valueOf(position));
return position;
}
}
if (newGroupsVisible)
{
- featureGroups.put(group, new Boolean(true));
+ featureGroups.put(group, Boolean.valueOf(true));
return true;
}
return false;
@Override
public void setGroupVisibility(String group, boolean visible)
{
- featureGroups.put(group, new Boolean(visible));
+ featureGroups.put(group, Boolean.valueOf(visible));
}
@Override
for (String gst : toset)
{
Boolean st = featureGroups.get(gst);
- featureGroups.put(gst, new Boolean(visible));
+ featureGroups.put(gst, Boolean.valueOf(visible));
if (st != null)
{
rdrw = rdrw || (visible != st.booleanValue());
// The Score objects contain a set of size one containing the range and
// an ArrayList<float> of size one containing the probabilty
basePairs.put(score.getRanges().first(),
- new Float(score.getScores().get(0)));
+ Float.valueOf(score.getScores().get(0)));
}
for (int i = 0, ri = 0, iEnd = struct.length(); i < iEnd; i++, ri++)
import compbio.metadata.PresetManager;
import compbio.metadata.RunnerConfig;
-public class Jws2Instance
+public class Jws2Instance implements AutoCloseable
{
public String hosturl;
}
@Override
- protected void finalize() throws Throwable
+ public void close()
{
if (service != null)
{
// ignore
}
}
- super.finalize();
+ // super.finalize();
}
public ParamDatastoreI getParamStore()
*
*/
-public class HttpResultSet extends FileParse
+public class HttpResultSet extends FileParse implements AutoCloseable
{
private HttpRequestBase cachedRequest;
*/
public List<DataProvider> createResultDataProviders()
{
- List<DataProvider> dp = new ArrayList<DataProvider>();
+ List<DataProvider> dp = new ArrayList<>();
for (JvDataType type : restJob.rsd.getResultDataTypes())
{
dp.add(new SimpleDataProvider(type, this, null));
*/
public Object[] parseResultSet() throws Exception, Error
{
- List<DataProvider> dp = new ArrayList<DataProvider>();
+ List<DataProvider> dp = new ArrayList<>();
Object[] results = null;
if (en == null)
}
@Override
- protected void finalize() throws Throwable
+ public void close()
{
dataIn = null;
cachedRequest = null;
} catch (Error ex)
{
}
- super.finalize();
+ // no finalize for FileParse
+ // super.close();
}
/**
--- /dev/null
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2018.09.18 at 01:33:02 PM BST
+//
+
+
+package jalview.xml.binding.jalview;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+
+/**
+ * <p>Java class for JalviewModelType complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="JalviewModelType">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="creationDate" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ * <element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="vamsasModel" type="{www.vamsas.ac.uk/jalview/version2}VAMSAS"/>
+ * <sequence>
+ * <element name="JSeq" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="features" type="{www.jalview.org}feature" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="pdbids" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <extension base="{www.jalview.org}pdbentry">
+ * <sequence>
+ * <element name="structureState" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </extension>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="hiddenSequences" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="rnaViewer" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="secondaryStructure" maxOccurs="unbounded">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="hidden" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewreference" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="JGroup" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="seq" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/>
+ * <element name="annotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="outlineColour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="displayBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="displayText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="colourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="Viewport" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="AnnotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
+ * <element name="hiddenColumns" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="calcIdParam" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet">
+ * <attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </extension>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="conservationSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="pidSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="showFullId" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="rightAlignIds" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showColourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="wrapAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="renderGaps" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showSequenceFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showNPfeatureTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showDbRefTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="followHighlight" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="followSelection" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showAnnotation" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="centreColumnLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showGroupConservation" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showGroupConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="startRes" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="startSeq" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="scaleProteinAsCdna" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="viewName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="sequenceSetId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="gatheredViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * <attribute name="complementId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="UserColours" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="UserColourScheme" type="{www.jalview.org/colours}JalviewUserColours"/>
+ * </sequence>
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="tree" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence minOccurs="0">
+ * <element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="FeatureSettings" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="setting" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
+ * <element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
+ * <attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="group" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "JalviewModelType", namespace = "www.jalview.org", propOrder = {
+ "creationDate",
+ "version",
+ "vamsasModel",
+ "jSeq",
+ "jGroup",
+ "viewport",
+ "userColours",
+ "tree",
+ "featureSettings"
+})
+public class JalviewModelType {
+
+ @XmlElement(required = true)
+ @XmlSchemaType(name = "dateTime")
+ protected XMLGregorianCalendar creationDate;
+ @XmlElement(required = true)
+ protected String version;
+ @XmlElement(required = true)
+ protected VAMSAS vamsasModel;
+ @XmlElement(name = "JSeq")
+ protected List<JalviewModelType.JSeq> jSeq;
+ @XmlElement(name = "JGroup")
+ protected List<JalviewModelType.JGroup> jGroup;
+ @XmlElement(name = "Viewport")
+ protected List<JalviewModelType.Viewport> viewport;
+ @XmlElement(name = "UserColours")
+ protected List<JalviewModelType.UserColours> userColours;
+ protected List<JalviewModelType.Tree> tree;
+ @XmlElement(name = "FeatureSettings")
+ protected JalviewModelType.FeatureSettings featureSettings;
+
+ /**
+ * Gets the value of the creationDate property.
+ *
+ * @return
+ * possible object is
+ * {@link XMLGregorianCalendar }
+ *
+ */
+ public XMLGregorianCalendar getCreationDate() {
+ return creationDate;
+ }
+
+ /**
+ * Sets the value of the creationDate property.
+ *
+ * @param value
+ * allowed object is
+ * {@link XMLGregorianCalendar }
+ *
+ */
+ public void setCreationDate(XMLGregorianCalendar value) {
+ this.creationDate = value;
+ }
+
+ /**
+ * Gets the value of the version property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Sets the value of the version property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setVersion(String value) {
+ this.version = value;
+ }
+
+ /**
+ * Gets the value of the vamsasModel property.
+ *
+ * @return
+ * possible object is
+ * {@link VAMSAS }
+ *
+ */
+ public VAMSAS getVamsasModel() {
+ return vamsasModel;
+ }
+
+ /**
+ * Sets the value of the vamsasModel property.
+ *
+ * @param value
+ * allowed object is
+ * {@link VAMSAS }
+ *
+ */
+ public void setVamsasModel(VAMSAS value) {
+ this.vamsasModel = value;
+ }
+
+ /**
+ * Gets the value of the jSeq property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the jSeq property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getJSeq().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.JSeq }
+ *
+ *
+ */
+ public List<JalviewModelType.JSeq> getJSeq() {
+ if (jSeq == null) {
+ jSeq = new ArrayList<JalviewModelType.JSeq>();
+ }
+ return this.jSeq;
+ }
+
+ /**
+ * Gets the value of the jGroup property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the jGroup property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getJGroup().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.JGroup }
+ *
+ *
+ */
+ public List<JalviewModelType.JGroup> getJGroup() {
+ if (jGroup == null) {
+ jGroup = new ArrayList<JalviewModelType.JGroup>();
+ }
+ return this.jGroup;
+ }
+
+ /**
+ * Gets the value of the viewport property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the viewport property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getViewport().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.Viewport }
+ *
+ *
+ */
+ public List<JalviewModelType.Viewport> getViewport() {
+ if (viewport == null) {
+ viewport = new ArrayList<JalviewModelType.Viewport>();
+ }
+ return this.viewport;
+ }
+
+ /**
+ * Gets the value of the userColours property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the userColours property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getUserColours().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.UserColours }
+ *
+ *
+ */
+ public List<JalviewModelType.UserColours> getUserColours() {
+ if (userColours == null) {
+ userColours = new ArrayList<JalviewModelType.UserColours>();
+ }
+ return this.userColours;
+ }
+
+ /**
+ * Gets the value of the tree property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the tree property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getTree().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.Tree }
+ *
+ *
+ */
+ public List<JalviewModelType.Tree> getTree() {
+ if (tree == null) {
+ tree = new ArrayList<JalviewModelType.Tree>();
+ }
+ return this.tree;
+ }
+
+ /**
+ * Gets the value of the featureSettings property.
+ *
+ * @return
+ * possible object is
+ * {@link JalviewModelType.FeatureSettings }
+ *
+ */
+ public JalviewModelType.FeatureSettings getFeatureSettings() {
+ return featureSettings;
+ }
+
+ /**
+ * Sets the value of the featureSettings property.
+ *
+ * @param value
+ * allowed object is
+ * {@link JalviewModelType.FeatureSettings }
+ *
+ */
+ public void setFeatureSettings(JalviewModelType.FeatureSettings value) {
+ this.featureSettings = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="setting" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
+ * <element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
+ * <attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="group" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "setting",
+ "group"
+ })
+ public static class FeatureSettings {
+
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.FeatureSettings.Setting> setting;
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.FeatureSettings.Group> group;
+
+ /**
+ * Gets the value of the setting property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the setting property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getSetting().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.FeatureSettings.Setting }
+ *
+ *
+ */
+ public List<JalviewModelType.FeatureSettings.Setting> getSetting() {
+ if (setting == null) {
+ setting = new ArrayList<JalviewModelType.FeatureSettings.Setting>();
+ }
+ return this.setting;
+ }
+
+ /**
+ * Gets the value of the group property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the group property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getGroup().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.FeatureSettings.Group }
+ *
+ *
+ */
+ public List<JalviewModelType.FeatureSettings.Group> getGroup() {
+ if (group == null) {
+ group = new ArrayList<JalviewModelType.FeatureSettings.Group>();
+ }
+ return this.group;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class Group {
+
+ @XmlAttribute(name = "name", required = true)
+ protected String name;
+ @XmlAttribute(name = "display", required = true)
+ protected boolean display;
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the display property.
+ *
+ */
+ public boolean isDisplay() {
+ return display;
+ }
+
+ /**
+ * Sets the value of the display property.
+ *
+ */
+ public void setDisplay(boolean value) {
+ this.display = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
+ * <element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
+ * <attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "attributeName",
+ "matcherSet"
+ })
+ public static class Setting {
+
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<String> attributeName;
+ @XmlElement(namespace = "www.jalview.org")
+ protected FeatureMatcherSet matcherSet;
+ @XmlAttribute(name = "type", required = true)
+ protected String type;
+ @XmlAttribute(name = "colour", required = true)
+ protected int colour;
+ @XmlAttribute(name = "display", required = true)
+ protected boolean display;
+ @XmlAttribute(name = "order")
+ protected Float order;
+ @XmlAttribute(name = "mincolour")
+ protected Integer mincolour;
+ @XmlAttribute(name = "noValueColour")
+ protected NoValueColour noValueColour;
+ @XmlAttribute(name = "threshold")
+ protected Float threshold;
+ @XmlAttribute(name = "threshstate")
+ protected Integer threshstate;
+ @XmlAttribute(name = "max")
+ protected Float max;
+ @XmlAttribute(name = "min")
+ protected Float min;
+ @XmlAttribute(name = "colourByLabel")
+ protected Boolean colourByLabel;
+ @XmlAttribute(name = "autoScale")
+ protected Boolean autoScale;
+
+ /**
+ * Gets the value of the attributeName property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the attributeName property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAttributeName().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ *
+ *
+ */
+ public List<String> getAttributeName() {
+ if (attributeName == null) {
+ attributeName = new ArrayList<String>();
+ }
+ return this.attributeName;
+ }
+
+ /**
+ * Gets the value of the matcherSet property.
+ *
+ * @return
+ * possible object is
+ * {@link FeatureMatcherSet }
+ *
+ */
+ public FeatureMatcherSet getMatcherSet() {
+ return matcherSet;
+ }
+
+ /**
+ * Sets the value of the matcherSet property.
+ *
+ * @param value
+ * allowed object is
+ * {@link FeatureMatcherSet }
+ *
+ */
+ public void setMatcherSet(FeatureMatcherSet value) {
+ this.matcherSet = value;
+ }
+
+ /**
+ * Gets the value of the type property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets the value of the type property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+ /**
+ * Gets the value of the colour property.
+ *
+ */
+ public int getColour() {
+ return colour;
+ }
+
+ /**
+ * Sets the value of the colour property.
+ *
+ */
+ public void setColour(int value) {
+ this.colour = value;
+ }
+
+ /**
+ * Gets the value of the display property.
+ *
+ */
+ public boolean isDisplay() {
+ return display;
+ }
+
+ /**
+ * Sets the value of the display property.
+ *
+ */
+ public void setDisplay(boolean value) {
+ this.display = value;
+ }
+
+ /**
+ * Gets the value of the order property.
+ *
+ * @return
+ * possible object is
+ * {@link Float }
+ *
+ */
+ public Float getOrder() {
+ return order;
+ }
+
+ /**
+ * Sets the value of the order property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Float }
+ *
+ */
+ public void setOrder(Float value) {
+ this.order = value;
+ }
+
+ /**
+ * Gets the value of the mincolour property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getMincolour() {
+ return mincolour;
+ }
+
+ /**
+ * Sets the value of the mincolour property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setMincolour(Integer value) {
+ this.mincolour = value;
+ }
+
+ /**
+ * Gets the value of the noValueColour property.
+ *
+ * @return
+ * possible object is
+ * {@link NoValueColour }
+ *
+ */
+ public NoValueColour getNoValueColour() {
+ if (noValueColour == null) {
+ return NoValueColour.MIN;
+ } else {
+ return noValueColour;
+ }
+ }
+
+ /**
+ * Sets the value of the noValueColour property.
+ *
+ * @param value
+ * allowed object is
+ * {@link NoValueColour }
+ *
+ */
+ public void setNoValueColour(NoValueColour value) {
+ this.noValueColour = value;
+ }
+
+ /**
+ * Gets the value of the threshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Float }
+ *
+ */
+ public Float getThreshold() {
+ return threshold;
+ }
+
+ /**
+ * Sets the value of the threshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Float }
+ *
+ */
+ public void setThreshold(Float value) {
+ this.threshold = value;
+ }
+
+ /**
+ * Gets the value of the threshstate property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getThreshstate() {
+ return threshstate;
+ }
+
+ /**
+ * Sets the value of the threshstate property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setThreshstate(Integer value) {
+ this.threshstate = value;
+ }
+
+ /**
+ * Gets the value of the max property.
+ *
+ * @return
+ * possible object is
+ * {@link Float }
+ *
+ */
+ public Float getMax() {
+ return max;
+ }
+
+ /**
+ * Sets the value of the max property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Float }
+ *
+ */
+ public void setMax(Float value) {
+ this.max = value;
+ }
+
+ /**
+ * Gets the value of the min property.
+ *
+ * @return
+ * possible object is
+ * {@link Float }
+ *
+ */
+ public Float getMin() {
+ return min;
+ }
+
+ /**
+ * Sets the value of the min property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Float }
+ *
+ */
+ public void setMin(Float value) {
+ this.min = value;
+ }
+
+ /**
+ * Gets the value of the colourByLabel property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isColourByLabel() {
+ return colourByLabel;
+ }
+
+ /**
+ * Sets the value of the colourByLabel property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setColourByLabel(Boolean value) {
+ this.colourByLabel = value;
+ }
+
+ /**
+ * Gets the value of the autoScale property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isAutoScale() {
+ return autoScale;
+ }
+
+ /**
+ * Sets the value of the autoScale property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setAutoScale(Boolean value) {
+ this.autoScale = value;
+ }
+
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="seq" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/>
+ * <element name="annotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="outlineColour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="displayBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="displayText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="colourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "seq",
+ "annotationColours"
+ })
+ public static class JGroup {
+
+ @XmlElement(namespace = "www.jalview.org", required = true)
+ protected List<String> seq;
+ @XmlElement(namespace = "www.jalview.org")
+ protected AnnotationColourScheme annotationColours;
+ @XmlAttribute(name = "start")
+ protected Integer start;
+ @XmlAttribute(name = "end")
+ protected Integer end;
+ @XmlAttribute(name = "name")
+ protected String name;
+ @XmlAttribute(name = "colour")
+ protected String colour;
+ @XmlAttribute(name = "consThreshold")
+ protected Integer consThreshold;
+ @XmlAttribute(name = "pidThreshold")
+ protected Integer pidThreshold;
+ @XmlAttribute(name = "outlineColour")
+ protected Integer outlineColour;
+ @XmlAttribute(name = "displayBoxes")
+ protected Boolean displayBoxes;
+ @XmlAttribute(name = "displayText")
+ protected Boolean displayText;
+ @XmlAttribute(name = "colourText")
+ protected Boolean colourText;
+ @XmlAttribute(name = "textCol1")
+ protected Integer textCol1;
+ @XmlAttribute(name = "textCol2")
+ protected Integer textCol2;
+ @XmlAttribute(name = "textColThreshold")
+ protected Integer textColThreshold;
+ @XmlAttribute(name = "showUnconserved")
+ protected Boolean showUnconserved;
+ @XmlAttribute(name = "ignoreGapsinConsensus")
+ protected Boolean ignoreGapsinConsensus;
+ @XmlAttribute(name = "showConsensusHistogram")
+ protected Boolean showConsensusHistogram;
+ @XmlAttribute(name = "showSequenceLogo")
+ protected Boolean showSequenceLogo;
+ @XmlAttribute(name = "normaliseSequenceLogo")
+ protected Boolean normaliseSequenceLogo;
+ @XmlAttribute(name = "id")
+ protected String id;
+
+ /**
+ * Gets the value of the seq property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the seq property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getSeq().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ *
+ *
+ */
+ public List<String> getSeq() {
+ if (seq == null) {
+ seq = new ArrayList<String>();
+ }
+ return this.seq;
+ }
+
+ /**
+ * Gets the value of the annotationColours property.
+ *
+ * @return
+ * possible object is
+ * {@link AnnotationColourScheme }
+ *
+ */
+ public AnnotationColourScheme getAnnotationColours() {
+ return annotationColours;
+ }
+
+ /**
+ * Sets the value of the annotationColours property.
+ *
+ * @param value
+ * allowed object is
+ * {@link AnnotationColourScheme }
+ *
+ */
+ public void setAnnotationColours(AnnotationColourScheme value) {
+ this.annotationColours = value;
+ }
+
+ /**
+ * Gets the value of the start property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getStart() {
+ return start;
+ }
+
+ /**
+ * Sets the value of the start property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setStart(Integer value) {
+ this.start = value;
+ }
+
+ /**
+ * Gets the value of the end property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getEnd() {
+ return end;
+ }
+
+ /**
+ * Sets the value of the end property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setEnd(Integer value) {
+ this.end = value;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the colour property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getColour() {
+ return colour;
+ }
+
+ /**
+ * Sets the value of the colour property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setColour(String value) {
+ this.colour = value;
+ }
+
+ /**
+ * Gets the value of the consThreshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getConsThreshold() {
+ return consThreshold;
+ }
+
+ /**
+ * Sets the value of the consThreshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setConsThreshold(Integer value) {
+ this.consThreshold = value;
+ }
+
+ /**
+ * Gets the value of the pidThreshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getPidThreshold() {
+ return pidThreshold;
+ }
+
+ /**
+ * Sets the value of the pidThreshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setPidThreshold(Integer value) {
+ this.pidThreshold = value;
+ }
+
+ /**
+ * Gets the value of the outlineColour property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getOutlineColour() {
+ return outlineColour;
+ }
+
+ /**
+ * Sets the value of the outlineColour property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setOutlineColour(Integer value) {
+ this.outlineColour = value;
+ }
+
+ /**
+ * Gets the value of the displayBoxes property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isDisplayBoxes() {
+ return displayBoxes;
+ }
+
+ /**
+ * Sets the value of the displayBoxes property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setDisplayBoxes(Boolean value) {
+ this.displayBoxes = value;
+ }
+
+ /**
+ * Gets the value of the displayText property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isDisplayText() {
+ return displayText;
+ }
+
+ /**
+ * Sets the value of the displayText property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setDisplayText(Boolean value) {
+ this.displayText = value;
+ }
+
+ /**
+ * Gets the value of the colourText property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isColourText() {
+ return colourText;
+ }
+
+ /**
+ * Sets the value of the colourText property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setColourText(Boolean value) {
+ this.colourText = value;
+ }
+
+ /**
+ * Gets the value of the textCol1 property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getTextCol1() {
+ return textCol1;
+ }
+
+ /**
+ * Sets the value of the textCol1 property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setTextCol1(Integer value) {
+ this.textCol1 = value;
+ }
+
+ /**
+ * Gets the value of the textCol2 property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getTextCol2() {
+ return textCol2;
+ }
+
+ /**
+ * Sets the value of the textCol2 property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setTextCol2(Integer value) {
+ this.textCol2 = value;
+ }
+
+ /**
+ * Gets the value of the textColThreshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getTextColThreshold() {
+ return textColThreshold;
+ }
+
+ /**
+ * Sets the value of the textColThreshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setTextColThreshold(Integer value) {
+ this.textColThreshold = value;
+ }
+
+ /**
+ * Gets the value of the showUnconserved property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowUnconserved() {
+ return showUnconserved;
+ }
+
+ /**
+ * Sets the value of the showUnconserved property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowUnconserved(Boolean value) {
+ this.showUnconserved = value;
+ }
+
+ /**
+ * Gets the value of the ignoreGapsinConsensus property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isIgnoreGapsinConsensus() {
+ if (ignoreGapsinConsensus == null) {
+ return true;
+ } else {
+ return ignoreGapsinConsensus;
+ }
+ }
+
+ /**
+ * Sets the value of the ignoreGapsinConsensus property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setIgnoreGapsinConsensus(Boolean value) {
+ this.ignoreGapsinConsensus = value;
+ }
+
+ /**
+ * Gets the value of the showConsensusHistogram property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowConsensusHistogram() {
+ if (showConsensusHistogram == null) {
+ return true;
+ } else {
+ return showConsensusHistogram;
+ }
+ }
+
+ /**
+ * Sets the value of the showConsensusHistogram property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowConsensusHistogram(Boolean value) {
+ this.showConsensusHistogram = value;
+ }
+
+ /**
+ * Gets the value of the showSequenceLogo property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowSequenceLogo() {
+ if (showSequenceLogo == null) {
+ return false;
+ } else {
+ return showSequenceLogo;
+ }
+ }
+
+ /**
+ * Sets the value of the showSequenceLogo property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowSequenceLogo(Boolean value) {
+ this.showSequenceLogo = value;
+ }
+
+ /**
+ * Gets the value of the normaliseSequenceLogo property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isNormaliseSequenceLogo() {
+ if (normaliseSequenceLogo == null) {
+ return false;
+ } else {
+ return normaliseSequenceLogo;
+ }
+ }
+
+ /**
+ * Sets the value of the normaliseSequenceLogo property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setNormaliseSequenceLogo(Boolean value) {
+ this.normaliseSequenceLogo = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="features" type="{www.jalview.org}feature" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="pdbids" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <extension base="{www.jalview.org}pdbentry">
+ * <sequence>
+ * <element name="structureState" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </extension>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="hiddenSequences" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="rnaViewer" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="secondaryStructure" maxOccurs="unbounded">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="hidden" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewreference" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "features",
+ "pdbids",
+ "hiddenSequences",
+ "rnaViewer"
+ })
+ public static class JSeq {
+
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<Feature> features;
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.JSeq.Pdbids> pdbids;
+ @XmlElement(namespace = "www.jalview.org", type = Integer.class)
+ protected List<Integer> hiddenSequences;
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.JSeq.RnaViewer> rnaViewer;
+ @XmlAttribute(name = "colour")
+ protected Integer colour;
+ @XmlAttribute(name = "start", required = true)
+ protected int start;
+ @XmlAttribute(name = "end", required = true)
+ protected int end;
+ @XmlAttribute(name = "id", required = true)
+ protected String id;
+ @XmlAttribute(name = "hidden")
+ protected Boolean hidden;
+ @XmlAttribute(name = "viewreference")
+ protected Boolean viewreference;
+
+ /**
+ * Gets the value of the features property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the features property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getFeatures().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Feature }
+ *
+ *
+ */
+ public List<Feature> getFeatures() {
+ if (features == null) {
+ features = new ArrayList<Feature>();
+ }
+ return this.features;
+ }
+
+ /**
+ * Gets the value of the pdbids property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the pdbids property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getPdbids().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.JSeq.Pdbids }
+ *
+ *
+ */
+ public List<JalviewModelType.JSeq.Pdbids> getPdbids() {
+ if (pdbids == null) {
+ pdbids = new ArrayList<JalviewModelType.JSeq.Pdbids>();
+ }
+ return this.pdbids;
+ }
+
+ /**
+ * Gets the value of the hiddenSequences property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the hiddenSequences property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getHiddenSequences().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Integer }
+ *
+ *
+ */
+ public List<Integer> getHiddenSequences() {
+ if (hiddenSequences == null) {
+ hiddenSequences = new ArrayList<Integer>();
+ }
+ return this.hiddenSequences;
+ }
+
+ /**
+ * Gets the value of the rnaViewer property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the rnaViewer property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getRnaViewer().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.JSeq.RnaViewer }
+ *
+ *
+ */
+ public List<JalviewModelType.JSeq.RnaViewer> getRnaViewer() {
+ if (rnaViewer == null) {
+ rnaViewer = new ArrayList<JalviewModelType.JSeq.RnaViewer>();
+ }
+ return this.rnaViewer;
+ }
+
+ /**
+ * Gets the value of the colour property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getColour() {
+ return colour;
+ }
+
+ /**
+ * Sets the value of the colour property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setColour(Integer value) {
+ this.colour = value;
+ }
+
+ /**
+ * Gets the value of the start property.
+ *
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * Sets the value of the start property.
+ *
+ */
+ public void setStart(int value) {
+ this.start = value;
+ }
+
+ /**
+ * Gets the value of the end property.
+ *
+ */
+ public int getEnd() {
+ return end;
+ }
+
+ /**
+ * Sets the value of the end property.
+ *
+ */
+ public void setEnd(int value) {
+ this.end = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the hidden property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isHidden() {
+ return hidden;
+ }
+
+ /**
+ * Sets the value of the hidden property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setHidden(Boolean value) {
+ this.hidden = value;
+ }
+
+ /**
+ * Gets the value of the viewreference property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isViewreference() {
+ return viewreference;
+ }
+
+ /**
+ * Sets the value of the viewreference property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setViewreference(Boolean value) {
+ this.viewreference = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <extension base="{www.jalview.org}pdbentry">
+ * <sequence>
+ * <element name="structureState" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * </extension>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "structureState"
+ })
+ public static class Pdbids
+ extends Pdbentry
+ {
+
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.JSeq.Pdbids.StructureState> structureState;
+
+ /**
+ * Gets the value of the structureState property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the structureState property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getStructureState().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.JSeq.Pdbids.StructureState }
+ *
+ *
+ */
+ public List<JalviewModelType.JSeq.Pdbids.StructureState> getStructureState() {
+ if (structureState == null) {
+ structureState = new ArrayList<JalviewModelType.JSeq.Pdbids.StructureState>();
+ }
+ return this.structureState;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "value"
+ })
+ public static class StructureState {
+
+ @XmlValue
+ protected String value;
+ @XmlAttribute(name = "visible")
+ protected Boolean visible;
+ @XmlAttribute(name = "viewId")
+ protected String viewId;
+ @XmlAttribute(name = "alignwithAlignPanel")
+ protected Boolean alignwithAlignPanel;
+ @XmlAttribute(name = "colourwithAlignPanel")
+ protected Boolean colourwithAlignPanel;
+ @XmlAttribute(name = "colourByJmol")
+ protected Boolean colourByJmol;
+ @XmlAttribute(name = "type")
+ protected String type;
+ @XmlAttribute(name = "width")
+ protected Integer width;
+ @XmlAttribute(name = "height")
+ protected Integer height;
+ @XmlAttribute(name = "xpos")
+ protected Integer xpos;
+ @XmlAttribute(name = "ypos")
+ protected Integer ypos;
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the visible property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Sets the value of the visible property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setVisible(Boolean value) {
+ this.visible = value;
+ }
+
+ /**
+ * Gets the value of the viewId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getViewId() {
+ return viewId;
+ }
+
+ /**
+ * Sets the value of the viewId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setViewId(String value) {
+ this.viewId = value;
+ }
+
+ /**
+ * Gets the value of the alignwithAlignPanel property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isAlignwithAlignPanel() {
+ if (alignwithAlignPanel == null) {
+ return true;
+ } else {
+ return alignwithAlignPanel;
+ }
+ }
+
+ /**
+ * Sets the value of the alignwithAlignPanel property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setAlignwithAlignPanel(Boolean value) {
+ this.alignwithAlignPanel = value;
+ }
+
+ /**
+ * Gets the value of the colourwithAlignPanel property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isColourwithAlignPanel() {
+ if (colourwithAlignPanel == null) {
+ return false;
+ } else {
+ return colourwithAlignPanel;
+ }
+ }
+
+ /**
+ * Sets the value of the colourwithAlignPanel property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setColourwithAlignPanel(Boolean value) {
+ this.colourwithAlignPanel = value;
+ }
+
+ /**
+ * Gets the value of the colourByJmol property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isColourByJmol() {
+ if (colourByJmol == null) {
+ return true;
+ } else {
+ return colourByJmol;
+ }
+ }
+
+ /**
+ * Sets the value of the colourByJmol property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setColourByJmol(Boolean value) {
+ this.colourByJmol = value;
+ }
+
+ /**
+ * Gets the value of the type property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets the value of the type property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+ /**
+ * Gets the value of the width property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the value of the width property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setWidth(Integer value) {
+ this.width = value;
+ }
+
+ /**
+ * Gets the value of the height property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the value of the height property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setHeight(Integer value) {
+ this.height = value;
+ }
+
+ /**
+ * Gets the value of the xpos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getXpos() {
+ return xpos;
+ }
+
+ /**
+ * Sets the value of the xpos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setXpos(Integer value) {
+ this.xpos = value;
+ }
+
+ /**
+ * Gets the value of the ypos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getYpos() {
+ return ypos;
+ }
+
+ /**
+ * Sets the value of the ypos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setYpos(Integer value) {
+ this.ypos = value;
+ }
+
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="secondaryStructure" maxOccurs="unbounded">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "secondaryStructure"
+ })
+ public static class RnaViewer {
+
+ @XmlElement(namespace = "www.jalview.org", required = true)
+ protected List<JalviewModelType.JSeq.RnaViewer.SecondaryStructure> secondaryStructure;
+ @XmlAttribute(name = "title")
+ protected String title;
+ @XmlAttribute(name = "viewId")
+ protected String viewId;
+ @XmlAttribute(name = "dividerLocation")
+ protected Integer dividerLocation;
+ @XmlAttribute(name = "selectedRna")
+ protected Integer selectedRna;
+ @XmlAttribute(name = "width")
+ protected Integer width;
+ @XmlAttribute(name = "height")
+ protected Integer height;
+ @XmlAttribute(name = "xpos")
+ protected Integer xpos;
+ @XmlAttribute(name = "ypos")
+ protected Integer ypos;
+
+ /**
+ * Gets the value of the secondaryStructure property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the secondaryStructure property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getSecondaryStructure().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.JSeq.RnaViewer.SecondaryStructure }
+ *
+ *
+ */
+ public List<JalviewModelType.JSeq.RnaViewer.SecondaryStructure> getSecondaryStructure() {
+ if (secondaryStructure == null) {
+ secondaryStructure = new ArrayList<JalviewModelType.JSeq.RnaViewer.SecondaryStructure>();
+ }
+ return this.secondaryStructure;
+ }
+
+ /**
+ * Gets the value of the title property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Sets the value of the title property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTitle(String value) {
+ this.title = value;
+ }
+
+ /**
+ * Gets the value of the viewId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getViewId() {
+ return viewId;
+ }
+
+ /**
+ * Sets the value of the viewId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setViewId(String value) {
+ this.viewId = value;
+ }
+
+ /**
+ * Gets the value of the dividerLocation property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getDividerLocation() {
+ return dividerLocation;
+ }
+
+ /**
+ * Sets the value of the dividerLocation property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setDividerLocation(Integer value) {
+ this.dividerLocation = value;
+ }
+
+ /**
+ * Gets the value of the selectedRna property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getSelectedRna() {
+ return selectedRna;
+ }
+
+ /**
+ * Sets the value of the selectedRna property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setSelectedRna(Integer value) {
+ this.selectedRna = value;
+ }
+
+ /**
+ * Gets the value of the width property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the value of the width property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setWidth(Integer value) {
+ this.width = value;
+ }
+
+ /**
+ * Gets the value of the height property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the value of the height property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setHeight(Integer value) {
+ this.height = value;
+ }
+
+ /**
+ * Gets the value of the xpos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getXpos() {
+ return xpos;
+ }
+
+ /**
+ * Sets the value of the xpos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setXpos(Integer value) {
+ this.xpos = value;
+ }
+
+ /**
+ * Gets the value of the ypos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getYpos() {
+ return ypos;
+ }
+
+ /**
+ * Sets the value of the ypos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setYpos(Integer value) {
+ this.ypos = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class SecondaryStructure {
+
+ @XmlAttribute(name = "title")
+ protected String title;
+ @XmlAttribute(name = "annotationId", required = true)
+ protected String annotationId;
+ @XmlAttribute(name = "gapped")
+ protected Boolean gapped;
+ @XmlAttribute(name = "viewerState")
+ protected String viewerState;
+
+ /**
+ * Gets the value of the title property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Sets the value of the title property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTitle(String value) {
+ this.title = value;
+ }
+
+ /**
+ * Gets the value of the annotationId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getAnnotationId() {
+ return annotationId;
+ }
+
+ /**
+ * Sets the value of the annotationId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setAnnotationId(String value) {
+ this.annotationId = value;
+ }
+
+ /**
+ * Gets the value of the gapped property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isGapped() {
+ return gapped;
+ }
+
+ /**
+ * Sets the value of the gapped property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setGapped(Boolean value) {
+ this.gapped = value;
+ }
+
+ /**
+ * Gets the value of the viewerState property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getViewerState() {
+ return viewerState;
+ }
+
+ /**
+ * Sets the value of the viewerState property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setViewerState(String value) {
+ this.viewerState = value;
+ }
+
+ }
+
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence minOccurs="0">
+ * <element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
+ * <attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "title",
+ "newick"
+ })
+ public static class Tree {
+
+ @XmlElement(namespace = "www.jalview.org")
+ protected String title;
+ @XmlElement(namespace = "www.jalview.org")
+ protected String newick;
+ @XmlAttribute(name = "fontName")
+ protected String fontName;
+ @XmlAttribute(name = "fontSize")
+ protected Integer fontSize;
+ @XmlAttribute(name = "fontStyle")
+ protected Integer fontStyle;
+ @XmlAttribute(name = "threshold")
+ protected Float threshold;
+ @XmlAttribute(name = "showBootstrap")
+ protected Boolean showBootstrap;
+ @XmlAttribute(name = "showDistances")
+ protected Boolean showDistances;
+ @XmlAttribute(name = "markUnlinked")
+ protected Boolean markUnlinked;
+ @XmlAttribute(name = "fitToWindow")
+ protected Boolean fitToWindow;
+ @XmlAttribute(name = "currentTree")
+ protected Boolean currentTree;
+ @XmlAttribute(name = "id")
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlID
+ @XmlSchemaType(name = "ID")
+ protected String id;
+ @XmlAttribute(name = "width")
+ protected Integer width;
+ @XmlAttribute(name = "height")
+ protected Integer height;
+ @XmlAttribute(name = "xpos")
+ protected Integer xpos;
+ @XmlAttribute(name = "ypos")
+ protected Integer ypos;
+
+ /**
+ * Gets the value of the title property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Sets the value of the title property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTitle(String value) {
+ this.title = value;
+ }
+
+ /**
+ * Gets the value of the newick property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNewick() {
+ return newick;
+ }
+
+ /**
+ * Sets the value of the newick property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setNewick(String value) {
+ this.newick = value;
+ }
+
+ /**
+ * Gets the value of the fontName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getFontName() {
+ return fontName;
+ }
+
+ /**
+ * Sets the value of the fontName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setFontName(String value) {
+ this.fontName = value;
+ }
+
+ /**
+ * Gets the value of the fontSize property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getFontSize() {
+ return fontSize;
+ }
+
+ /**
+ * Sets the value of the fontSize property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setFontSize(Integer value) {
+ this.fontSize = value;
+ }
+
+ /**
+ * Gets the value of the fontStyle property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getFontStyle() {
+ return fontStyle;
+ }
+
+ /**
+ * Sets the value of the fontStyle property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setFontStyle(Integer value) {
+ this.fontStyle = value;
+ }
+
+ /**
+ * Gets the value of the threshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Float }
+ *
+ */
+ public Float getThreshold() {
+ return threshold;
+ }
+
+ /**
+ * Sets the value of the threshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Float }
+ *
+ */
+ public void setThreshold(Float value) {
+ this.threshold = value;
+ }
+
+ /**
+ * Gets the value of the showBootstrap property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowBootstrap() {
+ return showBootstrap;
+ }
+
+ /**
+ * Sets the value of the showBootstrap property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowBootstrap(Boolean value) {
+ this.showBootstrap = value;
+ }
+
+ /**
+ * Gets the value of the showDistances property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowDistances() {
+ return showDistances;
+ }
+
+ /**
+ * Sets the value of the showDistances property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowDistances(Boolean value) {
+ this.showDistances = value;
+ }
+
+ /**
+ * Gets the value of the markUnlinked property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isMarkUnlinked() {
+ return markUnlinked;
+ }
+
+ /**
+ * Sets the value of the markUnlinked property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setMarkUnlinked(Boolean value) {
+ this.markUnlinked = value;
+ }
+
+ /**
+ * Gets the value of the fitToWindow property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isFitToWindow() {
+ return fitToWindow;
+ }
+
+ /**
+ * Sets the value of the fitToWindow property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setFitToWindow(Boolean value) {
+ this.fitToWindow = value;
+ }
+
+ /**
+ * Gets the value of the currentTree property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isCurrentTree() {
+ return currentTree;
+ }
+
+ /**
+ * Sets the value of the currentTree property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setCurrentTree(Boolean value) {
+ this.currentTree = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the width property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the value of the width property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setWidth(Integer value) {
+ this.width = value;
+ }
+
+ /**
+ * Gets the value of the height property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the value of the height property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setHeight(Integer value) {
+ this.height = value;
+ }
+
+ /**
+ * Gets the value of the xpos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getXpos() {
+ return xpos;
+ }
+
+ /**
+ * Sets the value of the xpos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setXpos(Integer value) {
+ this.xpos = value;
+ }
+
+ /**
+ * Gets the value of the ypos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getYpos() {
+ return ypos;
+ }
+
+ /**
+ * Sets the value of the ypos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setYpos(Integer value) {
+ this.ypos = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="UserColourScheme" type="{www.jalview.org/colours}JalviewUserColours"/>
+ * </sequence>
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "userColourScheme"
+ })
+ public static class UserColours {
+
+ @XmlElement(name = "UserColourScheme", namespace = "www.jalview.org", required = true)
+ protected JalviewUserColours userColourScheme;
+ @XmlAttribute(name = "id")
+ protected String id;
+
+ /**
+ * Gets the value of the userColourScheme property.
+ *
+ * @return
+ * possible object is
+ * {@link JalviewUserColours }
+ *
+ */
+ public JalviewUserColours getUserColourScheme() {
+ return userColourScheme;
+ }
+
+ /**
+ * Sets the value of the userColourScheme property.
+ *
+ * @param value
+ * allowed object is
+ * {@link JalviewUserColours }
+ *
+ */
+ public void setUserColourScheme(JalviewUserColours value) {
+ this.userColourScheme = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="AnnotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
+ * <element name="hiddenColumns" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="calcIdParam" maxOccurs="unbounded" minOccurs="0">
+ * <complexType>
+ * <complexContent>
+ * <extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet">
+ * <attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </extension>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </sequence>
+ * <attGroup ref="{www.jalview.org}swingwindow"/>
+ * <attribute name="conservationSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="pidSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="showFullId" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="rightAlignIds" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showColourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="wrapAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="renderGaps" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showSequenceFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showNPfeatureTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="showDbRefTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="followHighlight" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="followSelection" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showAnnotation" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="centreColumnLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showGroupConservation" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showGroupConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="startRes" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="startSeq" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="scaleProteinAsCdna" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
+ * <attribute name="viewName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="sequenceSetId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="gatheredViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * <attribute name="complementId" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "annotationColours",
+ "hiddenColumns",
+ "calcIdParam"
+ })
+ public static class Viewport {
+
+ @XmlElement(name = "AnnotationColours", namespace = "www.jalview.org")
+ protected AnnotationColourScheme annotationColours;
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.Viewport.HiddenColumns> hiddenColumns;
+ @XmlElement(namespace = "www.jalview.org")
+ protected List<JalviewModelType.Viewport.CalcIdParam> calcIdParam;
+ @XmlAttribute(name = "conservationSelected")
+ protected Boolean conservationSelected;
+ @XmlAttribute(name = "pidSelected")
+ protected Boolean pidSelected;
+ @XmlAttribute(name = "bgColour")
+ protected String bgColour;
+ @XmlAttribute(name = "consThreshold")
+ protected Integer consThreshold;
+ @XmlAttribute(name = "pidThreshold")
+ protected Integer pidThreshold;
+ @XmlAttribute(name = "title")
+ protected String title;
+ @XmlAttribute(name = "showFullId")
+ protected Boolean showFullId;
+ @XmlAttribute(name = "rightAlignIds")
+ protected Boolean rightAlignIds;
+ @XmlAttribute(name = "showText")
+ protected Boolean showText;
+ @XmlAttribute(name = "showColourText")
+ protected Boolean showColourText;
+ @XmlAttribute(name = "showUnconserved")
+ protected Boolean showUnconserved;
+ @XmlAttribute(name = "showBoxes")
+ protected Boolean showBoxes;
+ @XmlAttribute(name = "wrapAlignment")
+ protected Boolean wrapAlignment;
+ @XmlAttribute(name = "renderGaps")
+ protected Boolean renderGaps;
+ @XmlAttribute(name = "showSequenceFeatures")
+ protected Boolean showSequenceFeatures;
+ @XmlAttribute(name = "showNPfeatureTooltip")
+ protected Boolean showNPfeatureTooltip;
+ @XmlAttribute(name = "showDbRefTooltip")
+ protected Boolean showDbRefTooltip;
+ @XmlAttribute(name = "followHighlight")
+ protected Boolean followHighlight;
+ @XmlAttribute(name = "followSelection")
+ protected Boolean followSelection;
+ @XmlAttribute(name = "showAnnotation")
+ protected Boolean showAnnotation;
+ @XmlAttribute(name = "centreColumnLabels")
+ protected Boolean centreColumnLabels;
+ @XmlAttribute(name = "showGroupConservation")
+ protected Boolean showGroupConservation;
+ @XmlAttribute(name = "showGroupConsensus")
+ protected Boolean showGroupConsensus;
+ @XmlAttribute(name = "showConsensusHistogram")
+ protected Boolean showConsensusHistogram;
+ @XmlAttribute(name = "showSequenceLogo")
+ protected Boolean showSequenceLogo;
+ @XmlAttribute(name = "normaliseSequenceLogo")
+ protected Boolean normaliseSequenceLogo;
+ @XmlAttribute(name = "ignoreGapsinConsensus")
+ protected Boolean ignoreGapsinConsensus;
+ @XmlAttribute(name = "startRes")
+ protected Integer startRes;
+ @XmlAttribute(name = "startSeq")
+ protected Integer startSeq;
+ @XmlAttribute(name = "fontName")
+ protected String fontName;
+ @XmlAttribute(name = "fontSize")
+ protected Integer fontSize;
+ @XmlAttribute(name = "fontStyle")
+ protected Integer fontStyle;
+ @XmlAttribute(name = "scaleProteinAsCdna")
+ protected Boolean scaleProteinAsCdna;
+ @XmlAttribute(name = "viewName")
+ protected String viewName;
+ @XmlAttribute(name = "sequenceSetId")
+ protected String sequenceSetId;
+ @XmlAttribute(name = "gatheredViews")
+ protected Boolean gatheredViews;
+ @XmlAttribute(name = "textCol1")
+ protected Integer textCol1;
+ @XmlAttribute(name = "textCol2")
+ protected Integer textCol2;
+ @XmlAttribute(name = "textColThreshold")
+ protected Integer textColThreshold;
+ @XmlAttribute(name = "id")
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlID
+ @XmlSchemaType(name = "ID")
+ protected String id;
+ @XmlAttribute(name = "complementId")
+ protected String complementId;
+ @XmlAttribute(name = "width")
+ protected Integer width;
+ @XmlAttribute(name = "height")
+ protected Integer height;
+ @XmlAttribute(name = "xpos")
+ protected Integer xpos;
+ @XmlAttribute(name = "ypos")
+ protected Integer ypos;
+
+ /**
+ * Gets the value of the annotationColours property.
+ *
+ * @return
+ * possible object is
+ * {@link AnnotationColourScheme }
+ *
+ */
+ public AnnotationColourScheme getAnnotationColours() {
+ return annotationColours;
+ }
+
+ /**
+ * Sets the value of the annotationColours property.
+ *
+ * @param value
+ * allowed object is
+ * {@link AnnotationColourScheme }
+ *
+ */
+ public void setAnnotationColours(AnnotationColourScheme value) {
+ this.annotationColours = value;
+ }
+
+ /**
+ * Gets the value of the hiddenColumns property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the hiddenColumns property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getHiddenColumns().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.Viewport.HiddenColumns }
+ *
+ *
+ */
+ public List<JalviewModelType.Viewport.HiddenColumns> getHiddenColumns() {
+ if (hiddenColumns == null) {
+ hiddenColumns = new ArrayList<JalviewModelType.Viewport.HiddenColumns>();
+ }
+ return this.hiddenColumns;
+ }
+
+ /**
+ * Gets the value of the calcIdParam property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the calcIdParam property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getCalcIdParam().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link JalviewModelType.Viewport.CalcIdParam }
+ *
+ *
+ */
+ public List<JalviewModelType.Viewport.CalcIdParam> getCalcIdParam() {
+ if (calcIdParam == null) {
+ calcIdParam = new ArrayList<JalviewModelType.Viewport.CalcIdParam>();
+ }
+ return this.calcIdParam;
+ }
+
+ /**
+ * Gets the value of the conservationSelected property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isConservationSelected() {
+ return conservationSelected;
+ }
+
+ /**
+ * Sets the value of the conservationSelected property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setConservationSelected(Boolean value) {
+ this.conservationSelected = value;
+ }
+
+ /**
+ * Gets the value of the pidSelected property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isPidSelected() {
+ return pidSelected;
+ }
+
+ /**
+ * Sets the value of the pidSelected property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setPidSelected(Boolean value) {
+ this.pidSelected = value;
+ }
+
+ /**
+ * Gets the value of the bgColour property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getBgColour() {
+ return bgColour;
+ }
+
+ /**
+ * Sets the value of the bgColour property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setBgColour(String value) {
+ this.bgColour = value;
+ }
+
+ /**
+ * Gets the value of the consThreshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getConsThreshold() {
+ return consThreshold;
+ }
+
+ /**
+ * Sets the value of the consThreshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setConsThreshold(Integer value) {
+ this.consThreshold = value;
+ }
+
+ /**
+ * Gets the value of the pidThreshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getPidThreshold() {
+ return pidThreshold;
+ }
+
+ /**
+ * Sets the value of the pidThreshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setPidThreshold(Integer value) {
+ this.pidThreshold = value;
+ }
+
+ /**
+ * Gets the value of the title property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Sets the value of the title property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTitle(String value) {
+ this.title = value;
+ }
+
+ /**
+ * Gets the value of the showFullId property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowFullId() {
+ return showFullId;
+ }
+
+ /**
+ * Sets the value of the showFullId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowFullId(Boolean value) {
+ this.showFullId = value;
+ }
+
+ /**
+ * Gets the value of the rightAlignIds property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isRightAlignIds() {
+ return rightAlignIds;
+ }
+
+ /**
+ * Sets the value of the rightAlignIds property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setRightAlignIds(Boolean value) {
+ this.rightAlignIds = value;
+ }
+
+ /**
+ * Gets the value of the showText property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowText() {
+ return showText;
+ }
+
+ /**
+ * Sets the value of the showText property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowText(Boolean value) {
+ this.showText = value;
+ }
+
+ /**
+ * Gets the value of the showColourText property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowColourText() {
+ return showColourText;
+ }
+
+ /**
+ * Sets the value of the showColourText property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowColourText(Boolean value) {
+ this.showColourText = value;
+ }
+
+ /**
+ * Gets the value of the showUnconserved property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowUnconserved() {
+ if (showUnconserved == null) {
+ return false;
+ } else {
+ return showUnconserved;
+ }
+ }
+
+ /**
+ * Sets the value of the showUnconserved property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowUnconserved(Boolean value) {
+ this.showUnconserved = value;
+ }
+
+ /**
+ * Gets the value of the showBoxes property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowBoxes() {
+ return showBoxes;
+ }
+
+ /**
+ * Sets the value of the showBoxes property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowBoxes(Boolean value) {
+ this.showBoxes = value;
+ }
+
+ /**
+ * Gets the value of the wrapAlignment property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isWrapAlignment() {
+ return wrapAlignment;
+ }
+
+ /**
+ * Sets the value of the wrapAlignment property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setWrapAlignment(Boolean value) {
+ this.wrapAlignment = value;
+ }
+
+ /**
+ * Gets the value of the renderGaps property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isRenderGaps() {
+ return renderGaps;
+ }
+
+ /**
+ * Sets the value of the renderGaps property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setRenderGaps(Boolean value) {
+ this.renderGaps = value;
+ }
+
+ /**
+ * Gets the value of the showSequenceFeatures property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowSequenceFeatures() {
+ return showSequenceFeatures;
+ }
+
+ /**
+ * Sets the value of the showSequenceFeatures property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowSequenceFeatures(Boolean value) {
+ this.showSequenceFeatures = value;
+ }
+
+ /**
+ * Gets the value of the showNPfeatureTooltip property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowNPfeatureTooltip() {
+ return showNPfeatureTooltip;
+ }
+
+ /**
+ * Sets the value of the showNPfeatureTooltip property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowNPfeatureTooltip(Boolean value) {
+ this.showNPfeatureTooltip = value;
+ }
+
+ /**
+ * Gets the value of the showDbRefTooltip property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowDbRefTooltip() {
+ return showDbRefTooltip;
+ }
+
+ /**
+ * Sets the value of the showDbRefTooltip property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowDbRefTooltip(Boolean value) {
+ this.showDbRefTooltip = value;
+ }
+
+ /**
+ * Gets the value of the followHighlight property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isFollowHighlight() {
+ if (followHighlight == null) {
+ return true;
+ } else {
+ return followHighlight;
+ }
+ }
+
+ /**
+ * Sets the value of the followHighlight property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setFollowHighlight(Boolean value) {
+ this.followHighlight = value;
+ }
+
+ /**
+ * Gets the value of the followSelection property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isFollowSelection() {
+ if (followSelection == null) {
+ return true;
+ } else {
+ return followSelection;
+ }
+ }
+
+ /**
+ * Sets the value of the followSelection property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setFollowSelection(Boolean value) {
+ this.followSelection = value;
+ }
+
+ /**
+ * Gets the value of the showAnnotation property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isShowAnnotation() {
+ return showAnnotation;
+ }
+
+ /**
+ * Sets the value of the showAnnotation property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowAnnotation(Boolean value) {
+ this.showAnnotation = value;
+ }
+
+ /**
+ * Gets the value of the centreColumnLabels property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isCentreColumnLabels() {
+ if (centreColumnLabels == null) {
+ return false;
+ } else {
+ return centreColumnLabels;
+ }
+ }
+
+ /**
+ * Sets the value of the centreColumnLabels property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setCentreColumnLabels(Boolean value) {
+ this.centreColumnLabels = value;
+ }
+
+ /**
+ * Gets the value of the showGroupConservation property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowGroupConservation() {
+ if (showGroupConservation == null) {
+ return false;
+ } else {
+ return showGroupConservation;
+ }
+ }
+
+ /**
+ * Sets the value of the showGroupConservation property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowGroupConservation(Boolean value) {
+ this.showGroupConservation = value;
+ }
+
+ /**
+ * Gets the value of the showGroupConsensus property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowGroupConsensus() {
+ if (showGroupConsensus == null) {
+ return false;
+ } else {
+ return showGroupConsensus;
+ }
+ }
+
+ /**
+ * Sets the value of the showGroupConsensus property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowGroupConsensus(Boolean value) {
+ this.showGroupConsensus = value;
+ }
+
+ /**
+ * Gets the value of the showConsensusHistogram property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowConsensusHistogram() {
+ if (showConsensusHistogram == null) {
+ return true;
+ } else {
+ return showConsensusHistogram;
+ }
+ }
+
+ /**
+ * Sets the value of the showConsensusHistogram property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowConsensusHistogram(Boolean value) {
+ this.showConsensusHistogram = value;
+ }
+
+ /**
+ * Gets the value of the showSequenceLogo property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isShowSequenceLogo() {
+ if (showSequenceLogo == null) {
+ return false;
+ } else {
+ return showSequenceLogo;
+ }
+ }
+
+ /**
+ * Sets the value of the showSequenceLogo property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setShowSequenceLogo(Boolean value) {
+ this.showSequenceLogo = value;
+ }
+
+ /**
+ * Gets the value of the normaliseSequenceLogo property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isNormaliseSequenceLogo() {
+ if (normaliseSequenceLogo == null) {
+ return false;
+ } else {
+ return normaliseSequenceLogo;
+ }
+ }
+
+ /**
+ * Sets the value of the normaliseSequenceLogo property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setNormaliseSequenceLogo(Boolean value) {
+ this.normaliseSequenceLogo = value;
+ }
+
+ /**
+ * Gets the value of the ignoreGapsinConsensus property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isIgnoreGapsinConsensus() {
+ if (ignoreGapsinConsensus == null) {
+ return true;
+ } else {
+ return ignoreGapsinConsensus;
+ }
+ }
+
+ /**
+ * Sets the value of the ignoreGapsinConsensus property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setIgnoreGapsinConsensus(Boolean value) {
+ this.ignoreGapsinConsensus = value;
+ }
+
+ /**
+ * Gets the value of the startRes property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getStartRes() {
+ return startRes;
+ }
+
+ /**
+ * Sets the value of the startRes property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setStartRes(Integer value) {
+ this.startRes = value;
+ }
+
+ /**
+ * Gets the value of the startSeq property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getStartSeq() {
+ return startSeq;
+ }
+
+ /**
+ * Sets the value of the startSeq property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setStartSeq(Integer value) {
+ this.startSeq = value;
+ }
+
+ /**
+ * Gets the value of the fontName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getFontName() {
+ return fontName;
+ }
+
+ /**
+ * Sets the value of the fontName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setFontName(String value) {
+ this.fontName = value;
+ }
+
+ /**
+ * Gets the value of the fontSize property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getFontSize() {
+ return fontSize;
+ }
+
+ /**
+ * Sets the value of the fontSize property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setFontSize(Integer value) {
+ this.fontSize = value;
+ }
+
+ /**
+ * Gets the value of the fontStyle property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getFontStyle() {
+ return fontStyle;
+ }
+
+ /**
+ * Sets the value of the fontStyle property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setFontStyle(Integer value) {
+ this.fontStyle = value;
+ }
+
+ /**
+ * Gets the value of the scaleProteinAsCdna property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isScaleProteinAsCdna() {
+ if (scaleProteinAsCdna == null) {
+ return true;
+ } else {
+ return scaleProteinAsCdna;
+ }
+ }
+
+ /**
+ * Sets the value of the scaleProteinAsCdna property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setScaleProteinAsCdna(Boolean value) {
+ this.scaleProteinAsCdna = value;
+ }
+
+ /**
+ * Gets the value of the viewName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getViewName() {
+ return viewName;
+ }
+
+ /**
+ * Sets the value of the viewName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setViewName(String value) {
+ this.viewName = value;
+ }
+
+ /**
+ * Gets the value of the sequenceSetId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getSequenceSetId() {
+ return sequenceSetId;
+ }
+
+ /**
+ * Sets the value of the sequenceSetId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setSequenceSetId(String value) {
+ this.sequenceSetId = value;
+ }
+
+ /**
+ * Gets the value of the gatheredViews property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isGatheredViews() {
+ return gatheredViews;
+ }
+
+ /**
+ * Sets the value of the gatheredViews property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setGatheredViews(Boolean value) {
+ this.gatheredViews = value;
+ }
+
+ /**
+ * Gets the value of the textCol1 property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getTextCol1() {
+ return textCol1;
+ }
+
+ /**
+ * Sets the value of the textCol1 property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setTextCol1(Integer value) {
+ this.textCol1 = value;
+ }
+
+ /**
+ * Gets the value of the textCol2 property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getTextCol2() {
+ return textCol2;
+ }
+
+ /**
+ * Sets the value of the textCol2 property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setTextCol2(Integer value) {
+ this.textCol2 = value;
+ }
+
+ /**
+ * Gets the value of the textColThreshold property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getTextColThreshold() {
+ return textColThreshold;
+ }
+
+ /**
+ * Sets the value of the textColThreshold property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setTextColThreshold(Integer value) {
+ this.textColThreshold = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the complementId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getComplementId() {
+ return complementId;
+ }
+
+ /**
+ * Sets the value of the complementId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setComplementId(String value) {
+ this.complementId = value;
+ }
+
+ /**
+ * Gets the value of the width property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the value of the width property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setWidth(Integer value) {
+ this.width = value;
+ }
+
+ /**
+ * Gets the value of the height property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the value of the height property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setHeight(Integer value) {
+ this.height = value;
+ }
+
+ /**
+ * Gets the value of the xpos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getXpos() {
+ return xpos;
+ }
+
+ /**
+ * Sets the value of the xpos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setXpos(Integer value) {
+ this.xpos = value;
+ }
+
+ /**
+ * Gets the value of the ypos property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getYpos() {
+ return ypos;
+ }
+
+ /**
+ * Sets the value of the ypos property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setYpos(Integer value) {
+ this.ypos = value;
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet">
+ * <attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+ * <attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </extension>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class CalcIdParam
+ extends WebServiceParameterSet
+ {
+
+ @XmlAttribute(name = "calcId", required = true)
+ protected String calcId;
+ @XmlAttribute(name = "needsUpdate")
+ protected Boolean needsUpdate;
+ @XmlAttribute(name = "autoUpdate", required = true)
+ protected boolean autoUpdate;
+
+ /**
+ * Gets the value of the calcId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getCalcId() {
+ return calcId;
+ }
+
+ /**
+ * Sets the value of the calcId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setCalcId(String value) {
+ this.calcId = value;
+ }
+
+ /**
+ * Gets the value of the needsUpdate property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isNeedsUpdate() {
+ if (needsUpdate == null) {
+ return false;
+ } else {
+ return needsUpdate;
+ }
+ }
+
+ /**
+ * Sets the value of the needsUpdate property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setNeedsUpdate(Boolean value) {
+ this.needsUpdate = value;
+ }
+
+ /**
+ * Gets the value of the autoUpdate property.
+ *
+ */
+ public boolean isAutoUpdate() {
+ return autoUpdate;
+ }
+
+ /**
+ * Sets the value of the autoUpdate property.
+ *
+ */
+ public void setAutoUpdate(boolean value) {
+ this.autoUpdate = value;
+ }
+
+ }
+
+
+ /**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "")
+ public static class HiddenColumns {
+
+ @XmlAttribute(name = "start")
+ protected Integer start;
+ @XmlAttribute(name = "end")
+ protected Integer end;
+
+ /**
+ * Gets the value of the start property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getStart() {
+ return start;
+ }
+
+ /**
+ * Sets the value of the start property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setStart(Integer value) {
+ this.start = value;
+ }
+
+ /**
+ * Gets the value of the end property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public Integer getEnd() {
+ return end;
+ }
+
+ /**
+ * Sets the value of the end property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setEnd(Integer value) {
+ this.end = value;
+ }
+
+ }
+
+ }
+
+}
*
*/
public class EpsGraphics2D extends java.awt.Graphics2D
+ implements AutoCloseable
{
public static final String VERSION = "0.8.8";
* OutputStream is automatically flushed before being closed. If you forget to
* do this, the file may be incomplete.
*/
+ @Override
public void close() throws IOException
{
flush();
* Draws a 3D rectangle outline. If it is raised, light appears to come from
* the top left.
*/
+ @Override
public void draw3DRect(int x, int y, int width, int height, boolean raised)
{
Color originalColor = getColor();
* Fills a 3D rectangle. If raised, it has bright fill and light appears to
* come from the top left.
*/
+ @Override
public void fill3DRect(int x, int y, int width, int height, boolean raised)
{
Color originalColor = getColor();
/**
* Draws a Shape on the EPS document.
*/
+ @Override
public void draw(Shape s)
{
draw(s, "stroke");
/**
* Draws an Image on the EPS document.
*/
+ @Override
public boolean drawImage(Image img, AffineTransform xform,
ImageObserver obs)
{
/**
* Draws a BufferedImage on the EPS document.
*/
+ @Override
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
{
BufferedImage img1 = op.filter(img, null);
/**
* Draws a RenderedImage on the EPS document.
*/
+ @Override
public void drawRenderedImage(RenderedImage img, AffineTransform xform)
{
Hashtable properties = new Hashtable();
/**
* Draws a RenderableImage by invoking its createDefaultRendering method.
*/
+ @Override
public void drawRenderableImage(RenderableImage img, AffineTransform xform)
{
drawRenderedImage(img.createDefaultRendering(), xform);
/**
* Draws a string at (x,y)
*/
+ @Override
public void drawString(String str, int x, int y)
{
drawString(str, (float) x, (float) y);
/**
* Draws a string at (x,y)
*/
+ @Override
public void drawString(String s, float x, float y)
{
if (s != null && s.length() > 0)
* Draws the characters of an AttributedCharacterIterator, starting from
* (x,y).
*/
+ @Override
public void drawString(AttributedCharacterIterator iterator, int x, int y)
{
drawString(iterator, (float) x, (float) y);
* Draws the characters of an AttributedCharacterIterator, starting from
* (x,y).
*/
+ @Override
public void drawString(AttributedCharacterIterator iterator, float x,
float y)
{
/**
* Draws a GlyphVector at (x,y)
*/
+ @Override
public void drawGlyphVector(GlyphVector g, float x, float y)
{
Shape shape = g.getOutline(x, y);
/**
* Fills a Shape on the EPS document.
*/
+ @Override
public void fill(Shape s)
{
draw(s, "fill");
* Checks whether or not the specified Shape intersects the specified
* Rectangle, which is in device space.
*/
+ @Override
public boolean hit(Rectangle rect, Shape s, boolean onStroke)
{
return s.intersects(rect);
/**
* Returns the device configuration associated with this EpsGraphics2D object.
*/
+ @Override
public GraphicsConfiguration getDeviceConfiguration()
{
GraphicsConfiguration gc = null;
* Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does not
* make use of these.
*/
+ @Override
public void setComposite(Composite comp)
{
_composite = comp;
* Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
* of type Color are respected by EpsGraphics2D.
*/
+ @Override
public void setPaint(Paint paint)
{
_paint = paint;
* Sets the stroke. Only accepts BasicStroke objects (or subclasses of
* BasicStroke).
*/
+ @Override
public void setStroke(Stroke s)
{
if (s instanceof BasicStroke)
/**
* Sets a rendering hint. These are not used by EpsGraphics2D.
*/
+ @Override
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
{
// Do nothing.
* Returns the value of a single preference for the rendering algorithms.
* Rendering hints are not used by EpsGraphics2D.
*/
+ @Override
public Object getRenderingHint(RenderingHints.Key hintKey)
{
return null;
/**
* Sets the rendering hints. These are ignored by EpsGraphics2D.
*/
+ @Override
public void setRenderingHints(Map hints)
{
// Do nothing.
/**
* Adds rendering hints. These are ignored by EpsGraphics2D.
*/
+ @Override
public void addRenderingHints(Map hints)
{
// Do nothing.
/**
* Returns the preferences for the rendering algorithms.
*/
+ @Override
public RenderingHints getRenderingHints()
{
return new RenderingHints(null);
* Translates the origin of the EpsGraphics2D context to the point (x,y) in
* the current coordinate system.
*/
+ @Override
public void translate(int x, int y)
{
translate((double) x, (double) y);
* Concatenates the current EpsGraphics2D Transformation with a translation
* transform.
*/
+ @Override
public void translate(double tx, double ty)
{
transform(AffineTransform.getTranslateInstance(tx, ty));
/**
* Concatenates the current EpsGraphics2D Transform with a rotation transform.
*/
+ @Override
public void rotate(double theta)
{
rotate(theta, 0, 0);
* Concatenates the current EpsGraphics2D Transform with a translated rotation
* transform.
*/
+ @Override
public void rotate(double theta, double x, double y)
{
transform(AffineTransform.getRotateInstance(theta, x, y));
* Concatenates the current EpsGraphics2D Transform with a scaling
* transformation.
*/
+ @Override
public void scale(double sx, double sy)
{
transform(AffineTransform.getScaleInstance(sx, sy));
/**
* Concatenates the current EpsGraphics2D Transform with a shearing transform.
*/
+ @Override
public void shear(double shx, double shy)
{
transform(AffineTransform.getShearInstance(shx, shy));
* Composes an AffineTransform object with the Transform in this EpsGraphics2D
* according to the rule last-specified-first-applied.
*/
+ @Override
public void transform(AffineTransform Tx)
{
_transform.concatenate(Tx);
/**
* Sets the AffineTransform to be used by this EpsGraphics2D.
*/
+ @Override
public void setTransform(AffineTransform Tx)
{
if (Tx == null)
/**
* Gets the AffineTransform used by this EpsGraphics2D.
*/
+ @Override
public AffineTransform getTransform()
{
return new AffineTransform(_transform);
/**
* Returns the current Paint of the EpsGraphics2D object.
*/
+ @Override
public Paint getPaint()
{
return _paint;
/**
* returns the current Composite of the EpsGraphics2D object.
*/
+ @Override
public Composite getComposite()
{
return _composite;
/**
* Sets the background color to be used by the clearRect method.
*/
+ @Override
public void setBackground(Color color)
{
if (color == null)
/**
* Gets the background color that is used by the clearRect method.
*/
+ @Override
public Color getBackground()
{
return _backgroundColor;
* Returns the Stroke currently used. Guaranteed to be an instance of
* BasicStroke.
*/
+ @Override
public Stroke getStroke()
{
return _stroke;
* Intersects the current clip with the interior of the specified Shape and
* sets the clip to the resulting intersection.
*/
+ @Override
public void clip(Shape s)
{
if (_clip == null)
/**
* Returns the FontRenderContext.
*/
+ @Override
public FontRenderContext getFontRenderContext()
{
return _fontRenderContext;
/**
* Returns a new Graphics object that is identical to this EpsGraphics2D.
*/
+ @Override
public Graphics create()
{
return new EpsGraphics2D(this);
* Returns an EpsGraphics2D object based on this Graphics object, but with a
* new translation and clip area.
*/
+ @Override
public Graphics create(int x, int y, int width, int height)
{
Graphics g = create();
* Returns the current Color. This will be a default value (black) until it is
* changed using the setColor method.
*/
+ @Override
public Color getColor()
{
return _color;
/**
* Sets the Color to be used when drawing all future shapes, text, etc.
*/
+ @Override
public void setColor(Color c)
{
if (c == null)
* Sets the paint mode of this EpsGraphics2D object to overwrite the
* destination EpsDocument with the current color.
*/
+ @Override
public void setPaintMode()
{
// Do nothing - paint mode is the only method supported anyway.
* <b><i><font color="red">Not implemented</font></i></b> - performs no
* action.
*/
+ @Override
public void setXORMode(Color c1)
{
methodNotSupported();
/**
* Returns the Font currently being used.
*/
+ @Override
public Font getFont()
{
return _font;
/**
* Sets the Font to be used in future text.
*/
+ @Override
public void setFont(Font font)
{
if (font == null)
font = Font.decode(null);
}
_font = font;
- append("/" + _font.getPSName() + " findfont " + ((int) _font.getSize())
+ append("/" + _font.getPSName() + " findfont " + (_font.getSize())
+ " scalefont setfont");
}
/**
* Gets the font metrics of the current font.
*/
+ @Override
public FontMetrics getFontMetrics()
{
return getFontMetrics(getFont());
/**
* Gets the font metrics for the specified font.
*/
+ @Override
public FontMetrics getFontMetrics(Font f)
{
BufferedImage image = new BufferedImage(1, 1,
/**
* Returns the bounding rectangle of the current clipping area.
*/
+ @Override
public Rectangle getClipBounds()
{
if (_clip == null)
/**
* Intersects the current clip with the specified rectangle.
*/
+ @Override
public void clipRect(int x, int y, int width, int height)
{
clip(new Rectangle(x, y, width, height));
/**
* Sets the current clip to the rectangle specified by the given coordinates.
*/
+ @Override
public void setClip(int x, int y, int width, int height)
{
setClip(new Rectangle(x, y, width, height));
/**
* Gets the current clipping area.
*/
+ @Override
public Shape getClip()
{
if (_clip == null)
/**
* Sets the current clipping area to an arbitrary clip shape.
*/
+ @Override
public void setClip(Shape clip)
{
if (clip != null)
* <b><i><font color="red">Not implemented</font></i></b> - performs no
* action.
*/
+ @Override
public void copyArea(int x, int y, int width, int height, int dx, int dy)
{
methodNotSupported();
/**
* Draws a straight line from (x1,y1) to (x2,y2).
*/
+ @Override
public void drawLine(int x1, int y1, int x2, int y2)
{
Shape shape = new Line2D.Float(x1, y1, x2, y2);
/**
* Fills a rectangle with top-left corner placed at (x,y).
*/
+ @Override
public void fillRect(int x, int y, int width, int height)
{
Shape shape = new Rectangle(x, y, width, height);
/**
* Draws a rectangle with top-left corner placed at (x,y).
*/
+ @Override
public void drawRect(int x, int y, int width, int height)
{
Shape shape = new Rectangle(x, y, width, height);
* Clears a rectangle with top-left corner placed at (x,y) using the current
* background color.
*/
+ @Override
public void clearRect(int x, int y, int width, int height)
{
Color originalColor = getColor();
/**
* Draws a rounded rectangle.
*/
+ @Override
public void drawRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight)
{
/**
* Fills a rounded rectangle.
*/
+ @Override
public void fillRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight)
{
/**
* Draws an oval.
*/
+ @Override
public void drawOval(int x, int y, int width, int height)
{
Shape shape = new Ellipse2D.Float(x, y, width, height);
/**
* Fills an oval.
*/
+ @Override
public void fillOval(int x, int y, int width, int height)
{
Shape shape = new Ellipse2D.Float(x, y, width, height);
/**
* Draws an arc.
*/
+ @Override
public void drawArc(int x, int y, int width, int height, int startAngle,
int arcAngle)
{
/**
* Fills an arc.
*/
+ @Override
public void fillArc(int x, int y, int width, int height, int startAngle,
int arcAngle)
{
/**
* Draws a polyline.
*/
+ @Override
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
{
if (nPoints > 0)
/**
* Draws a polygon made with the specified points.
*/
+ @Override
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
{
Shape shape = new Polygon(xPoints, yPoints, nPoints);
/**
* Draws a polygon.
*/
+ @Override
public void drawPolygon(Polygon p)
{
draw(p);
/**
* Fills a polygon made with the specified points.
*/
+ @Override
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
{
Shape shape = new Polygon(xPoints, yPoints, nPoints);
/**
* Fills a polygon.
*/
+ @Override
public void fillPolygon(Polygon p)
{
draw(p, "fill");
/**
* Draws the specified characters, starting from (x,y)
*/
+ @Override
public void drawChars(char[] data, int offset, int length, int x, int y)
{
String string = new String(data, offset, length);
/**
* Draws the specified bytes, starting from (x,y)
*/
+ @Override
public void drawBytes(byte[] data, int offset, int length, int x, int y)
{
String string = new String(data, offset, length);
/**
* Draws an image.
*/
+ @Override
public boolean drawImage(Image img, int x, int y, ImageObserver observer)
{
return drawImage(img, x, y, Color.white, observer);
/**
* Draws an image.
*/
+ @Override
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer)
{
/**
* Draws an image.
*/
+ @Override
public boolean drawImage(Image img, int x, int y, Color bgcolor,
ImageObserver observer)
{
/**
* Draws an image.
*/
+ @Override
public boolean drawImage(Image img, int x, int y, int width, int height,
Color bgcolor, ImageObserver observer)
{
/**
* Draws an image.
*/
+ @Override
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
{
/**
* Draws an image.
*/
+ @Override
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2, Color bgcolor,
ImageObserver observer)
* only remaining EpsGraphics2D instance pointing at a EpsDocument object,
* then the EpsDocument object shall become eligible for garbage collection.
*/
+ @Override
public void dispose()
{
_document = null;
}
+ /* bsoares 2019-03-20
+ * finalize is now deprecated. Implementing AutoCloseable instead
/**
* Finalizes the object.
- */
+ @Override
public void finalize()
{
super.finalize();
}
+ */
/**
* Returns the entire contents of the EPS document, complete with headers and
* bounding box. The returned String is suitable for being written directly to
* disk as an EPS file.
*/
+ @Override
public String toString()
{
StringWriter writer = new StringWriter();
* Returns true if the specified rectangular area might intersect the current
* clipping area.
*/
+ @Override
public boolean hitClip(int x, int y, int width, int height)
{
if (_clip == null)
/**
* Returns the bounding rectangle of the current clipping area.
*/
+ @Override
public Rectangle getClipBounds(Rectangle r)
{
if (_clip == null)
{
_hashCode += getMatrix().hashCode();
}
- _hashCode += new Float(getExp()).hashCode();
- _hashCode += new Boolean(isEchofilter()).hashCode();
+ _hashCode += Float.valueOf(getExp()).hashCode();
+ _hashCode += Boolean.valueOf(isEchofilter()).hashCode();
if (getFilter() != null)
{
_hashCode += getFilter().hashCode();
_hashCode += getOutformat().hashCode();
}
_hashCode += getTopcombon();
- _hashCode += new Boolean(isAsync()).hashCode();
+ _hashCode += Boolean.valueOf(isAsync()).hashCode();
if (getEmail() != null)
{
_hashCode += getEmail().hashCode();
setAttachments(_call);
java.lang.Object _resp = _call.invoke(new java.lang.Object[] {
sequence, searchDatabases, taxonId,
- new java.lang.Boolean(onlyActive) });
+ java.lang.Boolean.valueOf(onlyActive) });
if (_resp instanceof java.rmi.RemoteException)
{
setAttachments(_call);
java.lang.Object _resp = _call.invoke(new java.lang.Object[] {
accession, ac_version, searchDatabases, taxonId,
- new java.lang.Boolean(onlyActive) });
+ java.lang.Boolean.valueOf(onlyActive) });
if (_resp instanceof java.rmi.RemoteException)
{
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import org.testng.Assert;
import org.testng.annotations.Test;
import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ModuleRef;
import io.github.classgraph.ScanResult;
public class CommandLineOperations
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
- private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed on
+ private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed
+ // on
// full test run than on
// individual tests
private static String classpath = null;
+ private static String modules = null;
+
+ private static String java_exe = null;
+
public synchronized static String getClassPath()
{
if (scanner == null)
scanner = new ClassGraph();
ScanResult scan = scanner.scan();
classpath = scan.getClasspath();
+ modules = "";
+ for (ModuleRef mr : scan.getModules())
+ {
+ modules.concat(mr.getName());
+ }
+ java_exe = System.getProperty("java.home") + File.separator + "bin"
+ + File.separator + "java";
+
}
while (classpath == null)
{
// Note: JAL-3065 - don't include quotes for lib/* because the arguments are
// not expanded by the shell
String classpath = getClassPath();
- String _cmd = "java "
+ String _cmd = java_exe + " "
+ (withAwt ? "-Djava.awt.headless=true" : "")
- + " -classpath " + classpath + " jalview.bin.Jalview ";
+ + " -classpath " + classpath
+ + (modules.length() > 2 ? "--add-modules=\"" + modules + "\""
+ : "")
+ + " jalview.bin.Jalview ";
Process ls2_proc = null;
Worker worker = null;
try
return worker;
}
+ @Test(groups = { "Functional" })
+ public void reportCurrentWorkingDirectory()
+ {
+ try
+ {
+ Path currentRelativePath = Paths.get("");
+ String s = currentRelativePath.toAbsolutePath().toString();
+ System.out.println("Test CWD is " + s);
+ } catch (Exception q)
+ {
+ q.printStackTrace();
+ }
+ }
+
@BeforeTest(alwaysRun = true)
public void initialize()
{
}
@Test(
- groups = { "Functional" },
+ groups =
+ { "Functional", "testben" },
dataProvider = "headlessModeOutputOperationsData")
public void testHeadlessModeOutputOperations(String harg, String type,
String fileName, boolean withAWT, int expectedMinFileSize,
worker.interrupt();
Thread.currentThread().interrupt();
worker.process.destroy();
- Assert.fail("Jalview did not exit after "
- + type
+ Assert.fail("Jalview did not exit after " + type
+ " generation (try running test again to verify - timeout at "
- + SETUP_TIMEOUT + "ms). ["
- + harg + "]");
+ + timeout + "ms). [" + harg + "]");
}
file.delete();
}
@DataProvider(name = "headlessModeOutputOperationsData")
public static Object[][] getHeadlessModeOutputParams()
{
- return new Object[][] {
- { "nodisplay -open examples/uniref50.fa", " -eps",
- "test/jalview/bin/test_uniref50_out.eps", true, MINFILESIZE_BIG,
- TEST_TIMEOUT },
+ // JBPNote: I'm not clear why need to specify full path for output file
+ // when running tests on build server, but we will keep this patch for now
+ // since it works.
+ // https://issues.jalview.org/browse/JAL-1889?focusedCommentId=21609&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-21609
+ String workingDir = "test/jalview/bin/";
+ return new Object[][] { { "nodisplay -open examples/uniref50.fa",
+ " -eps", workingDir + "test_uniref50_out.eps", true,
+ MINFILESIZE_BIG, TEST_TIMEOUT },
{ "nodisplay -open examples/uniref50.fa", " -eps",
- "test/jalview/bin/test_uniref50_out.eps", false,
+ workingDir + "test_uniref50_out.eps", false,
MINFILESIZE_BIG, TEST_TIMEOUT },
{ "nogui -open examples/uniref50.fa", " -eps",
- "test/jalview/bin/test_uniref50_out.eps", true, MINFILESIZE_BIG,
+ workingDir + "test_uniref50_out.eps", true, MINFILESIZE_BIG,
TEST_TIMEOUT },
{ "nogui -open examples/uniref50.fa", " -eps",
- "test/jalview/bin/test_uniref50_out.eps", false,
+ workingDir + "test_uniref50_out.eps", false,
MINFILESIZE_BIG, TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -eps",
- "test/jalview/bin/test_uniref50_out.eps", true, MINFILESIZE_BIG,
+ workingDir + "test_uniref50_out.eps", true, MINFILESIZE_BIG,
TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -svg",
- "test/jalview/bin/test_uniref50_out.svg", false,
+ workingDir + "test_uniref50_out.svg", false,
MINFILESIZE_BIG, TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -png",
- "test/jalview/bin/test_uniref50_out.png", true, MINFILESIZE_BIG,
+ workingDir + "test_uniref50_out.png", true, MINFILESIZE_BIG,
TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -html",
- "test/jalview/bin/test_uniref50_out.html", true,
+ workingDir + "test_uniref50_out.html", true,
MINFILESIZE_BIG, TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -fasta",
- "test/jalview/bin/test_uniref50_out.mfa", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.mfa", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -clustal",
- "test/jalview/bin/test_uniref50_out.aln", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.aln", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -msf",
- "test/jalview/bin/test_uniref50_out.msf", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.msf", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -pileup",
- "test/jalview/bin/test_uniref50_out.aln", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.aln", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -pir",
- "test/jalview/bin/test_uniref50_out.pir", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.pir", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -pfam",
- "test/jalview/bin/test_uniref50_out.pfam", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.pfam", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -blc",
- "test/jalview/bin/test_uniref50_out.blc", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT },
+ workingDir + "test_uniref50_out.blc", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT },
{ "headless -open examples/uniref50.fa", " -jalview",
- "test/jalview/bin/test_uniref50_out.jvp", true,
- MINFILESIZE_SMALL, TEST_TIMEOUT }, };
+ workingDir + "test_uniref50_out.jvp", true, MINFILESIZE_SMALL,
+ TEST_TIMEOUT }, };
}
}
cs.removeElement(1);
List<Integer> sel = cs.getSelected();
assertEquals(2, sel.size());
- assertEquals(new Integer(2), sel.get(0));
- assertEquals(new Integer(5), sel.get(1));
+ assertEquals(Integer.valueOf(2), sel.get(0));
+ assertEquals(Integer.valueOf(5), sel.get(1));
// removing an element in the list removes it
cs.removeElement(2);
assertEquals(1, sel.size());
sel = cs.getSelected();
assertEquals(1, sel.size());
- assertEquals(new Integer(5), sel.get(0));
+ assertEquals(Integer.valueOf(5), sel.get(0));
}
/**
12.5f, "group");
sf1.setValue("STRAND", "+");
sf1.setValue("Note", "Testing");
- Integer count = new Integer(7);
+ Integer count = Integer.valueOf(7);
sf1.setValue("Count", count);
SequenceFeature sf2 = new SequenceFeature(sf1);
assertEquals("+", sf1.getValue("STRAND"));
assertNull(sf1.getValue("strand")); // case-sensitive
assertEquals(".", sf1.getValue("unknown", "."));
- Integer i = new Integer(27);
+ Integer i = Integer.valueOf(27);
assertSame(i, sf1.getValue("Unknown", i));
}
import jalview.io.FileLoader;
import jalview.util.MessageManager;
-import java.awt.Event;
-import java.awt.EventQueue;
+import java.awt.event.InputEvent;import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException;
/*
* mouse at top left of unwrapped panel
*/
- MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
+ MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
0, 0, 0, false, 0);
MousePos pos = testee.findMousePosition(evt);
assertEquals(pos.column, 0);
* mouse at top left of wrapped panel; there is a gap of charHeight
* above the alignment
*/
- MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
+ MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
0, 0, 0, false, 0);
MousePos pos = testee.findMousePosition(evt);
assertEquals(pos.column, 0);
* cursor at bottom of gap above
*/
y = charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor over top of first sequence
*/
y = charHeight;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* cursor at bottom of first sequence
*/
y = 2 * charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* cursor at top of second sequence
*/
y = 2 * charHeight;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 1);
* cursor at bottom of second sequence
*/
y = 3 * charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 1);
* cursor at bottom of last sequence
*/
y = charHeight * (1 + alignmentHeight) - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* method reports index of nearest sequence above
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor still in the gap above annotations, now at the bottom of it
*/
y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor at the top of the n'th annotation
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor at the bottom of the n'th annotation
*/
y += annotationRows[n].height - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor in gap between wrapped widths
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at bottom of gap between wrapped widths
*/
y += charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at top of first sequence, second wrapped width
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* mouse at top left of wrapped panel; there is a gap of charHeight
* above the alignment
*/
- MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
+ MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
0, 0, 0, false, 0);
MousePos pos = testee.findMousePosition(evt);
assertEquals(pos.column, 0);
* two charHeights including scale panel
*/
y = 2 * charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor over top of first sequence
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* cursor at bottom of first sequence
*/
y += charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* cursor at top of second sequence
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 1);
* cursor at bottom of second sequence
*/
y += charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 1);
* (scale + gap + sequences)
*/
y = charHeight * (2 + alignmentHeight) - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor below sequences, in 3-pixel gap above annotations
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* method reports index of nearest sequence above
*/
y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor at the top of the n'th annotation
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor at the bottom of the n'th annotation
*/
y += annotationRows[n].height - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor in gap between wrapped widths
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at bottom of gap between wrapped widths
*/
y += charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at top of scale, second wrapped width
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at bottom of scale, second wrapped width
*/
y += charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at top of first sequence, second wrapped width
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* mouse at top left of wrapped panel; there is a gap of charHeight
* above the alignment
*/
- MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
+ MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
0, 0, 0, false, 0);
MousePos pos = testee.findMousePosition(evt);
assertEquals(pos.column, 0);
* cursor over top of first sequence
*/
y = charHeight;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
* cursor at bottom of last sequence
*/
y = charHeight * (1 + alignmentHeight) - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, alignmentHeight - 1);
* cursor below sequences, at top of charHeight gap between widths
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor below sequences, at top of charHeight gap between widths
*/
y += charHeight - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, -1);
* cursor at the top of the first sequence, second width
*/
y += 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
false, 0);
pos = testee.findMousePosition(evt);
assertEquals(pos.seqIndex, 0);
/*
* mouse at top left of unwrapped panel
*/
- MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
+ MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
0, 0, 0, false, 0);
assertEquals(testee.findColumn(evt), 0);
* not quite one charWidth across
*/
x = charWidth-1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
0, 0, 0, false, 0);
assertEquals(testee.findColumn(evt), 0);
* one charWidth across
*/
x = charWidth;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), 1);
* two charWidths across
*/
x = 2 * charWidth;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), 2);
* limited to last column of seqcanvas
*/
x = 20000;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
SeqCanvas seqCanvas = alignFrame.alignPanel.getSeqPanel().seqCanvas;
int w = seqCanvas.getWidth();
alignFrame.getViewport().hideColumns(4, 9);
x = 5 * charWidth + 2;
// x is in 6th visible column, absolute column 12, or 11 base 0
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), 11);
}
/*
* mouse at top left of wrapped panel, no West (left) scale
*/
- MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
+ MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
0, 0, 0, false, 0);
assertEquals(testee.findColumn(evt), 0);
* not quite one charWidth across
*/
x = charWidth-1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
0, 0, 0, false, 0);
assertEquals(testee.findColumn(evt), 0);
* one charWidth across
*/
x = charWidth;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), 1);
int labelWidth = (int) PA.getValue(seqCanvas, "labelWidthWest");
assertTrue(labelWidth > 0);
x = labelWidth - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), -1);
x = labelWidth;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), 0);
int residuesWide = av.getRanges().getViewportWidth();
assertTrue(residuesWide > 0);
x = labelWidth + charWidth * residuesWide - 1;
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), residuesWide - 1);
assertTrue(residuesWide2 > 0);
assertTrue(residuesWide2 < residuesWide); // available width reduced
x += 1; // just over left edge of scale right
- evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
+ evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
false, 0);
assertEquals(testee.findColumn(evt), -1);
@DataProvider(name = "identifyFiles")
public Object[][] IdentifyFileDP()
{
- return new Object[][] {
- { "examples/example.json", FileFormat.Json },
+ return new Object[][] { { "examples/example.json", FileFormat.Json },
{ "examples/plantfdx.fa", FileFormat.Fasta },
{ "examples/dna_interleaved.phy", FileFormat.Phylip },
{ "examples/2GIS.pdb", FileFormat.PDB },
{ "examples/testdata/simpleGff3.gff", FileFormat.Features },
{ "examples/testdata/test.jvp", FileFormat.Jalview },
{ "examples/testdata/test.cif", FileFormat.MMCif },
- {
- "examples/testdata/cullpdb_pc25_res3.0_R0.3_d150729_chains9361.fasta.15316",
+ { "examples/testdata/cullpdb_pc25_res3.0_R0.3_d150729_chains9361.fasta.15316",
FileFormat.Fasta },
{ "resources/scoreModel/pam250.scm", FileFormat.ScoreMatrix },
{ "resources/scoreModel/blosum80.scm", FileFormat.ScoreMatrix }
- // { "examples/testdata/test.amsa", "AMSA" },
- // { "examples/test.jnet", "JnetFile" },
+ // { "examples/testdata/test.amsa", "AMSA" },
+ // { "examples/test.jnet", "JnetFile" },
};
}
// too few columns:
assertFalse(id.looksLikeFeatureData("1 \t 2 \t 3 \t 4 \t 5"));
// GFF format:
- assertTrue(id
- .looksLikeFeatureData("Seq1\tlocal\tHelix\t2456\t2462\tss"));
+ assertTrue(
+ id.looksLikeFeatureData("Seq1\tlocal\tHelix\t2456\t2462\tss"));
// Jalview format:
assertTrue(id.looksLikeFeatureData("Helix\tSeq1\t-1\t2456\t2462\tss"));
// non-numeric start column:
assertEquals("Threshold line not identical.",
aa_original[i].threshold, aa_new[i].threshold);
// graphGroup may differ, but pattern should be the same
- Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2);
- Integer n_ggrp = new Integer(aa_new[i].graphGroup + 2);
+ Integer o_ggrp = Integer.valueOf(aa_original[i].graphGroup + 2);
+ Integer n_ggrp = Integer.valueOf(aa_new[i].graphGroup + 2);
BitSet orig_g = orig_groups.get(o_ggrp);
BitSet new_g = new_groups.get(n_ggrp);
if (orig_g == null)
import jalview.gui.JvOptionPane;
import java.awt.Button;
-import java.awt.Event;
import java.awt.Toolkit;
+import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import org.testng.annotations.BeforeClass;
assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
0, 0, clickCount, isPopupTrigger, buttonNo), mac));
- mods = Event.CTRL_MASK;
+ mods = InputEvent.CTRL_DOWN_MASK | InputEvent.BUTTON1_DOWN_MASK;
assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
0, 0, clickCount, isPopupTrigger, buttonNo), mac));
- mods = Event.META_MASK;
+ mods = InputEvent.META_DOWN_MASK | InputEvent.BUTTON1_DOWN_MASK;
assertTrue(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
0, 0, clickCount, isPopupTrigger, buttonNo), mac));
assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
0, 0, clickCount, isPopupTrigger, buttonNo), mac));
- mods = Event.CTRL_MASK;
+ mods = InputEvent.CTRL_DOWN_MASK;
assertTrue(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
0, 0, clickCount, isPopupTrigger, buttonNo), mac));
- mods = Event.CTRL_MASK | Event.SHIFT_MASK | Event.ALT_MASK;
+ mods = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK
+ | InputEvent.ALT_DOWN_MASK;
clickCount = 2;
buttonNo = 2;
isPopupTrigger = true;
--- /dev/null
+#!/usr/bin/env bash
+
+CMD=$(basename $0)
+
+usage() {
+ echo "Usage: $CMD [-v N] /path/to/jarfile" >&2
+ echo " -v N build jar with alternative classes for version N of java (optional, defaults to base jar packages which is usually 8)" >&2
+}
+
+usagexit() {
+ usage
+ exit 1
+}
+
+error() {
+ echo $1 >&2
+ usagexit
+}
+
+VERSION=""
+while getopts v: opt
+do
+ case "${opt}"
+ in
+ v) VERSION=${OPTARG};;
+ esac
+done
+shift $((OPTIND-1))
+
+JARFILE=$1
+[ -z $JARFILE ] && usagexit
+[ -f $JARFILE ] || error "No file $JARFILE"
+[ -r $JARFILE ] || error "$JARFILE not readable"
+
+EXT=.jar
+SUFFIX=-SINGLE_RELEASE
+FILENAME=$(basename $JARFILE)
+BASE=$(basename -s $EXT $JARFILE)
+DIR=$(dirname $JARFILE)
+
+# set absolute path to $JARFILE if not specified
+[ x${DIR#/} = x$DIR ] && DIR=$(cd "$DIR" && pwd)
+
+TMPDIR=/tmp/$USER-$CMD-$BASE-$$
+
+[ x$FILENAME = x$BASE ] && error "Should be $EXT file"
+
+mkdir -p $TMPDIR || error "Could not create tmp dir $TMPDIR"
+cd $TMPDIR
+jar -xvf $JARFILE > /dev/null
+VDIR=$TMPDIR/META-INF/versions
+
+[ -d $VDIR ] || error "$JARFILE doesn't look like a multi-release jar file"
+
+if [ -z $VERSION ]; then
+ # no version set... nothing to copy
+ echo ""
+elif [ -d $VDIR/$VERSION ]; then
+ # this version has alternative classes for the version asked for, copy them into the base jar
+ tar -cf - -C $VDIR/$VERSION . | tar -xf - -C $TMPDIR
+else
+ echo "No specific classes for version $VERSION" >&2
+ echo "Available alternative versions are" >&2
+ cd $VDIR
+ ls >&2
+fi
+
+# remove the alternative versions
+/bin/rm -r $VDIR
+
+# alter the manifest. note sed on macos is a bit weird
+if [ `uname -s` = "Darwin" ]; then
+ sed -E -i '' 's/^([Mm]ulti-[Rr]elease):).*/\1 false/' $TMPDIR/META-INF/MANIFEST.MF
+else
+ sed -E -i 's/^([Mm]ulti-[Rr]elease):).*/\1 false/' $TMPDIR/META-INF/MANIFEST.MF
+fi
+
+jar -cvf $DIR/${BASE}${SUFFIX}${EXT} -C $TMPDIR . > /dev/null
+rm -rf $TMPDIR
+
--- /dev/null
+#!/usr/bin/env bash
+
+TYPES="Boolean|Character|Double|Float|Long|Integer" find src test -type f -name "*.java" -exec perl -p -i -e 's/\bnew\s+(java\.lang\.)?($ENV{TYPES})\(/${1}${2}.valueOf(/;' {} +
+
+find src test -type f -name "*.java" -exec perl -p -i -e 's/(InputEvent|KeyEvent)\s*\.\s*([A-Z0-9]+)_MASK\b/${1}.${2}_DOWN_MASK/g;' {} +
+
+find src test -type f -name "*.java" -exec perl -p -i -e 's/\b(e|evt)\.getModifiers\b/${1}.getModifiersEx/g;' {} +
+
+find src test -type f -name "*.java" -exec perl -p -i -e 's/\.getMenuShortcutKeyMask\b/\.getMenuShortcutKeyMaskEx/g;' {} +
+
+#
+find src test -type f -name "*.java" -exec perl -p -i -e 'if ( s/^\s*import\s+java\.awt\.Event\s*;\s*$/import java.awt.event.InputEvent;/ ) { $event = 1 }; if ($event == 1) { s/\b(java\.awt\.)?Event\s*\.\s*([A-Z0-9]+)_MASK\b/InputEvent.${2}_DOWN_MASK/g; s/\b(java\.awt\.)?Event\s*\.\s*(MOUSE_MOVE)/MouseEvent.MOUSE_MOVED/g }' {} +
if (versions == null)
{
versions = new Hashtable();
- versions.put("45.3", "1.0");
+ versions.put("45.3", "1.0.2");
versions.put("45.3", "1.1");
versions.put("46.0", "1.2");
versions.put("47.0", "1.3");
versions.put("50.0", "1.6");
versions.put("51.0", "1.7");
versions.put("52.0", "1.8");
+ versions.put("53.0", "9");
+ versions.put("54.0", "10");
+ versions.put("55.0", "11");
}
String version = (String) versions.get(major + "." + minor);
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<install4j version="7.0.9" transformSequenceNumber="7">
+ <directoryPresets config="../../../../../buildtools/jre/openjdk-java_vm/macos-jdk8u202-b08-jre" />
+ <application name="Jalview" distributionSourceDir="" applicationId="6595-2347-1923-0725" mediaDir="../../build/install4j" mediaFilePattern="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:sys.version}" compression="6" lzmaCompression="true" pack200Compression="false" excludeSignedFromPacking="true" commonExternalFiles="false" createMd5Sums="true" shrinkRuntime="true" shortName="Jalview" publisher="University of Dundee" publisherWeb="http://www.jalview.org/" version="$$VERSION$$" allPathsRelative="true" backupOnSave="false" autoSave="false" convertDotsToUnderscores="true" macSignature="????" macVolumeId="5aac4968c304f65" javaMinVersion="9999999999" javaMaxVersion="" allowBetaVM="true" jdkMode="jdk" jdkName="JDK 11.0">
+ <languages skipLanguageSelection="false" languageSelectionInPrincipalLanguage="false">
+ <principalLanguage id="en" customLocalizationFile="" />
+ <additionalLanguages />
+ </languages>
+ <searchSequence>
+ <directory location="jre" />
+ </searchSequence>
+ <variables>
+ <variable name="OSX_KEYSTORE" value="" description="" category="" />
+ <variable name="JSIGN_SH" value="" description="" category="" />
+ </variables>
+ <mergedProjects />
+ <codeSigning macEnabled="true" macPkcs12File="${compiler:OSX_KEYSTORE}" windowsEnabled="false" windowsKeySource="pkcs12" windowsPvkFile="" windowsSpcFile="" windowsPkcs12File="" windowsPkcs11Library="" windowsPkcs11Slot="">
+ <windowsKeystoreIdentifier issuer="" serial="" subject="" />
+ <windowsPkcs11Identifier issuer="" serial="" subject="" />
+ </codeSigning>
+ </application>
+ <files keepModificationTimes="false" missingFilesStrategy="warn" globalExcludeSuffixes="" defaultOverwriteMode="4" defaultUninstallMode="2" launcherOverwriteMode="3" defaultFileMode="644" defaultDirMode="755">
+ <filesets>
+ <fileset name="Full file set" id="734" customizedId="" />
+ <fileset name="Mac OS X JRE" id="880" customizedId="" />
+ <fileset name="Windows JRE" id="882" customizedId="" />
+ </filesets>
+ <roots>
+ <root id="735" fileset="734" location="" />
+ <root id="881" fileset="880" location="" />
+ <root id="883" fileset="882" location="" />
+ </roots>
+ <mountPoints>
+ <mountPoint id="454" root="" location="" mode="755" />
+ <mountPoint id="736" root="735" location="" mode="755" />
+ <mountPoint id="884" root="881" location="" mode="755" />
+ <mountPoint id="885" root="883" location="" mode="755" />
+ </mountPoints>
+ <entries>
+ <dirEntry mountPoint="454" file="../../getdown/files/$$JAVA_VERSION$$" overwriteMode="4" shared="false" fileMode="644" uninstallMode="2" overrideFileMode="false" overrideOverwriteMode="true" overrideUninstallMode="true" entryMode="direct" subDirectory="files" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="736" file="../../getdown/website/$$JAVA_VERSION$$" overwriteMode="4" shared="false" fileMode="644" uninstallMode="2" overrideFileMode="false" overrideOverwriteMode="true" overrideUninstallMode="true" entryMode="direct" subDirectory="files" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="884" file="$$MACOS_JAVA_VM_DIR$$" overwriteMode="4" shared="false" fileMode="755" uninstallMode="0" overrideFileMode="true" overrideOverwriteMode="false" overrideUninstallMode="true" entryMode="subdir" subDirectory="jre" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="885" file="$$WINDOWS_JAVA_VM_DIR$$" overwriteMode="4" shared="false" fileMode="755" uninstallMode="0" overrideFileMode="true" overrideOverwriteMode="false" overrideUninstallMode="true" entryMode="subdir" subDirectory="jre" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ </entries>
+ <components>
+ <component name="jalview_getdown" id="1031" customizedId="" displayDescription="false" hideHelpButton="false" selected="true" changeable="true" downloadable="false" hidden="false">
+ <description />
+ <include all="false">
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ </include>
+ <dependencies />
+ </component>
+ <component name="macos_java_vm" id="1155" customizedId="" displayDescription="false" hideHelpButton="false" selected="true" changeable="true" downloadable="false" hidden="false">
+ <description />
+ <include all="false">
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ </include>
+ <dependencies />
+ </component>
+ <component name="windows_java_vm" id="1156" customizedId="" displayDescription="false" hideHelpButton="false" selected="true" changeable="true" downloadable="false" hidden="false">
+ <description />
+ <include all="false">
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </include>
+ <dependencies />
+ </component>
+ <component name="getdown" id="1276" customizedId="" displayDescription="false" hideHelpButton="false" selected="true" changeable="true" downloadable="false" hidden="false">
+ <description />
+ <include all="false">
+ <entry location=".i4j_fileset_" fileType="regular" />
+ </include>
+ <dependencies />
+ </component>
+ </components>
+ </files>
+ <launchers>
+ <launcher name="Offline Jalview Launcher" id="737" customizedId="" external="false" excludeFromMenu="false" unixMode="755" unixAutoStart="true" menuName="${compiler:sys.shortName}" icnsFile="../../resources/images/jalview_logos.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="734" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:sys.shortName}" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJavaMaxVersionOverride="false" javaMaxVersionOverride="" checkUpdater="false" updateExecutionMode="unattendedProgress" unattendedUpdateTitle="${i18n:updater.WindowTitle("${compiler:sys.fullName}")}">
+ <executable name="${compiler:sys.shortName}" type="1" iconSet="true" iconFile="../../resources/images/jalview_logos.ico" executableDir="." redirectStderr="true" stderrFile="error.log" stderrMode="overwrite" redirectStdout="true" stdoutFile="output.log" stdoutMode="overwrite" failOnStderrOutput="true" executableMode="1" changeWorkingDirectory="true" workingDirectory="." singleInstance="true" serviceStartType="2" serviceDependencies="" serviceDescription="" jreLocation="" executionLevel="asInvoker" checkConsoleParameter="true" globalSingleInstance="false" singleInstanceActivate="true" dpiAware="java9+">
+ <versionInfo include="true" fileVersion="" fileDescription="${compiler:sys.shortName}" legalCopyright="..." internalName="${compiler:sys.shortName}" productName="${compiler:sys.shortName}" />
+ </executable>
+ <splashScreen show="false" width="640" height="480" bitmapFile="../../resources/images/jalview_logo_background_fade-640x480.png" textOverlay="true">
+ <text>
+ <statusLine x="85" y="81" text="${compiler:sys.shortName}" fontSize="18" fontColor="0,0,0" bold="false" />
+ <versionLine x="85" y="109" text="version ${compiler:sys.version}" fontSize="8" fontColor="0,0,0" bold="false" />
+ </text>
+ </splashScreen>
+ <java mainClass="com.threerings.getdown.launcher.GetdownApp" mainMode="1" vmParameters="" arguments="." allowVMPassthroughParameters="true" preferredVM="" bundleRuntime="true">
+ <classPath>
+ <archive location="getdown-launcher.jar" failOnError="true" />
+ <archive location="dist/commons-compress-1.18.jar" failOnError="true" />
+ </classPath>
+ <modulePath />
+ <nativeLibraryDirectories />
+ <vmOptions />
+ </java>
+ <includedFiles />
+ <unextractableFiles />
+ <vmOptionsFile mode="template" overwriteMode="0" fileMode="644">
+ <content />
+ </vmOptionsFile>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <infoPlist mode="1" file="">
+ <content />
+ </infoPlist>
+ <iconImageFiles>
+ <file path="../../resources/images/Jalview_Logo.png" />
+ </iconImageFiles>
+ </launcher>
+ <launcher name="Network Jalview Launcher" id="1402" customizedId="" external="false" excludeFromMenu="false" unixMode="755" unixAutoStart="true" menuName="${compiler:sys.shortName}" icnsFile="../../resources/images/jalview_logos.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:sys.shortName}" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJavaMaxVersionOverride="false" javaMaxVersionOverride="" checkUpdater="false" updateExecutionMode="unattendedProgress" unattendedUpdateTitle="${i18n:updater.WindowTitle("${compiler:sys.fullName}")}">
+ <executable name="Jalview" type="1" iconSet="true" iconFile="../../resources/images/jalview_logos.ico" executableDir="." redirectStderr="true" stderrFile="error.log" stderrMode="overwrite" redirectStdout="true" stdoutFile="output.log" stdoutMode="overwrite" failOnStderrOutput="true" executableMode="1" changeWorkingDirectory="true" workingDirectory="." singleInstance="true" serviceStartType="2" serviceDependencies="" serviceDescription="" jreLocation="" executionLevel="asInvoker" checkConsoleParameter="true" globalSingleInstance="false" singleInstanceActivate="true" dpiAware="java9+">
+ <versionInfo include="true" fileVersion="" fileDescription="${compiler:sys.shortName}" legalCopyright="..." internalName="${compiler:sys.shortName}" productName="${compiler:sys.shortName}" />
+ </executable>
+ <splashScreen show="false" width="640" height="480" bitmapFile="../../resources/images/jalview_logo_background_fade-640x480.png" textOverlay="true">
+ <text>
+ <statusLine x="85" y="81" text="${compiler:sys.shortName}" fontSize="18" fontColor="0,0,0" bold="false" />
+ <versionLine x="85" y="109" text="version ${compiler:sys.version}" fontSize="8" fontColor="0,0,0" bold="false" />
+ </text>
+ </splashScreen>
+ <java mainClass="com.threerings.getdown.launcher.GetdownApp" mainMode="1" vmParameters="" arguments="." allowVMPassthroughParameters="true" preferredVM="" bundleRuntime="true">
+ <classPath>
+ <archive location="getdown-launcher.jar" failOnError="true" />
+ <archive location="dist/commons-compress-1.18.jar" failOnError="true" />
+ </classPath>
+ <modulePath />
+ <nativeLibraryDirectories />
+ <vmOptions />
+ </java>
+ <includedFiles />
+ <unextractableFiles />
+ <vmOptionsFile mode="template" overwriteMode="0" fileMode="644">
+ <content />
+ </vmOptionsFile>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <infoPlist mode="1" file="">
+ <content />
+ </infoPlist>
+ <iconImageFiles>
+ <file path="../../resources/images/Jalview_Logo.png" />
+ </iconImageFiles>
+ </launcher>
+ </launchers>
+ <installerGui installerType="1" addOnAppId="" suggestPreviousLocations="true" autoUpdateDescriptorUrl="" useAutoUpdateBaseUrl="false" autoUpdateBaseUrl="">
+ <staticMembers script="" />
+ <customCode />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <applications>
+ <application name="" id="installer" customizedId="" beanClass="com.install4j.runtime.beans.applications.InstallerApplication" enabled="true" commentSet="false" comment="" actionElevationType="none" styleId="35" fileset="" customIcnsFile="../../resources/images/jalview_logos.icns" customIcoFile="../../resources/images/jalview_logos.ico" macEntitlementsFile="" automaticLauncherIntegration="false" launchMode="startupFirstWindow" launchInNewProcess="true" launchSchedule="updateSchedule" allLaunchers="true">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.applications.InstallerApplication">
+ <void property="useCustomIcon">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <styleOverrides>
+ <styleOverride name="Customize banner image" enabled="true">
+ <group name="" id="146" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans />
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </styleOverride>
+ <styleOverride name="Jalview" enabled="true">
+ <formComponent name="Watermark" id="352" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="5" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Jalview" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SeparatorComponent">
+ <void property="enabledTitleText">
+ <boolean>false</boolean>
+ </void>
+ <void property="labelText">
+ <string>install4j</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>labelText</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ </styleOverride>
+ </styleOverrides>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <launcherIds />
+ <variables />
+ <startup>
+ <screen name="" id="1" customizedId="" beanClass="com.install4j.runtime.beans.screens.StartupScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.StartupScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="22" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.RequestPrivilegesAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.RequestPrivilegesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents />
+ </screen>
+ </startup>
+ <screens>
+ <screen name="" id="2" customizedId="" beanClass="com.install4j.runtime.beans.screens.WelcomeScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.WelcomeScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides>
+ <styleOverride name="Customize banner image" enabled="true">
+ <group name="" id="145" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>25</int>
+ <int>143</int>
+ <int>220</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans />
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </styleOverride>
+ </styleOverrides>
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="7" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" enabled="true" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="true" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction">
+ <void property="excludedVariables">
+ <array class="java.lang.String" length="1">
+ <void index="0">
+ <string>sys.installationDir</string>
+ </void>
+ </array>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>context.getBooleanVariable("sys.confirmedUpdateInstallation")</condition>
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="3" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:welcomeMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>!context.isConsole()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="4" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
+ <void property="consoleScript">
+ <object class="com.install4j.api.beans.ScriptProperty">
+ <void property="value">
+ <string>String message = context.getMessage("ConsoleWelcomeLabel", context.getApplicationName());
+return console.askOkCancel(message, true);
+</string>
+ </void>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="5" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.UpdateAlertComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Update Alert" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.UpdateAlertComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>updateCheck</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ <formComponent name="" id="6" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="20" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${i18n:ClickNext}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="8" customizedId="" beanClass="com.install4j.runtime.beans.screens.InstallationDirectoryScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.InstallationDirectoryScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition>!context.getBooleanVariable("sys.confirmedUpdateInstallation")</condition>
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="11" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" enabled="true" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="true" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction">
+ <void property="excludedVariables">
+ <array class="java.lang.String" length="1">
+ <void index="0">
+ <string>sys.installationDir</string>
+ </void>
+ </array>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>context.getVariable("sys.responseFile") == null</condition>
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="9" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="25" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${i18n:SelectDirLabel(${compiler:sys.fullName})}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="10" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.InstallationDirectoryChooserComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Installation Directory Chooser" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.InstallationDirectoryChooserComponent">
+ <void property="requestFocus">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>suggestAppDir</propertyName>
+ <propertyName>validateApplicationId</propertyName>
+ <propertyName>existingDirWarning</propertyName>
+ <propertyName>checkWritable</propertyName>
+ <propertyName>manualEntryAllowed</propertyName>
+ <propertyName>checkFreeSpace</propertyName>
+ <propertyName>showRequiredDiskSpace</propertyName>
+ <propertyName>showFreeDiskSpace</propertyName>
+ <propertyName>allowSpacesOnUnix</propertyName>
+ <propertyName>validationScript</propertyName>
+ <propertyName>standardValidation</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="12" customizedId="" beanClass="com.install4j.runtime.beans.screens.ComponentsScreen" enabled="false" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.ComponentsScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents>
+ <formComponent name="" id="13" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${i18n:SelectComponentsLabel2}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>!context.isConsole()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="14" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ComponentSelectorComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Installation Components" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ComponentSelectorComponent">
+ <void property="fillVertical">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>selectionChangedScript</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="15" customizedId="" beanClass="com.install4j.runtime.beans.screens.InstallationScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="true" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.InstallationScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="17" customizedId="" beanClass="com.install4j.runtime.beans.actions.InstallFilesAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="2" errorMessage="${i18n:FileCorrupted}">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.InstallFilesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="18" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.CreateProgramGroupAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.CreateProgramGroupAction">
+ <void property="uninstallerMenuName">
+ <string>${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>!context.getBooleanVariable("sys.programGroupDisabled")</condition>
+ </action>
+ <action name="" id="19" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.RegisterAddRemoveAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.RegisterAddRemoveAction">
+ <void property="itemName">
+ <string>${compiler:sys.fullName} ${compiler:sys.version}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="124" customizedId="" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction" enabled="false" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.control.SetVariableAction">
+ <void property="script">
+ <object class="com.install4j.api.beans.ScriptProperty">
+ <void property="value">
+ <string />
+ </void>
+ </object>
+ </void>
+ <void property="variableName">
+ <string />
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>true</condition>
+ </action>
+ <action name="" id="134" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.AddVmOptionsAction" enabled="false" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.AddVmOptionsAction">
+ <void property="launcherId">
+ <string>121</string>
+ </void>
+ <void property="vmOptions">
+ <array class="java.lang.String" length="0" />
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="16" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ProgressComponent">
+ <void property="initialStatusMessage">
+ <string>${i18n:WizardPreparing}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="20" customizedId="" beanClass="com.install4j.runtime.beans.screens.FinishedScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="true" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.FinishedScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="573" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.CreateDesktopLinkAction" enabled="false" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.CreateDesktopLinkAction">
+ <void property="name">
+ <string>${compiler:sys.fullName}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>context.getBooleanVariable("createDesktopLinkAction")</condition>
+ </action>
+ <action name="" id="575" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.AddStartupItemAction" enabled="false" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.AddStartupItemAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="576" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.AddToDockAction" enabled="false" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.AddToDockAction" />
+ </java>
+ </serializedBean>
+ <condition>context.getBooleanVariable("addToDockAction")</condition>
+ </action>
+ <action name="" id="578" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction">
+ <void property="description">
+ <string>Jalview Project File</string>
+ </void>
+ <void property="extension">
+ <string>jvp</string>
+ </void>
+ <void property="launcherId">
+ <string>121</string>
+ </void>
+ <void property="macIconFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/file.png</string>
+ </object>
+ </void>
+ <void property="macRole">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.actions.desktop.MacAssociationRole</class>
+ <string>EDITOR</string>
+ </object>
+ </void>
+ <void property="windowsIconFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/file.png</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="21" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="10" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:finishedMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Add a desktop link" id="574" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.CheckboxComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.CheckboxComponent">
+ <void property="checkboxText">
+ <string>${i18n:CreateDesktopIcon}</string>
+ </void>
+ <void property="initiallySelected">
+ <boolean>true</boolean>
+ </void>
+ <void property="variableName">
+ <string>createDesktopLinkAction</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Add an executable to the dock" id="577" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.CheckboxComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.CheckboxComponent">
+ <void property="checkboxText">
+ <string>${i18n:AddToDock}</string>
+ </void>
+ <void property="initiallySelected">
+ <boolean>true</boolean>
+ </void>
+ <void property="variableName">
+ <string>addToDockAction</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>Util.isMacOS()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ </screens>
+ </application>
+ <application name="" id="uninstaller" customizedId="" beanClass="com.install4j.runtime.beans.applications.UninstallerApplication" enabled="true" commentSet="false" comment="" actionElevationType="none" styleId="41" fileset="" customIcnsFile="" customIcoFile="" macEntitlementsFile="" automaticLauncherIntegration="false" launchMode="startupFirstWindow" launchInNewProcess="true" launchSchedule="updateSchedule" allLaunchers="true">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.applications.UninstallerApplication">
+ <void property="customMacosExecutableName">
+ <string>${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</string>
+ </void>
+ <void property="useCustomMacosExecutableName">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <styleOverrides>
+ <styleOverride name="Customize banner image" enabled="true">
+ <group name="" id="147" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>192</int>
+ <int>192</int>
+ <int>192</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans />
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </styleOverride>
+ </styleOverrides>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <launcherIds />
+ <variables />
+ <startup>
+ <screen name="" id="23" customizedId="" beanClass="com.install4j.runtime.beans.screens.StartupScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.StartupScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="33" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" enabled="true" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="34" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.RequireInstallerPrivilegesAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.RequireInstallerPrivilegesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents />
+ </screen>
+ </startup>
+ <screens>
+ <screen name="" id="24" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallWelcomeScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="41" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallWelcomeScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents>
+ <formComponent name="" id="25" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="10" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:welcomeMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>!context.isConsole()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="26" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
+ <void property="consoleScript">
+ <object class="com.install4j.api.beans.ScriptProperty">
+ <void property="value">
+ <string>String message = context.getMessage("ConfirmUninstall", context.getApplicationName());
+return console.askYesNo(message, true);
+</string>
+ </void>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="27" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallationScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallationScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="659" customizedId="" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.control.SetProgressAction">
+ <void property="progressChangeType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.actions.control.ProgressChangeType</class>
+ <string>SET_INDETERMINATE</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="29" customizedId="" beanClass="com.install4j.runtime.beans.actions.UninstallFilesAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.UninstallFilesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="1525" customizedId="" beanClass="com.install4j.runtime.beans.actions.files.DeleteFileAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.files.DeleteFileAction">
+ <void property="files">
+ <array class="java.io.File" length="10">
+ <void index="0">
+ <object class="java.io.File">
+ <string>jre</string>
+ </object>
+ </void>
+ <void index="1">
+ <object class="java.io.File">
+ <string>.install4j</string>
+ </object>
+ </void>
+ <void index="2">
+ <object class="java.io.File">
+ <string>dist</string>
+ </object>
+ </void>
+ <void index="3">
+ <object class="java.io.File">
+ <string>resource</string>
+ </object>
+ </void>
+ <void index="4">
+ <object class="java.io.File">
+ <string>getdown-launcher.jar</string>
+ </object>
+ </void>
+ <void index="5">
+ <object class="java.io.File">
+ <string>getdown-launcher-old.jar</string>
+ </object>
+ </void>
+ <void index="6">
+ <object class="java.io.File">
+ <string>getdown-launcher-new.jar</string>
+ </object>
+ </void>
+ <void index="7">
+ <object class="java.io.File">
+ <string>digest.txt</string>
+ </object>
+ </void>
+ <void index="8">
+ <object class="java.io.File">
+ <string>digest2.txt</string>
+ </object>
+ </void>
+ <void index="9">
+ <object class="java.io.File">
+ <string>getdown.txt</string>
+ </object>
+ </void>
+ </array>
+ </void>
+ <void property="recursive">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="660" customizedId="" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.control.SetProgressAction">
+ <void property="percentValue">
+ <int>100</int>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="28" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ProgressComponent">
+ <void property="initialStatusMessage">
+ <string>${i18n:UninstallerPreparing}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="32" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallFailureScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="true" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallFailureScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents />
+ </screen>
+ <screen name="" id="30" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallSuccessScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="41" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="true" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallSuccessScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents>
+ <formComponent name="" id="31" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="10" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:successMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ </screens>
+ </application>
+ </applications>
+ <styles defaultStyleId="35">
+ <style name="Standard" id="35" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle" />
+ </java>
+ </serializedBean>
+ <formComponents>
+ <formComponent name="Header" id="36" customizedId="" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.NestedStyleComponent">
+ <void property="styleId">
+ <string>48</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <group name="Main" id="37" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="imageEdgeAxisType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.AxisType</class>
+ <string>HORIZONTAL</string>
+ </object>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="imageOverlap">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="" id="38" customizedId="" beanClass="com.install4j.runtime.beans.styles.ContentComponent" enabled="true" commentSet="false" comment="" insetTop="10" insetLeft="20" insetBottom="10" insetRight="20" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ContentComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Watermark" id="39" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="5" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Jalview" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SeparatorComponent">
+ <void property="enabledTitleText">
+ <boolean>false</boolean>
+ </void>
+ <void property="labelText">
+ <string>install4j</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>labelText</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ <formComponent name="Footer" id="40" customizedId="" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.NestedStyleComponent">
+ <void property="styleId">
+ <string>52</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames />
+ </group>
+ </formComponents>
+ </style>
+ <style name="Banner" id="41" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle" />
+ </java>
+ </serializedBean>
+ <formComponents>
+ <group name="" id="42" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>25</int>
+ <int>143</int>
+ <int>220</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>${compiler:sys.install4jHome}/resource/styles/wizard.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="" id="43" customizedId="" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ScreenTitleComponent">
+ <void property="labelFontSizePercent">
+ <int>130</int>
+ </void>
+ <void property="labelFontStyle">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontStyle</class>
+ <string>BOLD</string>
+ </object>
+ </void>
+ <void property="labelFontType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontType</class>
+ <string>DERIVED</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="44" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SeparatorComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="45" customizedId="" beanClass="com.install4j.runtime.beans.styles.ContentComponent" enabled="true" commentSet="false" comment="" insetTop="10" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ContentComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ <formComponent name="" id="46" customizedId="" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.NestedStyleComponent">
+ <void property="styleId">
+ <string>52</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </style>
+ <group name="Style components" id="47" customizedId="" beanClass="com.install4j.runtime.beans.groups.StyleGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.StyleGroup" />
+ </java>
+ </serializedBean>
+ <beans>
+ <style name="Standard header" id="48" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle">
+ <void property="fillVertical">
+ <boolean>false</boolean>
+ </void>
+ <void property="standalone">
+ <boolean>false</boolean>
+ </void>
+ <void property="verticalAnchor">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.beans.Anchor</class>
+ <string>NORTH</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <formComponents>
+ <group name="" id="49" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize title bar" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageAnchor">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.beans.Anchor</class>
+ <string>NORTHEAST</string>
+ </object>
+ </void>
+ <void property="imageEdgeBorderWidth">
+ <int>2</int>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>icon:${installer:sys.installerApplicationMode}_header.png</string>
+ </object>
+ </void>
+ <void property="imageInsets">
+ <object class="java.awt.Insets">
+ <int>0</int>
+ <int>5</int>
+ <int>1</int>
+ <int>1</int>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>0</int>
+ <int>20</int>
+ <int>0</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="Title" id="50" customizedId="" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ScreenTitleComponent">
+ <void property="labelFontStyle">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontStyle</class>
+ <string>BOLD</string>
+ </object>
+ </void>
+ <void property="labelFontType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontType</class>
+ <string>DERIVED</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Subtitle" id="51" customizedId="" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="8" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ScreenTitleComponent">
+ <void property="titleType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.styles.TitleType</class>
+ <string>SUB_TITLE</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames>
+ <propertyName>backgroundColor</propertyName>
+ <propertyName>foregroundColor</propertyName>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageFile</propertyName>
+ <propertyName>imageOverlap</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </formComponents>
+ </style>
+ <style name="Standard footer" id="52" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle">
+ <void property="fillVertical">
+ <boolean>false</boolean>
+ </void>
+ <void property="standalone">
+ <boolean>false</boolean>
+ </void>
+ <void property="verticalAnchor">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.beans.Anchor</class>
+ <string>SOUTH</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <formComponents>
+ <group name="" id="53" customizedId="" beanClass="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup">
+ <void property="alignFirstLabel">
+ <boolean>false</boolean>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>3</int>
+ <int>5</int>
+ <int>8</int>
+ <int>5</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="" id="54" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SpringComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SpringComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Back button" id="55" customizedId="" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
+ <void property="buttonText">
+ <string>< ${i18n:ButtonBack}</string>
+ </void>
+ <void property="controlButtonType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.context.ControlButtonType</class>
+ <string>PREVIOUS</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Next button" id="56" customizedId="" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
+ <void property="buttonText">
+ <string>${i18n:ButtonNext} ></string>
+ </void>
+ <void property="controlButtonType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.context.ControlButtonType</class>
+ <string>NEXT</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Cancel button" id="57" customizedId="" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="5" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
+ <void property="buttonText">
+ <string>${i18n:ButtonCancel}</string>
+ </void>
+ <void property="controlButtonType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.context.ControlButtonType</class>
+ <string>CANCEL</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames />
+ </group>
+ </formComponents>
+ </style>
+ </beans>
+ </group>
+ </styles>
+ </installerGui>
+ <mediaSets>
+ <linuxDeb name="Linux Deb Archive" id="153" customizedId="" mediaFileName="" installDir="/opt/${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" overwriteNeverAsConfigFiles="false" dependencies="" bzip="true" description="Jalview Desktop" maintainerEmail="help@jalview.org" architectureSet="false" architecture="">
+ <excludedComponents>
+ <component id="1155" />
+ <component id="1156" />
+ <component id="1276" />
+ </excludedComponents>
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="1402" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <preInstallScript mode="1" file="">
+ <content />
+ </preInstallScript>
+ <postInstallScript mode="1" file="">
+ <content />
+ </postInstallScript>
+ <preUninstallScript mode="1" file="">
+ <content />
+ </preUninstallScript>
+ <postUninstallScript mode="1" file="">
+ <content />
+ </postUninstallScript>
+ </linuxDeb>
+ <linuxRPM name="Linux RPM" id="570" customizedId="" mediaFileName="" installDir="/opt/${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" overwriteNeverAsConfigFiles="false" dependencies="" os="linux" arch="i386">
+ <excludedComponents>
+ <component id="1155" />
+ <component id="1156" />
+ <component id="1276" />
+ </excludedComponents>
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="1402" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <preInstallScript mode="1" file="">
+ <content />
+ </preInstallScript>
+ <postInstallScript mode="1" file="">
+ <content />
+ </postInstallScript>
+ <preUninstallScript mode="1" file="">
+ <content />
+ </preUninstallScript>
+ <postUninstallScript mode="1" file="">
+ <content />
+ </postUninstallScript>
+ </linuxRPM>
+ <windows name="Offline Windows" id="743" customizedId="" mediaFileName="${compiler:sys.shortName}-OFFLINE_${compiler:sys.platform}_${compiler:sys.version}-j$$JAVA_INTEGER_VERSION$$" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="64" runPostProcessor="true" postProcessor="${compiler:JSIGN_SH} $EXECUTABLE" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="$$WINDOWS_JAVA_VM_TGZ$$" manualJREEntry="true" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" customInstallBaseDir="" contentFilesType="1" verifyIntegrity="true">
+ <excludedComponents>
+ <component id="1155" />
+ <component id="1156" />
+ <component id="1276" />
+ </excludedComponents>
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="1402" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ </windows>
+ <macosArchive name="Offline macOS Single Bundle Archive" id="878" customizedId="" mediaFileName="${compiler:sys.shortName}-OFFLINE_${compiler:sys.platform}-app_${compiler:sys.version}-j$$JAVA_INTEGER_VERSION$$" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" archiveType="dmg" volumeName="${compiler:sys.shortName} Installer" launcherId="737">
+ <excludedComponents>
+ <component id="1156" />
+ <component id="1276" />
+ </excludedComponents>
+ <includedDownloadableComponents />
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <topLevelFiles>
+ <symlink name="" "" target="/Applications" />
+ <file name=".background/jalview_dmg_background.png" file="./jalview_dmg_background.png" />
+ <file name=".DS_Store" file="./DS_Store" />
+ <symlink name="Jalview.app/Contents/Resources/app/jre/Contents/MacOS/libjli.dylib" target="../Home/lib/jli/libjli.dylib" />
+ </topLevelFiles>
+ </macosArchive>
+ <windows name="Network Windows" id="1272" customizedId="" mediaFileName="${compiler:sys.shortName}-NETWORK_${compiler:sys.platform}_${compiler:sys.version}-j$$JAVA_INTEGER_VERSION$$" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="64" runPostProcessor="true" postProcessor="${compiler:JSIGN_SH} $EXECUTABLE" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="$$WINDOWS_JAVA_VM_TGZ$$" manualJREEntry="true" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" customInstallBaseDir="" contentFilesType="1" verifyIntegrity="true">
+ <excludedComponents>
+ <component id="1031" />
+ <component id="1155" />
+ <component id="1156" />
+ </excludedComponents>
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="737" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ </windows>
+ <macosArchive name="Network macOS Single Bundle Archive" id="1274" customizedId="" mediaFileName="${compiler:sys.shortName}-NETWORK_${compiler:sys.platform}-app_${compiler:sys.version}-j$$JAVA_INTEGER_VERSION$$" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" archiveType="dmg" volumeName="${compiler:sys.shortName} Installer" launcherId="1402">
+ <excludedComponents>
+ <component id="1031" />
+ <component id="1156" />
+ </excludedComponents>
+ <includedDownloadableComponents />
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <topLevelFiles>
+ <symlink name="" "" target="/Applications" />
+ <file name=".background/jalview_dmg_background.png" file="./jalview_dmg_background.png" />
+ <file name=".DS_Store" file="./DS_Store" />
+ <symlink name="Jalview.app/Contents/Resources/app/jre/Contents/MacOS/libjli.dylib" target="../Home/lib/jli/libjli.dylib" />
+ </topLevelFiles>
+ </macosArchive>
+ </mediaSets>
+ <buildIds buildAll="false">
+ <mediaSet refId="153" />
+ <mediaSet refId="570" />
+ <mediaSet refId="743" />
+ <mediaSet refId="878" />
+ <mediaSet refId="1272" />
+ <mediaSet refId="1274" />
+ </buildIds>
+ <buildOptions verbose="false" faster="false" disableSigning="false" disableJreBundling="true" debug="false" />
+</install4j>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<install4j version="7.0.9" transformSequenceNumber="7">
+ <directoryPresets config="libjli.dylib" />
+ <application name="Jalview" distributionSourceDir="" applicationId="6595-2347-1923-0725" mediaDir="../../build/install4j" mediaFilePattern="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:sys.version}" compression="6" lzmaCompression="true" pack200Compression="false" excludeSignedFromPacking="true" commonExternalFiles="false" createMd5Sums="true" shrinkRuntime="true" shortName="Jalview" publisher="University of Dundee" publisherWeb="http://www.jalview.org/" version="DEVELOPMENT" allPathsRelative="true" backupOnSave="false" autoSave="false" convertDotsToUnderscores="true" macSignature="????" macVolumeId="5aac4968c304f65" javaMinVersion="1.8" javaMaxVersion="" allowBetaVM="true" jdkMode="jdk" jdkName="JDK 11.0">
+ <languages skipLanguageSelection="false" languageSelectionInPrincipalLanguage="false">
+ <principalLanguage id="en" customLocalizationFile="" />
+ <additionalLanguages />
+ </languages>
+ <searchSequence>
+ <directory location="java_vm" />
+ </searchSequence>
+ <variables />
+ <mergedProjects />
+ <codeSigning macEnabled="false" macPkcs12File="" windowsEnabled="false" windowsKeySource="pkcs12" windowsPvkFile="" windowsSpcFile="" windowsPkcs12File="" windowsPkcs11Library="" windowsPkcs11Slot="">
+ <windowsKeystoreIdentifier issuer="" serial="" subject="" />
+ <windowsPkcs11Identifier issuer="" serial="" subject="" />
+ </codeSigning>
+ </application>
+ <files keepModificationTimes="false" missingFilesStrategy="warn" globalExcludeSuffixes="" defaultOverwriteMode="4" defaultUninstallMode="2" launcherOverwriteMode="3" defaultFileMode="644" defaultDirMode="755">
+ <filesets>
+ <fileset name="Full file set" id="734" customizedId="" />
+ <fileset name="Mac OS X JRE" id="880" customizedId="" />
+ <fileset name="Windows JRE" id="882" customizedId="" />
+ <fileset name="Full Files With MacOS JRE" id="1015" customizedId="" />
+ <fileset name="Full Files With Windows JRE" id="1017" customizedId="" />
+ </filesets>
+ <roots>
+ <root id="735" fileset="734" location="" />
+ <root id="881" fileset="880" location="" />
+ <root id="883" fileset="882" location="" />
+ <root id="1016" fileset="1015" location="" />
+ <root id="1018" fileset="1017" location="" />
+ </roots>
+ <mountPoints>
+ <mountPoint id="454" root="" location="" mode="755" />
+ <mountPoint id="736" root="735" location="" mode="755" />
+ <mountPoint id="884" root="881" location="" mode="755" />
+ <mountPoint id="885" root="883" location="" mode="755" />
+ <mountPoint id="1019" root="1016" location="" mode="755" />
+ <mountPoint id="1020" root="1018" location="" mode="755" />
+ </mountPoints>
+ <entries>
+ <dirEntry mountPoint="454" file="../../getdown/files" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="true" overrideUninstallMode="true" entryMode="direct" subDirectory="files" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="736" file="../../getdown/website" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="true" overrideUninstallMode="true" entryMode="direct" subDirectory="files" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="884" file="./jres/macosx-amd64-1.8.0_202/java_vm" overwriteMode="4" shared="false" fileMode="755" uninstallMode="0" overrideFileMode="true" overrideOverwriteMode="false" overrideUninstallMode="true" entryMode="subdir" subDirectory="java_vm" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="885" file="./jres/windows-amd64-1.8.0_202/java_vm" overwriteMode="4" shared="false" fileMode="755" uninstallMode="0" overrideFileMode="true" overrideOverwriteMode="false" overrideUninstallMode="true" entryMode="subdir" subDirectory="java_vm" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="1019" file="../../getdown/website" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="true" overrideUninstallMode="true" entryMode="direct" subDirectory="files" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="1019" file="./jres/macosx-amd64-1.8.0_202/java_vm" overwriteMode="4" shared="false" fileMode="755" uninstallMode="0" overrideFileMode="true" overrideOverwriteMode="false" overrideUninstallMode="true" entryMode="subdir" subDirectory="java_vm" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="1020" file="../../getdown/website" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="true" overrideUninstallMode="true" entryMode="direct" subDirectory="files" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ <dirEntry mountPoint="1020" file="./jres/windows-amd64-1.8.0_202/java_vm" overwriteMode="4" shared="false" fileMode="755" uninstallMode="0" overrideFileMode="true" overrideOverwriteMode="false" overrideUninstallMode="true" entryMode="subdir" subDirectory="java_vm" excludeSuffixes="" dirMode="755" overrideDirMode="false">
+ <exclude />
+ </dirEntry>
+ </entries>
+ <components>
+ <component name="jalview_getdown" id="1031" customizedId="" displayDescription="false" hideHelpButton="false" selected="true" changeable="true" downloadable="false" hidden="false">
+ <description />
+ <include all="false">
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </include>
+ <dependencies />
+ </component>
+ </components>
+ </files>
+ <launchers>
+ <launcher name="Jalview Launcher" id="121" customizedId="" external="false" excludeFromMenu="false" unixMode="755" unixAutoStart="true" menuName="${compiler:sys.shortName}-${compiler:sys.version}" icnsFile="../../resources/images/jalview_logos.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:sys.shortName}" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJavaMaxVersionOverride="false" javaMaxVersionOverride="" checkUpdater="false" updateExecutionMode="unattendedProgress" unattendedUpdateTitle="${i18n:updater.WindowTitle("${compiler:sys.fullName}")}">
+ <executable name="Jalview" type="1" iconSet="true" iconFile="../../resources/images/jalview_logos.ico" executableDir="." redirectStderr="true" stderrFile="error.log" stderrMode="overwrite" redirectStdout="true" stdoutFile="output.log" stdoutMode="overwrite" failOnStderrOutput="true" executableMode="1" changeWorkingDirectory="true" workingDirectory="." singleInstance="true" serviceStartType="2" serviceDependencies="" serviceDescription="" jreLocation="" executionLevel="asInvoker" checkConsoleParameter="true" globalSingleInstance="false" singleInstanceActivate="true" dpiAware="java9+">
+ <versionInfo include="false" fileVersion="" fileDescription="" legalCopyright="" internalName="" productName="" />
+ </executable>
+ <splashScreen show="false" width="640" height="480" bitmapFile="../../resources/images/jalview_logo_background_fade-640x480.png" textOverlay="true">
+ <text>
+ <statusLine x="85" y="81" text="${compiler:sys.shortName}" fontSize="18" fontColor="0,0,0" bold="false" />
+ <versionLine x="85" y="109" text="version ${compiler:sys.version}" fontSize="8" fontColor="0,0,0" bold="false" />
+ </text>
+ </splashScreen>
+ <java mainClass="com.threerings.getdown.launcher.GetdownApp" mainMode="1" vmParameters="" arguments="." allowVMPassthroughParameters="true" preferredVM="" bundleRuntime="true">
+ <classPath>
+ <archive location="getdown-launcher.jar" failOnError="false" />
+ <archive location="commons-compress-1.18.jar" failOnError="false" />
+ </classPath>
+ <modulePath />
+ <nativeLibraryDirectories />
+ <vmOptions />
+ </java>
+ <includedFiles />
+ <unextractableFiles />
+ <vmOptionsFile mode="template" overwriteMode="0" fileMode="644">
+ <content />
+ </vmOptionsFile>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <infoPlist mode="1" file="">
+ <content />
+ </infoPlist>
+ <iconImageFiles>
+ <file path="../../resources/images/Jalview_Logo.png" />
+ </iconImageFiles>
+ </launcher>
+ <launcher name="MacOS Offline Jalview Launcher" id="737" customizedId="" external="false" excludeFromMenu="false" unixMode="755" unixAutoStart="true" menuName="${compiler:sys.shortName}-${compiler:sys.version}" icnsFile="../../resources/images/jalview_logos.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="1015" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:sys.shortName}" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJavaMaxVersionOverride="false" javaMaxVersionOverride="" checkUpdater="false" updateExecutionMode="unattendedProgress" unattendedUpdateTitle="${i18n:updater.WindowTitle("${compiler:sys.fullName}")}">
+ <executable name="Jalview" type="1" iconSet="true" iconFile="../../resources/images/jalview_logos.ico" executableDir="." redirectStderr="true" stderrFile="error.log" stderrMode="overwrite" redirectStdout="true" stdoutFile="output.log" stdoutMode="overwrite" failOnStderrOutput="true" executableMode="1" changeWorkingDirectory="true" workingDirectory="." singleInstance="true" serviceStartType="2" serviceDependencies="" serviceDescription="" jreLocation="" executionLevel="asInvoker" checkConsoleParameter="true" globalSingleInstance="false" singleInstanceActivate="true" dpiAware="java9+">
+ <versionInfo include="false" fileVersion="" fileDescription="" legalCopyright="" internalName="" productName="" />
+ </executable>
+ <splashScreen show="false" width="640" height="480" bitmapFile="../../resources/images/jalview_logo_background_fade-640x480.png" textOverlay="true">
+ <text>
+ <statusLine x="85" y="81" text="${compiler:sys.shortName}" fontSize="18" fontColor="0,0,0" bold="false" />
+ <versionLine x="85" y="109" text="version ${compiler:sys.version}" fontSize="8" fontColor="0,0,0" bold="false" />
+ </text>
+ </splashScreen>
+ <java mainClass="com.threerings.getdown.launcher.GetdownApp" mainMode="1" vmParameters="" arguments="." allowVMPassthroughParameters="true" preferredVM="" bundleRuntime="true">
+ <classPath>
+ <archive location="getdown-launcher.jar" failOnError="false" />
+ <archive location="commons-compress-1.18.jar" failOnError="false" />
+ </classPath>
+ <modulePath />
+ <nativeLibraryDirectories />
+ <vmOptions />
+ </java>
+ <includedFiles />
+ <unextractableFiles />
+ <vmOptionsFile mode="template" overwriteMode="0" fileMode="644">
+ <content />
+ </vmOptionsFile>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <infoPlist mode="1" file="">
+ <content />
+ </infoPlist>
+ <iconImageFiles>
+ <file path="../../resources/images/Jalview_Logo.png" />
+ </iconImageFiles>
+ </launcher>
+ <launcher name="Windows Offline Jalview Launcher" id="1022" customizedId="" external="false" excludeFromMenu="false" unixMode="755" unixAutoStart="true" menuName="${compiler:sys.shortName}-${compiler:sys.version}" icnsFile="../../resources/images/jalview_logos.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="1017" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:sys.shortName}" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJavaMaxVersionOverride="false" javaMaxVersionOverride="" checkUpdater="false" updateExecutionMode="unattendedProgress" unattendedUpdateTitle="${i18n:updater.WindowTitle("${compiler:sys.fullName}")}">
+ <executable name="Jalview" type="1" iconSet="true" iconFile="../../resources/images/jalview_logos.ico" executableDir="." redirectStderr="true" stderrFile="error.log" stderrMode="overwrite" redirectStdout="true" stdoutFile="output.log" stdoutMode="overwrite" failOnStderrOutput="true" executableMode="1" changeWorkingDirectory="true" workingDirectory="." singleInstance="true" serviceStartType="2" serviceDependencies="" serviceDescription="" jreLocation="" executionLevel="asInvoker" checkConsoleParameter="true" globalSingleInstance="false" singleInstanceActivate="true" dpiAware="java9+">
+ <versionInfo include="false" fileVersion="" fileDescription="" legalCopyright="" internalName="" productName="" />
+ </executable>
+ <splashScreen show="false" width="640" height="480" bitmapFile="../../resources/images/jalview_logo_background_fade-640x480.png" textOverlay="true">
+ <text>
+ <statusLine x="85" y="81" text="${compiler:sys.shortName}" fontSize="18" fontColor="0,0,0" bold="false" />
+ <versionLine x="85" y="109" text="version ${compiler:sys.version}" fontSize="8" fontColor="0,0,0" bold="false" />
+ </text>
+ </splashScreen>
+ <java mainClass="com.threerings.getdown.launcher.GetdownApp" mainMode="1" vmParameters="" arguments="." allowVMPassthroughParameters="true" preferredVM="" bundleRuntime="true">
+ <classPath>
+ <archive location="getdown-launcher.jar" failOnError="false" />
+ <archive location="commons-compress-1.18.jar" failOnError="false" />
+ </classPath>
+ <modulePath />
+ <nativeLibraryDirectories />
+ <vmOptions />
+ </java>
+ <includedFiles />
+ <unextractableFiles />
+ <vmOptionsFile mode="template" overwriteMode="0" fileMode="644">
+ <content />
+ </vmOptionsFile>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <infoPlist mode="1" file="">
+ <content />
+ </infoPlist>
+ <iconImageFiles>
+ <file path="../../resources/images/Jalview_Logo.png" />
+ </iconImageFiles>
+ </launcher>
+ </launchers>
+ <installerGui installerType="1" addOnAppId="" suggestPreviousLocations="true" autoUpdateDescriptorUrl="" useAutoUpdateBaseUrl="false" autoUpdateBaseUrl="">
+ <staticMembers script="" />
+ <customCode />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <applications>
+ <application name="" id="installer" customizedId="" beanClass="com.install4j.runtime.beans.applications.InstallerApplication" enabled="true" commentSet="false" comment="" actionElevationType="none" styleId="35" fileset="" customIcnsFile="../../resources/images/jalview_logos.icns" customIcoFile="../../resources/images/jalview_logos.ico" macEntitlementsFile="" automaticLauncherIntegration="false" launchMode="startupFirstWindow" launchInNewProcess="true" launchSchedule="updateSchedule" allLaunchers="true">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.applications.InstallerApplication">
+ <void property="useCustomIcon">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <styleOverrides>
+ <styleOverride name="Customize banner image" enabled="true">
+ <group name="" id="146" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans />
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </styleOverride>
+ <styleOverride name="Jalview" enabled="true">
+ <formComponent name="Watermark" id="352" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="5" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Jalview" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SeparatorComponent">
+ <void property="enabledTitleText">
+ <boolean>false</boolean>
+ </void>
+ <void property="labelText">
+ <string>install4j</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>labelText</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ </styleOverride>
+ </styleOverrides>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <launcherIds />
+ <variables />
+ <startup>
+ <screen name="" id="1" customizedId="" beanClass="com.install4j.runtime.beans.screens.StartupScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.StartupScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="22" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.RequestPrivilegesAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.RequestPrivilegesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents />
+ </screen>
+ </startup>
+ <screens>
+ <screen name="" id="2" customizedId="" beanClass="com.install4j.runtime.beans.screens.WelcomeScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.WelcomeScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides>
+ <styleOverride name="Customize banner image" enabled="true">
+ <group name="" id="145" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>25</int>
+ <int>143</int>
+ <int>220</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans />
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </styleOverride>
+ </styleOverrides>
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="7" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" enabled="true" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="true" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction">
+ <void property="excludedVariables">
+ <array class="java.lang.String" length="1">
+ <void index="0">
+ <string>sys.installationDir</string>
+ </void>
+ </array>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>context.getBooleanVariable("sys.confirmedUpdateInstallation")</condition>
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="3" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:welcomeMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>!context.isConsole()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="4" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
+ <void property="consoleScript">
+ <object class="com.install4j.api.beans.ScriptProperty">
+ <void property="value">
+ <string>String message = context.getMessage("ConsoleWelcomeLabel", context.getApplicationName());
+return console.askOkCancel(message, true);
+</string>
+ </void>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="5" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.UpdateAlertComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Update Alert" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.UpdateAlertComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>updateCheck</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ <formComponent name="" id="6" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="20" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${i18n:ClickNext}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="8" customizedId="" beanClass="com.install4j.runtime.beans.screens.InstallationDirectoryScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.InstallationDirectoryScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition>!context.getBooleanVariable("sys.confirmedUpdateInstallation")</condition>
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="11" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" enabled="true" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="true" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction">
+ <void property="excludedVariables">
+ <array class="java.lang.String" length="1">
+ <void index="0">
+ <string>sys.installationDir</string>
+ </void>
+ </array>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>context.getVariable("sys.responseFile") == null</condition>
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="9" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="25" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${i18n:SelectDirLabel(${compiler:sys.fullName})}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="10" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.InstallationDirectoryChooserComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Installation Directory Chooser" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.InstallationDirectoryChooserComponent">
+ <void property="requestFocus">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>suggestAppDir</propertyName>
+ <propertyName>validateApplicationId</propertyName>
+ <propertyName>existingDirWarning</propertyName>
+ <propertyName>checkWritable</propertyName>
+ <propertyName>manualEntryAllowed</propertyName>
+ <propertyName>checkFreeSpace</propertyName>
+ <propertyName>showRequiredDiskSpace</propertyName>
+ <propertyName>showFreeDiskSpace</propertyName>
+ <propertyName>allowSpacesOnUnix</propertyName>
+ <propertyName>validationScript</propertyName>
+ <propertyName>standardValidation</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="12" customizedId="" beanClass="com.install4j.runtime.beans.screens.ComponentsScreen" enabled="false" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.ComponentsScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents>
+ <formComponent name="" id="13" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${i18n:SelectComponentsLabel2}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>!context.isConsole()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="14" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ComponentSelectorComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Installation Components" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ComponentSelectorComponent">
+ <void property="fillVertical">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>selectionChangedScript</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="15" customizedId="" beanClass="com.install4j.runtime.beans.screens.InstallationScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="true" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.InstallationScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="17" customizedId="" beanClass="com.install4j.runtime.beans.actions.InstallFilesAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="2" errorMessage="${i18n:FileCorrupted}">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.InstallFilesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="18" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.CreateProgramGroupAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.CreateProgramGroupAction">
+ <void property="uninstallerMenuName">
+ <string>${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>!context.getBooleanVariable("sys.programGroupDisabled")</condition>
+ </action>
+ <action name="" id="19" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.RegisterAddRemoveAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.RegisterAddRemoveAction">
+ <void property="itemName">
+ <string>${compiler:sys.fullName} ${compiler:sys.version}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="124" customizedId="" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction" enabled="false" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.control.SetVariableAction">
+ <void property="script">
+ <object class="com.install4j.api.beans.ScriptProperty">
+ <void property="value">
+ <string />
+ </void>
+ </object>
+ </void>
+ <void property="variableName">
+ <string />
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>true</condition>
+ </action>
+ <action name="" id="134" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.AddVmOptionsAction" enabled="false" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.AddVmOptionsAction">
+ <void property="launcherId">
+ <string>121</string>
+ </void>
+ <void property="vmOptions">
+ <array class="java.lang.String" length="0" />
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="16" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ProgressComponent">
+ <void property="initialStatusMessage">
+ <string>${i18n:WizardPreparing}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="20" customizedId="" beanClass="com.install4j.runtime.beans.screens.FinishedScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="true" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.FinishedScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="573" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.CreateDesktopLinkAction" enabled="false" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.CreateDesktopLinkAction">
+ <void property="name">
+ <string>${compiler:sys.fullName}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition>context.getBooleanVariable("createDesktopLinkAction")</condition>
+ </action>
+ <action name="" id="575" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.AddStartupItemAction" enabled="false" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.AddStartupItemAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="576" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.AddToDockAction" enabled="false" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.AddToDockAction" />
+ </java>
+ </serializedBean>
+ <condition>context.getBooleanVariable("addToDockAction")</condition>
+ </action>
+ <action name="" id="578" customizedId="" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction">
+ <void property="description">
+ <string>Jalview Project File</string>
+ </void>
+ <void property="extension">
+ <string>jvp</string>
+ </void>
+ <void property="launcherId">
+ <string>121</string>
+ </void>
+ <void property="macIconFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/file.png</string>
+ </object>
+ </void>
+ <void property="macRole">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.actions.desktop.MacAssociationRole</class>
+ <string>EDITOR</string>
+ </object>
+ </void>
+ <void property="windowsIconFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/file.png</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="21" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="10" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:finishedMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Add a desktop link" id="574" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.CheckboxComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.CheckboxComponent">
+ <void property="checkboxText">
+ <string>${i18n:CreateDesktopIcon}</string>
+ </void>
+ <void property="initiallySelected">
+ <boolean>true</boolean>
+ </void>
+ <void property="variableName">
+ <string>createDesktopLinkAction</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Add an executable to the dock" id="577" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.CheckboxComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.CheckboxComponent">
+ <void property="checkboxText">
+ <string>${i18n:AddToDock}</string>
+ </void>
+ <void property="initiallySelected">
+ <boolean>true</boolean>
+ </void>
+ <void property="variableName">
+ <string>addToDockAction</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>Util.isMacOS()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ </screens>
+ </application>
+ <application name="" id="uninstaller" customizedId="" beanClass="com.install4j.runtime.beans.applications.UninstallerApplication" enabled="true" commentSet="false" comment="" actionElevationType="none" styleId="41" fileset="" customIcnsFile="" customIcoFile="" macEntitlementsFile="" automaticLauncherIntegration="false" launchMode="startupFirstWindow" launchInNewProcess="true" launchSchedule="updateSchedule" allLaunchers="true">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.applications.UninstallerApplication">
+ <void property="customMacosExecutableName">
+ <string>${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</string>
+ </void>
+ <void property="useCustomMacosExecutableName">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <styleOverrides>
+ <styleOverride name="Customize banner image" enabled="true">
+ <group name="" id="147" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>192</int>
+ <int>192</int>
+ <int>192</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans />
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </styleOverride>
+ </styleOverrides>
+ <customScript mode="1" file="">
+ <content />
+ </customScript>
+ <launcherIds />
+ <variables />
+ <startup>
+ <screen name="" id="23" customizedId="" beanClass="com.install4j.runtime.beans.screens.StartupScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.StartupScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="33" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" enabled="true" commentSet="false" comment="" actionElevationType="inherit" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="34" customizedId="" beanClass="com.install4j.runtime.beans.actions.misc.RequireInstallerPrivilegesAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.misc.RequireInstallerPrivilegesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents />
+ </screen>
+ </startup>
+ <screens>
+ <screen name="" id="24" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallWelcomeScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="41" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallWelcomeScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents>
+ <formComponent name="" id="25" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="10" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:welcomeMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript>!context.isConsole()</visibilityScript>
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="26" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
+ <void property="consoleScript">
+ <object class="com.install4j.api.beans.ScriptProperty">
+ <void property="value">
+ <string>String message = context.getMessage("ConfirmUninstall", context.getApplicationName());
+return console.askYesNo(message, true);
+</string>
+ </void>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="27" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallationScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="false" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallationScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions>
+ <action name="" id="659" customizedId="" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.control.SetProgressAction">
+ <void property="progressChangeType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.actions.control.ProgressChangeType</class>
+ <string>SET_INDETERMINATE</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="29" customizedId="" beanClass="com.install4j.runtime.beans.actions.UninstallFilesAction" enabled="true" commentSet="false" comment="" actionElevationType="elevated" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.UninstallFilesAction" />
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ <action name="" id="660" customizedId="" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" enabled="true" commentSet="false" comment="" actionElevationType="none" rollbackBarrier="false" rollbackBarrierExitCode="0" multiExec="false" failureStrategy="1" errorMessage="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.actions.control.SetProgressAction">
+ <void property="percentValue">
+ <int>100</int>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <condition />
+ </action>
+ </actions>
+ <formComponents>
+ <formComponent name="" id="28" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.ProgressComponent">
+ <void property="initialStatusMessage">
+ <string>${i18n:UninstallerPreparing}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ <screen name="" id="32" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallFailureScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="true" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallFailureScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents />
+ </screen>
+ <screen name="" id="30" customizedId="" beanClass="com.install4j.runtime.beans.screens.UninstallSuccessScreen" enabled="true" commentSet="false" comment="" actionElevationType="inherit" styleId="41" rollbackBarrier="false" rollbackBarrierExitCode="0" backButton="2" finishScreen="true" wizardIndexChangeType="unchanged" wizardIndexKey="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.screens.UninstallSuccessScreen" />
+ </java>
+ </serializedBean>
+ <styleOverrides />
+ <condition />
+ <validation />
+ <preActivation />
+ <postActivation />
+ <actions />
+ <formComponents>
+ <formComponent name="" id="31" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="10" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
+ <void property="labelText">
+ <string>${form:successMessage}</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </screen>
+ </screens>
+ </application>
+ </applications>
+ <styles defaultStyleId="35">
+ <style name="Standard" id="35" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle" />
+ </java>
+ </serializedBean>
+ <formComponents>
+ <formComponent name="Header" id="36" customizedId="" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.NestedStyleComponent">
+ <void property="styleId">
+ <string>48</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <group name="Main" id="37" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="imageEdgeAxisType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.AxisType</class>
+ <string>HORIZONTAL</string>
+ </object>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>../../resources/images/jalview_logo_background_fade-640x480.png</string>
+ </object>
+ </void>
+ <void property="imageOverlap">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="" id="38" customizedId="" beanClass="com.install4j.runtime.beans.styles.ContentComponent" enabled="true" commentSet="false" comment="" insetTop="10" insetLeft="20" insetBottom="10" insetRight="20" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ContentComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Watermark" id="39" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="5" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="true" externalParametrizationName="Jalview" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SeparatorComponent">
+ <void property="enabledTitleText">
+ <boolean>false</boolean>
+ </void>
+ <void property="labelText">
+ <string>install4j</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames>
+ <propertyName>labelText</propertyName>
+ </externalParametrizationPropertyNames>
+ </formComponent>
+ <formComponent name="Footer" id="40" customizedId="" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.NestedStyleComponent">
+ <void property="styleId">
+ <string>52</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames />
+ </group>
+ </formComponents>
+ </style>
+ <style name="Banner" id="41" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle" />
+ </java>
+ </serializedBean>
+ <formComponents>
+ <group name="" id="42" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageEdgeBackgroundColor">
+ <object class="java.awt.Color">
+ <int>25</int>
+ <int>143</int>
+ <int>220</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="imageEdgeBorder">
+ <boolean>true</boolean>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>${compiler:sys.install4jHome}/resource/styles/wizard.png</string>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>5</int>
+ <int>10</int>
+ <int>10</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="" id="43" customizedId="" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" enabled="true" commentSet="false" comment="" insetTop="0" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ScreenTitleComponent">
+ <void property="labelFontSizePercent">
+ <int>130</int>
+ </void>
+ <void property="labelFontStyle">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontStyle</class>
+ <string>BOLD</string>
+ </object>
+ </void>
+ <void property="labelFontType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontType</class>
+ <string>DERIVED</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="44" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SeparatorComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="" id="45" customizedId="" beanClass="com.install4j.runtime.beans.styles.ContentComponent" enabled="true" commentSet="false" comment="" insetTop="10" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ContentComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageEdgeBackgroundColor</propertyName>
+ <propertyName>imageFile</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ <formComponent name="" id="46" customizedId="" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="0" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.NestedStyleComponent">
+ <void property="styleId">
+ <string>52</string>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </formComponents>
+ </style>
+ <group name="Style components" id="47" customizedId="" beanClass="com.install4j.runtime.beans.groups.StyleGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.StyleGroup" />
+ </java>
+ </serializedBean>
+ <beans>
+ <style name="Standard header" id="48" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle">
+ <void property="fillVertical">
+ <boolean>false</boolean>
+ </void>
+ <void property="standalone">
+ <boolean>false</boolean>
+ </void>
+ <void property="verticalAnchor">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.beans.Anchor</class>
+ <string>NORTH</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <formComponents>
+ <group name="" id="49" customizedId="" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="true" externalParametrizationName="Customize title bar" externalParametrizationMode="include">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
+ <void property="backgroundColor">
+ <object class="java.awt.Color">
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ <int>255</int>
+ </object>
+ </void>
+ <void property="borderSides">
+ <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
+ <void property="bottom">
+ <boolean>true</boolean>
+ </void>
+ </object>
+ </void>
+ <void property="imageAnchor">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.beans.Anchor</class>
+ <string>NORTHEAST</string>
+ </object>
+ </void>
+ <void property="imageEdgeBorderWidth">
+ <int>2</int>
+ </void>
+ <void property="imageFile">
+ <object class="com.install4j.api.beans.ExternalFile">
+ <string>icon:${installer:sys.installerApplicationMode}_header.png</string>
+ </object>
+ </void>
+ <void property="imageInsets">
+ <object class="java.awt.Insets">
+ <int>0</int>
+ <int>5</int>
+ <int>1</int>
+ <int>1</int>
+ </object>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>0</int>
+ <int>20</int>
+ <int>0</int>
+ <int>10</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="Title" id="50" customizedId="" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ScreenTitleComponent">
+ <void property="labelFontStyle">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontStyle</class>
+ <string>BOLD</string>
+ </object>
+ </void>
+ <void property="labelFontType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.formcomponents.FontType</class>
+ <string>DERIVED</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Subtitle" id="51" customizedId="" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="8" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.ScreenTitleComponent">
+ <void property="titleType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.runtime.beans.styles.TitleType</class>
+ <string>SUB_TITLE</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames>
+ <propertyName>backgroundColor</propertyName>
+ <propertyName>foregroundColor</propertyName>
+ <propertyName>imageAnchor</propertyName>
+ <propertyName>imageFile</propertyName>
+ <propertyName>imageOverlap</propertyName>
+ </externalParametrizationPropertyNames>
+ </group>
+ </formComponents>
+ </style>
+ <style name="Standard footer" id="52" customizedId="" beanClass="com.install4j.runtime.beans.styles.FormStyle" enabled="true" commentSet="false" comment="">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.FormStyle">
+ <void property="fillVertical">
+ <boolean>false</boolean>
+ </void>
+ <void property="standalone">
+ <boolean>false</boolean>
+ </void>
+ <void property="verticalAnchor">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.beans.Anchor</class>
+ <string>SOUTH</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <formComponents>
+ <group name="" id="53" customizedId="" beanClass="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup" enabled="true" commentSet="false" comment="" actionElevationType="inherit" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup">
+ <void property="alignFirstLabel">
+ <boolean>false</boolean>
+ </void>
+ <void property="insets">
+ <object class="java.awt.Insets">
+ <int>3</int>
+ <int>5</int>
+ <int>8</int>
+ <int>5</int>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <beans>
+ <formComponent name="" id="54" customizedId="" beanClass="com.install4j.runtime.beans.formcomponents.SpringComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.formcomponents.SpringComponent" />
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Back button" id="55" customizedId="" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
+ <void property="buttonText">
+ <string>< ${i18n:ButtonBack}</string>
+ </void>
+ <void property="controlButtonType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.context.ControlButtonType</class>
+ <string>PREVIOUS</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Next button" id="56" customizedId="" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
+ <void property="buttonText">
+ <string>${i18n:ButtonNext} ></string>
+ </void>
+ <void property="controlButtonType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.context.ControlButtonType</class>
+ <string>NEXT</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ <formComponent name="Cancel button" id="57" customizedId="" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" enabled="true" commentSet="false" comment="" insetTop="" insetLeft="5" insetBottom="" insetRight="" resetInitOnPrevious="false" useExternalParametrization="false" externalParametrizationName="" externalParametrizationMode="all">
+ <serializedBean>
+ <java class="java.beans.XMLDecoder">
+ <object class="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
+ <void property="buttonText">
+ <string>${i18n:ButtonCancel}</string>
+ </void>
+ <void property="controlButtonType">
+ <object class="java.lang.Enum" method="valueOf">
+ <class>com.install4j.api.context.ControlButtonType</class>
+ <string>CANCEL</string>
+ </object>
+ </void>
+ </object>
+ </java>
+ </serializedBean>
+ <initScript />
+ <visibilityScript />
+ <externalParametrizationPropertyNames />
+ </formComponent>
+ </beans>
+ <externalParametrizationPropertyNames />
+ </group>
+ </formComponents>
+ </style>
+ </beans>
+ </group>
+ </styles>
+ </installerGui>
+ <mediaSets>
+ <windows name="Windows" id="130" customizedId="" mediaFileName="" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="64" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="windows-amd64-11.0.2" manualJREEntry="false" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" customInstallBaseDir="" contentFilesType="1" verifyIntegrity="true">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="121" />
+ <launcher id="737" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ <entry location=".i4j_fileset_1015" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ </windows>
+ <macos name="macOS Single Bundle Archive with Getdown JRE" id="131" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}-installer_${compiler:sys.version}" installDir="${compiler:sys.fullName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="macosx-amd64-1.8.0_202_unpacked" manualJREEntry="false" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" requiredVmIdPrefix="" customInstallBaseDir="" contentFilesType="1" installerName="${i18n:InstallerName(${compiler:sys.fullName})}" volumeName="${compiler:sys.shortName}" compressDmg="true" launcherId="121">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <topLevelFiles />
+ </macos>
+ <unixInstaller name="Unix Installer" id="132" customizedId="" mediaFileName="" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="" manualJREEntry="false" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" customInstallBaseDir="" contentFilesType="1">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="737" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <installerScript mode="1" file="">
+ <content />
+ </installerScript>
+ </unixInstaller>
+ <macosArchive name="macOS Single Bundle Archive" id="152" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}-app_${compiler:sys.version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="macosx-amd64-11.0.2" manualJREEntry="false" archiveType="dmg" volumeName="${compiler:sys.shortName}" launcherId="121">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <topLevelFiles>
+ <symlink name="" "" target="/Applications" />
+ <file name=".background/jalview_dmg_background.png" file="../../resources/install4j/jalview_dmg_background.png" />
+ <file name=".DS_Store" file="../../resources/install4j/DS_Store" />
+ </topLevelFiles>
+ </macosArchive>
+ <linuxDeb name="Linux Deb Archive" id="153" customizedId="" mediaFileName="" installDir="/opt/${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" overwriteNeverAsConfigFiles="false" dependencies="" bzip="true" description="Jalview Desktop" maintainerEmail="help@jalview.org" architectureSet="false" architecture="">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="121" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <preInstallScript mode="1" file="">
+ <content />
+ </preInstallScript>
+ <postInstallScript mode="1" file="">
+ <content />
+ </postInstallScript>
+ <preUninstallScript mode="1" file="">
+ <content />
+ </preUninstallScript>
+ <postUninstallScript mode="1" file="">
+ <content />
+ </postUninstallScript>
+ </linuxDeb>
+ <linuxRPM name="Linux RPM" id="570" customizedId="" mediaFileName="" installDir="/opt/${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" overwriteNeverAsConfigFiles="false" dependencies="" os="linux" arch="i386">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="121" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <preInstallScript mode="1" file="">
+ <content />
+ </preInstallScript>
+ <postInstallScript mode="1" file="">
+ <content />
+ </postInstallScript>
+ <preUninstallScript mode="1" file="">
+ <content />
+ </preUninstallScript>
+ <postUninstallScript mode="1" file="">
+ <content />
+ </postUninstallScript>
+ </linuxRPM>
+ <macosArchive name="Offline macOS Single Bundle Archive" id="739" customizedId="" mediaFileName="${compiler:sys.shortName}-OFFLINE_${compiler:sys.platform}-app_${compiler:sys.version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="macosx-amd64-11.0.2" manualJREEntry="false" archiveType="dmg" volumeName="${compiler:sys.shortName} Offline Installer" launcherId="737">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <topLevelFiles>
+ <symlink name="" "" target="/Applications" />
+ <file name=".background/jalview_dmg_background.png" file="../../resources/install4j/jalview_dmg_background.png" />
+ <file name=".DS_Store" file="../../resources/install4j/DS_Store" />
+ </topLevelFiles>
+ </macosArchive>
+ <unixInstaller name="Offline Unix Installer" id="741" customizedId="" mediaFileName="${compiler:sys.shortName}-OFFLINE_${compiler:sys.platform}_${compiler:sys.version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="" manualJREEntry="false" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" customInstallBaseDir="" contentFilesType="1">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="121" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <installerScript mode="1" file="">
+ <content />
+ </installerScript>
+ </unixInstaller>
+ <windows name="Offline Windows" id="743" customizedId="" mediaFileName="${compiler:sys.shortName}-OFFLINE_${compiler:sys.platform}_${compiler:sys.version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="64" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="" manualJREEntry="false" bundleType="1" jreURL="" jreShared="false" directDownload="false" installOnlyIfNecessary="false" customInstallBaseDir="" contentFilesType="1" verifyIntegrity="true">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedLaunchers>
+ <launcher id="121" />
+ <launcher id="737" />
+ </excludedLaunchers>
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_734" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ <entry location=".i4j_fileset_1015" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ </windows>
+ <macosArchive name="Offline macOS Single Bundle Archive with Getdown JRE" id="878" customizedId="" mediaFileName="${compiler:sys.shortName}-OFFLINE_${compiler:sys.platform}-app_${compiler:sys.version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="true" includedJRE="" manualJREEntry="false" archiveType="dmg" volumeName="${compiler:sys.shortName} Offline Installer" launcherId="737">
+ <excludedComponents />
+ <includedDownloadableComponents />
+ <excludedBeans />
+ <overriddenPrincipalLanguage id="en" customLocalizationFile="" />
+ <exclude>
+ <entry location=".i4j_fileset_" fileType="regular" />
+ <entry location=".i4j_fileset_880" fileType="regular" />
+ <entry location=".i4j_fileset_882" fileType="regular" />
+ </exclude>
+ <variables />
+ <autoUpdate useMinUpdatableVersion="false" minUpdatableVersion="" useMaxUpdatableVersion="false" maxUpdatableVersion="">
+ <commentFiles />
+ <customAttributes />
+ </autoUpdate>
+ <topLevelFiles>
+ <symlink name="" "" target="/Applications" />
+ <file name=".background/jalview_dmg_background.png" file="./jalview_dmg_background.png" />
+ <file name=".DS_Store" file="./DS_Store" />
+ </topLevelFiles>
+ </macosArchive>
+ </mediaSets>
+ <buildIds buildAll="false">
+ <mediaSet refId="153" />
+ <mediaSet refId="570" />
+ <mediaSet refId="743" />
+ <mediaSet refId="878" />
+ </buildIds>
+ <buildOptions verbose="true" faster="true" disableSigning="true" disableJreBundling="false" debug="false" />
+</install4j>
--- /dev/null
+#/usr/bin/env bash
+
+# Be in the jalview top level dir.
+# lib -- contains usual jalview jar files
+# make sure it contains the extra jar files needed in classpath for Java 11
+# j11lib -- contains java11 style modules to be put into the JRE (not needed at runtime)
+#
+# j11jre -- dir containing JRE environments for jalview
+#
+# creates file modules.new which is comma-separated list of modules needed, can be used like this in jlink argument
+# and a java 11 JRE in j11jre/jre-new
+
+( for x in lib/*.jar j11lib/*.jar dist/jalview.jar; do echo $x >&2; jdeps --list-deps --module-path j11lib $x | grep -v Warning: | grep -v "JDK removed" | sed -e 's/^ *//;s/\/.*//;s/$/,/;'; done ) | sort -u | perl -p -e 'chomp;' | perl -p -e 's/,$//;chomp;' > modules.new
+
+if [ x$JAVA_HOME != x ]; then
+ jlink --no-header-files --no-man-pages --strip-debug --module-path "$JAVA_HOME/jmods:j11lib" --add-modules `cat modules.new` --compress=2 --output j11jre/jre-new
+else
+ jlink --no-header-files --no-man-pages --strip-debug --module-path "j11lib" --add-modules `cat modules.new` --compress=2 --output j11jre/jre-new
+fi
+
+
+# or if you're in a hurry for a one-liner...
+#jlink --no-header-files --no-man-pages --strip-debug --module-path "$JAVA_HOME/jmods:j11lib" --add-modules ` ( for x in lib/*.jar j11lib/*.jar dist/jalview.jar; do echo $x >&2; jdeps --list-deps --module-path j11mod $x | grep -v "Warning:" | grep -v "JDK removed" | sed -e 's/^ *//;s/\/.*//;s/$/,/;'; done ) | sort -u | perl -p -e 'chomp;' | perl -p -e 's/,$//;chomp;' ` --compress=2 --output j11jre/jre-new
--- /dev/null
+#!/usr/bin/env bash
+
+CMD=$(basename $0)
+
+usage() {
+ echo "Usage: $CMD /path/to/jarfile" >&2
+}
+
+usagexit() {
+ usage
+ exit 1
+}
+
+error() {
+ echo $1 >&2
+ usagexit
+}
+
+JARFILE=$1
+[ -z $JARFILE ] && usagexit
+[ -f $JARFILE ] || error "No file $JARFILE"
+[ -r $JARFILE ] || error "$JARFILE not readable"
+
+EXT=.jar
+SUFFIX=-MODULE
+FILENAME=$(basename $JARFILE)
+BASE=$(basename -s $EXT $JARFILE)
+DIR=$(dirname $JARFILE)
+
+# set absolute path to $JARFILE if not specified
+[ x${DIR#/} = x$DIR ] && DIR=$(cd "$DIR" && pwd)
+
+ABSJARFILE=$DIR/$FILENAME
+
+TMPDIR=/tmp/$USER-$CMD-$BASE-$$
+
+[ x$FILENAME = x$BASE ] && error "Should be $EXT file"
+
+mkdir -p $TMPDIR/jar || error "Could not create tmp dir $TMPDIR/jar"
+mkdir -p $TMPDIR/info || error "Could not create tmp dir $TMPDIR/info"
+cd $TMPDIR/jar
+jar -xvf $ABSJARFILE > /dev/null
+jdeps --module-path="$DIR" --generate-module-info $TMPDIR/info $ABSJARFILE
+# next line assuming only one module-info.java file created, I think this is always true...? It'll just use the last one if not.
+find $TMPDIR/info -name "module-info.java" -exec /bin/mv {} . \;
+[ -e ./module-info.java ] || error "No module-info.java file found in $TMPDIR/info"
+javac -d $TMPDIR/jar ./module-info.java
+jar -cvf $DIR/${BASE}${SUFFIX}${EXT} -C $TMPDIR/jar . > /dev/null
+rm -rf $TMPDIR
+
+
--- /dev/null
+public class showJVMVersion {
+ public static void main(String args[]) {
+ System.out.println(System.getProperty("java.version"));
+ }
+}