Merge branch 'develop' into features/r2_11_2_alphafold/JAL-2349_JAL-3855
authorJim Procter <j.procter@dundee.ac.uk>
Wed, 16 Feb 2022 13:27:25 +0000 (13:27 +0000)
committerJim Procter <j.procter@dundee.ac.uk>
Wed, 16 Feb 2022 13:27:25 +0000 (13:27 +0000)
combined new logic for 2.11.2 3d-beacons with original hack to resolve PAE and CIF
 Conflicts:
src/jalview/ws/dbsources/EBIAlfaFold.java

511 files changed:
THIRDPARTYLIBS
build.gradle
doc/README-DMG_background_image_creation.md [moved from utils/install4j/README-DMG_background_image_creation.md with 100% similarity]
doc/README-DMG_creation.md [moved from utils/install4j/README-DMG_creation.md with 100% similarity]
doc/README_convert_PNG_to_ICNS_and_ICO [moved from utils/install4j/README_convert_PNG_to_ICNS_and_ICO with 62% similarity]
getdown/lib/FJVL_VERSION
getdown/lib/JVL_VERSION
getdown/lib/getdown-core.jar
getdown/lib/getdown-launcher-local.jar
getdown/lib/getdown-launcher.jar
getdown/src/getdown/ant/pom.xml
getdown/src/getdown/core/pom.xml
getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java [new file with mode: 0644]
getdown/src/getdown/launcher/pom.xml
getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyPanel.java
getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/ProxyUtil.java
getdown/src/getdown/mvn_cmd
getdown/src/getdown/pom.xml
gradle.properties
help/help/help.jhm
help/help/helpTOC.xml
help/help/html/features/3dbeacons_button.png [new file with mode: 0644]
help/help/html/features/3dbeacons_structurechooser.png [new file with mode: 0644]
help/help/html/features/3dstructuredata_popupmenu.png [new file with mode: 0644]
help/help/html/features/annotationsFormat.html
help/help/html/features/chimera.html
help/help/html/features/clarguments.html
help/help/html/features/commandline.html
help/help/html/features/groovy.html
help/help/html/features/jvlfiles.html
help/help/html/features/preferences.html
help/help/html/features/pymol.html [new file with mode: 0644]
help/help/html/features/schooser_main.png
help/help/html/features/schooser_viewbutton.png [new file with mode: 0644]
help/help/html/features/search.html
help/help/html/features/search.png
help/help/html/features/selectfetchdb.gif
help/help/html/features/seqfetch.html
help/help/html/features/seqfetcher.gif
help/help/html/features/structurechooser.html
help/help/html/features/viewingpdbs.html
help/help/html/groovy/featuresCounter.html
help/help/html/index.html
help/help/html/keys.html
help/help/html/logging.html [new file with mode: 0644]
help/help/html/memory.html
help/help/html/releases.html
help/help/html/webServices/newsreader.html
help/help/html/whatsNew.html
j11lib/Jmol-15.1.3.jar [deleted file]
j11lib/Jmol-NO_LOG4J-14.31.53.jar [new file with mode: 0644]
j11lib/getdown-core.jar
j11lib/groovy-all-2.4.21-indy.jar [moved from j11lib/groovy-all-2.4.12-indy.jar with 58% similarity]
j11lib/jabaws-min-client-2.2.0.jar [deleted file]
j11lib/jabaws-min-client-NO_LOG4J-2.2.0.jar [new file with mode: 0644]
j11lib/log4j-api-2.17.1.jar [new file with mode: 0644]
j11lib/log4j-core-2.17.1.jar [new file with mode: 0644]
j11lib/log4j-slf4j18-impl-2.17.1.jar [new file with mode: 0644]
j11lib/log4j-to-slf4j-2.0-rc2.jar [deleted file]
j11lib/slf4j-api-1.7.26.jar [deleted file]
j11lib/slf4j-api-1.7.32.jar [new file with mode: 0644]
j11lib/slf4j-log4j12-1.7.26.jar [deleted file]
j8lib/Jmol-14.29.17.jar [deleted file]
j8lib/Jmol-NO_LOG4J-14.31.53.jar [new file with mode: 0644]
j8lib/getdown-core.jar
j8lib/groovy-all-2.4.21-indy.jar [moved from j8lib/groovy-all-2.4.12-indy.jar with 58% similarity]
j8lib/jabaws-min-client-2.2.0.jar [deleted file]
j8lib/jabaws-min-client-NO_LOG4J-2.2.0.jar [new file with mode: 0644]
j8lib/log4j-api-2.17.1.jar [new file with mode: 0644]
j8lib/log4j-core-2.17.1.jar [new file with mode: 0644]
j8lib/log4j-slf4j18-impl-2.17.1.jar [new file with mode: 0644]
j8lib/log4j-to-slf4j-2.0-rc2.jar [deleted file]
j8lib/slf4j-api-1.7.32.jar [new file with mode: 0644]
j8lib/slf4j-api-1.7.7.jar [deleted file]
j8lib/slf4j-log4j12-1.7.7.jar [deleted file]
lib/Jmol-14.29.17.jar [deleted file]
resources/fts/pdb_data_columns.txt
resources/fts/tdbeacons_data_columns.txt [new file with mode: 0644]
resources/images/3d-beacons-logo-transparent.png [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
schemas/vamsas.xsd
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java
src/jalview/analysis/AlignSeq.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/AnnotationSorter.java
src/jalview/analysis/Conservation.java
src/jalview/analysis/CrossRef.java
src/jalview/analysis/Finder.java
src/jalview/analysis/GeneticCodes.java
src/jalview/analysis/PCA.java
src/jalview/analysis/SequenceIdMatcher.java
src/jalview/analysis/TreeModel.java
src/jalview/api/DBRefEntryI.java
src/jalview/api/FeatureRenderer.java
src/jalview/api/FeatureSettingsModelI.java
src/jalview/api/FeaturesDisplayedI.java
src/jalview/api/structures/JalviewStructureDisplayI.java
src/jalview/bin/Cache.java
src/jalview/bin/Console.java [new file with mode: 0644]
src/jalview/bin/HiDPISetting.java
src/jalview/bin/Jalview.java
src/jalview/bin/JalviewLite.java
src/jalview/bin/Launcher.java
src/jalview/bin/MemorySetting.java
src/jalview/commands/ChangeCaseCommand.java
src/jalview/commands/EditCommand.java
src/jalview/datamodel/AlignedCodonFrame.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/DBRefEntry.java
src/jalview/datamodel/DBRefSource.java
src/jalview/datamodel/MappedFeatures.java
src/jalview/datamodel/Mapping.java
src/jalview/datamodel/PDBEntry.java
src/jalview/datamodel/SearchResults.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceFeature.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/features/FeatureMatcher.java
src/jalview/datamodel/features/FeatureMatcherSet.java
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblInfo.java
src/jalview/ext/ensembl/EnsemblLookup.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/ext/htsjdk/VCFReader.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/jmol/JmolCommands.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/ext/pymol/PymolCommands.java
src/jalview/ext/pymol/PymolManager.java
src/jalview/ext/rbvi/chimera/ChimeraCommands.java
src/jalview/ext/rbvi/chimera/ChimeraXCommands.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/ext/so/SequenceOntology.java
src/jalview/fts/api/FTSRestClientI.java
src/jalview/fts/api/StructureFTSRestClientI.java [new file with mode: 0644]
src/jalview/fts/core/FTSDataColumnPreferences.java
src/jalview/fts/core/FTSRestClient.java
src/jalview/fts/core/FTSRestRequest.java
src/jalview/fts/core/FTSRestResponse.java
src/jalview/fts/core/GFTSPanel.java
src/jalview/fts/service/alphafold/AlphafoldRestClient.java
src/jalview/fts/service/pdb/PDBFTSRestClient.java
src/jalview/fts/service/threedbeacons/.gitignore [new file with mode: 0644]
src/jalview/fts/service/threedbeacons/TDB_FTSData.java [new file with mode: 0644]
src/jalview/fts/service/threedbeacons/TDBeaconsFTSPanel.java [new file with mode: 0644]
src/jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.java [new file with mode: 0644]
src/jalview/gui/APQHandlers.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationExporter.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/BlogReader.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/Console.java
src/jalview/gui/CrossRefAction.java
src/jalview/gui/CutAndPasteHtmlTransfer.java
src/jalview/gui/CutAndPasteTransfer.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FeatureTypeSettings.java
src/jalview/gui/Finder.java
src/jalview/gui/JDatabaseTree.java
src/jalview/gui/OOMWarning.java
src/jalview/gui/OptsAndParamsPage.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/PromptUserConfig.java
src/jalview/gui/PymolBindingModel.java
src/jalview/gui/PymolViewer.java
src/jalview/gui/RotatableCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/Slider.java
src/jalview/gui/SplitFrame.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewer.java
src/jalview/gui/StructureViewerBase.java
src/jalview/gui/TreePanel.java
src/jalview/gui/UserDefinedColours.java
src/jalview/gui/UserQuestionnaireCheck.java
src/jalview/gui/VamsasApplication.java
src/jalview/gui/ViewSelectionMenu.java
src/jalview/gui/WebserviceInfo.java
src/jalview/gui/WsJobParameters.java
src/jalview/gui/WsParamSetManager.java
src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java [new file with mode: 0644]
src/jalview/gui/structurechooser/StructureChooserQuerySource.java [new file with mode: 0644]
src/jalview/gui/structurechooser/TDBResultAnalyser.java [new file with mode: 0644]
src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java [new file with mode: 0644]
src/jalview/io/AlignFile.java
src/jalview/io/AnnotationFile.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/BackupFiles.java
src/jalview/io/BackupFilesPresetEntry.java
src/jalview/io/BioJsHTMLOutput.java
src/jalview/io/EMBLLikeFlatFile.java [new file with mode: 0644]
src/jalview/io/EmblFlatFile.java [new file with mode: 0644]
src/jalview/io/FastaFile.java
src/jalview/io/FeaturesFile.java
src/jalview/io/FileFormat.java
src/jalview/io/FileFormats.java
src/jalview/io/FileLoader.java
src/jalview/io/FileParse.java
src/jalview/io/FormatAdapter.java
src/jalview/io/GenBankFile.java [new file with mode: 0644]
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/io/JPredFile.java
src/jalview/io/JSONFile.java
src/jalview/io/JalviewFileFilter.java
src/jalview/io/JalviewFileView.java
src/jalview/io/JnetAnnotationMaker.java
src/jalview/io/MSFfile.java
src/jalview/io/ModellerDescription.java
src/jalview/io/NewickFile.java
src/jalview/io/PDBFeatureSettings.java
src/jalview/io/SequenceAnnotationReport.java
src/jalview/io/StockholmFile.java
src/jalview/io/StructureFile.java
src/jalview/io/VamsasAppDatastore.java
src/jalview/io/gff/ExonerateHelper.java
src/jalview/io/packed/ParsePackedSet.java
src/jalview/io/vamsas/DatastoreItem.java
src/jalview/io/vamsas/DatastoreRegistry.java
src/jalview/io/vamsas/Dbref.java
src/jalview/io/vamsas/Rangetype.java
src/jalview/io/vamsas/Sequencefeature.java
src/jalview/io/vamsas/Sequencemapping.java
src/jalview/io/vamsas/Tree.java
src/jalview/io/vcf/VCFLoader.java
src/jalview/javascript/MouseOverListener.java
src/jalview/javascript/log4j/Appender.java [deleted file]
src/jalview/javascript/log4j/ConsoleAppender.java [deleted file]
src/jalview/javascript/log4j/Layout.java [deleted file]
src/jalview/javascript/log4j/Level.java [deleted file]
src/jalview/javascript/log4j/Logger.java [deleted file]
src/jalview/javascript/log4j/Priority.java [deleted file]
src/jalview/javascript/log4j/SimpleLayout.java [deleted file]
src/jalview/javascript/log4j/WriterAppender.java [deleted file]
src/jalview/javascript/log4j/spi/LoggingEvent.java [deleted file]
src/jalview/javascript/log4j/spi/OptionHandler.java [deleted file]
src/jalview/jbgui/FilterOption.java [new file with mode: 0644]
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GPreferences.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/jbgui/GWsPreferences.java
src/jalview/json/binding/biojson/v1/ColourSchemeMapper.java
src/jalview/log/JLogger.java [new file with mode: 0644]
src/jalview/log/JLoggerI.java [new file with mode: 0644]
src/jalview/log/JLoggerLog4j.java [new file with mode: 0644]
src/jalview/log/JalviewAppender.java [moved from src/jalview/gui/JalviewAppender.java with 56% similarity]
src/jalview/project/Jalview2XML.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/schemes/ClustalxColourScheme.java
src/jalview/schemes/ColourSchemeLoader.java
src/jalview/schemes/ColourSchemes.java
src/jalview/schemes/FeatureColour.java
src/jalview/schemes/FeatureSettingsAdapter.java
src/jalview/schemes/ResidueProperties.java
src/jalview/schemes/UserColourScheme.java
src/jalview/structure/StructureCommandsBase.java
src/jalview/structure/StructureCommandsI.java
src/jalview/structure/StructureImportSettings.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/urls/UrlLinkTableModel.java
src/jalview/util/BrowserLauncher.java
src/jalview/util/CaseInsensitiveString.java
src/jalview/util/ChannelProperties.java
src/jalview/util/ColorUtils.java
src/jalview/util/Comparison.java
src/jalview/util/DBRefUtils.java
src/jalview/util/DnaUtils.java
src/jalview/util/LaunchUtils.java [new file with mode: 0644]
src/jalview/util/Log4j.java [new file with mode: 0644]
src/jalview/util/MapList.java
src/jalview/util/MappingUtils.java
src/jalview/util/MessageManager.java
src/jalview/util/ParseHtmlBodyAndLinks.java
src/jalview/util/Platform.java
src/jalview/util/StringUtils.java
src/jalview/util/matcher/Matcher.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
src/jalview/viewmodel/seqfeatures/FeaturesDisplayed.java
src/jalview/ws/AWSThread.java
src/jalview/ws/DBRefFetcher.java
src/jalview/ws/SequenceFetcher.java
src/jalview/ws/dbsources/EBIAlfaFold.java
src/jalview/ws/dbsources/EmblCdsSource.java
src/jalview/ws/dbsources/EmblFlatfileSource.java [new file with mode: 0644]
src/jalview/ws/dbsources/EmblSource.java
src/jalview/ws/dbsources/EmblXmlSource.java
src/jalview/ws/dbsources/TDBeacons.java [new file with mode: 0644]
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/dbsources/Xfam.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/io/mime/MimeTypes.java
src/jalview/ws/jws1/Discoverer.java
src/jalview/ws/jws1/JPredClient.java
src/jalview/ws/jws1/JPredThread.java
src/jalview/ws/jws1/MsaWSClient.java
src/jalview/ws/jws1/MsaWSThread.java
src/jalview/ws/jws1/SeqSearchWSClient.java
src/jalview/ws/jws1/SeqSearchWSThread.java
src/jalview/ws/jws2/AADisorderClient.java
src/jalview/ws/jws2/AbstractJabaCalcWorker.java
src/jalview/ws/jws2/JabaWsServerQuery.java
src/jalview/ws/jws2/Jws2Client.java
src/jalview/ws/jws2/Jws2Discoverer.java
src/jalview/ws/jws2/MsaWSClient.java
src/jalview/ws/jws2/MsaWSThread.java
src/jalview/ws/jws2/SequenceAnnotationWSClient.java
src/jalview/ws/jws2/dm/JabaOption.java
src/jalview/ws/rest/HttpResultSet.java
src/jalview/ws/rest/InputType.java
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestJobThread.java
src/jalview/ws/seqfetcher/ASequenceFetcher.java
src/jalview/ws/sifts/SiftsClient.java
src/jalview/xml/binding/jalview/AlcodonFrame.java
src/jalview/xml/binding/jalview/Annotation.java
src/jalview/xml/binding/jalview/AnnotationColourScheme.java
src/jalview/xml/binding/jalview/AnnotationElement.java
src/jalview/xml/binding/jalview/DoubleMatrix.java
src/jalview/xml/binding/jalview/DoubleVector.java
src/jalview/xml/binding/jalview/Feature.java
src/jalview/xml/binding/jalview/FeatureMatcher.java
src/jalview/xml/binding/jalview/FeatureMatcherSet.java
src/jalview/xml/binding/jalview/FilterBy.java
src/jalview/xml/binding/jalview/JalviewModel.java
src/jalview/xml/binding/jalview/JalviewUserColours.java
src/jalview/xml/binding/jalview/MapListType.java
src/jalview/xml/binding/jalview/Mapping.java
src/jalview/xml/binding/jalview/NoValueColour.java
src/jalview/xml/binding/jalview/ObjectFactory.java
src/jalview/xml/binding/jalview/PcaDataType.java
src/jalview/xml/binding/jalview/Pdbentry.java
src/jalview/xml/binding/jalview/Sequence.java
src/jalview/xml/binding/jalview/SequenceSet.java
src/jalview/xml/binding/jalview/SequenceType.java
src/jalview/xml/binding/jalview/ThresholdType.java
src/jalview/xml/binding/jalview/VAMSAS.java
src/jalview/xml/binding/jalview/WebServiceParameterSet.java
src/jalview/xml/binding/jalview/package-info.java
src/mc_view/PDBChain.java
src/mc_view/PDBfile.java
swingjs/SwingJS-site.zip
swingjs/differences.txt
swingjs/net.sf.j2s.core-j11.jar
swingjs/net.sf.j2s.core.jar
swingjs/timestamp
swingjs/ver/3.3.1-j11/DEV_NOTES.txt [new file with mode: 0644]
swingjs/ver/3.3.1-j11/SwingJS-site.zip [new file with mode: 0644]
swingjs/ver/3.3.1-j11/_j2sclasslist.txt [new file with mode: 0644]
swingjs/ver/3.3.1-j11/differences.txt [new file with mode: 0644]
swingjs/ver/3.3.1-j11/net.sf.j2s.core-j11.jar [new file with mode: 0644]
swingjs/ver/3.3.1-j11/timestamp [new file with mode: 0644]
swingjs/ver/3.3.1/DEV_NOTES.txt [new file with mode: 0644]
swingjs/ver/3.3.1/SwingJS-site.zip [new file with mode: 0644]
swingjs/ver/3.3.1/_j2sclasslist.txt [new file with mode: 0644]
swingjs/ver/3.3.1/differences.txt [new file with mode: 0644]
swingjs/ver/3.3.1/net.sf.j2s.core.jar [new file with mode: 0644]
swingjs/ver/3.3.1/timestamp [new file with mode: 0644]
test/jalview/analysis/AlignmentGenerator.java
test/jalview/analysis/CrossRefTest.java
test/jalview/analysis/RnaTest.java
test/jalview/bin/CommandLineOperations.java
test/jalview/bin/HiDPISettingTest2.java
test/jalview/bin/testProps.jvprops
test/jalview/commands/EditCommandTest.java
test/jalview/datamodel/AlignedCodonFrameTest.java
test/jalview/datamodel/DBRefEntryTest.java
test/jalview/datamodel/PDBEntryTest.java
test/jalview/datamodel/ResidueCountTest.java
test/jalview/datamodel/SequenceFeatureTest.java
test/jalview/datamodel/SequenceTest.java
test/jalview/ext/ensembl/EnsemblCdnaTest.java
test/jalview/ext/ensembl/EnsemblGeneTest.java
test/jalview/ext/jmol/JmolCommandsTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/ext/paradise/TestAnnotate3D.java
test/jalview/ext/pymol/PymolCommandsTest.java
test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java
test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java
test/jalview/ext/rbvi/chimera/JalviewChimeraView.java
test/jalview/fts/service/pdb/PDBFTSPanelTest.java
test/jalview/fts/service/pdb/PDBFTSRestClientTest.java
test/jalview/fts/threedbeacons/.gitignore [new file with mode: 0644]
test/jalview/fts/threedbeacons/TDBeaconsFTSRestClientTest.java [new file with mode: 0644]
test/jalview/fts/threedbeacons/TDBeaconsPanelTest.java [new file with mode: 0644]
test/jalview/fts/threedbeacons/p01308_pdbfts_query.txt [new file with mode: 0644]
test/jalview/fts/threedbeacons/p01308_pdbfts_resp.txt [new file with mode: 0644]
test/jalview/fts/threedbeacons/p01308_tdb_resp.txt [new file with mode: 0644]
test/jalview/gui/JAL1353bugdemo.java
test/jalview/gui/PopupMenuTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java [new file with mode: 0644]
test/jalview/io/AnnotationFileIOTest.java
test/jalview/io/BackupFilesTest.java
test/jalview/io/EmblFlatFileTest.java [new file with mode: 0644]
test/jalview/io/FileFormatsTest.java
test/jalview/io/FileIOTester.java
test/jalview/io/GenBankFileTest.java [new file with mode: 0644]
test/jalview/io/IdentifyFileTest.java
test/jalview/io/J03321.embl.txt [new file with mode: 0644]
test/jalview/io/J03321.gb [new file with mode: 0644]
test/jalview/io/J03321_rna.embl.txt [new file with mode: 0644]
test/jalview/io/WindowsFileLoadAndSaveTest.java [new file with mode: 0644]
test/jalview/io/vcf/VCFLoaderTest.java
test/jalview/project/Jalview2xmlTests.java
test/jalview/structures/models/AAStructureBindingModelTest.java
test/jalview/util/Log4jTest.java [new file with mode: 0644]
test/jalview/util/MapListTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/util/log4jTestProps.jvprops [new file with mode: 0644]
test/jalview/ws/dbsources/EmblXmlSourceTest.java [moved from test/jalview/ws/dbsources/EmblSourceTest.java with 91% similarity]
test/jalview/ws/dbsources/UniprotTest.java
test/jalview/ws/ebi/EBIFetchClientTest.java
test/jalview/ws/gui/Jws2ParamView.java
test/jalview/ws/jabaws/DisorderAnnotExportImport.java
test/jalview/ws/jabaws/RNAStructExportImport.java
test/jalview/ws/jws2/ParameterUtilsTest.java
test/jalview/ws/rest/ShmmrRSBSService.java
test/jalview/ws/seqfetcher/DbRefFetcherTest.java
test/junit/extensions/PrivilegedAccessor.java
utils/channels/default/resources/channel.props
utils/channels/develop/images/jalview_develop_logo.svg
utils/channels/release/images/jalview_logo.svg
utils/channels/test-release/channel_gradle.properties
utils/channels/test-release/images/jalview_logo.icns [deleted file]
utils/channels/test-release/images/jalview_logo.ico [deleted file]
utils/channels/test-release/images/jalview_logo.png [deleted file]
utils/channels/test-release/images/jalview_logo.svg [deleted file]
utils/channels/test-release/images/jalview_test-release_banner.xcf
utils/channels/test-release/images/jalview_test-release_getdown_background.png
utils/channels/test-release/images/jalview_test-release_getdown_background.xcf [moved from utils/channels/test-release/images/jalview_getdown_background.xcf with 98% similarity]
utils/channels/test-release/images/jalview_test-release_getdown_background_error.png
utils/channels/test-release/images/jalview_test-release_getdown_background_initialising.png
utils/channels/test-release/images/jalview_test-release_logo-84.png [new file with mode: 0644]
utils/channels/test-release/images/jalview_test-release_logo-88.png [new file with mode: 0644]
utils/channels/test-release/images/jalview_test-release_logo.icns [new file with mode: 0644]
utils/channels/test-release/images/jalview_test-release_logo.ico [new file with mode: 0644]
utils/channels/test-release/images/jalview_test-release_logo.png [new file with mode: 0644]
utils/channels/test-release/images/jalview_test-release_logo.svg [new file with mode: 0644]
utils/channels/test-release/resources/channel.props
utils/channels/test-release/resources/images/jalview_logo-128.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-16.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-256.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-32.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-38.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-48.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-512.png [deleted file]
utils/channels/test-release/resources/images/jalview_logo-64.png [deleted file]
utils/channels/test-release/resources/images/jalview_test-release_banner.png
utils/channels/test-release/resources/images/jalview_test-release_logo-128.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-16.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-256.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-32.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-38.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-48.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-512.png [new file with mode: 0644]
utils/channels/test-release/resources/images/jalview_test-release_logo-64.png [new file with mode: 0644]
utils/channels/test-release/resources/images/rotatable_jalview_logo-38.png [deleted file]
utils/channels/test-release/resources/images/rotatable_jalview_test-release_logo-38.png [new file with mode: 0644]
utils/create_iconfiles.sh [deleted file]
utils/debian/build_gradle.patch [new file with mode: 0644]
utils/debian/debian/icons/128x128/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/icons/16x16/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/icons/16x16/mimetypes/x-jalview-file.png [new file with mode: 0644]
utils/debian/debian/icons/22x22/mimetypes/x-jalview-file.png [new file with mode: 0644]
utils/debian/debian/icons/24x24/mimetypes/x-jalview-file.png [new file with mode: 0644]
utils/debian/debian/icons/256x256/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/icons/32x32/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/icons/32x32/mimetypes/x-jalview-file.png [new file with mode: 0644]
utils/debian/debian/icons/48x48/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/icons/48x48/mimetypes/x-jalview-file.png [new file with mode: 0644]
utils/debian/debian/icons/512x512/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/icons/512x512/mimetypes/x-jalview-file.png [new file with mode: 0644]
utils/debian/debian/icons/64x64/apps/jalview-icon.png [new file with mode: 0644]
utils/debian/debian/jalview-file.png [deleted file]
utils/debian/debian/jalview-mime.xml
utils/debian/debian/jalview.desktop
utils/debian/debian/wrappers/jalview [new file with mode: 0755]
utils/debian/debian_build.gradle [new file with mode: 0644]
utils/debian/etc/jalview_properties [new file with mode: 0644]
utils/debian/file_associations_template-shared-mime-info.xml
utils/debian/mime_types_for_debian.pl
utils/download_jdks.sh
utils/download_jres.sh
utils/install4j/auto_file_associations-i4j8.pl
utils/install4j/file_associations_auto-Info_plist.xml
utils/install4j/file_associations_auto-install4j8.xml
utils/install4j/file_associations_template-install4j8.xml
utils/install4j/install4j8_template.install4j
utils/install4j/jvl_file.icns [new file with mode: 0644]
utils/install4j/jvl_file.ico [new file with mode: 0644]
utils/install4j/jvl_file.png [new file with mode: 0644]
utils/install4j/jvl_file.svg [new file with mode: 0644]
utils/jalviewjs/classlists/jvexamplefile.txt
utils/jalviewjs/libjs/jmol-app.zip
utils/mk_jalview_icons.sh [new file with mode: 0755]

index fa922d9..a202e97 100644 (file)
@@ -29,7 +29,7 @@ httpclient-4.0.3.jar
 httpcore-4.0.1.jar
 httpmime-4.0.3.jar
 intervalstore-v1.0.jar
-jabaws-min-client-2.2.0.jar
+jabaws-min-client-NO_LOG4J-2.2.0.jar   Apache license
 java-json.jar
 jaxrpc.jar
 jersey-client-1.19.4.jar       CDDL 1.1 + GPL2 w/ CPE - http://glassfish.java.net/public/CDDL+GPL_1_1.html
@@ -42,22 +42,25 @@ jetty-util-9.2.10.v20150310.jar
 jfreesvg-2.1.jar       GPL v3 licensed library from the JFree suite - http://www.jfree.org/jfreesvg/
 JGoogleAnalytics_0.3.jar       APL 2.0 License - http://code.google.com/p/jgoogleanalytics/
 jhall.jar
-Jmol-14.6.4_2016.10.26.jar     GPL/LGPLv2 http://sourceforge.net/projects/jmol/files/
+Jmol-14.31.53.jar      GPL/LGPLv2 built manually from commit https://github.com/BobHanson/Jmol-SwingJS/commit/a6a2fb767e3fc2a73e72d926a11fd93a0e4c9f23 (excluded jspecview/application to compile)
 json_simple-1.1.jar    Apache 2.0 license - downloaded from https://code.google.com/p/json-simple/downloads/list (will move to 1.1.1 version when jalview is mavenised and osgi-ised)
 jsoup-1.8.1.jar
 jsr311-api-1.1.1.jar
 jswingreader-0.3.jar   Apache license - built from http://jswingreader.sourceforge.net/ svn/trunk v12
 libquaqua64-8.0.jnilib.jar     quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/ 
 libquaqua-8.0.jnilib.jar       quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/ 
-log4j-1.2.8.jar
+log4j-1.2-api-2.16.0.jar       Apache license version 2.0
+log4j-api-2.16.0.jar   Apache license version 2.0
+log4j-core-2.16.0.jar  Apache license version 2.0
+log4j-slf4j18-impl-2.16.0.jar  Apache license version 2.0
 mail.jar
 miglayout-4.0-swing.jar        BSD - http://www.migcalendar.com/miglayout/versions/4.0/license.txt
 quaqua-filechooser-only-8.0.jar        quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/ 
 regex.jar
 saaj.jar
 servlet-api-3.1.jar
-slf4j-api-1.7.7.jar
-slf4j-log4j12-1.7.7.jar
+slf4j-api-1.7.32.jar   MIT license - https://opensource.org/licenses/mit-license.php
+slf4j-log4j12-1.7.32.jar       MIT license - https://opensource.org/licenses/mit-license.php
 vamsas-client.jar
 VAqua5-patch.jar       This is a patched version of VAqua v5 (latest stable) by Alan Snyder et al. GPLv3 with Classpath exception, also includes contributions from Quaqua: http://violetlib.org/vaqua/overview.html - see doc/patching-vaqua.txt for patch details, and http://issues.jalview.org/browse/JAL-2988 for details of the bug that the patch addresses.
 VARNAv3-93.jar GPL licenced software by K�vin Darty, Alain Denise and Yann Ponty - http://varna.lri.fr
@@ -111,12 +114,9 @@ javax.xml.soap-api.jar     CDDL + GPLv2 with classpath exception - https://github.co
 jaxb-api-2.3.1.jar     CDDL 1.1 + GPL2 w/ CPE - https://oss.oracle.com/licenses/CDDL+GPL-1.1
 jaxb-runtime-2.3.2.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
 jaxws-api-2.3.1.jar    CDDL + GPLv2 with classpath exception - https://github.com/javaee/jax-ws-spec/blob/master/LICENSE.md
-Jmol-14.6.4_2016.10.26-no_netscape.jar GPL/LGPLv2 http://sourceforge.net/projects/jmol/files/
 jsr311-api-1.1.1.jar   CDDL License - http://www.opensource.org/licenses/cddl1.php
 mimepull-1.9.11.jar    Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
 policy-2.7.6.jar       Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
-slf4j-api-1.7.26.jar   MIT License - https://opensource.org/licenses/mit-license.php
-slf4j-log4j12-1.7.26.jar       MIT License - https://opensource.org/licenses/mit-license.php
 stax-ex-1.8.1.jar      Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
 stax2-api-4.2.jar      The BSD License - http://www.opensource.org/licenses/bsd-license.php
 streambuffer-1.5.7.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php
index ee7be0f..34a3461 100644 (file)
@@ -52,6 +52,7 @@ repositories {
 }
 
 
+
 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
 def string(Object o) {
   return o == null ? "" : o.toString()
@@ -102,6 +103,7 @@ ext {
   // Import channel_properties
   channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
   channelGradleProperties = string("${channelDir}/channel_gradle.properties")
+  channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
   overrideProperties(channelGradleProperties, false)
   // local build environment properties
   // can be "projectDir/local.properties"
@@ -419,16 +421,16 @@ ext {
     '--add-modules', j11modules
     ]
      */
-  } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
-    JAVA_INTEGER_VERSION = JAVA_VERSION
-    libDir = j11libDir
-    libDistDir = j11libDir
-    compile_source_compatibility = JAVA_VERSION
-    compile_target_compatibility = JAVA_VERSION
+  } else if (JAVA_VERSION.equals("17")) {
+    JAVA_INTEGER_VERSION = string("17")
+    libDir = j17libDir
+    libDistDir = j17libDir
+    compile_source_compatibility = 17
+    compile_target_compatibility = 17
     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
-    eclipseJavaRuntimeName = string("JavaSE-11")
+    eclipseJavaRuntimeName = string("JavaSE-17")
     /* compile without modules -- using classpath libraries
     additional_compiler_args += [
     '--module-path', modules_compileClasspath.asPath,
@@ -1409,6 +1411,8 @@ jar {
   def outputDir = "${jalviewDir}/${package_dir}"
   destinationDirectory = file(outputDir)
   archiveFileName = rootProject.name+".jar"
+  duplicatesStrategy "EXCLUDE"
+
 
   exclude "cache*/**"
   exclude "*.jar"
@@ -1474,6 +1478,9 @@ shadowJar {
     attributes "Implementation-Version": JALVIEW_VERSION,
     "Application-Name": install4jApplicationName
   }
+
+  duplicatesStrategy "INCLUDE"
+
   mainClassName = shadow_jar_main_class
   mergeServiceFiles()
   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
@@ -1505,6 +1512,12 @@ task getdownWebsite() {
     }
     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
 
+    copy {
+      from channelPropsFile
+      into getdownWebsiteDir
+    }
+    getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
+
     // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
     def props = project.properties.sort { it.key }
     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
@@ -1678,6 +1691,7 @@ task getdownWebsite() {
       from launchJvl
       from getdownLauncher
       from "${getdownWebsiteDir}/${getdown_build_properties}"
+      from "${getdownWebsiteDir}/${channel_props}"
       if (file(getdownLauncher).getName() != getdown_launcher) {
         rename(file(getdownLauncher).getName(), getdown_launcher)
       }
@@ -2393,6 +2407,10 @@ task jalviewjsSyncAllLibs (type: Sync) {
   preserve {
     include "**"
   }
+
+  // should this be exclude really ?
+  duplicatesStrategy "INCLUDE"
+
   outputs.files outputFiles
   inputs.files inputFiles
 }
@@ -2640,7 +2658,7 @@ def jalviewjsCallCore(String name, FileCollection list, String prefixFile, Strin
           new org.apache.tools.ant.util.TeeOutputStream(
             logErrFOS,
             stderr),
-          errorOutput)
+          System.err)
     } else {
       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
         logOutFOS,
similarity index 62%
rename from utils/install4j/README_convert_PNG_to_ICNS_and_ICO
rename to doc/README_convert_PNG_to_ICNS_and_ICO
index cf71c06..11892e0 100644 (file)
@@ -1,4 +1,23 @@
-## Creating the .ico (Windows) and .icns (macOS) files from PNG images in linux
+## There is now a script utils/mk_jalview_icons.sh that creates the .icns and .ico icon files, and also the rotatable icon.
+Run it as
+```
+mk_jalview_icons.sh <BASENAME>-512.png
+```
+Having an existing 512x512 PNG image with the above filename format is important.
+It will then create multiple files
+`<BASENAME>-<N>.png`
+for N being 16, 32, 38, 48, 64, 128, 256.
+**NB** You might want to edit these as described below.  The `mk_jalview_icons.sh` will not overwrite these files, but it
+will overwrite the `.ico` and `.icns` files, so after editing the `<BASENAME>-<N>.png` files, just run the script again.
+
+As below, the script relies on ImageMagick and icnsutils being installed with `convert` and `png2icns` in the PATH.
+
+The rotatable logo will also be created (and overwritten) as
+`rotatable_<BASENAME>-38.png`
+
+
+## Old text
+### Creating the .ico (Windows) and .icns (macOS) files from PNG images in linux
 
 Create multiple square versions of your icon at the following resolutions:
 16x16, 32x32, 48x48, 64x64, 128x128, 256x256, 512x512
@@ -25,7 +44,7 @@ as png2icns complains if it finds one!
 
 This icon is used by the web services progress window, with the rotating Jalview logo.
 It requires some small margin of white pixels around the logo to enable antialiasing around the edge of the logo.
-You can make one form a 48x48 transparent logo with
+You can make one form a 38x38 transparent logo with
 ```
 convert jalview_logo-38.png -gravity center -background white -extent 60x60 rotatable_jalview_logo-38.png
 ```
index df225c8..2cac91c 100644 (file)
@@ -1 +1 @@
-1.8.3-1.2.10_FJVL
+1.8.3-1.2.11_FJVL
index 6f6eed4..99f8359 100644 (file)
@@ -1 +1 @@
-1.8.3-1.2.10_JVL
+1.8.3-1.2.11_JVL
index dadce6e..a11a269 100644 (file)
Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ
index 88036f9..4ac9d5d 100644 (file)
Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ
index 4e2a98c..999c3fa 100644 (file)
Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ
index 9b26d50..e67984c 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.10_FJVL</version>
+    <version>1.8.3-1.2.11_FJVL</version>
   </parent>
 
   <artifactId>getdown-ant</artifactId>
index eb6f388..f909444 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.10_FJVL</version>
+    <version>1.8.3-1.2.11_FJVL</version>
   </parent>
 
   <artifactId>getdown-core</artifactId>
index 2022750..9deb5bc 100644 (file)
@@ -31,7 +31,7 @@ import java.util.zip.GZIPInputStream;
 
 import jalview.bin.HiDPISetting;
 import jalview.bin.MemorySetting;
-//import com.install4j.api.launcher.Variables;
+import jalview.util.LaunchUtils;
 
 import com.threerings.getdown.util.*;
 // avoid ambiguity with java.util.Base64 which we can't use as it's 1.8+
@@ -1181,6 +1181,17 @@ public class Application
             continue;
           }
         }
+
+        // use saved preferences if no cmdline args
+        LaunchUtils.loadChannelProps(getAppDir());
+        if (LaunchUtils.getBooleanUserPreference(MemorySetting.CUSTOMISED_SETTINGS)) {
+          if (jvmmempc == null) {
+            jvmmempc = LaunchUtils.getUserPreference(MemorySetting.MEMORY_JVMMEMPC);
+          }
+          if (jvmmemmax == null) {
+            jvmmemmax = LaunchUtils.getUserPreference(MemorySetting.MEMORY_JVMMEMMAX);
+          }
+        }
         
         // add the memory setting from jvmmempc and jvmmemmax
         long maxMemLong = -1;
@@ -1253,7 +1264,9 @@ public class Application
         String[] sargs = args.toArray(new String[args.size()]);
         log.info("Running " + StringUtil.join(sargs, "\n  "));
 
-        return Runtime.getRuntime().exec(sargs, envp, getAppDir());
+        // don't set the working dir, leave it the same as the working dir of the invocation
+        //return Runtime.getRuntime().exec(sargs, envp, getAppDir());
+        return Runtime.getRuntime().exec(sargs, envp);
     }
 
     /**
index 5d7f14c..55e304d 100644 (file)
@@ -1,4 +1,6 @@
 /*
+
+  private static String ADJUSTMENT_MESSAGE = null;
  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
@@ -31,6 +33,7 @@ package jalview.bin;
  * @author bsoares
  *
  */
+
 public class MemorySetting
 {
   public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = "jvmmempc";
@@ -49,13 +52,33 @@ public class MemorySetting
 
   private static final long NOMEM_MAX_HEAPSIZE_GB_DEFAULT = 8;
 
+  public static final String NS = "MEMORY";
+
+  public static final String CUSTOMISED_SETTINGS = NS
+          + "_CUSTOMISED_SETTINGS";
+
+  public static final String MEMORY_JVMMEMPC = NS + "_"
+          + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.toUpperCase();
+
+  public static final String MEMORY_JVMMEMMAX = NS + "_"
+          + MAX_HEAPSIZE_PROPERTY_NAME.toUpperCase();
+
   protected static boolean logToClassChecked = false;
 
+  public static String memorySuffixes = "bkmgt"; // order of the suffixes is
+                                                 // important!
+
   public static long getMemorySetting()
   {
     return getMemorySetting(null, null);
   }
 
+  public static long getMemorySetting(String jvmmemmaxarg,
+          String jvmmempcarg)
+  {
+    return getMemorySetting(jvmmemmaxarg, jvmmempcarg, true, false);
+  }
+
   /**
    * Decide on appropriate memory setting for Jalview based on the two arguments
    * values: jvmmempc - the maximum percentage of total physical memory to
@@ -83,99 +106,66 @@ public class MemorySetting
    * @param jvmmempcarg
    *          Max percentage of physical memory to use. Defaults to "90".
    * 
+   * @param useProps
+   *          boolean to decide whether to look at System properties.
+   * 
    * @return The amount of memory (in bytes) to allocate to Jalview
    */
   public static long getMemorySetting(String jvmmemmaxarg,
-          String jvmmempcarg)
+          String jvmmempcarg, boolean useProps, boolean quiet)
   {
     // actual Xmx value-to-be
     long maxMemLong = -1;
+    clearAdjustmentMessage();
 
     // (absolute) jvmmaxmem setting, start with default
     long memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
-    if (jvmmemmaxarg == null)
+    if (jvmmemmaxarg == null && useProps)
     {
       jvmmemmaxarg = System.getProperty(MAX_HEAPSIZE_PROPERTY_NAME);
     }
     String jvmmemmax = jvmmemmaxarg;
     if (jvmmemmax != null && jvmmemmax.length() > 0)
     {
-      long multiplier = 1;
-      switch (jvmmemmax.toLowerCase().substring(jvmmemmax.length() - 1))
-      {
-      case "t":
-        multiplier = 1099511627776L; // 2^40
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "g":
-        multiplier = 1073741824; // 2^30
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "m":
-        multiplier = 1048576; // 2^20
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "k":
-        multiplier = 1024; // 2^10
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "b":
-        multiplier = 1; // 2^0
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      default:
-        break;
-      }
-
       // parse the arg
       try
       {
-        memmax = Long.parseLong(jvmmemmax);
+        memmax = memoryStringToLong(jvmmemmax);
+        if (memmax == 0)
+        {
+          throw (new NumberFormatException("Not allowing 0"));
+        }
       } catch (NumberFormatException e)
       {
         memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
-        System.out.println("MemorySetting Property '"
+        setAdjustmentMessage("MemorySetting Property '"
                 + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
-                + "') badly formatted, using default ("
-                + MAX_HEAPSIZE_GB_DEFAULT + "g).");
-      }
-
-      // apply multiplier if not too big (i.e. bigger than a long)
-      if (Long.MAX_VALUE / memmax < multiplier)
-      {
-        memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
-        System.out.println("MemorySetting Property '"
-                + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
-                + ") too big, using default (" + MAX_HEAPSIZE_GB_DEFAULT
-                + "g).");
-      }
-      else
-      {
-        memmax = multiplier * memmax;
+                + "') badly formatted or 0, using default ("
+                + MAX_HEAPSIZE_GB_DEFAULT + "g).", quiet);
       }
 
       // check at least minimum value (this accounts for negatives too)
       if (memmax < APPLICATION_MIN_MEMORY)
       {
         memmax = APPLICATION_MIN_MEMORY;
-        System.out.println("MemorySetting Property '"
+        setAdjustmentMessage("MemorySetting Property '"
                 + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
                 + ") too small, using minimum (" + APPLICATION_MIN_MEMORY
-                + ").");
+                + ").", quiet);
       }
 
     }
     else
     {
       // no need to warn if no setting
-      // System.out.println("MemorySetting Property '" + maxHeapSizeProperty
+      // adjustmentMessage("MemorySetting Property '" + maxHeapSizeProperty
       // + "' not
       // set.");
     }
 
     // get max percent of physical memory, starting with default
     float percent = MAX_HEAPSIZE_PERCENT_DEFAULT;
-    if (jvmmempcarg == null)
+    if (jvmmempcarg == null && useProps)
     {
       jvmmempcarg = System.getProperty(MAX_HEAPSIZE_PERCENT_PROPERTY_NAME);
     }
@@ -185,24 +175,24 @@ public class MemorySetting
     {
       if (jvmmempc != null)
       {
-        float trypercent = Float.parseFloat(jvmmempc);
-        if (0 < trypercent && trypercent <= 100f)
+        int trypercent = Integer.parseInt(jvmmempc);
+        if (0 <= trypercent && trypercent <= 100)
         {
           percent = trypercent;
         }
         else
         {
-          System.out.println("MemorySetting Property '"
+          setAdjustmentMessage("MemorySetting Property '"
                   + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME
-                  + "' should be in range 1..100. Using default " + percent
-                  + "%");
+                  + "' should be in range 0..100. Using default " + percent
+                  + "%", quiet);
         }
       }
     } catch (NumberFormatException e)
     {
-      System.out.println("MemorySetting property '"
+      setAdjustmentMessage("MemorySetting property '"
               + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' (" + jvmmempcarg
-              + ") badly formatted");
+              + ") badly formatted", quiet);
     }
 
     // catch everything in case of no com.sun.management.OperatingSystemMXBean
@@ -223,10 +213,10 @@ public class MemorySetting
         {
           mempc = physicalMem - LEAVE_FREE_MIN_MEMORY;
           reducedmempc = true;
-          System.out.println("MemorySetting Property '"
+          setAdjustmentMessage("MemorySetting Property '"
                   + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' (" + jvmmempcarg
                   + ") too large. Leaving free space for OS and reducing to ("
-                  + mempc + ").");
+                  + mempc + ").", quiet);
         }
 
         // check for minimum application memsize
@@ -234,16 +224,16 @@ public class MemorySetting
         {
           if (reducedmempc)
           {
-            System.out.println("Reduced MemorySetting (" + mempc
+            setAdjustmentMessage("Reduced MemorySetting (" + mempc
                     + ") too small. Increasing to application minimum ("
-                    + APPLICATION_MIN_MEMORY + ").");
+                    + APPLICATION_MIN_MEMORY + ").", quiet);
           }
           else
           {
-            System.out.println("MemorySetting Property '"
+            setAdjustmentMessage("MemorySetting Property '"
                     + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' ("
                     + jvmmempcarg + ") too small. Using minimum ("
-                    + APPLICATION_MIN_MEMORY + ").");
+                    + APPLICATION_MIN_MEMORY + ").", quiet);
           }
           mempc = APPLICATION_MIN_MEMORY;
         }
@@ -252,19 +242,21 @@ public class MemorySetting
       {
         // not enough memory for application, just try and grab what we can!
         mempc = physicalMem;
-        System.out.println(
+        setAdjustmentMessage(
                 "Not enough physical memory for application. Ignoring MemorySetting Property '"
                         + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' ("
                         + jvmmempcarg
                         + "). Using maximum memory available ("
-                        + physicalMem + ").");
+                        + physicalMem + ").",
+                quiet);
       }
 
     } catch (Throwable t)
     {
       memoryPercentError = true;
-      System.out.println(
-              "Problem calling GetMemory.getPhysicalMemory(). Likely to be problem with com.sun.management.OperatingSystemMXBean");
+      setAdjustmentMessage(
+              "Problem calling GetMemory.getPhysicalMemory(). Likely to be problem with com.sun.management.OperatingSystemMXBean",
+              quiet);
       t.printStackTrace();
     }
 
@@ -281,9 +273,10 @@ public class MemorySetting
                                                               // == null))
             && memmax > NOMEM_MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE)
     {
-      System.out.println(
+      setAdjustmentMessage(
               "Capping maximum memory to " + NOMEM_MAX_HEAPSIZE_GB_DEFAULT
-                      + "g due to failure to read physical memory size.");
+                      + "g due to failure to read physical memory size.",
+              quiet);
       memmax = NOMEM_MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
     }
 
@@ -299,4 +292,120 @@ public class MemorySetting
     return maxMemLong;
   }
 
+  public static boolean isValidMemoryString(String text)
+  {
+    if (text.length() > 0)
+    {
+      char lastChar = text.charAt(text.length() - 1);
+      char[] otherChars = text.substring(0, text.length() - 1)
+              .toCharArray();
+      for (char c : otherChars)
+      {
+        if (c < '0' || c > '9')
+        {
+          return false;
+        }
+      }
+      if ((lastChar < '0' || lastChar > '9') && memorySuffixes
+              .indexOf(Character.toLowerCase(lastChar)) == -1)
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static long memoryStringToLong(String memString)
+          throws NumberFormatException
+  {
+    if (!isValidMemoryString(memString)) // not valid
+    {
+      throw (new NumberFormatException("Not a valid memory string"));
+    }
+    char suffix = Character
+            .toLowerCase(memString.charAt(memString.length() - 1));
+    if ('0' <= suffix && suffix <= '9') // no suffix
+    {
+      return Long.valueOf(memString);
+    }
+    if (memorySuffixes.indexOf(suffix) == -1) // suffix is unknown
+    {
+      return -1;
+    }
+
+    long multiplier = (long) Math.pow(2,
+            memorySuffixes.indexOf(suffix) * 10); // note order of suffixes in
+                                                  // memorySuffixes important
+                                                  // here!
+    // parse the arg. NumberFormatExceptions passed on to calling method
+    long mem = Long
+            .parseLong(memString.substring(0, memString.length() - 1));
+    if (mem == 0)
+    {
+      return 0;
+    }
+
+    // apply multiplier only if result is not too big (i.e. bigger than a long)
+    if (Long.MAX_VALUE / mem > multiplier)
+    {
+      return multiplier * mem;
+    }
+    else
+    {
+      // number too big for a Long. Limit to Long.MAX_VALUE
+      System.out.println("Memory parsing of '" + memString
+              + "' produces number too big.  Limiting to Long.MAX_VALUE="
+              + Long.MAX_VALUE);
+      return Long.MAX_VALUE;
+    }
+  }
+
+  public static String memoryLongToString(long mem)
+  {
+    return memoryLongToString(mem, "%.1f");
+  }
+
+  public static String memoryLongToString(long mem, String format)
+  {
+    int exponent = 0;
+    float num = mem;
+    char suffix = 'b';
+
+    for (int i = 0; i < memorySuffixes.length(); i++)
+    {
+      char s = Character.toUpperCase(memorySuffixes.charAt(i));
+      if (mem < (long) Math.pow(2, exponent + 10)
+              || i == memorySuffixes.length() - 1) // last suffix
+      {
+        suffix = s;
+        num = (float) (mem / Math.pow(2, exponent));
+        break;
+      }
+      exponent += 10;
+    }
+
+    return String.format(format, num) + suffix;
+  }
+
+  private static String ADJUSTMENT_MESSAGE = null;
+
+  private static void setAdjustmentMessage(String reason, boolean quiet)
+  {
+    ADJUSTMENT_MESSAGE = reason;
+    if (!quiet)
+    {
+      System.out.println(reason);
+    }
+  }
+
+  public static void clearAdjustmentMessage()
+  {
+    ADJUSTMENT_MESSAGE = null;
+  }
+
+  public static String getAdjustmentMessage()
+  {
+    return ADJUSTMENT_MESSAGE;
+  }
+
 }
\ No newline at end of file
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java b/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java
new file mode 100644 (file)
index 0000000..40f6110
--- /dev/null
@@ -0,0 +1,288 @@
+package jalview.util;
+
+import java.awt.Image;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.swing.ImageIcon;
+
+public class ChannelProperties
+{
+
+  public static final String CHANNEL_PROPERTIES_FILENAME = "channel.props";
+
+  private static Properties channelProps;
+
+  private static final Properties defaultProps;
+
+  private static Map<String, Image> imageMap = new HashMap<String, Image>();
+
+  private static Map<String, URL> urlMap = new HashMap<String, URL>();
+
+  private static final ArrayList<Image> iconList;
+
+  static
+  {
+    defaultProps = new Properties();
+    // these should be kept up to date, but in real life they should never
+    // actually be used anyway.
+    defaultProps.put("app_name", "Jalview");
+    defaultProps.put("banner", "/default_images/jalview_banner.png");
+    defaultProps.put("logo.16", "/default_images/jalview_logo-16.png");
+    defaultProps.put("logo.32", "/default_images/jalview_logo-32.png");
+    defaultProps.put("logo.38", "/default_images/jalview_logo-38.png");
+    defaultProps.put("logo.48", "/default_images/jalview_logo-48.png");
+    defaultProps.put("logo.64", "/default_images/jalview_logo-64.png");
+    defaultProps.put("logo.128", "/default_images/jalview_logo-128.png");
+    defaultProps.put("logo.256", "/default_images/jalview_logo-256.png");
+    defaultProps.put("logo.512", "/default_images/jalview_logo-512.png");
+    defaultProps.put("rotatable_logo.48",
+            "/default_images/rotatable_jalview_logo-38.png");
+    defaultProps.put("bg_logo.28", "/default_images/barton_group-28.png");
+    defaultProps.put("bg_logo.30", "/default_images/barton_group-30.png");
+    defaultProps.put("bg_logo.32", "/default_images/barton_group-32.png");
+    defaultProps.put("uod_banner.28", "/default_images/UoD_banner-28.png");
+    defaultProps.put("uod_banner.30", "/default_images/UoD_banner-30.png");
+    defaultProps.put("uod_banner.32", "/default_images/UoD_banner-32.png");
+    defaultProps.put("default_appbase",
+            "https://www.jalview.org/getdown/release/1.8");
+    defaultProps.put("preferences.filename", ".jalview_properties");
+
+    // load channel_properties
+    Properties tryChannelProps = new Properties();
+    URL channelPropsURL = ChannelProperties.class
+            .getResource("/" + CHANNEL_PROPERTIES_FILENAME);
+    if (channelPropsURL == null)
+    {
+      // complete failure of channel_properties, set all properties to defaults
+      System.err.println("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
+              + "' file at '"
+              + (channelPropsURL == null ? "null"
+                      : channelPropsURL.toString())
+              + "'. Using class defaultProps.");
+      tryChannelProps = defaultProps;
+    }
+    else
+    {
+      try
+      {
+        InputStream channelPropsIS = channelPropsURL.openStream();
+        tryChannelProps.load(channelPropsIS);
+        channelPropsIS.close();
+      } catch (IOException e)
+      {
+        System.err.println(e.getMessage());
+        // return false;
+      }
+    }
+    channelProps = tryChannelProps;
+
+    /*
+     * The following slight palava for caching an icon list is so that all sizes of icons
+     * are the same. i.e. if there are /any/ channel_properties icons to use, then _only_
+     * use those channel_properties icons, don't mix in class default icons for missing
+     * sizes.  If there are _no_ (usable) channel icons then we can use the class default icons.
+     */
+    iconList = new ArrayList<Image>();
+    List<String> sizes = Arrays.asList("16", "32", "48", "64", "128", "256",
+            "512");
+    for (String size : sizes)
+    {
+      Image logo = null;
+      // not using defaults or class props first time through
+      logo = ChannelProperties.getImage("logo." + size, null, false);
+      if (logo != null)
+      {
+        iconList.add(logo);
+      }
+    }
+    // now add the class defaults if there were no channel icons defined
+    if (iconList.size() == 0)
+    {
+      for (String size : sizes)
+      {
+        Image logo = null;
+        String path = defaultProps.getProperty("logo." + size);
+        URL imageURL = ChannelProperties.class.getResource(path);
+        ImageIcon imgIcon = imageURL == null ? null
+                : new ImageIcon(imageURL);
+        logo = imgIcon == null ? null : imgIcon.getImage();
+        if (logo != null)
+        {
+          iconList.add(logo);
+        }
+      }
+    }
+  }
+
+  protected static void loadProps(File dir)
+  {
+    File channelPropsFile = new File(dir, CHANNEL_PROPERTIES_FILENAME);
+    if (channelPropsFile.exists())
+    {
+      try
+      {
+        InputStream is = new FileInputStream(channelPropsFile);
+        channelProps.load(is);
+      } catch (FileNotFoundException e)
+      {
+        System.err.println(e.getMessage());
+      } catch (IOException e)
+      {
+        System.err.println(e.getMessage());
+      }
+    }
+  }
+
+  private static Properties channelProps()
+  {
+    return channelProps;
+  }
+
+  private static Map<String, Image> imageMap()
+  {
+    return imageMap;
+  }
+
+  private static Map<String, URL> urlMap()
+  {
+    return urlMap;
+  }
+
+  /*
+   * getProperty(key) will get property value from channel_properties for key.
+   * If no property for key is found, it will fall back to using the defaultProps defined for this class.
+   */
+  public static String getProperty(String key)
+  {
+    return getProperty(key, null, true);
+  }
+
+  /*
+   * getProperty(key, defaultVal) will get property value from channel_properties for key.
+   * If no property for key is found, it will return defaultVal and NOT fall back to the class defaultProps.
+   */
+  public static String getProperty(String key, String defaultVal)
+  {
+    return getProperty(key, defaultVal, false);
+  }
+
+  /*
+   * internal method.  note that setting useClassDefaultProps=true will ignore the provided defaultVal
+   */
+  private static String getProperty(String key, String defaultVal,
+          boolean useClassDefaultProps)
+  {
+    if (channelProps() != null)
+    {
+      if (channelProps().containsKey(key))
+      {
+        return channelProps().getProperty(key,
+                useClassDefaultProps ? defaultProps.getProperty(key)
+                        : defaultVal);
+      }
+      else
+      {
+        System.err.println("Failed to get channel property '" + key + "'");
+      }
+    }
+    return null;
+  }
+
+  /*
+   * getImage(key) returns the channel defined image for property key. If that is null (e.g. due to
+   * no defined channel image or the image file being corrupt/unusable/missing) it uses the image
+   * defined in defaultChannelProps
+   */
+  public static Image getImage(String key)
+  {
+    return getImage(key, null, true);
+  }
+
+  /*
+   * getImage(key, defaultImg) will get image associated with value from channel_properties for key.
+   * If no property or associated image for key is found (or is usable), it will return defaultImg
+   * and NOT fall back to the class defaultProps.
+   */
+  public static Image getImage(String key, Image defaultImg)
+  {
+    return getImage(key, defaultImg, false);
+  }
+
+  /*
+   * internal method.  note that setting useClassDefaultImage=true will ignore the provided defaultImg
+   */
+  private static Image getImage(String key, Image defaultImg,
+          boolean useClassDefaultImage)
+  {
+    Image img = null;
+    if (imageMap().containsKey(key))
+    {
+      img = imageMap().get(key);
+    }
+    // Catch a previously untried or failed load
+    if (img == null)
+    {
+      String path = getProperty(key, null, useClassDefaultImage);
+      if (path == null) // no channel property or class default property (if
+                        // requested)
+      {
+        return useClassDefaultImage ? null : defaultImg;
+      }
+
+      URL imageURL = ChannelProperties.class.getResource(path);
+      ImageIcon imgIcon = imageURL == null ? null : new ImageIcon(imageURL);
+      img = imgIcon == null ? null : imgIcon.getImage();
+      if (img == null)
+      {
+        System.err.println(
+                "Failed to load channel image " + key + "=" + path);
+        if (!useClassDefaultImage)
+        {
+          return defaultImg;
+        }
+      }
+      else
+      {
+        imageMap().put(key, img);
+        urlMap.put(key, imageURL);
+      }
+    }
+    return img;
+  }
+
+  /*
+   * Public method to get the URL object pointing to a cached image.
+   */
+  public static URL getImageURL(String key)
+  {
+    if (getImage(key) != null)
+    {
+      if (urlMap().containsKey(key))
+      {
+        return urlMap().getOrDefault(key, null);
+      }
+      System.err.println(
+              "Do not use getImageURL(key) before using getImage(key...)");
+    }
+    return null;
+  }
+
+  /*
+   * Get a List of Icon images of different sizes.
+   */
+  public static ArrayList<Image> getIconList()
+  {
+    return iconList;
+  }
+}
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java
new file mode 100644 (file)
index 0000000..3302dba
--- /dev/null
@@ -0,0 +1,56 @@
+package jalview.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Properties;
+
+public class LaunchUtils
+{
+
+  public static void loadChannelProps(File dir)
+  {
+    ChannelProperties.loadProps(dir);
+  }
+
+  private static Properties userPreferences = null;
+
+  public static String getUserPreference(String key)
+  {
+    if (userPreferences == null)
+    {
+      String channelPrefsFilename = ChannelProperties
+              .getProperty("preferences.filename");
+      if (channelPrefsFilename == null)
+      {
+        return null;
+      }
+      File propertiesFile = new File(System.getProperty("user.home"),
+              channelPrefsFilename);
+      if (!propertiesFile.exists())
+      {
+        return null;
+      }
+      try
+      {
+        userPreferences = new Properties();
+        userPreferences.load(new FileInputStream(propertiesFile));
+      } catch (FileNotFoundException e)
+      {
+        // didn't find user preferences file
+        return null;
+      } catch (IOException e)
+      {
+        System.err.println(e.getMessage());
+        return null;
+      }
+    }
+    return userPreferences.getProperty(key);
+  }
+
+  public static boolean getBooleanUserPreference(String key)
+  {
+    return Boolean.parseBoolean(getUserPreference(key));
+  }
+}
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java
new file mode 100644 (file)
index 0000000..d758395
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * 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.
+ */
+package jalview.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class StringUtils
+{
+  private static final Pattern DELIMITERS_PATTERN = Pattern
+          .compile(".*='[^']*(?!')");
+
+  private static final char PERCENT = '%';
+
+  private static final boolean DEBUG = false;
+
+  /*
+   * URL encoded characters, indexed by char value
+   * e.g. urlEncodings['='] = urlEncodings[61] = "%3D"
+   */
+  private static String[] urlEncodings = new String[255];
+
+  /**
+   * Returns a new character array, after inserting characters into the given
+   * character array.
+   * 
+   * @param in
+   *          the character array to insert into
+   * @param position
+   *          the 0-based position for insertion
+   * @param count
+   *          the number of characters to insert
+   * @param ch
+   *          the character to insert
+   */
+  public static final char[] insertCharAt(char[] in, int position,
+          int count, char ch)
+  {
+    char[] tmp = new char[in.length + count];
+
+    if (position >= in.length)
+    {
+      System.arraycopy(in, 0, tmp, 0, in.length);
+      position = in.length;
+    }
+    else
+    {
+      System.arraycopy(in, 0, tmp, 0, position);
+    }
+
+    int index = position;
+    while (count > 0)
+    {
+      tmp[index++] = ch;
+      count--;
+    }
+
+    if (position < in.length)
+    {
+      System.arraycopy(in, position, tmp, index, in.length - position);
+    }
+
+    return tmp;
+  }
+
+  /**
+   * Delete
+   * 
+   * @param in
+   * @param from
+   * @param to
+   * @return
+   */
+  public static final char[] deleteChars(char[] in, int from, int to)
+  {
+    if (from >= in.length || from < 0)
+    {
+      return in;
+    }
+
+    char[] tmp;
+
+    if (to >= in.length)
+    {
+      tmp = new char[from];
+      System.arraycopy(in, 0, tmp, 0, from);
+      to = in.length;
+    }
+    else
+    {
+      tmp = new char[in.length - to + from];
+      System.arraycopy(in, 0, tmp, 0, from);
+      System.arraycopy(in, to, tmp, from, in.length - to);
+    }
+    return tmp;
+  }
+
+  /**
+   * Returns the last part of 'input' after the last occurrence of 'token'. For
+   * example to extract only the filename from a full path or URL.
+   * 
+   * @param input
+   * @param token
+   *          a delimiter which must be in regular expression format
+   * @return
+   */
+  public static String getLastToken(String input, String token)
+  {
+    if (input == null)
+    {
+      return null;
+    }
+    if (token == null)
+    {
+      return input;
+    }
+    String[] st = input.split(token);
+    return st[st.length - 1];
+  }
+
+  /**
+   * Parses the input string into components separated by the delimiter. Unlike
+   * String.split(), this method will ignore occurrences of the delimiter which
+   * are nested within single quotes in name-value pair values, e.g. a='b,c'.
+   * 
+   * @param input
+   * @param delimiter
+   * @return elements separated by separator
+   */
+  public static String[] separatorListToArray(String input,
+          String delimiter)
+  {
+    int seplen = delimiter.length();
+    if (input == null || input.equals("") || input.equals(delimiter))
+    {
+      return null;
+    }
+    List<String> jv = new ArrayList<>();
+    int cp = 0, pos, escape;
+    boolean wasescaped = false, wasquoted = false;
+    String lstitem = null;
+    while ((pos = input.indexOf(delimiter, cp)) >= cp)
+    {
+      escape = (pos > 0 && input.charAt(pos - 1) == '\\') ? -1 : 0;
+      if (wasescaped || wasquoted)
+      {
+        // append to previous pos
+        jv.set(jv.size() - 1, lstitem = lstitem + delimiter
+                + input.substring(cp, pos + escape));
+      }
+      else
+      {
+        jv.add(lstitem = input.substring(cp, pos + escape));
+      }
+      cp = pos + seplen;
+      wasescaped = escape == -1;
+      // last separator may be in an unmatched quote
+      wasquoted = DELIMITERS_PATTERN.matcher(lstitem).matches();
+    }
+    if (cp < input.length())
+    {
+      String c = input.substring(cp);
+      if (wasescaped || wasquoted)
+      {
+        // append final separator
+        jv.set(jv.size() - 1, lstitem + delimiter + c);
+      }
+      else
+      {
+        if (!c.equals(delimiter))
+        {
+          jv.add(c);
+        }
+      }
+    }
+    if (jv.size() > 0)
+    {
+      String[] v = jv.toArray(new String[jv.size()]);
+      jv.clear();
+      if (DEBUG)
+      {
+        System.err.println("Array from '" + delimiter
+                + "' separated List:\n" + v.length);
+        for (int i = 0; i < v.length; i++)
+        {
+          System.err.println("item " + i + " '" + v[i] + "'");
+        }
+      }
+      return v;
+    }
+    if (DEBUG)
+    {
+      System.err.println(
+              "Empty Array from '" + delimiter + "' separated List");
+    }
+    return null;
+  }
+
+  /**
+   * Returns a string which contains the list elements delimited by the
+   * separator. Null items are ignored. If the input is null or has length zero,
+   * a single delimiter is returned.
+   * 
+   * @param list
+   * @param separator
+   * @return concatenated string
+   */
+  public static String arrayToSeparatorList(String[] list, String separator)
+  {
+    StringBuffer v = new StringBuffer();
+    if (list != null && list.length > 0)
+    {
+      for (int i = 0, iSize = list.length; i < iSize; i++)
+      {
+        if (list[i] != null)
+        {
+          if (v.length() > 0)
+          {
+            v.append(separator);
+          }
+          // TODO - escape any separator values in list[i]
+          v.append(list[i]);
+        }
+      }
+      if (DEBUG)
+      {
+        System.err
+                .println("Returning '" + separator + "' separated List:\n");
+        System.err.println(v);
+      }
+      return v.toString();
+    }
+    if (DEBUG)
+    {
+      System.err.println(
+              "Returning empty '" + separator + "' separated List\n");
+    }
+    return "" + separator;
+  }
+
+  /**
+   * Converts a list to a string with a delimiter before each term except the
+   * first. Returns an empty string given a null or zero-length argument. This
+   * can be replaced with StringJoiner in Java 8.
+   * 
+   * @param terms
+   * @param delim
+   * @return
+   */
+  public static String listToDelimitedString(List<String> terms,
+          String delim)
+  {
+    StringBuilder sb = new StringBuilder(32);
+    if (terms != null && !terms.isEmpty())
+    {
+      boolean appended = false;
+      for (String term : terms)
+      {
+        if (appended)
+        {
+          sb.append(delim);
+        }
+        appended = true;
+        sb.append(term);
+      }
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Convenience method to parse a string to an integer, returning 0 if the
+   * input is null or not a valid integer
+   * 
+   * @param s
+   * @return
+   */
+  public static int parseInt(String s)
+  {
+    int result = 0;
+    if (s != null && s.length() > 0)
+    {
+      try
+      {
+        result = Integer.parseInt(s);
+      } catch (NumberFormatException ex)
+      {
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Compares two versions formatted as e.g. "3.4.5" and returns -1, 0 or 1 as
+   * the first version precedes, is equal to, or follows the second
+   * 
+   * @param v1
+   * @param v2
+   * @return
+   */
+  public static int compareVersions(String v1, String v2)
+  {
+    return compareVersions(v1, v2, null);
+  }
+
+  /**
+   * Compares two versions formatted as e.g. "3.4.5b1" and returns -1, 0 or 1 as
+   * the first version precedes, is equal to, or follows the second
+   * 
+   * @param v1
+   * @param v2
+   * @param pointSeparator
+   *          a string used to delimit point increments in sub-tokens of the
+   *          version
+   * @return
+   */
+  public static int compareVersions(String v1, String v2,
+          String pointSeparator)
+  {
+    if (v1 == null || v2 == null)
+    {
+      return 0;
+    }
+    String[] toks1 = v1.split("\\.");
+    String[] toks2 = v2.split("\\.");
+    int i = 0;
+    for (; i < toks1.length; i++)
+    {
+      if (i >= toks2.length)
+      {
+        /*
+         * extra tokens in v1
+         */
+        return 1;
+      }
+      String tok1 = toks1[i];
+      String tok2 = toks2[i];
+      if (pointSeparator != null)
+      {
+        /*
+         * convert e.g. 5b2 into decimal 5.2 for comparison purposes
+         */
+        tok1 = tok1.replace(pointSeparator, ".");
+        tok2 = tok2.replace(pointSeparator, ".");
+      }
+      try
+      {
+        float f1 = Float.valueOf(tok1);
+        float f2 = Float.valueOf(tok2);
+        int comp = Float.compare(f1, f2);
+        if (comp != 0)
+        {
+          return comp;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.err
+                .println("Invalid version format found: " + e.getMessage());
+        return 0;
+      }
+    }
+
+    if (i < toks2.length)
+    {
+      /*
+       * extra tokens in v2 
+       */
+      return -1;
+    }
+
+    /*
+     * same length, all tokens match
+     */
+    return 0;
+  }
+
+  /**
+   * Converts the string to all lower-case except the first character which is
+   * upper-cased
+   * 
+   * @param s
+   * @return
+   */
+  public static String toSentenceCase(String s)
+  {
+    if (s == null)
+    {
+      return s;
+    }
+    if (s.length() <= 1)
+    {
+      return s.toUpperCase();
+    }
+    return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+  }
+
+  /**
+   * A helper method that strips off any leading or trailing html and body tags.
+   * If no html tag is found, then also html-encodes angle bracket characters.
+   * 
+   * @param text
+   * @return
+   */
+  public static String stripHtmlTags(String text)
+  {
+    if (text == null)
+    {
+      return null;
+    }
+    String tmp2up = text.toUpperCase();
+    int startTag = tmp2up.indexOf("<HTML>");
+    if (startTag > -1)
+    {
+      text = text.substring(startTag + 6);
+      tmp2up = tmp2up.substring(startTag + 6);
+    }
+    // is omission of "<BODY>" intentional here??
+    int endTag = tmp2up.indexOf("</BODY>");
+    if (endTag > -1)
+    {
+      text = text.substring(0, endTag);
+      tmp2up = tmp2up.substring(0, endTag);
+    }
+    endTag = tmp2up.indexOf("</HTML>");
+    if (endTag > -1)
+    {
+      text = text.substring(0, endTag);
+    }
+
+    if (startTag == -1 && (text.contains("<") || text.contains(">")))
+    {
+      text = text.replaceAll("<", "&lt;");
+      text = text.replaceAll(">", "&gt;");
+    }
+    return text;
+  }
+
+  /**
+   * Answers the input string with any occurrences of the 'encodeable'
+   * characters replaced by their URL encoding
+   * 
+   * @param s
+   * @param encodable
+   * @return
+   */
+  public static String urlEncode(String s, String encodable)
+  {
+    if (s == null || s.isEmpty())
+    {
+      return s;
+    }
+
+    /*
+     * do % encoding first, as otherwise it may double-encode!
+     */
+    if (encodable.indexOf(PERCENT) != -1)
+    {
+      s = urlEncode(s, PERCENT);
+    }
+
+    for (char c : encodable.toCharArray())
+    {
+      if (c != PERCENT)
+      {
+        s = urlEncode(s, c);
+      }
+    }
+    return s;
+  }
+
+  /**
+   * Answers the input string with any occurrences of {@code c} replaced with
+   * their url encoding. Answers the input string if it is unchanged.
+   * 
+   * @param s
+   * @param c
+   * @return
+   */
+  static String urlEncode(String s, char c)
+  {
+    String decoded = String.valueOf(c);
+    if (s.indexOf(decoded) != -1)
+    {
+      String encoded = getUrlEncoding(c);
+      if (!encoded.equals(decoded))
+      {
+        s = s.replace(decoded, encoded);
+      }
+    }
+    return s;
+  }
+
+  /**
+   * Answers the input string with any occurrences of the specified (unencoded)
+   * characters replaced by their URL decoding.
+   * <p>
+   * Example: {@code urlDecode("a%3Db%3Bc", "-;=,")} should answer
+   * {@code "a=b;c"}.
+   * 
+   * @param s
+   * @param encodable
+   * @return
+   */
+  public static String urlDecode(String s, String encodable)
+  {
+    if (s == null || s.isEmpty())
+    {
+      return s;
+    }
+
+    for (char c : encodable.toCharArray())
+    {
+      String encoded = getUrlEncoding(c);
+      if (s.indexOf(encoded) != -1)
+      {
+        String decoded = String.valueOf(c);
+        s = s.replace(encoded, decoded);
+      }
+    }
+    return s;
+  }
+
+  /**
+   * Does a lazy lookup of the url encoding of the given character, saving the
+   * value for repeat lookups
+   * 
+   * @param c
+   * @return
+   */
+  private static String getUrlEncoding(char c)
+  {
+    if (c < 0 || c >= urlEncodings.length)
+    {
+      return String.valueOf(c);
+    }
+
+    String enc = urlEncodings[c];
+    if (enc == null)
+    {
+      try
+      {
+        enc = urlEncodings[c] = URLEncoder.encode(String.valueOf(c),
+                "UTF-8");
+      } catch (UnsupportedEncodingException e)
+      {
+        enc = urlEncodings[c] = String.valueOf(c);
+      }
+    }
+    return enc;
+  }
+
+  public static int firstCharPosIgnoreCase(String text, String chars)
+  {
+    int min = text.length() + 1;
+    for (char c : chars.toLowerCase().toCharArray())
+    {
+      int i = text.toLowerCase().indexOf(c);
+      if (0 <= i && i < min)
+      {
+        min = i;
+      }
+    }
+    return min < text.length() + 1 ? min : -1;
+  }
+}
index b5e68f2..5284412 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.10_FJVL</version>
+    <version>1.8.3-1.2.11_FJVL</version>
   </parent>
 
   <artifactId>getdown-launcher</artifactId>
index 2178273..5d697df 100644 (file)
@@ -40,6 +40,12 @@ public final class ProxyPanel extends JPanel implements ActionListener
         _getdown = getdown;
         _msgs = msgs;
 
+        String[] hostPortAuthUser = ProxyUtil.jalviewProxyProperties(getdown._app);
+        String host = hostPortAuthUser[0];
+        String port = hostPortAuthUser[1];
+        boolean proxyAuth = Boolean.parseBoolean(hostPortAuthUser[2]);
+        String username = hostPortAuthUser[3];
+
         setLayout(new VGroupLayout());
         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
         add(new SaneLabelField(get("m.configure_proxy")));
@@ -48,11 +54,13 @@ public final class ProxyPanel extends JPanel implements ActionListener
         JPanel row = new JPanel(new GridLayout());
         row.add(new SaneLabelField(get("m.proxy_host")), BorderLayout.WEST);
         row.add(_host = new SaneTextField());
+        _host.setText(host);
         add(row);
 
         row = new JPanel(new GridLayout());
         row.add(new SaneLabelField(get("m.proxy_port")), BorderLayout.WEST);
         row.add(_port = new SaneTextField());
+        _port.setText(port);
         add(row);
 
         add(new Spacer(5, 5));
@@ -60,20 +68,22 @@ public final class ProxyPanel extends JPanel implements ActionListener
         row = new JPanel(new GridLayout());
         row.add(new SaneLabelField(get("m.proxy_auth_required")), BorderLayout.WEST);
         _useAuth = new JCheckBox();
+        _useAuth.setSelected(proxyAuth);
         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);
+        _username.setText(username);
+        _username.setEnabled(_useAuth.isSelected());
         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);
+        _password.setEnabled(_useAuth.isSelected());
         row.add(_password);
         add(row);
 
index a36b5fa..cb51ca4 100644 (file)
@@ -6,8 +6,10 @@
 package com.threerings.getdown.launcher;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintStream;
 import java.net.Authenticator;
 import java.net.HttpURLConnection;
@@ -19,6 +21,8 @@ import java.net.URLConnection;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
+import jalview.util.LaunchUtils;
+
 import ca.beq.util.win32.registry.RegistryKey;
 import ca.beq.util.win32.registry.RegistryValue;
 import ca.beq.util.win32.registry.RootKey;
@@ -88,15 +92,43 @@ public class ProxyUtil {
             port = hostPort[1];
         }
 
+        // look in jalview_properties
+        String[] hostPortAuthUser = jalviewProxyProperties(app);
+        host = hostPortAuthUser[0];
+        port = hostPortAuthUser[1];
+        boolean proxyAuth = Boolean.parseBoolean(hostPortAuthUser[2]);
+        String username = hostPortAuthUser[3];
+
         if (StringUtil.isBlank(host)) {
             return false;
         }
 
         // yay, we found a proxy configuration, configure it in the app
-        initProxy(app, host, port, null, null);
+        initProxy(app, host, port, username, null);
         return true;
     }
 
+    public static String[] jalviewProxyProperties(Application app) {
+      String host = null;
+      String port = null;
+      boolean proxyAuth = false;
+      String username = null;
+      LaunchUtils.loadChannelProps(app.getAppDir());
+      if (LaunchUtils.getBooleanUserPreference("USE_PROXY")) {
+        host = LaunchUtils.getUserPreference("PROXY_SERVER_HTTPS");
+        port = LaunchUtils.getUserPreference("PROXY_PORT_HTTPS");
+        if (StringUtil.isBlank(host)) {
+          host = LaunchUtils.getUserPreference("PROXY_SERVER");
+          port = LaunchUtils.getUserPreference("PROXY_PORT");
+        }
+        proxyAuth = LaunchUtils.getBooleanUserPreference("PROXY_AUTH");
+        if (proxyAuth) {
+          username = LaunchUtils.getUserPreference("PROXY_AUTH_USERNAME");
+        }
+      }
+      return new String[]{ host, port, String.valueOf(proxyAuth), username };
+    }
+
     public static boolean canLoadWithoutProxy (URL rurl)
     {
         log.info("Testing whether proxy is needed, via: " + rurl);
@@ -179,6 +211,7 @@ public class ProxyUtil {
     public static void initProxy (Application app, String host, String port,
                                   String username, String password)
     {
+System.out.println("**** initProxy(app, '"+host+"', "+port+", '"+username+"', "+(password==null?"null":"*x"+password.length())+")");
         // check whether we have saved proxy credentials
         String appDir = app.getAppDir().getAbsolutePath();
         ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
index 65e5fb9..4ffb086 100755 (executable)
@@ -3,7 +3,7 @@
 if [ x$JVLVERSION != x ]; then
   export VERSION=$JVLVERSION
 else
-  export VERSION=1.8.3-1.2.10_JVL
+  export VERSION=1.8.3-1.2.11_JVL
 fi
 
 if [ x${VERSION%_JVL} = x$VERSION ]; then
index 7a0fd27..61b1440 100644 (file)
@@ -10,7 +10,7 @@
   <groupId>com.threerings.getdown</groupId>
   <artifactId>getdown</artifactId>
   <packaging>pom</packaging>
-  <version>1.8.3-1.2.10_FJVL</version>
+  <version>1.8.3-1.2.11_FJVL</version>
 
   <name>getdown</name>
   <description>An application installer and updater.</description>
index d0fb57d..8eec281 100644 (file)
@@ -100,8 +100,8 @@ getdown_alt_java8_min_version  = 01080000
 getdown_alt_java8_max_version  = 01089999
 getdown_alt_java11_min_version = 11000000
 getdown_alt_java11_max_version =
-#getdown_alt_java11_txt_multi_java_location = [windows-amd64] /getdown/jre/windows-jre11.jar,[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
+#getdown_alt_java11_txt_multi_java_location = [windows-amd64] /getdown/jre/jre-11-windows-x64.zip,[linux-amd64] /getdown/jre/jre-11-linux-x64.zip,[mac os x] /getdown/jre/jre-11-mac-x64.zip
+#getdown_alt_java8_txt_multi_java_location = [windows-amd64] /getdown/jre/jre-8-windows-x64.zip,[linux-amd64] /getdown/jre/jre-8-linux-x64.zip,[mac os x] /getdown/jre/jre-8-mac-x64.zip
 jre_installs_dir = ~/buildtools/jre
 
 j8libDir = j8lib
@@ -112,6 +112,7 @@ j11modules = com.sun.istack.runtime,com.sun.xml.bind,com.sun.xml.fastinfoset,com
 flexmark_css = utils/doc/github.css
 
 channel_properties_dir = utils/channels
+channel_props = channel.props
 
 install4j_home_dir = ~/buildtools/install4j8
 install4j_copyright_message = ...
@@ -222,7 +223,7 @@ j2s.excluded.paths = test;testng;util
 #j2s.compiler.nonqualified.classes = null
 #j2s.compiler.mode = debug
 #a semicolon-separated list of package (foo.) or class (foo.bar) replacements to be made 
-j2s.class.replacements = org.apache.log4j.->jalview.javascript.log4j.
+#j2s.class.replacements = org.apache.logging.log4j.->jalview.javascript.log4j.
 j2s.template.html = utils/jalviewjs/template.html
 j2s_coretemplate_html = utils/jalviewjs/coretemplate.html
 #output file name for logging methods declared - delete the file to regenerate a listing 
index 99d010d..449f34c 100755 (executable)
@@ -55,6 +55,7 @@
    <mapID target="pdbmcviewer" url="html/features/pdbviewer.html"/>
    <mapID target="pdbjmol" url="html/features/jmol.html"/>
    <mapID target="chimera" url="html/features/chimera.html"/>
+   <mapID target="pymol" url="html/features/pymol.html"/>
    <mapID target="chimera.annotxfer" url="html/features/chimera.html#annotxfer"/>
    <mapID target="varna" url="html/features/varna.html"/>
    <mapID target="xsspannotation" url="html/features/xsspannotation.html"/>
    
    <mapID target="importvcf" url="html/features/importvcf.html" />
    <mapID target="importvcf.attribs" url="html/features/importvcf.html#attribs" />
+   <mapID target="logging" url="html/logging.html" />
 </map>
index a0c7fe6..9f1942c 100755 (executable)
@@ -27,7 +27,7 @@
         <tocitem text="Virtual Features in CDS/Protein Views" target="splitframe.virtualfeats"/>
                                <tocitem text="VCF Variant Attributes" target="importvcf.attribs"/>
                                <tocitem text="Feature Filters and Attribute Colourschemes" target="features.featureschemes" />
-                               
+        <tocitem text="The Java Console, Logging and Reporting Bugs" target="logging" />
                </tocitem>
                
                <tocitem text="Editing Alignments" target="edit" />
                </tocitem>
                <tocitem text="3D Structure Data" target="viewingpdbs" expand="false">
                        <tocitem text="PDB Sequence Fetcher" target="pdbfetcher" />
-                       <tocitem text="PDB Structure Chooser" target="pdbchooser" />
+                       <tocitem text="PDB &amp; 3D-Beacons Structure Chooser" target="pdbchooser" />
                        <tocitem text="Jmol Viewer" target="pdbjmol" />
-                       <tocitem text="Chimera Viewer" target="chimera" />                      
+                       <tocitem text="Chimera Viewer" target="chimera" />
+                       <tocitem text="Pymol Viewer" target="pymol" />                  
                </tocitem>
                <tocitem text="Viewing RNA structures" target="varna" expand="false"/>
                <tocitem text="Opening URLs from Jalview" target="urllinks" expand="true">
                        </tocitem>
                </tocitem>
                <tocitem text="Preferences" target="preferences" />
+    <tocitem text="The Java Console, Logging and Reporting Bugs" target="logging" />
                <tocitem text="Scripting with Groovy" target="groovy">
                        <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
                </tocitem>
diff --git a/help/help/html/features/3dbeacons_button.png b/help/help/html/features/3dbeacons_button.png
new file mode 100644 (file)
index 0000000..2dae1f6
Binary files /dev/null and b/help/help/html/features/3dbeacons_button.png differ
diff --git a/help/help/html/features/3dbeacons_structurechooser.png b/help/help/html/features/3dbeacons_structurechooser.png
new file mode 100644 (file)
index 0000000..cd7fdab
Binary files /dev/null and b/help/help/html/features/3dbeacons_structurechooser.png differ
diff --git a/help/help/html/features/3dstructuredata_popupmenu.png b/help/help/html/features/3dstructuredata_popupmenu.png
new file mode 100644 (file)
index 0000000..e5de4ca
Binary files /dev/null and b/help/help/html/features/3dstructuredata_popupmenu.png differ
index fcdb908..3517929 100755 (executable)
@@ -189,6 +189,7 @@ GRAPHLINE&#9;<em>graph_name</em>&#9;<em>value</em>&#9;<em>label</em>&#9;<em>colo
         available in Jalview applet due to AWT 1.1 limitations</em>)</li>
   </ul>
   </p>
+  <hr />
   <p>
     <strong><a name="groupdefs">SEQUENCE_GROUP</a></strong><br />
     Groups of sequences and column ranges can be defined using a tab
@@ -199,7 +200,8 @@ GRAPHLINE&#9;<em>graph_name</em>&#9;<em>value</em>&#9;<em>label</em>&#9;<em>colo
   <p>The sequences can be defined by alignment index and a range of
     sequences can be defined in a comma delimited field such as</p>
   <p>2-5,8-15,20,22</p>
-  <p>Enter * to select all groups.</p>
+  <p>Enter * to select all sequences.</p>
+  <p>Set both <em>Group_Start</em> and <em>Group_End</em> to * to include the full sequence(s) range.
   <p>
     <strong>Note:</strong> If the alignment indices are not known, enter
     -1, followed by a tab and then a tab delimited list of sequence IDs.
index e1227de..eadfa06 100644 (file)
 </head>
 <body>
   <p>
-    <strong>The Chimera Viewer</strong>
+    <strong>The Chimera and ChimeraX Viewers</strong>
   </p>
   <p>
     Since Jalview 2.8.2, <a href="http://www.cgl.ucsf.edu/chimera/">Chimera</a>
     (http://www.cgl.ucsf.edu/chimera/) can be used for viewing
     structures opened via the <a href="structurechooser.html"><strong>&quot;View
-        Structure Data..&quot;</strong> dialog</a>.
+    Structure Data..&quot;</strong> dialog</a>. In Jalview 2.11.2, support 
+    was also added for ChimeraX.
   </p>
   <p>
     You can set a default choice of Jmol or Chimera structure viewer in
index 0d800cf..1eecfb9 100644 (file)
   parameters, then include it at the beginning of the command line to
   ensure they are processed before any remaining arguments.
   <br>
+  Typical command line execution follows the following pattern:
+  <pre>
+  jalview -open &lt;Alignment File/URL&gt; [additional import arguments] [export arguments]
+  </pre>
+  
   <table width="100%" border="1" cellspacing="0" cellpadding="0">
     <tr>
       <td width="27%"><div align="center">-nodisplay</div></td>
           User Interface. (automatically disables questionnaire, version
           and usage stats checks)</div></td>
     </tr>
-
+    <tr>
+      <td><div align="center">-open FILE/URL</div></td>
+      <td><div align="left">Specify the alignment file to
+          open or process by providing additional arguments.</div></td>
+    </tr>
     <tr>
       <td><div align="center">-props FILE/URL</div></td>
       <td><div align="left">Use the given Jalview properties
index e00d390..0ef78f9 100644 (file)
@@ -38,7 +38,7 @@
 
   <ul>
     <li>Standard installation on Linux/Unix:<pre>
-       /PATH_TO_JALVIEW/Jalview -open http://www.jalview.org/examples/jpred_msa.fasta -annotations http://www.jalview.org/examples/jpred_msa.seq.concise -colour Clustal</pre>
+       /PATH_TO_JALVIEW/Jalview -open https://www.jalview.org/examples/jpred_msa.fasta -annotations https://www.jalview.org/examples/jpred_msa.seq.concise -colour Clustal</pre>
     </li>
     <li>Standard installation on Windows:<pre>
       \PATH_TO_JALVIEW\Jalview.exe -open %HOMEPATH%\myalignment.fa</pre>
@@ -65,10 +65,31 @@ open /Applications/Jalview.app --args -open ~/myalignment.fa</pre><em>(put
   </p>
   <p>
     <strong>Passing JVM Arguments to Jalview</strong><br /> If you need
-    to modify parameters for Jalview's Java Virtual Machine, then take a
-    look at the instructions for how to <a href="../memory.html#jvm">setting
-      the JVM's maximum memory</a>.
+    to modify parameters for Jalview's Java Virtual Machine, or
+    configure system properties, then take a look at the instructions
+    for how to <a href="../memory.html#jvm">setting the JVM's
+      maximum memory</a>.<br /> 
+  <p>
+    <strong>Changing Jalview's 'Look and Feel'</strong> <br />If you
+    are experiencing issues with the font size or layout of Jalview's
+    GUI, you can try changing Jalview's 'Look and feel' by
+    specifying a custom system property 'laf' on startup (see <a
+      href="../memory.html#jvm">setting the JVM's memory</a> for
+    instructions on how to do this for your platform). <br />For the
+    Jalview standalone executable jar, simply provide one of the
+    property settings before the -jar argument
   </p>
+  <ul>
+    <li>-Dlaf=system (default look and feel for the OS)</li>
+    <li>-Dlaf=crossplatform (Java's Metal Look and Feel)</li>
+    <li>-Dlaf=nimbus (Java's alternative Nimbus Look and Feel)</li>
+    <li>-Dlaf=mac (only has an effect on OSX)</li>
+    <li>-Dlaf=gtk (only has an effect on Linux)</li>
+  </ul>
+  The currently configured look and feel is logged to Jalview's console.
+  Once the look and feel has been changed, it will be stored in
+  Jalview's .jalview_properties file for future Jalview sessions.
+
   <p>&nbsp;</p>
   <p>&nbsp;</p>
 </body>
index ead4436..cc91154 100644 (file)
@@ -39,7 +39,7 @@
     installation of Groovy. Just select <strong>Tools&#8594;Groovy
       Console...</strong> from the Jalview Desktop's drop-down menu. After a
     short pause, you should then see the <a
-      href="http://groovy-lang.org/groovyconsole.html">Groovy
+      href="https://groovy-lang.org/groovyconsole.html">Groovy
       Console</a> appear. This allows you to interactively execute Groovy
     scripts whilst Jalview is running. We've also provided a <strong>Calculations&#8594;Execute
       Groovy Script</strong> button so you can execute the currently loaded
@@ -101,7 +101,7 @@ print currentAlFrame.getTitle();</pre>
     InstallAnywhere version of Jalview, you can find additional groovy
     scripts in the examples/groovy subfolder of the installation
     directory. The examples are also available at <a
-      href="http://www.jalview.org/examples/groovy">http://www.jalview.org/examples/groovy</a>.
+      href="https://www.jalview.org/examples/groovy">https://www.jalview.org/examples/groovy</a>.
   </p>
   <p>
     <em>Using Groovy to add new Alignment Calculations</em><br />We've
@@ -115,8 +115,8 @@ print currentAlFrame.getTitle();</pre>
     <em>Creating custom colourschemes</em><br/>
     You can create your own alignment colourschemes with a groovy script. We've provided two examples:<br/>
     <ul>
-    <li><a href="http://www.jalview.org/examples/groovy/colourConserved.groovy">colourConserved.groovy</a> creates an 'Conserved' colourscheme - similar to the classic <a href="http://www.nrbsc.org/old/gfx/genedoc/">GeneDOC</a> shading model.</li>
-    <li><a href="http://www.jalview.org/examples/groovy/colourUnconserved.groovy">colourUnconserved.groovy</a> creates an 'Unconserved' colourscheme, where any unconserved residues are coloured pink.</li>
+    <li><a href="https://www.jalview.org/examples/groovy/colourConserved.groovy">colourConserved.groovy</a> creates an 'Conserved' colourscheme - similar to the classic <a href="http://www.nrbsc.org/old/gfx/genedoc/">GeneDOC</a> shading model.</li>
+    <li><a href="https://www.jalview.org/examples/groovy/colourUnconserved.groovy">colourUnconserved.groovy</a> creates an 'Unconserved' colourscheme, where any unconserved residues are coloured pink.</li>
     
     </ul>
   </p>
index 27742b3..e23af30 100644 (file)
   <pre>
 # Jalview Launch File
 # Please install the Jalview Desktop from 
-# http://www.jalview.org/getdown/release
+# https://www.jalview.org/getdown/release
 # and then try to open this file again
 jalview.apparg=-open
-jalview.apparg=http://www.jalview.org/examples/jpred_msa.fasta
+jalview.apparg=https://www.jalview.org/examples/jpred_msa.fasta
 jalview.apparg=-annotations
-jalview.apparg=http://www.jalview.org/examples/jpred_msa.seq.concise
+jalview.apparg=https://www.jalview.org/examples/jpred_msa.seq.concise
 jalview.apparg=-colour
 jalview.apparg=Clustal
 </pre>
@@ -62,7 +62,7 @@ jalview.apparg=Clustal
 # Please install the Jalview Desktop from 
 # http://www.jalview.org/getdown/release
 # and then try to open this file again
-appbase=http://www.jalview.org/getdown/archive/2_10_5/
+appbase=https://www.jalview.org/getdown/archive/2_10_5/
 </pre>
   For security, the Jalview application will only allow
   <em>appbase</em> URLs from www.jalview.org.
index 58b06db..5a3fe7a 100755 (executable)
     <em>Add Temperature Factor annotation to alignment</em> - if
     selected, values extracted from the Temperature Factor column for
     the backbone atoms in the PDB file will be extracted as annotation
-    lines shown on the alignment.
+    lines shown on the alignment.<br/><em>Since 2.11.2, scores from the Temperature Column for structures imported via the 3D-Beacons network may be shown instead as model quality or reliability scores.</em>
   <p>
-    <em>Default structure viewer</em> - choose Jmol or CHIMERA for
+    <em>Default structure viewer</em> - choose Jmol, CHIMERA, CHIMERAX or PYMOL for
     viewing 3D structures.
   <p>
-    <em>Path to Chimera program</em> - Optional, as Jalview will search
-    standard installation paths for Windows, Linux or MacOS. If you have
-    installed Chimera in a non-standard location, you can specify it
-    here, by entering the full path to the Chimera executable program.
-    Double-click this field to open a file chooser dialog.
-  <p>
+    <em>Path to Chimera/X/Pymol program</em> - Optional, as Jalview will search
+    standard installation paths for Windows, Linux or MacOS. If Jalview cannot locate the installation for your selected structure viewer, a dialog will be shown. If you have
+    installed the chosen viewer in a non-standard location, you can specify it
+    here, by entering the full path to its executable.<br/>For Chimera, locate the path to the chimera program, similarly for ChimeraX and Pymol. Rather than typing in the path, you can also <em>double-click this field</em> to open a file chooser dialog.</p>
   <p>
     <em>PDB Fields shown in Search and Structure Summaries</em> - ticks
     in this table indicate fields shown by default when browsing results
diff --git a/help/help/html/features/pymol.html b/help/help/html/features/pymol.html
new file mode 100644 (file)
index 0000000..573310a
--- /dev/null
@@ -0,0 +1,240 @@
+<html>
+<!--
+ * 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.
+ -->
+<head>
+<title>The Pymol PDB Viewer</title>
+</head>
+<body>
+  <p>
+    <strong>The Pymol Viewer</strong>
+  </p>
+  <p>
+    In Jalview 2.11.2, support was added for viewing structures opened
+    via the <a href="structurechooser.html"><strong>&quot;View
+        Structure Data..&quot;</strong> dialog</a> with <a
+      href="https://pymol.org/2/">Pymol</a> (https://pymol.org/2/). Like
+    with <a href="chimera.html">Chimera and ChimeraX</a>, Pymol views
+    can be saved and restored from Jalview Project files on any machine
+    with it installed, and structures can be coloured and superimposed
+    according to the alignment.
+  </p>
+  <p>
+    <em>Configuring Jalview to use Pymol</em><br /> You can configure
+    Pymol as your preferred structure viewer in <a
+      href="preferences.html#structure"> Preferences</a>. Jalview will
+    look for an existing installation, and will ask you to specify the
+    installation's path if it cannot be found. You can also optionally
+    specify the path to the Pymol program here if you want Jalview to
+    use a specific installation.
+  </p>
+  <p>
+    <strong>Jalview requires Pymol V 2.5.0 (community edition)
+      or later</strong> <br />Jalview requires Pymol's RPC interface, which is
+    not available in older versions of the Pymol community edition.
+  </p>
+  <p>
+    <strong>Known Limitations</strong><br />
+  </p>
+  <ul>
+    <li>Pymol does not support some forms of legacy structural data
+      (e.g. the 1A70 C-alpha only PDB file included in the Jalview
+      example project).</li>
+    <li>Pymol to Jalview communication does not support transfer of
+      properties or highlighting sequence regions corresponding to
+      structure selections or mouse-overs in Pymol.</li>
+    <li>Jalview to Pymol communication currently doesn't highlight
+      the positions on structures corresponging to moused over residues
+      in Jalview.</li>
+  </ul>
+  <p>
+    Basic screen operations (see <a
+      href="https://pymol.org/dokuwiki/doku.php?id=mouse">Pymol Wiki</a>
+    at https://pymol.org/dokuwiki/doku.php?id=mouse for full details).
+  <table border="1">
+    <tr>
+      <td><strong>Action</strong></td>
+      <td><strong>Windows</strong></td>
+      <td><strong>Unix</strong></td>
+      <td><strong>Mac/OSX</strong></td>
+    </tr>
+    <tr>
+      <td>Rotate View</td>
+      <td>Left Click and Drag</td>
+      <td>Left Click and Drag</td>
+      <td>Left Click and Drag</td>
+    </tr>
+    <tr>
+      <td>Zoom</td>
+      <td>Right Click<br> drag mouse up or down
+      </td>
+      <td>Right Click<br>drag mouse up or down
+      </td>
+      <td>cmd or Right + Click and drag mouse up or down, <br>or
+        use mouse scroll button
+      </td>
+    </tr>
+    <tr>
+      <td>Move Origin</td>
+      <td>Middle Button + Drag</td>
+      <td>Middle Button and drag</td>
+      <td>alt + Click<br> and drag
+      </td>
+    </tr>
+    <tr>
+      <td>Select Residues</td>
+      <td>Ctrl + Click (and drag to select a region)</td>
+      <td>Ctrl + Click (and drag)</td>
+      <td>Ctrl + Click (and drag)</td>
+    </tr>
+  </table>
+  </p>
+  <p>
+    <strong>Jalview Controls</strong>
+  <p>The Jalview Pymol View window has up to five menus:</p>
+  <ul>
+    <li><Strong>File<br>
+    </strong>
+      <ul>
+        <li><strong>View Mapping<br>
+        </strong><em> Opens a text window showing the alignment between the
+            residues corresponding to alpha-carbon atoms in the PDB
+            structure and the residues in the associated sequence.</em></li>
+      </ul></li>
+    <li><strong>View</strong>
+      <ul>
+        <li><strong>Show Chains<br>
+        </strong><em>Select which of the PDB file's chains (if more than
+            one) are to be displayed.</em></li>
+        <li><strong>Colour by ..<br></strong><em>Submenu
+            allowing specific alignment views to be selected for
+            colouring associated chains in the structure display. This
+            menu contains all the alignment views associated with the
+            structure view, with those used to colour the view indicated
+            by ticks. Addditionally, it contains the following menu
+            entries:</em>
+          <ul>
+            <li><strong>Select many views<br></strong><em>When
+                this option is enabled, selecting an alignment view adds
+                it to the set used to colour the structures. Use this
+                when colouring structures related to a number of
+                alignments involving different domains or chains which
+                are shown in the same structure view.</em></li>
+            <li><strong>Select all views<br></strong><em>This
+                is only enabled when </em><strong>Select many views</strong><em>
+                is also enabled, and will add all associated views to
+                the set used to colour the structure display.</em></li>
+            <li><strong>Invert selection<br></strong><em>This
+                is only enabled when </em><strong>Select many views</strong><em>
+                is also enabled, and will replace the current set of
+                views with any remaining views not currently used to
+                colour the structure display.</em></li>
+          </ul></li>
+      </ul>
+    <li><strong>Colours<br>
+    </strong>
+      <ul>
+        <li><strong>By Sequence<br>
+        </strong><em> Colours each residue in the structure with the colour
+            of its corresponding residue in the associated sequence as
+            rendered in the associated alignment views, including any
+            UniProt sequence features or region colourings.<br />Pick
+            which of the associated alignment views are used to colour
+            the structures using the <strong>View&#8594;Colour
+              by ..</strong> sub menu.
+        </em><br> Residues which only exist in the PDB structure are
+          coloured white if they are insertions (relative to the
+          associated sequence in the alignment) and grey if they are N
+          or C terminal flanks outside the region mapped to the
+          alignment window's sequence.</em></li>
+        <li><strong>By Chain<br>
+        </strong><em>Uses Pymol's 'spectrum(chain)' command to apply a
+            different colour to each chain.</em></li>
+        <li><strong>Charge &amp; Cysteine<br>
+        </strong><em> Highlights cysteines in yellow, anionic (Aspartic Acid
+            or Glutamic Acid) residues in red, and cationic (Lysine or
+            Arginine) residues in blue.</em></li>
+        <li><strong>Colour with Pymol<br></strong><em>Defers
+            any colouring operations to Pymol. Select this if you want
+            to use the Pymol scripting interface or menu to modify the
+            view directly.</em></li>
+        <li><strong>Standard and User Defined Jalview
+            colourschemes.<br>
+        </strong><em>The remaining entries apply the colourschemes available
+            from the standard and user defined <a
+            href="../colourSchemes/index.html">amino acid colours</a>.
+        </em></li>
+      </ul></li>
+    <li><strong>Pymol<br>
+    </strong><em>This pulldown menu provides access to Pymol's capabilities
+        from Jalview.</em>
+      <ul>
+        <li><strong><a name="sAlign">Align</a> <br> </strong><em>
+            When selected, the associated alignment will be used to
+            superimpose all the structures in the view onto the first
+            structure in the alignment via the pair_fit command. The regions used to calculate
+            the superposition will be highlighted using the 'Cartoon'
+            rendering style, and the remaining data shown as a chain
+            trace. RMSD values are output in the Pymol log.<br /> <br />
+        </em></li>
+        <li><a name="annotxfer"><strong>Write Jalview
+              features</strong></a><br /> <em>Selecting this option will create
+            new atom properties for any features currently visible in
+            the associated alignment views. This allows those atoms to
+            be selected and analysed in Pymol directly. </em><br>
+          <ul>
+            <li>Feature transfer in Pymol is experimental.</li>
+            <li>To select by a particular feature use the string
+              matching syntax:<br> select foo,p.jv_helix in helix
+            </li>
+            <li>To view transferred properties use Pymol's
+              Properties Inspector</li>
+            <li>For more information see <a
+              href="https://pymol.org/dokuwiki/doku.php?id=properties#selection_language">Property
+                based selection in Pymol's Documentation</a>.
+            </li>
+          </ul></li>
+      </ul></li>
+    <li><strong>Help<br>
+    </strong>
+      <ul>
+        <li><strong>Pymol Help<br>
+        </strong><em>Access the Pymol Help documentation in a new browser
+            window. window.</em></li>
+      </ul></li>
+  </ul>
+  <p>
+    <strong>Pymol and Windows Firewall</strong>
+  </p>
+  Jalview and Pymol communicate using the
+  <a href="https://pymolwiki.org/index.php/RPC">Pymol's XML-RPC over
+    HTTP interface</a>(https://pymolwiki.org/index.php/RPC).
+
+  <br> Technically this requires both Pymol and Jalview to open
+  ports on the local network, and this may be blocked by Windows
+  Firewall with a warning message such as
+  <br /> "Windows Firewall has blocked some features of this program"
+  (where the program may be java.exe or javaw.exe).
+  <br /> To allow Jalview and Pymol to interact, you may need to add
+  permission for the program to communicate over the network. This can
+  be done from the warning dialogue, or in Control Panel, Firewall
+  settings.
+</body>
+</html>
index ca793fd..07a1a3c 100644 (file)
Binary files a/help/help/html/features/schooser_main.png and b/help/help/html/features/schooser_main.png differ
diff --git a/help/help/html/features/schooser_viewbutton.png b/help/help/html/features/schooser_viewbutton.png
new file mode 100644 (file)
index 0000000..f14481e
Binary files /dev/null and b/help/help/html/features/schooser_viewbutton.png differ
index eec68ee..837d7b3 100755 (executable)
@@ -36,7 +36,7 @@ td {
   </p>
   <p>The search box is displayed by pressing Control and F or
     selecting &quot;Find...&quot; from the &quot;Search&quot; menu.</p>
-  <img src="search.png" width="398" height="124">
+  <img src="search.png" width="400" height="152">
   <p>&quot;Find next&quot; will find the next occurrence of the
     specified and adjust the alignment window view to show it, and
     &quot;Find all&quot; highlights all matches for a pattern. The
@@ -48,18 +48,19 @@ td {
       of posix and perl style regex - see below for a summary)</li>
     <li>Gaps are ignored when matching the query to the sequences
       in the alignment.</li>
+    <li>Hidden columns can optionally be ignored (<em>since Jalview 2.11</em>)</li>
     <li>The search is applied to both sequences and their IDs, and
       optionally also to the description string (<em>since Jalview
         2.10</em>)
     </li>
     <li>If a region is selected, then search will <strong>only</strong>
-      be performed on that region.
+      be performed on that region.<br />
+    <em>Tip: to quickly clear the current selection, click the
+        alignment view you wish to search, then press 'Escape'.</em>
     </li>
-    <li>To quickly clear the current selection, press the
-      &quot;Escape&quot; key.</li>
     <li>Tick the &quot;Match Case&quot; box to perform a case
       sensitive search.</li>
-    <li>To access a <a ref="#queryhistory">previously used
+    <li>To access a <a href="#queryhistory">previously used
         query</a> press the down arrow or click on the button on the right
       of the text field.
   </ul>
@@ -155,12 +156,13 @@ td {
     stored along with your Jalview user preferences. To open the search
     history, click on the button to the right of the query field, or
     press the down arrow key.</p>
-  <img src="searchhist.png" width="404" height="185" align="left" />
-  <p>The search history keeps up to 99 queries by default. To clear
+  <p><img src="searchhist.png" width="404" height="185" />
+  </p><p>The search history keeps up to 99 queries by default. To clear
     the history, or modify the size of the history, right-click the text
     box.</p>
-  <img src="searchclearhist.png" width="402" height="127" align="left" />
-  <p>
+  <p><img src="searchclearhist.png" width="402" height="127"/>
+  </p>
+<p width="100%">
     <strong>Other dialogs that provide a query history</strong>
   </p>
   <p>
index 89adb1a..47c18f4 100644 (file)
Binary files a/help/help/html/features/search.png and b/help/help/html/features/search.png differ
index de0a7e6..6103b31 100644 (file)
Binary files a/help/help/html/features/selectfetchdb.gif and b/help/help/html/features/selectfetchdb.gif differ
index e726c49..7d4a389 100755 (executable)
@@ -38,7 +38,7 @@
       the database you want to retrieve sequences</strong> from the database
     chooser.
   </p>
-  <img src="selectfetchdb.gif" align="left" width="480" height="204"
+  <img src="selectfetchdb.gif" align="left"
     alt="Database selection dialog for fetching sequences (introduced in Jalview 2.8)">
   <p>
     The databases are shown as a tree, and ordered alphabetically;
         accession ids</strong> (as a semi-colon separated list), or press the
       &quot;Example&quot; button to paste the example accession for the
       currently selected database into the retrieval box. Finally, press
-      &quot;OK&quot; to initiate the retrieval.</li>
+      &quot;OK&quot; to initiate the retrieval.
+      <br />
+      For the PDB and UniProt sequence fetchers, choose the "Retrieve IDs" tab
+      to search for accession ids.</li>
   </ol>
 
-  <p>If you use the WSDBFetch sequence fetcher services (EMBL,
-    UniProt, PFAM, and RFAM) in work for publication, please cite:</p>
-  <p>
-    Pillai S., Silventoinen V., Kallio K., Senger M., Sobhany S., Tate
-    J., Velankar S., Golovin A., Henrick K., Rice P., Stoehr P., Lopez
-    R. <br> SOAP-based services provided by the European
-    Bioinformatics Institute.<br> Nucleic Acids Res. 33(1):W25-W28
-    (2005) <br> <br>
-  </p>
+  <p>If you use the Sequence Fetcher, please remember to cite the
+    corresponding services (linked to below):</p>
+  <ul>
+    <li>Ensembl - <a
+      href="https://github.com/Ensembl/ensembl-rest/wiki#citing">The
+        Ensembl REST API</a></li>
+    <li>EMBL/EMBLCDS - Provided by the <a
+      href="https://www.ebi.ac.uk/ena/browser/api/#/ENA_Browser_Data_API/getFlatFileUsingGET">European
+        Nucleotide Archive's ENA Data API</a><br />
+    <em>Note: Versions of Jalview prior to 2.11.1.1 employed the
+        XML endpoint of the ENA browser, which was retired in August
+        2020.</em></li>
+    <li>Uniprot - Free Text Search and Retrieval via the <a
+      href="https://www.uniprot.org/help/api">Uniprot REST API</a></li>
+    <li>PDB - Free Text Search via the <a
+      href="https://www.ebi.ac.uk/pdbe/api/doc/search.html">PDBe
+        REST API</a> and retrieval via <a
+      href="https://www.ebi.ac.uk/Tools/dbfetch/">WSDbFetch</a><br />
+      Pillai S., Silventoinen V., Kallio K., Senger M., Sobhany S., Tate
+      J., Velankar S., Golovin A., Henrick K., Rice P., Stoehr P., Lopez
+      R. <br> SOAP-based services provided by the European
+      Bioinformatics Institute.<br> Nucleic Acids Res.
+      33(1):W25-W28 (2005) <br> <br>
+    </li>
+  </ul>
 </body>
 </html>
index 03ddd79..6b9ff21 100644 (file)
Binary files a/help/help/html/features/seqfetcher.gif and b/help/help/html/features/seqfetcher.gif differ
index 785c429..11cad6b 100644 (file)
     The Structure Chooser allows you to select
     3D structures to view for the currently selected set of
     sequences. It is opened by selecting the <strong>"3D
-      Structure Data..."</strong> option from the Sequence ID panel's <a
-      href="../menus/popupMenu.html">pop-up menu</a>. The dialog
+      Structure Data..."</strong> option from the Sequence ID panel's
+      <a href="../menus/popupMenu.html">pop-up menu</a>. <br/>
+      <img src="3dstructuredata_popupmenu.png" alt="pop-up menu"/>
+      <br/>
+      The dialog
     provides:
   </p>
   <ul>
@@ -69,6 +72,9 @@
     associated with the sequence. It does this based on the sequence's
     ID string, and any other associated database IDs. <br />
     <br />
+    Since Jalview 2.11.2, you can also <a href="#3dbeaconssearch">initiate a search
+    of the 3D-Beacons Network</a>.
+  </p>
   <p>
     <strong><a name="cachedstructview">Viewing existing
         structures for your sequences</a></strong>
@@ -86,7 +92,7 @@
   </p>
   <p>Jalview can automatically select the best structures according
     to meta-data provided by the PDB. For alignments with no existing
-    structure data, the 'Best Quality' structure for each sequence will
+    structure data, the 'PDBe Best Quality' structure for each sequence will
     by default be selected, but clicking on the drop down menu allows
     other criteria to be chosen, including Resolution (only defined for
     X-Ray structures), Highest Protein Chain etc. When 'Invert' is
     <br>The screenshot above shows the Structure Chooser displayed after
     selecting all the sequences in the Jalview example project. If no
     structures were auto-discovered, options for manually associating
-    PDB records will be shown (see below).<p>
+    PDB records will be shown (see below).
+
+  <p>
+    <strong><a name="3dbeaconssearch">3D-Beacons Network Search</a></strong>
+  </p>
+  <p>
+    To initiate a search of the 3D-Beacons Network&mdash;which searches
+    across experimentally determined and predicted structure models from
+    several resources including PDBe, AlphaFold DB, SWISS-MODEL, PED, SASDB, Genome3D and
+    PDBe-KB&mdash;click on the <strong>3D-Beacons Search</strong> button at the top of the
+    Structure Chooser window.
+    <br/>
+    <img src="3dbeacons_button.png"/>
+    <br/>
+    The 3D-Beacons Network search requires UniProt references and Jalview will ask
+    to attempt to fetch these references for the selected sequences.
+    UniProt references might not always be found in which case you can revert to the PDB
+    search.
+    <br/>
+    <img src="3dbeacons_structurechooser.png"/>
+    <br/>
+    If structures are found through the 3D-Beacons network you can filter which structures
+    are shown using the drop-down filter at the top of the Structure Chooser window.
+    <br/>
+    You can view information about each related model, such as the resource providing
+    each model, in the columns displayed. You can sort the list of models by clicking on
+    column headings.
+    <br/>
+    Select and view the structures in the usual way using the <a href="viewingpdbs.html#afterviewbutton">open structure options</a> at
+    the bottom of the Structure Chooser window.
+  </p>
+
+  <p>
     <strong>Exploration of meta-data for available structures</strong>
   </p>
   <p>Information on each structure available is displayed in columns
       2.9. </em>
   </p>
 </body>
-</html>
\ No newline at end of file
+</html>
index b1ad4ba..947b96b 100755 (executable)
@@ -24,7 +24,7 @@
 </head>
 <body>
   <p>
-    <strong>Discovering and Viewing PDB Structures</strong>
+    <strong>Discovering and Viewing PDB and 3D-Beacons structures</strong>
   </p>
   Jalview can be used to explore the 3D structures of sequences in an
   alignment by following the steps below:
@@ -34,7 +34,7 @@
         menu</a> to open the <a href="structurechooser.html">Structure
         Chooser</a> dialog box.
       <ul>
-        <li>If one or more structures exists for the given
+        <li>If one or more structures exist in the PDB for the given
           sequence, the <a href="structurechooser.html">Structure
             Chooser</a> dialog will open with them listed in the results
           pane.
           href="structurechooser.html">Structure Chooser</a> interface
           will present options for manual association of PDB structures.
         </li>
+       <li>
+          Since Jalview 2.11.2 you can also search the 3D-Beacons Network
+         for structures.  The 3D-Beacons Network acts as a one-stop shop for protein
+         structures by combining and standardising data from several providers.
+         See <a href="structurechooser.html#3dbeaconssearch">3D-Beacons Search</a> for
+         instructions.
+       </li>
       </ul>
     </li>
-    <li><strong>Selecting Structures</strong><br />You can select
+    <li><strong>Selecting PDB Structures</strong><br />
+      If one or more structures have been found from the PDB, you can select
       the structures that you want to open and view by selecting them
       with the mouse and keyboard.<br />By default, if structures were
       discovered, then some will already be selected according to the
@@ -79,7 +87,8 @@
     <strong>Structure Viewers in the Jalview Desktop</strong><br /> The
     <a href="jmol.html">Jmol viewer</a> has been included since Jalview
     2.3. Jalview 2.8.2 included support for <a href="chimera.html">Chimera</a>,
-    provided it is installed and can be launched by Jalview. The default
+    provided it is installed and can be launched by Jalview. ChimeraX and PyMOL
+    support is included from Jalview 2.11.2. The default
     viewer can be configured in the <a href="preferences.html#structure">Structure
       tab</a> in the <strong>Tools&rarr;Preferences</strong> dialog box.
   
     for more information.
   </p>
   <p>
-    <img src="schooser_viewbutton.png"
-      style="width: 465px; height: 81px" /><br/> <strong><a
+    <strong><a
       name="afterviewbutton">Controlling where the new structures
         will be shown</a></strong>
+    <br/>
+    <img src="schooser_viewbutton.png" />
         <br />The Structure Chooser offers several options
-    for viewing a structure. <br/><strong>New View</strong> will open a new
+    for viewing a structure. <br/>
+    The <strong>Open new structure view</strong> button will open a new
     structure viewer for the selected structures, but if there are views
     already open, you can select which one to use, and press the <strong>Add</strong>
     button. Jalview can automatically superimpose new structures based
index 3b6705b..bd7144e 100644 (file)
@@ -43,7 +43,7 @@
   </ol>
   <strong>Please note: The 2.10.2 feature counting interface is not compatible with earlier versions.</strong><br/><br/>
   <em><a
-    href="http://www.jalview.org/examples/groovy/featuresCounter.groovy">http://www.jalview.org/examples/groovy/featuresCounter.groovy</a>
+    href="https://www.jalview.org/examples/groovy/featuresCounter.groovy">https://www.jalview.org/examples/groovy/featuresCounter.groovy</a>
     - rendered with <a href="http://hilite.me">hilite.me</a></em>
   <!-- HTML generated using hilite.me --><div style="background: #f8f8f8; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #408080; font-style: italic">/*</span>
 <span style="color: #408080; font-style: italic"> * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)</span>
index 442c508..a6bb1b6 100755 (executable)
@@ -45,7 +45,7 @@
   <p>
     For more information, you might also want to take a look at the
     documentation section of the Jalview website (<a
-      href="http://www.jalview.org/about/documentation">http://www.jalview.org/about/documentation</a>).
+      href="https://www.jalview.org/about/documentation">https://www.jalview.org/about/documentation</a>).
   </p>
   <p>
     If you are using the Jalview Desktop application and are looking for
     google the online version of these pages. If you don't find what you
     are looking for, or want to report a bug or make a feature request,
     then get in contact over at <a
-      href="http://www.jalview.org/community">http://www.jalview.org/community</a>
+      href="https://www.jalview.org/community">https://www.jalview.org/community</a>
+  </p>
+  <p>
+    <strong>Logging, troubleshooting and reporting bugs</strong><br />If
+    something seems to be wrong with your Jalview installation, or you
+    think you've found a problem, take a look at <a href="logging.html">Jalview's
+      logging and bug reporting</a> documentation.
   </p>
-
   <p>
     <strong>Citing Jalview</strong><br />If you use Jalview in your
     work, please cite the Jalview 2 paper in Bioinformatics:
index 29b6813..0faa1d5 100755 (executable)
       <td><strong>Cursor Keys<br> (Arrow Keys)
       </strong></td>
       <td>Cursor</td>
-      <td>Move cursor around alignment</td>
+      <td>Move cursor around alignment.<br /> Press SHIFT to move
+        cursor from an aligned region to next gap, or to the next
+        aligned region when at a gap.
+      </td>
     </tr>
     <tr>
       <td><strong>Cursor Keys<br> (Arrow Keys)
diff --git a/help/help/html/logging.html b/help/help/html/logging.html
new file mode 100644 (file)
index 0000000..4d7e2e3
--- /dev/null
@@ -0,0 +1,221 @@
+<html>
+<!--
+ * 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.
+ -->
+<head>
+<title>The Java Console, Logging and Reporting Bugs</title>
+</head>
+<body>
+  <p>
+    <strong>The Java Console, Logging and Reporting Bugs<br /></strong>
+  </p>
+  <p>
+    Like most programs, Jalview contains bugs, despite our best efforts.
+    However, Jalview also produces a series of messages during its
+    operation, often referred to as 'logs'. These logs provide a record
+    of Jalview's operation. They can also be extremely useful when <a
+      href="#reportingbugs">reporting bugs</a>, since they help the
+    Jalview developers diagnose and find a workaround for specific
+    problems that you might encounter.
+  </p>
+  <p>
+    The primary place to look for logs is in the <a href="#java_console">Java
+      Console</a> which you can open from within Jalview by going to the <em>Tools</em>
+    menu and checking the box next to <em>Show Java Console</em>. This
+    option is stored in your Jalview preferences file and so is
+    remembered across Jalview sessions.
+  </p>
+  <p>The Java Console will show you information about what the
+    Jalview application is doing (often in the background) whilst it is
+    running.</p>
+  <p>However, when tracking down problems preventing Jalview from
+    starting up properly, you need to look at the startup logs - which
+    are not shown in the Jalview Console. The location of these depends
+    on how you launched Jalview:</p>
+  <p>
+    <strong>Jalview Desktop Installation Launch Logs</strong><br />If you are using
+    a standard desktop version of Jalview installed from one of our
+    install4j installers, then messages about Jalview's initial launch
+    can be found in
+  <pre>JALVIEW_APP_DIR/launcher.log</pre>
+  where
+  <em>JALVIEW_APP_DIR</em> is the directory that Jalview's application
+  was installed into.
+  <br /> For Jalview 2.11.0 onwards:
+  <ul>
+    <li>In Windows this is <em>%APPDATA%\Local\Jalview</em> by
+      default
+    </li>
+    <li>In macOS this is <em>/Applications/Jalview.app/Contents/Resources/app</em>
+      by default
+    </li>
+    <li>In Linux and other Unix OSes this is <em>~/opt/jalview</em>
+      by default
+    </li>
+  </ul>
+  <p><strong>Jalview Executable Jar Launch Logs</strong><br/>If you are using the Jalview executable jar file (also
+  used by bioconda and OSX homebrew installations) then the default run class (
+  <em>jalview.bin.Launcher</em> -- a minimised launcher that will set
+  memory and linux dpi settings before re-launching
+  <em>jalview.bin.Jalview</em>), will output logging information to
+  STDOUT and STDERR.
+  </p>
+
+  <p><strong>
+    <a name="java_console">Java Console and Log Level</a>
+  </strong></p>
+  <p>
+    The Java Console is opened by selecting <strong>Tools
+      &rarr; Show Java Console</strong>. The visibility of the console is stored
+    in your preferences, so if you quit Jalview with the console open,
+    it will be shown the next time you start Jalview. You can close the
+    console by selecting the same menu option again, or just closing the
+    console window.
+  </p>
+  <p>The Java Console's text display always shows information about
+    your system and Jalview installation details. The rest are the most
+    recent messages output during your Jalview session. Some messages
+    are only captured by the console when it is open, so to get a full
+    log for debugging a problem, enable the console and then restart
+    Jalview.</p>
+
+  <p>
+    Jalview logging will automatically scroll the text in the Java Console
+    but if you want to examine a particular part of the logs whilst logging
+    is still going on you can click on any part of the text area to
+    stop this behaviour.  A border should appear arround the
+    text area to signify that autoscroll has been turned off.  You can
+    toggle the autoscroll behaviour on and off by clicking again on the
+    text area.
+  </p>
+  <p>
+    You can temporarily control the detail of what appears as output by
+    selecting a <em>Log level</em> using the drop-down list at the
+    bottom left of the console. There are several levels to choose from:
+    The most verbose is TRACE, followed by DEBUG, INFO, WARN. When the
+    Console is opened, the default level will be chosen (INFO).
+  </p>
+  <p>
+    <strong>Note! If you change the log level in the Java
+      Console, this change will only persist for as long as the console
+      is open. Once you close the console the log level will revert back
+      to what it had been when you opened the console (usually INFO).</strong>
+  </p>
+  <p><strong>Permanently changing Jalview's default log level</strong><br/>
+    You can change the default log level by editing the Jalview
+    preferences file, <em>.jalview_properties</em>, found in your home
+    directory (on Windows: %HOMEPATH%, or the folder above 'My
+    Documents'; on macOS: ~ or /Users/<em>username</em>; on linux/unix:
+    ~ or /home/<em>username</em>), and setting the property <em>logs.Jalview.level</em>
+    to the log level you prefer, e.g.
+  <pre>
+  logs.Jalview.level=DEBUG
+  </pre>
+  You can also set the property
+  <pre>
+  logs.Axis.level=DEBUG
+  </pre>
+  <p>to get debug information for Jalview's JPred service. The Axis log
+  level cannot be set from within the Java Console.
+  </p>
+  <p>
+    You can also set the <em>logs.jalview.level</em> property to a log level
+    not usually presented in the Java Console (though restricted to log
+    levels used by Apache Log4j -- see <a
+      href="https://logging.apache.org/log4j/2.x/manual/customloglevels.html">Log4j
+      Custom Log Levels</a> for details of the standard log levels
+    available). Jalview does not currently define any custom log levels.
+    If you do set the property with a log level that is normally not
+    visible in the Java Console this should be respected and visibly
+    selected when you open the console.
+  </p>
+  <p>
+    The <em>Clear</em> button at the bottom of the console will clear
+    all logging messages except for the initial system information which
+    is rewritten to the console.
+  </p>
+  <p>
+    The <em>Copy to clipboard</em> button at the bottom right of the
+    console will copy all of the text in the console to your system
+    clipboard, ready to paste into another application (e.g. email
+    composer or issue tracker).
+  </p>
+
+  <p><strong><a name="reportingbugs">Reporting Bugs</a></strong></p>
+
+  <p>
+    If you come across a problem in Jalview where something is not
+    working as described, or how you think it should, you should first
+    check the <a href="https://www.jalview.org/faq">Jalview FAQ</a> to
+    see if this is a known problem and if there is a suggested
+    workaround.
+  </p>
+  <p>
+    If there is no FAQ answer covering your problem then you can submit
+    a bug report on the <a href="https://issues.jalview.org/">Jalview
+      Issue Tracker</a>. It is good practice to search the issue tracker
+    first to see if the issue has already been reported. If an issue
+    already exists please continue to add your own comments to the issue
+    which may well help narrow down the problem, if not then you can
+    create an account and submit a new bug report:
+  </p>
+  <p>
+    Make sure that you set Project to <em>Jalview (JAL)</em>, and Issue
+    Type to <em>Bug</em> or <em>New Feature</em> or <em>Improvement</em>
+    appropriately.<br /> Give a one line summary of the issue in the <em>Summary</em>.
+    <br /> In the <em>Environment</em> text box you can describe the
+    system you are using. This is usually most easily done by opening
+    the Java Console, clicking the <em>Clear</em> button, and then
+    immediately on the <em>Copy to clipboard</em> button, and then
+    pasting the clipboard into the text box.
+  </p>
+  <p>
+    You can then give more detailed information about how to recreate
+    the problem in the <em>Description</em> text box. If you want to
+    attach any screenshots or example alignment files that demonstrate
+    the problem then you can drag them to the Create Issue dialog in
+    your browser, or use the <em>Attachment</em> browse facility to
+    locate them on your computer.
+  </p>
+
+  <p>
+    To help the Jalview team with diagnosing a particular issue, it is
+    really helpful if you can also add more detailed logs output whilst
+    re-creating the problem. To do this, open the Java Console, click
+    the <em>Clear</em> button and select TRACE in the <em>Log level</em>
+    drop down list. <br /> Whilst leaving the console open, perform the
+    task in Jalview that re-creates the problem. <br /> Then you can
+    copy the debug information in the Java Console by clicking on the <em>Copy
+      to clipboard</em> button and then paste that into the Description, or a
+    Comment of your issue.
+  </p>
+
+  <p>
+    For other queries or comments about Jalview, remember you can
+    contact the Jalview team using email via the
+    <a href="https://www.jalview.org/mailman/listinfo/jalview-discuss">Jalview
+      discussion list</a>, on Twitter <a
+      href="https://twitter.com/Jalview/">@Jalview</a>, or for technical
+    discussions, via the Jalview developer's chatroom at
+    <a href="https://gitter.im/jalview/developers">https://gitter.im/jalview/developers</a>.
+  </p>
+
+</body>
+</html>
index 0374dcb..7d6fb85 100755 (executable)
@@ -80,7 +80,7 @@
       arguments, but you must put the <em>jvl</em> file first, e.g. <pre>
       /PATH_TO_JALVIEW/Jalview /path/to/file/mymemorysetting.jvl /path/to/alignments/myalignment.fa</pre> Alternatively, you can use the standard Jalview command line
       arguments with or without the jvl file (first), e.g. <pre>
-       /PATH_TO_JALVIEW/Jalview /path/to/file/mymemorysetting.jvl -open http://www.jalview.org/examples/jpred_msa.fasta -annotations http://www.jalview.org/examples/jpred_msa.seq.concise -colour Clustal</pre> You can use command line arguments to control memory
+       /PATH_TO_JALVIEW/Jalview /path/to/file/mymemorysetting.jvl -open https://www.jalview.org/examples/jpred_msa.fasta -annotations https://www.jalview.org/examples/jpred_msa.seq.concise -colour Clustal</pre> You can use command line arguments to control memory
       settings in Windows and macOS too: <br /> In Windows you must
       use, e.g. <pre>
       \PATH_TO_JALVIEW\Jalview.exe %HOMEPATH%\mymemorysetting.jvl -open %HOMEPATH%\myalignment.fa</pre> In macOS you can use the macOS <em>open</em> command like this: <pre>
index c83741a..6c86e2e 100755 (executable)
@@ -1,3 +1,4 @@
+
 <html>
 <!--
  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
@@ -51,23 +52,417 @@ li:before {
   </p>
   <table border="1">
     <tr>
-      <th nowrap><em>Release</em></th>
+      <th nowrap><a id="Jalview.$$Version-Rel$$"><em>Release</em></th>
       <th><em>New Features</em></th>
       <th><em>Issues Resolved</em></th>
     </tr>
     <tr>
       <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.2">2.11.2</a><a id="Jalview.2.11.2.0">.0</a><br />
+          <em>24/02/2022</em></strong></td>
+      <td align="left" valign="top">
+        <ul>
+          <li>
+            <!-- -->
+          </li>
+        </ul> <!-- <em>Development</em>
+        <ul>
+          <li>Updated building instructions</li>
+        </ul> -->
+
+      </td>
+      <td>
+        <ul>
+          <li>
+            TO DOCUMENT: JAL-3700,JAL-3751,JAL-3763
+          </li>
+          <li>
+            <!-- JAL-3915 -->Removed RNAview checkbox and logic from
+            Structure Preferences
+          </li>
+        </ul> <em>Development</em>
+        <ul>
+          <li>Fixed non-fatal gradle errors during build</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.7">.7</a><br />
+          <em>18/01/2022</em></strong></td>
+      <td></td>
+      <td align="left" valign="top">
+        <ul>
+          <li>
+            <!-- JAL-3703, JAL-3935 -->Files open in Jalview cannot be
+            updated by Jalview or other applications (Windows, other non
+            Unix/BSD OSs)
+          </li>
+        </ul> <em>Security</em>
+        <ul>
+          <li>
+            <!-- JAL-3937 -->Enable AIA download of HTTPS intermediate
+            certificates.
+          </li>
+        </ul>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.6">.6</a><br />
+          <em>6/01/2022</em></strong></td>
+
+      <td align="left" valign="top"><em>Security</em>
+        <ul>
+          <li>
+            <!-- JAL-3934 -->Version bump library dependency: Log4j 2.16.0 to 2.17.0.
+            </li>
+        </ul></td>
+      <td>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.5">.5</a><br />
+          <em>20/12/2021</em></strong></td>
+
+      <td align="left" valign="top"><em>Security</em>
+        <ul>
+          <li>
+            <!-- JAL-3933 -->Update library dependency: Log4j 2.16.0
+            (was log4j 1.2.x).
+        </ul> <em>Development</em>
+        <ul>
+          <li>Updated building instructions</li>
+        </ul></td>
+      <td>
+        <ul>
+          <li>
+            <!-- JAL-3840 -->Occupancy calculation is incorrect for
+            alignment columns with over -1+2^32 gaps (breaking filtering
+            and display)
+          </li>
+          <li>
+            <!-- JAL-3833 -->Caps on Hi-DPI scaling to prevent crazy
+            scale factors being set with buggy window-managers (linux
+            only)
+          </li>
+        </ul> <em>Development</em>
+        <ul>
+          <li>Fixed non-fatal gradle errors during build</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.4">.4</a><br />
+          <em>09/03/2021</em></strong></td>
+      <td align="left" valign="top"><em>Improved control of
+          Jalview's use of network services via jalview_properties</em>
+        <ul>
+          <li>
+            <!-- JAL-3814 -->New .jalview_properties token controlling
+            launch of the news browser (like -nonews argument)
+          </li>
+          <li>
+            <!-- JAL-3813 -->New .jalview_properties token controlling
+            download of linkout URLs from
+            www.jalview.org/services/identifiers
+          </li>
+          <li>
+            <!-- JAL-3812 -->New .jalview_properties token controlling
+            download of BIOJSHTML templates
+          </li>
+          <li>
+            <!-- JAL-3811 -->New 'Discover Web Services' option to
+            trigger a one off JABAWS discovery if autodiscovery was
+            disabled
+          </li>
+        </ul></td>
+      <td align="left" valign="top">
+        <ul>
+          <li>
+            <!-- JAL-3818 -->Intermittent deadlock opening structure in
+            Jmol
+          </li>
+        </ul> <em>New Known defects</em>
+        <ul>
+          <li>
+            <!-- JAL-3705 -->Protein Cross-Refs for Gene Sequence not
+            always restored from project (since 2.10.3)
+          </li>
+          <li>
+            <!-- JAL-3806 -->Selections from tree built from CDS aren't
+            propagated to Protein alignment (since 2.11.1.3)
+          </li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.3">.3</a><br />
+          <em>29/10/2020</em></strong></td>
+      <td align="left" valign="top">
+        <ul>
+
+        </ul>
+      </td>
+      <td align="left" valign="top">
+        <ul>
+          <li>
+            <!-- JAL-3765 -->Find doesn't always highlight all matching
+            positions in a sequence (bug introduced in 2.11.1.2)
+          </li>
+          <li>
+            <!-- JAL-3760 -->Alignments containing one or more protein
+            sequences can be classed as nucleotide
+          </li>
+          <li>
+            <!-- JAL-3748 -->CDS alignment doesn't match original CDS
+            sequences after alignment of protein products (known defect
+            first reported for 2.11.1.0)
+          </li>
+          <li>
+            <!-- JAL-3725 -->No tooltip or popup menu for genomic
+            features outwith CDS shown overlaid on protein
+          </li>
+          <li>
+            <!-- JAL-3751 -->Overlapping CDS in ENA accessions are not
+            correctly mapped by Jalview (e.g. affects viral CDS with
+            ribosomal slippage, since 2.9.0)
+          </li>
+          <li>
+            <!-- JAL-3763 -->Spliced transcript CDS sequences don't show
+            CDS features
+          </li>
+          <li>
+            <!-- JAL-3700 -->Selections in CDS sequence panel don't
+            always select corresponding protein sequences
+          </li>
+          <li>
+            <!-- JAL-3759 --> <em>Make groups from selection</em> for a
+            column selection doesn't always ignore hidden columns
+          </li>
+        </ul> <em>Installer</em>
+        <ul>
+          <li>
+            <!-- JAL-3611 -->Space character in Jalview install path on
+            Windows prevents install4j launching getdown
+          </li>
+        </ul> <em>Development</em>
+        <ul>
+          <li>
+            <!-- JAL-3248 -->Fixed typos and specified compatible gradle
+            version numbers in doc/building.md
+          </li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
+          id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.2">.2</a><br />
+          <em>25/09/2020</em></strong></td>
+      <td align="left" valign="top">
+        <ul>
+        </ul>
+      </td>
+      <td align="left" valign="top">
+        <ul>
+          <li>
+            <!-- JAL-3757 -->Fresh install of Jalview 2.11.1.1 reports
+            "Encountered problems opening
+            https://www.jalview.org/examples/exampleFile_2_7.jvp"
+          </li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" align="center" nowrap><strong><a
           id="Jalview.2.11.1">2.11.1</a><a id="Jalview.2.11.1.1">.1</a><br />
-          <em>13/07/2020</em></strong></td>
+          <em>17/09/2020</em></strong></td>
       <td align="left" valign="top">
         <ul>
-        <!-- -->
-       </ul>
+          <li>
+            <!-- JAL-3638 -->Shift+arrow keys navigate to next gap or
+            residue in cursor mode
+          </li>
+          <li>
+            <!-- JAL-3695 -->Support import of VCF 4.3 by updating
+            HTSJDK from 2.12 to 2.23
+          </li>
+          <li>
+            <!-- JAL-3621 -->IntervalStore library updated to v.1.1:
+            optimisations and improvements suggested by Bob Hanson and
+            improved compatibility with JalviewJS
+          </li>
+          <li>
+            <!-- JAL-3615 -->Retrieve GZipped stockholm formatted
+            alignments from Pfam and Rfam
+          </li>
+          <li>
+            <!-- JAL-2656 -->Recognise GZipped content for URLs and File
+            import (no longer based on .gz extension)
+          </li>
+          <li>
+            <!-- JAL-3570 -->Updated Spanish Translation for 2.11.1
+          </li>
+          <li>
+            <!-- JAL-3692 -->Migrate EMBL record retrieval to use latest
+            ENA Browser (https://www.ebi.ac.uk/ena/browser/home) and
+            EMBL flat file
+          </li>
+          <li>
+            <!-- JAL-3667 -->Improved warning messages, debug logging
+            and fixed Retry action when Jalview encounters errors when
+            saving or making backup files.
+          </li>
+          <li>
+            <!-- JAL-3676 -->Enhanced Jalview Java Console:
+            <ul>
+              <li>Jalview's logging level can be configured</li>
+              <li>Copy to Clipboard Buttion</li>
+            </ul>
+          </li>
+          <li>
+            <!-- JAL-3541 -->Improved support for Hi-DPI (4K) screens
+            when running on Linux (Requires Java 11+)
+          </li>
+        </ul> <em>Launching Jalview</em>
+        <ul>
+          <li>
+            <!-- JAL-3608 -->Configure Jalview Desktop's look and feel
+            through a system property
+          </li>
+          <li>
+            <!-- JAL-3477 -->Improved built-in documentation and command
+            line help for configuring Jalview's memory
+          </li>                   
+        </ul>
       </td>
       <td align="left" valign="top">
         <ul>
-         <li><!-- JAL-3493 -->Escape does not clear highlights on the alignment (Since Jalview 2.10.3)</li>
-       </ul>
+          <li>
+            <!-- JAL-3691 -->Conservation and Quality tracks are shown
+            but not calculated and no protein or DNA score models are
+            available for tree/PCA calculation when launched with
+            Turkish language locale
+          </li>
+          <li>
+            <!-- JAL-3493 -->Escape does not clear highlights on the
+            alignment (Since Jalview 2.10.3)
+          </li>
+          <li>
+            <!--  JAL-3680 -->Alt+Left or Right arrow in cursor mode
+            doesn't slide selected sequences, just sequence under cursor
+          </li>
+          <li>
+            <!-- JAL-3732 -->Alt+Up/Down in cursor mode doesn't move
+            sequence under the cursor
+          </li>
+          <li>
+            <!-- JAL-3613 -->Peptide-to-CDS tracking broken when
+            multiple EMBL gene products shown for a single contig
+          </li>
+          <li>
+            <!-- JAL-3696 -->Errors encountered when processing variants
+            from VCF files yield "Error processing VCF: Format specifier
+            '%s'" on the console
+          </li>
+          <li>
+            <!-- JAL-3697 -->Count of features not shown can be wrong
+            when there are both local and complementary features mapped
+            to the position under the cursor
+          </li>
+          <li>
+            <!-- JAL-3673 -->Sequence ID for reference sequence is
+            clipped when Right align Sequence IDs enabled
+          </li>
+          <li>
+            <!-- JAL-2983 -->Slider with negative range values not
+            rendered correctly in VAqua4 (Since 2.10.4)
+          </li>
+          <li>
+            <!-- JAL-3685 -->Single quotes not displayed correctly in
+            internationalised text for some messages and log output
+          </li>
+          <li>
+            <!-- JAL-3490 -->Find doesn't report matches that span
+            hidden gapped columns
+          </li>
+          <li>
+            <!-- JAL-3597 -->Resolved memory leaks in Tree and PCA
+            panels, Alignment viewport and annotation renderer.
+          </li>
+          <li>
+            <!-- JAL-3561 -->Jalview ignores file format parameter
+            specifying output format when exporting an alignment via the
+            command line
+          </li>
+          <li>
+            <!-- JAL-3667 -->Windows 10: For a minority of users, if
+            backups are not enabled, Jalview sometimes fails to
+            overwrite an existing file and raises a warning dialog. (in
+            2.11.0, and 2.11.1.0, the workaround is to try to save the
+            file again, and if that fails, delete the original file and
+            save in place.)
+          </li>
+          <li>
+            <!-- JAL-3750 -->Cannot process alignments from HTTPS urls
+            via command line
+          </li>
+          <li>
+            <!-- JAL-3741 -->References to http://www.jalview.org in
+            program and documentation
+          </li>
+        </ul> <em>Launching Jalview</em>
+        <ul>
+          <li>
+            <!-- JAL-3718 -->Jalview application fails when launched the
+            first time for a version that has different jars to the
+            previous launched version.
+          </li>
+        </ul> <em>Developing Jalview</em>
+        <ul>
+          <li>
+            <!-- JAL-3541 -->Fixed issue with cleaning up old coverage
+            data, causing cloverReport gradle task to fail with an
+            OutOfMemory error.
+          </li>
+          <li>
+            <!-- JAL-3280 -->Migrated the Jalview Version Checker to
+            monitor the release channel
+          </li>
+        </ul> <em>New Known defects</em>
+        <ul>
+          <li>
+            <!-- JAL-3748 -->CDS shown in result of submitting proteins
+            in a CDS/Protein alignment to a web service is wrong when
+            proteins share a common transcript sequence (e.g.
+            genome of RNA viruses)
+          </li>
+          <li>
+            <!-- JAL-3576 -->Co-located features exported and re-imported
+            are ordered differently when shown on alignment and in
+            tooltips. (Also affects v2.11.1.0)
+          </li>
+          <li>
+            <!-- JAL-3702 -->Drag and drop of alignment file onto
+            alignment window when in a HiDPI scaled mode in Linux only
+            works for the top left quadrant of the alignment window
+          </li>
+          <li>
+            <!-- JAL-3701 -->Stale build data in jalview standalone jar
+            builds (only affects 2.11.1.1 branch)
+          </li>
+          <li>
+            <!-- JAL-3127 -->Sequence ID colourscheme not re-applied
+            when alignment view restored from project (since Jalview 2.11.0)
+          </li>
+          <li>
+            <!-- JAL-3749 -->Duplicate CDS sequences are generated when
+            protein products for certain ENA records are repeatedly
+            shown via Calculate-&gt;Show Cross Refs
+          </li>
+        </ul>
       </td>
     </tr>
     <tr>
index c3c1d3f..2e8b69a 100644 (file)
@@ -25,7 +25,7 @@
   <p>
     <strong>The Jalview Desktop RSS News Reader</strong><br /> The
     Jalview Desktop includes a built in news reader for the <a
-      href="http://www.jalview.org/feeds/desktop/rss">Jalview
+      href="https://www.jalview.org/feeds/desktop/rss">Jalview
       Desktop News Channel</a>.
   </p>
 
@@ -48,9 +48,9 @@
   <br />
   <p>
     The <em>Jalview news reader</em> was introduced in <a
-      href="http://www.jalview.org/releaseHistory.html#Jalview2.7">Jalview
+      href="https://www.jalview.org/releaseHistory.html#Jalview2.7">Jalview
       version 2.7</a>. Its implementation is based on <a
-      href="http://jswingreader.sourceforge.net/">JSwingReader</a>.
+      href="https://jswingreader.sourceforge.net/">JSwingReader</a>.
   </p>
   <br />
   <em>If you need to prevent the news-reader opening, then add the
index 0f0c7f1..0cf5661 100755 (executable)
 </head>
 <body>
   <p>
-    <strong>Jalview 2.11.1.0</strong>
+    <strong>Welcome to Jalview Version $$Version-Rel$$ !!</strong>
+    <br />Please take a
+    look at the <a href="releases.html#Jalview.$$Version-Rel$$">release
+      notes</a> for this build. Read on for the highlights.
   </p>
   <p>
-    Jalview 2.11.1.0 is the first minor release for the 2.11 series.
-    Along with a number of critical bug fixes and improvements it brings
-    new functionality for mapping sequence features between CDS and
-    Protein alignments. It is also the first release made under a new <em>four</em>
-    number versioning scheme, which will allow us to keep track of
-    patches and bug fixes.
+    <strong>Highlights in 2.11.2</strong>
+  </p>
+  <p><strong>New features for working with 3D Structure</strong><br/>
+    Jalview 2.11.2 features a number of new capabilities:<ul><li><strong>Linked viewing with <em>ChimeraX</em> and <em>PyMol</em></strong><br/>Simply configure your prefered viewer for 3D molecular data in <a href="features/preferences.html#structure">Jalview's structure preferences</a>, make sure that Jalview can locate the viewer's installation, and open a new view via the 3D Structure Chooser!</li>
+      <li><strong>View predicted protein structures via 3D-Beacons</strong><br/>
+       Jalview 2.11.2's <a href="features/structurechooser.html">Structure Chooser includes a client for the 3D-Beacons Network</a>, a new service that allows predicted and observed 3D models for proteins in Uniprot from a range of resources, including AlphaFold DB, SWISS-MODEL and a growing number of other resources. 
+      </li>
+  <p><strong>Retrieval
   </p>
-  <ul>
-    <li><strong>Virtual Features</strong><br />In previous
-      versions of Jalview, specific nucleotide sequence features such as
-      genomic variants and exons were transferred to protein products on
-      import. Jalview 2.11.1 instead provides 'virtual features' that
-      can be enabled and overlaid on linked CDS/Protein views via their
-      <a href="features/splitView.html#virtualfeats">Sequence
-        Features dialog</a>. This allows more analyses of nucleotide and
-      peptide sequence features on alignments in a more flexible and
-      memory efficient way than in earlier versions.<br />
-    <em>Note: Virtual features work best when variants are
-        annotated with CSQ fields. Please <a
-        href="features/importvcf.html#computepepvariants">see this
-          Groovy script workaround</a> if you are working with VCF files
-        without CSQ fields.
-    </em></li>
-    <li><strong>Improved VCF data import</strong><br /> <a
-      href="features/importvcf.html#attribs">Standard attributes for
-        filtering variants</a> (e.g. position, QUAL field etc) are now
-      extracted from VCF files. This new feature was suggested by a user
-      at the Jalview booth during ISMB 2019.</li>
-    <li><strong>Extended feature attributes are exported
-        in GFF3</strong><br />Complex attributes from VCF files can be exported
-      and imported via GFF3</li>
-    <li><strong>Updated Jalview Installer and Launcher</strong><br />Jalview's
-      installation packages are now built with Install4j 8, which brings
-      better support for Linux and improved control of file
-      associations. New <a href="memory.html#jvm">parameters on the
-        Jalview launcher</a> allow an upper memory limit to be specified <em>via</em>
-      a Jalview launch file, to prevent it from hogging your system.</li>
-  </ul>
   <p>
-    See the <a href="releases.html#Jalview.2.11.1.0">2.11.1.0
-      release notes</a> for full details of bugs fixed and new known issues.
+    For the full release notes, see <a
+      href="releases.html#Jalview.2.11.1.4">the Jalview 2.11.1.4
+      release notes</a>.
   </p>
   <p>
-    <em>JalviewJS News</em><br />With the release of Jalview 2.11.1.0,
-    the team are now focused on bringing JalviewJS to full production.
-    To follow our progress take a look at <em>http://www.jalview.org/jalview-js/</em>
-    and follow updates on our new <a
-      href="https://github.com/jalview/jalview-js/">JalviewJS
-      Releases github repository</a>.
+    <strong>Known Issues</strong>
   </p>
+  <p>New known issues in this release affect recovery of CDS/Protein
+    relationships from project files, and interactive selection of
+    protein sequences from a tree built on linked nucleotide sequences.
+    We will provide patches for these issues as soon as possible.</p>
+  </ul>
 </body>
 </html>
diff --git a/j11lib/Jmol-15.1.3.jar b/j11lib/Jmol-15.1.3.jar
deleted file mode 100644 (file)
index 1672e67..0000000
Binary files a/j11lib/Jmol-15.1.3.jar and /dev/null differ
diff --git a/j11lib/Jmol-NO_LOG4J-14.31.53.jar b/j11lib/Jmol-NO_LOG4J-14.31.53.jar
new file mode 100644 (file)
index 0000000..df7aa7d
Binary files /dev/null and b/j11lib/Jmol-NO_LOG4J-14.31.53.jar differ
index dadce6e..a11a269 100644 (file)
Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ
similarity index 58%
rename from j11lib/groovy-all-2.4.12-indy.jar
rename to j11lib/groovy-all-2.4.21-indy.jar
index bb246a3..15ee98d 100644 (file)
Binary files a/j11lib/groovy-all-2.4.12-indy.jar and b/j11lib/groovy-all-2.4.21-indy.jar differ
diff --git a/j11lib/jabaws-min-client-2.2.0.jar b/j11lib/jabaws-min-client-2.2.0.jar
deleted file mode 100644 (file)
index 37426c3..0000000
Binary files a/j11lib/jabaws-min-client-2.2.0.jar and /dev/null differ
diff --git a/j11lib/jabaws-min-client-NO_LOG4J-2.2.0.jar b/j11lib/jabaws-min-client-NO_LOG4J-2.2.0.jar
new file mode 100644 (file)
index 0000000..3838eeb
Binary files /dev/null and b/j11lib/jabaws-min-client-NO_LOG4J-2.2.0.jar differ
diff --git a/j11lib/log4j-api-2.17.1.jar b/j11lib/log4j-api-2.17.1.jar
new file mode 100644 (file)
index 0000000..1aae243
Binary files /dev/null and b/j11lib/log4j-api-2.17.1.jar differ
diff --git a/j11lib/log4j-core-2.17.1.jar b/j11lib/log4j-core-2.17.1.jar
new file mode 100644 (file)
index 0000000..4682527
Binary files /dev/null and b/j11lib/log4j-core-2.17.1.jar differ
diff --git a/j11lib/log4j-slf4j18-impl-2.17.1.jar b/j11lib/log4j-slf4j18-impl-2.17.1.jar
new file mode 100644 (file)
index 0000000..a2bce46
Binary files /dev/null and b/j11lib/log4j-slf4j18-impl-2.17.1.jar differ
diff --git a/j11lib/log4j-to-slf4j-2.0-rc2.jar b/j11lib/log4j-to-slf4j-2.0-rc2.jar
deleted file mode 100644 (file)
index 4bbf54a..0000000
Binary files a/j11lib/log4j-to-slf4j-2.0-rc2.jar and /dev/null differ
diff --git a/j11lib/slf4j-api-1.7.26.jar b/j11lib/slf4j-api-1.7.26.jar
deleted file mode 100644 (file)
index d2f27ac..0000000
Binary files a/j11lib/slf4j-api-1.7.26.jar and /dev/null differ
diff --git a/j11lib/slf4j-api-1.7.32.jar b/j11lib/slf4j-api-1.7.32.jar
new file mode 100644 (file)
index 0000000..b16a078
Binary files /dev/null and b/j11lib/slf4j-api-1.7.32.jar differ
diff --git a/j11lib/slf4j-log4j12-1.7.26.jar b/j11lib/slf4j-log4j12-1.7.26.jar
deleted file mode 100644 (file)
index aed1195..0000000
Binary files a/j11lib/slf4j-log4j12-1.7.26.jar and /dev/null differ
diff --git a/j8lib/Jmol-14.29.17.jar b/j8lib/Jmol-14.29.17.jar
deleted file mode 100644 (file)
index 136eb93..0000000
Binary files a/j8lib/Jmol-14.29.17.jar and /dev/null differ
diff --git a/j8lib/Jmol-NO_LOG4J-14.31.53.jar b/j8lib/Jmol-NO_LOG4J-14.31.53.jar
new file mode 100644 (file)
index 0000000..df7aa7d
Binary files /dev/null and b/j8lib/Jmol-NO_LOG4J-14.31.53.jar differ
index dadce6e..a11a269 100644 (file)
Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ
similarity index 58%
rename from j8lib/groovy-all-2.4.12-indy.jar
rename to j8lib/groovy-all-2.4.21-indy.jar
index bb246a3..15ee98d 100644 (file)
Binary files a/j8lib/groovy-all-2.4.12-indy.jar and b/j8lib/groovy-all-2.4.21-indy.jar differ
diff --git a/j8lib/jabaws-min-client-2.2.0.jar b/j8lib/jabaws-min-client-2.2.0.jar
deleted file mode 100644 (file)
index 37426c3..0000000
Binary files a/j8lib/jabaws-min-client-2.2.0.jar and /dev/null differ
diff --git a/j8lib/jabaws-min-client-NO_LOG4J-2.2.0.jar b/j8lib/jabaws-min-client-NO_LOG4J-2.2.0.jar
new file mode 100644 (file)
index 0000000..3838eeb
Binary files /dev/null and b/j8lib/jabaws-min-client-NO_LOG4J-2.2.0.jar differ
diff --git a/j8lib/log4j-api-2.17.1.jar b/j8lib/log4j-api-2.17.1.jar
new file mode 100644 (file)
index 0000000..1aae243
Binary files /dev/null and b/j8lib/log4j-api-2.17.1.jar differ
diff --git a/j8lib/log4j-core-2.17.1.jar b/j8lib/log4j-core-2.17.1.jar
new file mode 100644 (file)
index 0000000..4682527
Binary files /dev/null and b/j8lib/log4j-core-2.17.1.jar differ
diff --git a/j8lib/log4j-slf4j18-impl-2.17.1.jar b/j8lib/log4j-slf4j18-impl-2.17.1.jar
new file mode 100644 (file)
index 0000000..a2bce46
Binary files /dev/null and b/j8lib/log4j-slf4j18-impl-2.17.1.jar differ
diff --git a/j8lib/log4j-to-slf4j-2.0-rc2.jar b/j8lib/log4j-to-slf4j-2.0-rc2.jar
deleted file mode 100644 (file)
index 4bbf54a..0000000
Binary files a/j8lib/log4j-to-slf4j-2.0-rc2.jar and /dev/null differ
diff --git a/j8lib/slf4j-api-1.7.32.jar b/j8lib/slf4j-api-1.7.32.jar
new file mode 100644 (file)
index 0000000..b16a078
Binary files /dev/null and b/j8lib/slf4j-api-1.7.32.jar differ
diff --git a/j8lib/slf4j-api-1.7.7.jar b/j8lib/slf4j-api-1.7.7.jar
deleted file mode 100644 (file)
index b28e220..0000000
Binary files a/j8lib/slf4j-api-1.7.7.jar and /dev/null differ
diff --git a/j8lib/slf4j-log4j12-1.7.7.jar b/j8lib/slf4j-log4j12-1.7.7.jar
deleted file mode 100644 (file)
index 12c804e..0000000
Binary files a/j8lib/slf4j-log4j12-1.7.7.jar and /dev/null differ
diff --git a/lib/Jmol-14.29.17.jar b/lib/Jmol-14.29.17.jar
deleted file mode 100644 (file)
index 136eb93..0000000
Binary files a/lib/Jmol-14.29.17.jar and /dev/null differ
index 278b86e..38f0853 100644 (file)
@@ -75,7 +75,6 @@ Space Group;spacegroup;String;g6;50;400;95;false;false
 Cath Code;cath_code;String;g2;50;400;95;false;false
 Tax Id;tax_id;String;g2;50;400;95;false;false
 Tax Query;tax_query;String;g2;50;400;95;false;false
-Interacting Entity Id;interacting_entity_id;String;g2;50;400;95;false;false
 Interacting Molecules;interacting_molecules;String;g6;50;400;95;false;false
 Pubmed Id;pubmed_id;int;g2;50;400;95;false;false
 Status;status;String;g6;50;400;95;false;false
diff --git a/resources/fts/tdbeacons_data_columns.txt b/resources/fts/tdbeacons_data_columns.txt
new file mode 100644 (file)
index 0000000..3e4d1c8
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+tdbeacons_data_columns
+#
+_group.id
+_group.name
+_group.sort_order
+g1;ModelInfo;1
+g2;Quality;2
+g3;Miscellaneous;3
+
+#
+_data_column.primary_key;model_url
+_data_column.default_response_page_size;100
+#
+_data_column.name
+_data_column.code
+_data_column.group_id
+_data_column.data_type  | _data_column.isFormated | _data_column.significantDigit
+_data_column.min_col_width
+_data_column.max_col_width
+_data_column.preferred_col_width
+_data_column.is_shown_by_default
+_data_column.is_searchable
+Uniprot Id;id;String;g1;80;150;85;false;false
+Uniprot Start;uniprot_start;Integer;g1;80;150;85;true;false
+Uniprot End;uniprot_end;Integer;g1;80;150;85;true;false
+Provider;provider;String;g1;80;150;85;true;false
+Model id;model_identifier;String;g3;80;150;85;true;false
+Model Category;model_category;String;g1;80;150;85;true;false
+Model Type;model_type;String;g1;80;150;85;false;false
+Title;model_title;String;g1;100;150;105;true;false
+Resolution;resolution;double|T|3;g2;80;150;85;true;false
+Confidence;confidence_avg_local_score;double|T|2;g2;100;150;105;true;false
+Confidence Score Type;confidence_type;String;g2;100;150;105;true;false
+Confidence Score Version;confidence_version;String;g2;100;150;105;true;false
+Coverage;coverage;double|T|2;g2;80;150;85;true;false
+Sequence Identity;sequence_identity;double|T|1;g2;80;150;85;false;false
+Created Date;created;string;g3;80;150;85;true;false
+UniProt Accession;uniprot_accession;String;g1;50;400;95;false;true
+Url;model_url;String;g3;100;150;105;true;false
+Model Format;model_format;String;g3;20;60;20;true;false
+Page URL;model_page_url;String;g3;100;150;105;true;false
+Ensemble Sample Url;ensembl_sample_url;String;g3;100;150;105;false;false
diff --git a/resources/images/3d-beacons-logo-transparent.png b/resources/images/3d-beacons-logo-transparent.png
new file mode 100644 (file)
index 0000000..88aca46
Binary files /dev/null and b/resources/images/3d-beacons-logo-transparent.png differ
index d8217d2..b448b4c 100644 (file)
@@ -118,6 +118,7 @@ action.paste_annotations = Paste Annotations
 action.format = Format
 action.select = Select
 action.new_view = New View
+action.new_structure_view_with = Open new structure view with {0}
 action.close = Close
 action.add = Add
 action.save_as = Save as...
@@ -328,6 +329,7 @@ label.successfully_pasted_alignment_file = Successfully pasted alignment file
 label.paste_your_alignment_file = Paste your alignment file here
 label.paste_your = Paste your
 label.finished_searching = Finished searching
+label.subsequence_matches_found = {0} subsequence matches found
 label.search_results= Search results {0} : {1}
 label.found_match_for = Found match for {0}
 label.font = Font:
@@ -511,6 +513,12 @@ label.load_tree_file = Load a tree file
 label.retrieve_parse_sequence_database_records_alignment_or_selected_sequences = Retrieve and parse sequence database records for the alignment or the currently selected sequences
 label.standard_databases = Standard Databases
 label.fetch_embl_uniprot = Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources
+label.fetch_uniprot_references = Fetch Uniprot references
+label.search_3dbeacons = 3D-Beacons Search
+label.find_models_from_3dbeacons = Search 3D-Beacons for 3D structures and models
+label.3dbeacons = 3D-Beacons
+label.fetch_references_for = Fetch database references for {0} sequences ?
+label.fetch_references_for_3dbeacons = 3D Beacons needs Uniprot References. Fetch database references for {0} sequences ?
 label.reset_min_max_colours_to_defaults = Reset min and max colours to defaults from user preferences.
 label.align_structures_using_linked_alignment_views = Superpose structures using {0} selected alignment view(s)
 label.threshold_feature_display_by_score = Threshold the feature display by score.
@@ -617,8 +625,8 @@ label.editing = Editing
 label.web_services = Web Services
 label.right_click_to_edit_currently_selected_parameter = Right click to edit currently selected parameter.
 label.let_jmol_manage_structure_colours = Let Jmol manage structure colours
-label.fetch_chimera_attributes = Fetch Chimera attributes
-label.fetch_chimera_attributes_tip = Copy Chimera attribute to Jalview feature
+label.fetch_viewer_attributes = Fetch {0} attributes
+label.fetch_viewer_attributes_tip = Copy {0} attribute to Jalview feature
 label.marks_leaves_tree_not_associated_with_sequence = Marks leaves of tree not associated with a sequence
 label.index_web_services_menu_by_host_site = Index web services in menu by the host site
 label.option_want_informed_web_service_URL_cannot_be_accessed_jalview_when_starts_up = Check this option if you want to be informed<br>when a web service URL cannot be accessed by Jalview<br>when it starts up
@@ -710,7 +718,7 @@ error.superposition_failed = Superposition failed: {0}
 label.insufficient_residues = Not enough aligned residues ({0}) to perform superposition
 label.create_viewer_attributes = Write Jalview features
 label.create_viewer_attributes_tip = Set structure residue attributes for Jalview features
-label.attributes_set = {0} attribute values set on Chimera
+label.attributes_set = {0} attribute values set on {1}
 label.sort_alignment_by_tree = Sort Alignment By Tree
 label.mark_unlinked_leaves = Mark Unlinked Leaves
 label.associate_leaves_with = Associate Leaves With
@@ -931,7 +939,7 @@ label.groovy_support_failed = Jalview Groovy Support Failed
 label.couldnt_create_groovy_shell = Couldn't create the groovy Shell. Check the error log for the details of what went wrong.
 error.unsupported_version_calcIdparam = Unsupported Version for calcIdparam {0}
 error.implementation_error_cant_reorder_tree = Implementation Error: Can't reorder this tree. Not DefaultMutableTreeNode.
-error.invalid_value_for_option = Invalid value {0} for option {1}
+error.invalid_value_for_option = Invalid value ''{0}'' for option ''{1}''
 error.implementation_error_cannot_import_vamsas_doc = Implementation Error - cannot import existing vamsas document into an existing session, Yet!
 label.vamsas_doc_couldnt_be_opened_as_new_session = VAMSAS Document could not be opened as a new session - please choose another
 error.setstatus_called_non_existent_job_pane = setStatus called for non-existent job pane {0}
@@ -955,7 +963,6 @@ error.implementation_error_minlen_must_be_greater_zero = Implementation error: m
 error.implementation_error_msawbjob_called = Implementation error - StartJob(MsaWSJob) called on a WSJobInstance {0}
 error.implementation_error_cannot_attach_ws_menu_entry = IMPLEMENTATION ERROR: cannot attach WS Menu Entry without service handle reference!
 error.parameter_migration_not_implemented_yet = Parameter migration not implemented yet
-error.implementation_error_cannot_set_jaba_option = Implementation error: cannot set Jaba Option to a value outside its allowed value range!
 error.implementation_error_valuetype_doesnt_support_jabaws_type = IMPLEMENTATION ERROR: jalview.ws.params.ValueConstrainI.ValueType does not support the JABAWS type : {0}
 error.cannot_create_jabaws_param_set = Cannot create a JabaWSParamSet from non-JabaWS parameters
 error.cannot_set_arguments_to_jabaws_param_set = Cannot set arguments to a JabaWSParamSet that are not JabaWS arguments
@@ -1049,7 +1056,6 @@ exception.unable_to_create_internet_config = Unable to create an Internet Config
 exception.invocation_target_calling_url = InvocationTargetException while calling openURL: {0}
 exception.illegal_access_calling_url = IllegalAccessException while calling openURL: {0}
 exception.interrupted_launching_browser = InterruptedException while launching browser: {0}
-exception.ebiembl_retrieval_failed_on = EBI EMBL XML retrieval failed on {0}:{1}
 exception.no_pdb_records_for_chain = No PDB Records for {0} chain {1}
 exception.unexpected_handling_rnaml_translation_for_pdb = Unexpected exception when handling RNAML translation of PDB data
 exception.couldnt_recover_sequence_properties_for_alignment = Couldn't recover sequence properties for alignment
@@ -1101,6 +1107,8 @@ status.collecting_job_results = Collecting job results.
 status.fetching_db_refs = Fetching db refs
 status.loading_cached_pdb_entries = Loading Cached PDB Entries
 status.searching_for_pdb_structures = Searching for PDB Structures
+status.searching_3d_beacons = Searching 3D Beacons
+status.no_structures_discovered_from_3d_beacons = No models discovered from 3D Beacons
 status.opening_file_for = opening file for
 status.colouring_structures = Colouring structures
 label.font_doesnt_have_letters_defined = Font doesn't have letters defined\nso cannot be used\nwith alignment data
@@ -1134,6 +1142,7 @@ label.add_annotations_for = Add annotations for
 action.choose_annotations = Choose Annotations...
 label.choose_annotations = Choose Annotations
 label.find = Find
+label.in = in
 label.invalid_search = Search string invalid
 error.invalid_regex = Invalid regular expression
 label.ignore_gaps_consensus = Ignore Gaps In Consensus
@@ -1390,3 +1399,14 @@ label.log_level = Log level
 label.log_level_tooltip = Temporarily set the log level for this console. The log level will revert to {0} when this Java console is closed.
 label.copy_to_clipboard = Copy to clipboard
 label.copy_to_clipboard_tooltip = Copy all of the log text in this console to the system clipboard
+label.startup = Startup
+label.memory = Memory
+label.customise_memory_settings = Customise maximum memory settings
+label.memory_setting_text = New memory settings will only come into effect the next time you start Jalview
+label.maximum_memory_used = Maximum memory limited to both
+label.percent_of_physical_memory = Maximum percent of physical memory
+label.maximum_memory = Maximum absolute memory
+label.maximum_memory_tooltip = Enter memory as an integer number optionally followed by 'b', 'k', 'm', 'g' or 't'
+label.adjustments_for_this_computer = Adjustments for this computer
+label.memory_example_text = Maximum memory that would be used with these settings on this computer
+label.memory_example_tooltip = The memory allocated to Jalview is the smaller of the percentage of physical memory (default 90%) and the maximum absolute memory (default 32GB). If your computer's memory cannot be ascertained then the maximum absolute memory defaults to 8GB (if not customised).<br>Jalview will always try and reserve 512MB for the OS and at least 512MB for itself.
index fdf4201..49e05e3 100644 (file)
@@ -253,7 +253,7 @@ label.min_value = Valor m
 label.no_value = Sin valor
 label.colour_by_label = Color por etiquetas
 label.new_feature = Nueva función
-label.match_case = Hacer corresponder mayúsculas y minúsculas
+label.match_case = Distinguir min/mayúsculas
 label.view_alignment_editor = Ver en el editor de alineamientos
 label.labels = Etiquetas
 label.output_values = Valores de salida...
@@ -294,6 +294,7 @@ label.successfully_pasted_alignment_file = Fichero de alineamiento pegado exitos
 label.paste_your_alignment_file = Pegar su fichero de alineamiento aquí
 label.paste_your = Pegar su
 label.finished_searching = Búsqueda finalizada
+label.subsequence_matches_found = {0} resultados encontrados en subsequencias
 label.search_results= Buscar Resultados {0} : {1}
 label.found_match_for = Buscar coincidencia para {0}
 label.font = Fuente:
@@ -856,7 +857,7 @@ label.groovy_support_failed = El soporte Groovy de Jalview ha fallado
 label.couldnt_create_groovy_shell = No es posible crear el shell de Groovy. Compruebe el fichero de log para conocer los detalles.
 error.unsupported_version_calcIdparam = Versión no soportada de {0}
 error.implementation_error_cant_reorder_tree = Error de implementación: no es posible reordenar este Ã¡rbol. No DefaultMutableTreeNode.
-error.invalid_value_for_option = Valor no válido de {0} para la opción {1}
+error.invalid_value_for_option = Valor no válido de ''{0}'' para la opción ''{1}''
 error.implementation_error_cannot_import_vamsas_doc = Error de implementación - todavía no es posible importar el documento VAMSAS existente en una sesión existente.
 label.vamsas_doc_couldnt_be_opened_as_new_session = El documento VAMSAS no ha podido abrirse como una nueva sesión. Por favor, escoja otra.
 error.setstatus_called_non_existent_job_pane = se lllamado a setStatus para el panel de trabajo {0} no existente
@@ -880,7 +881,6 @@ error.implementation_error_minlen_must_be_greater_zero = Error de implementaci
 error.implementation_error_msawbjob_called = Error de implementación - StartJob(MsaWSJob) invocado en un WSJobInstance {0}
 error.implementation_error_cannot_attach_ws_menu_entry = Error de implementación: Â¡no es posible adjunto una WS Menu Entry sin una referencia a un manejador del servicio!
 error.parameter_migration_not_implemented_yet = La migración de parámetros no se ha implementado todavía
-error.implementation_error_cannot_set_jaba_option = Error de implementación: no es posible establecer el valor de Jaba Option a un valor fuera de su rango permitido
 error.implementation_error_valuetype_doesnt_support_jabaws_type = Error de implementación: jalview.ws.params.ValueConstrainI.ValueType no soporta el tipo JABAWS: {0}
 error.cannot_create_jabaws_param_set = No es posible crear un JabaWSParamSet con parámetros no JabaWS
 error.cannot_set_arguments_to_jabaws_param_set = No es posible establecer argumentos en JabaWSParamSet que no sean argumentos JabaWS 
@@ -974,7 +974,6 @@ exception.unable_to_create_internet_config = Imposible crear una instancia de co
 exception.invocation_target_calling_url = InvocationTargetException mientras se invocaba openURL: {0}
 exception.illegal_access_calling_url = IllegalAccessException mientras se invocaba openURL: {0}
 exception.interrupted_launching_browser = InterruptedException mientras se lanzaba el navegador: {0}
-exception.ebiembl_retrieval_failed_on = La recuperación de datos EBI EMBL XML ha fallado en {0}:{1}
 exception.no_pdb_records_for_chain = No se han encontrado registros {0} para la cadena {1}
 exception.unexpected_handling_rnaml_translation_for_pdb = Excepcion inesperada cuando se traducían a RNAML los datos PDB
 exception.couldnt_recover_sequence_properties_for_alignment = No es posible recuperar las propiedades de la secuencia para el alineamiento
@@ -1120,6 +1119,7 @@ action.set_as_reference=Marcar como Referencia
 action.unmark_as_reference=Desmarcar como Referencia
 label.open_viewer_failed=Error al abrir {0} - está instalado?\nCompruebe ruta en Preferencias, Estructura
 label.find=Buscar
+label.in = en
 label.select_pdb_file=Seleccionar Fichero PDB
 label.structures_filter=Filtro de Estructuras
 label.scale_protein_to_cdna=Adaptar proteína a cDNA
@@ -1389,3 +1389,14 @@ label.log_level = Nivel del registro
 label.log_level_tooltip = Establezca temporalmente el nivel de registro para esta consola. El nivel de registro volverá a {0} cuando se cierre esta consola de Java.
 label.copy_to_clipboard = Copiar en el portapapeles
 label.copy_to_clipboard_tooltip = Copie todo el texto de registro en esta consola al portapapeles del sistema
+label.startup = Inicio
+label.memory = Memoria
+label.customise_memory_settings = Personalizar la configuración de memoria máxima
+label.memory_setting_text = La nueva configuración de memoria solo entrará en vigor la próxima vez que inicie Jalview
+label.maximum_memory_used = Memoria máxima limitada a ambos
+label.percent_of_physical_memory = Porcentaje máximo de memoria física
+label.maximum_memory = Memoria absoluta máxima
+label.maximum_memory_tooltip = Ingrese la memoria como un número entero seguido opcionalmente por 'b', 'k', 'm', 'g' o 't'
+label.adjustments_for_this_computer = Ajustes para esta computadora
+label.memory_example_text = Memoria máxima que se usaría con esta configuración en esta computadora
+label.memory_example_tooltip = La memoria asignada a Jalview es el menor entre el porcentaje de memoria física (predeterminado 90%) y la memoria absoluta máxima (predeterminado 32 GB). Si no se puede determinar la memoria de su computadora, la memoria absoluta máxima predeterminada es de 8 GB (si no está personalizada).<br>Jalview siempre intentará reservar 512 MB para el sistema operativo y al menos 512 MB para sí mismo.
index 20c19dd..333a4e4 100755 (executable)
                                                                                </xs:documentation>
                                                                        </xs:annotation>
                                                                </xs:attribute>
+                                                               <xs:attribute name="canonical" type="xs:boolean" default="false">
+                                                                       <xs:annotation>
+                                                                               <xs:documentation>
+                                                                                       true for the representative accession for databases where multiple accessions map to the same entry (eg. Uniprot)
+                                                                               </xs:documentation>
+                                                                       </xs:annotation>
+                                                               </xs:attribute>
                                                        </xs:complexType>
                                                </xs:element>
                                        </xs:sequence>
index d7e7937..19d6a8b 100644 (file)
@@ -38,6 +38,9 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -363,7 +366,7 @@ public class ChimeraManager
    * Select something in Chimera
    * 
    * @param command
-   *          the selection command to pass to Chimera
+   *                  the selection command to pass to Chimera
    */
   public void select(String command)
   {
@@ -509,8 +512,8 @@ public class ChimeraManager
 
   /**
    * Return the list of depiction presets available from within Chimera. Chimera
-   * will return the list as a series of lines with the format: Preset type
-   * number "description"
+   * will return the list as a series of lines with the format: Preset type number
+   * "description"
    * 
    * @return list of presets
    */
@@ -551,9 +554,9 @@ public class ChimeraManager
   }
 
   /**
-   * Launch Chimera, unless an instance linked to this object is already
-   * running. Returns true if chimera is successfully launched, or already
-   * running, else false.
+   * Launch Chimera, unless an instance linked to this object is already running.
+   * Returns true if chimera is successfully launched, or already running, else
+   * false.
    * 
    * @param chimeraPaths
    * @return
@@ -696,7 +699,7 @@ public class ChimeraManager
    * Determine the color that Chimera is using for this model.
    * 
    * @param model
-   *          the ChimeraModel we want to get the Color for
+   *                the ChimeraModel we want to get the Color for
    * @return the default model Color for this model in Chimera
    */
   public Color getModelColor(ChimeraModel model)
@@ -713,11 +716,11 @@ public class ChimeraManager
   /**
    * 
    * Get information about the residues associated with a model. This uses the
-   * Chimera listr command. We don't return the resulting residues, but we add
-   * the residues to the model.
+   * Chimera listr command. We don't return the resulting residues, but we add the
+   * residues to the model.
    * 
    * @param model
-   *          the ChimeraModel to get residue information for
+   *                the ChimeraModel to get residue information for
    * 
    */
   public void addResidues(ChimeraModel model)
@@ -809,10 +812,10 @@ public class ChimeraManager
    * Send a command to Chimera.
    * 
    * @param command
-   *          Command string to be send.
+   *                  Command string to be send.
    * @param reply
-   *          Flag indicating whether the method should return the reply from
-   *          Chimera or not.
+   *                  Flag indicating whether the method should return the reply
+   *                  from Chimera or not.
    * @return List of Strings corresponding to the lines in the Chimera reply or
    *         <code>null</code>.
    */
@@ -833,7 +836,7 @@ public class ChimeraManager
      */
     int waited = 0;
     int pause = 25;
-    while (busy  && waited < 1001)
+    while (busy && waited < 1001)
     {
       try
       {
@@ -876,8 +879,15 @@ public class ChimeraManager
     String method = getHttpRequestMethod();
     if ("GET".equals(method))
     {
-      command = command.replace(" ", "+").replace("#", "%23")
-              .replace("|", "%7C").replace(";", "%3B");
+      try
+      {
+        command = URLEncoder.encode(command, StandardCharsets.UTF_8.name());
+      } catch (UnsupportedEncodingException e)
+      {
+        command = command.replace(" ", "+").replace("#", "%23")
+                .replace("|", "%7C").replace(";", "%3B")
+                .replace(":", "%3A");
+      }
     }
     commands.add(new BasicNameValuePair("command", command));
 
index 5cf8a73..0a248cf 100644 (file)
@@ -69,13 +69,13 @@ public class StructureManager
    * 0.93 is ChimeraX latest, 1.0 expected soon
    */
   private static String[] CHIMERA_VERSIONS = new String[] { "1.16.2",
-      "1.16.1", "1.16",
-      "1.15.2", "1.15.1", "1.15", "1.14.2", "1.14.1", "1.14",
-      "1.13.1", "1.13", "1.12.2", "1.12.1", "1.12", "1.11.2",
+      "1.16.1", "1.16", "1.15.2", "1.15.1", "1.15", "1.14.2", "1.14.1",
+      "1.14", "1.13.1", "1.13", "1.12.2", "1.12.1", "1.12", "1.11.2",
       "1.11.2", "1.11.1", "1.11" };
 
-  private static String[] CHIMERAX_VERSIONS = new String[] { "1.0", "0.93",
-      "0.92", "0.91", "0.9" };
+  // Missing 1.1 as this has known bug see JAL-2422
+  private static String[] CHIMERAX_VERSIONS = new String[] { "1.2.5", "1.0",
+      "0.93", "0.92", "0.91", "0.9" };
 
   static final String[] defaultStructureKeys = { "Structure", "pdb",
       "pdbFileName", "PDB ID", "structure", "biopax.xref.PDB", "pdb_ids",
@@ -561,8 +561,8 @@ public class StructureManager
 
   /**
    * This is called by the selectionListener to let us know that the user has
-   * changed their selection in Chimera. We need to go back to Chimera to find
-   * out what is currently selected and update our list.
+   * changed their selection in Chimera. We need to go back to Chimera to find out
+   * what is currently selected and update our list.
    */
   public void chimeraSelectionChanged()
   {
@@ -677,11 +677,11 @@ public class StructureManager
   }
 
   /**
-   * Add a selection to the selection list. This is called primarily by the
-   * Model Navigator Dialog to keep the selections in sync
+   * Add a selection to the selection list. This is called primarily by the Model
+   * Navigator Dialog to keep the selections in sync
    * 
    * @param selectionToAdd
-   *          the selection to add to our list
+   *                         the selection to add to our list
    */
   public void addChimSelection(ChimeraStructuralObject selectionToAdd)
   {
@@ -698,7 +698,7 @@ public class StructureManager
    * Model Navigator Dialog to keep the selections in sync
    * 
    * @param selectionToRemove
-   *          the selection to remove from our list
+   *                            the selection to remove from our list
    */
   public void removeChimSelection(ChimeraStructuralObject selectionToRemove)
   {
@@ -936,16 +936,10 @@ public class StructureManager
     // }
     // }
 
-    /*
-     * Jalview addition: check if path set in user preferences
-     */
+    String os = System.getProperty("os.name");
     String userPath = Cache
             .getDefault(isChimeraX ? Preferences.CHIMERAX_PATH
                     : Preferences.CHIMERA_PATH, null);
-    if (userPath != null)
-    {
-      pathList.add(userPath);
-    }
 
     /*
      * paths are based on getChimeraPaths() in
@@ -957,15 +951,61 @@ public class StructureManager
     String chimera = isChimeraX ? "ChimeraX" : "Chimera";
     String chimeraExe = isChimeraX ? "ChimeraX" : "chimera";
 
+    /*
+     * Jalview addition: check if path set in user preferences
+     */
+    if (userPath != null)
+    {
+      // in macos, deal with the user selecting the .app folder
+      boolean adjusted = false;
+      if (os.startsWith("Mac") && userPath.endsWith((".app")))
+      {
+        String possiblePath = String.format("%s/Contents/MacOS/%s",
+                userPath, chimeraExe);
+        if (new File(possiblePath).exists())
+        {
+          pathList.add(possiblePath);
+          adjusted = true;
+        }
+      }
+      if (!adjusted)
+      {
+        pathList.add(userPath);
+      }
+    }
+
     // Add default installation paths
-    String os = System.getProperty("os.name");
     if (os.startsWith("Linux"))
     {
-      // todo should this be /chimeraX/ for ChimeraX? not in structureVizX code
-      pathList.add("/usr/local/chimera/bin/" + chimeraExe);
-      pathList.add("/usr/local/bin/" + chimeraExe);
-      pathList.add("/usr/bin/" + chimeraExe);
-      pathList.add(System.getProperty("user.home") + "/opt/bin/" + chimeraExe);
+      // ChimeraX .deb and .rpm packages put symbolic link from /usr/bin/chimerax
+      pathList.add(String.format("/usr/bin/%s", chimeraExe.toLowerCase()));
+      pathList.add(String.format("/usr/bin/%s", chimeraExe));
+
+      pathList.add(
+              String.format("/usr/local/bin/%s", chimeraExe.toLowerCase()));
+      pathList.add(String.format("/usr/local/bin/%s", chimeraExe));
+
+      // these paths also used by .deb and .rpm
+      pathList.add(String.format("/usr/lib/ucsf-%s/bin/%s",
+              chimera.toLowerCase(), chimeraExe));
+      pathList.add(String.format("/usr/libexec/UCSF-%s/bin/%s", chimera,
+              chimeraExe));
+
+      pathList.add(String.format("/usr/local/chimera/bin/%s", chimeraExe));
+
+      // user home paths
+      pathList.add(String.format("%s/bin/%s",
+              System.getProperty("user.home"), chimeraExe.toLowerCase()));
+      pathList.add(String.format("%s/bin/%s",
+              System.getProperty("user.home"), chimeraExe));
+      pathList.add(String.format("%s/opt/bin/%s",
+              System.getProperty("user.home"), chimeraExe.toLowerCase()));
+      pathList.add(String.format("%s/opt/bin/%s",
+              System.getProperty("user.home"), chimeraExe));
+      pathList.add(String.format("%s/local/bin/%s",
+              System.getProperty("user.home"), chimeraExe.toLowerCase()));
+      pathList.add(String.format("%s/local/bin/%s",
+              System.getProperty("user.home"), chimeraExe));
     }
     else if (os.startsWith("Windows"))
     {
@@ -983,12 +1023,32 @@ public class StructureManager
           pathList.add(path);
           pathList.add(path + ".exe");
         }
+        // try without a version number too
+        String path = String.format("%s\\%s\\bin\\%s", root, chimera,
+                chimeraExe);
+        pathList.add(path);
+        pathList.add(path + ".exe");
       }
     }
     else if (os.startsWith("Mac"))
     {
+      // check for installations with version numbers first
+      String[] candidates = isChimeraX ? CHIMERAX_VERSIONS
+              : CHIMERA_VERSIONS;
+      for (String version : candidates)
+      {
+        pathList.add(
+                String.format("/Applications/%s-%s.app/Contents/MacOS/%s",
+                        chimera, version, chimeraExe));
+        pathList.add(
+                String.format("%s/Applications/%s-%s.app/Contents/MacOS/%s",
+                        System.getProperty("user.home"), chimera, version,
+                        chimeraExe));
+      }
       pathList.add(String.format("/Applications/%s.app/Contents/MacOS/%s",
               chimera, chimeraExe));
+      pathList.add(String.format("%s/Applications/%s.app/Contents/MacOS/%s",
+              System.getProperty("user.home"), chimera, chimeraExe));
     }
     return pathList;
   }
index 1b2578e..2fb6ce1 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import jalview.analysis.scoremodels.PIDModel;
 import jalview.analysis.scoremodels.ScoreMatrix;
 import jalview.analysis.scoremodels.ScoreModels;
@@ -148,7 +150,7 @@ public class AlignSeq
   public AlignSeq(SequenceI s1, String string1, SequenceI s2,
           String string2, String type)
   {
-    seqInit(s1, string1.toUpperCase(), s2, string2.toUpperCase(), type);
+    seqInit(s1, string1.toUpperCase(Locale.ROOT), s2, string2.toUpperCase(Locale.ROOT), type);
   }
 
   /**
index 0c40873..28f23b2 100644 (file)
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import jalview.bin.Console;
 import jalview.commands.RemoveGapColCommand;
 import jalview.datamodel.AlignedCodon;
 import jalview.datamodel.AlignedCodonFrame;
@@ -44,22 +63,6 @@ import jalview.util.IntRangeComparator;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
 /**
  * grab bag of useful alignment manipulation operations Expect these to be
  * refactored elsewhere at some point.
@@ -181,9 +184,9 @@ public class AlignmentUtils
       // TODO use Character.toLowerCase to avoid creating String objects?
       char[] upstream = new String(ds
               .getSequence(s.getStart() - 1 - ustream_ds, s.getStart() - 1))
-                      .toLowerCase().toCharArray();
+                      .toLowerCase(Locale.ROOT).toCharArray();
       char[] downstream = new String(
-              ds.getSequence(s_end - 1, s_end + dstream_ds)).toLowerCase()
+              ds.getSequence(s_end - 1, s_end + dstream_ds)).toLowerCase(Locale.ROOT)
                       .toCharArray();
       char[] coreseq = s.getSequence();
       char[] nseq = new char[offset + upstream.length + downstream.length
@@ -462,7 +465,7 @@ public class AlignmentUtils
     if (cdnaLength != mappedLength && cdnaLength > 2)
     {
       String lastCodon = String.valueOf(cdnaSeqChars,
-              cdnaLength - CODON_LENGTH, CODON_LENGTH).toUpperCase();
+              cdnaLength - CODON_LENGTH, CODON_LENGTH).toUpperCase(Locale.ROOT);
       for (String stop : ResidueProperties.STOP_CODONS)
       {
         if (lastCodon.equals(stop))
@@ -479,7 +482,7 @@ public class AlignmentUtils
      */
     int startOffset = 0;
     if (cdnaLength != mappedLength && cdnaLength > 2
-            && String.valueOf(cdnaSeqChars, 0, CODON_LENGTH).toUpperCase()
+            && String.valueOf(cdnaSeqChars, 0, CODON_LENGTH).toUpperCase(Locale.ROOT)
                     .equals(ResidueProperties.START))
     {
       startOffset += CODON_LENGTH;
@@ -1995,45 +1998,31 @@ public class AlignmentUtils
 
     SequenceI newSeq = null;
 
-    final MapList maplist = mapping.getMap();
-    if (maplist.isContiguous() && maplist.isFromForwardStrand())
-    {
-      /*
-       * just a subsequence, keep same dataset sequence
-       */
-      int start = maplist.getFromLowest();
-      int end = maplist.getFromHighest();
-      newSeq = seq.getSubSequence(start - 1, end);
-      newSeq.setName(seqId);
-    }
-    else
-    {
-      /*
-       * construct by splicing mapped from ranges
-       */
-      char[] seqChars = seq.getSequence();
-      List<int[]> fromRanges = maplist.getFromRanges();
-      int cdsWidth = MappingUtils.getLength(fromRanges);
-      char[] newSeqChars = new char[cdsWidth];
+    /*
+     * construct CDS sequence by splicing mapped from ranges
+     */
+    char[] seqChars = seq.getSequence();
+    List<int[]> fromRanges = mapping.getMap().getFromRanges();
+    int cdsWidth = MappingUtils.getLength(fromRanges);
+    char[] newSeqChars = new char[cdsWidth];
 
-      int newPos = 0;
-      for (int[] range : fromRanges)
+    int newPos = 0;
+    for (int[] range : fromRanges)
+    {
+      if (range[0] <= range[1])
       {
-        if (range[0] <= range[1])
-        {
-          // forward strand mapping - just copy the range
-          int length = range[1] - range[0] + 1;
-          System.arraycopy(seqChars, range[0] - 1, newSeqChars, newPos,
-                  length);
-          newPos += length;
-        }
-        else
+        // forward strand mapping - just copy the range
+        int length = range[1] - range[0] + 1;
+        System.arraycopy(seqChars, range[0] - 1, newSeqChars, newPos,
+                length);
+        newPos += length;
+      }
+      else
+      {
+        // reverse strand mapping - copy and complement one by one
+        for (int i = range[0]; i >= range[1]; i--)
         {
-          // reverse strand mapping - copy and complement one by one
-          for (int i = range[0]; i >= range[1]; i--)
-          {
-            newSeqChars[newPos++] = Dna.getComplement(seqChars[i - 1]);
-          }
+          newSeqChars[newPos++] = Dna.getComplement(seqChars[i - 1]);
         }
       }
 
@@ -2067,9 +2056,8 @@ public class AlignmentUtils
           }
           else
           {
-            System.err.println(
-                    "JAL-2154 regression: warning - found (and ignnored a duplicate CDS sequence):"
-                            + mtch.toString());
+            Console.error(
+                    "JAL-2154 regression: warning - found (and ignored) a duplicate CDS sequence:" + mtch.toString());
           }
         }
       }
index 2f556f1..c9ed570 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
@@ -368,7 +370,7 @@ public class AnnotationSorter
     {
       return 1;
     }
-    return label1.toUpperCase().compareTo(label2.toUpperCase());
+    return label1.toUpperCase(Locale.ROOT).compareTo(label2.toUpperCase(Locale.ROOT));
   }
 
   /**
index ff38c08..6cc9dd3 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import jalview.analysis.scoremodels.ScoreMatrix;
 import jalview.analysis.scoremodels.ScoreModels;
 import jalview.datamodel.AlignmentAnnotation;
@@ -312,7 +314,7 @@ public class Conservation
   protected static void recordConservation(Map<String, Integer> resultMap,
           String res)
   {
-    res = res.toUpperCase();
+    res = res.toUpperCase(Locale.ROOT);
     for (Entry<String, Map<String, Integer>> property : ResidueProperties.propHash
             .entrySet())
     {
index c54357e..1783f37 100644 (file)
@@ -443,6 +443,11 @@ public class CrossRef
         addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
                 retrievedDss);
       }
+      // JBPNote: What assumptions are made for dbref structures on 
+      // retrieved sequences ?
+      // addedXref will be true means importCrossRefSeq found 
+      // sequences with dbrefs with mappings to sequences congruent with dss 
+
       if (!addedXref)
       {
         // try again, after looking for matching IDs
@@ -516,7 +521,9 @@ public class CrossRef
 
   /**
    * process sequence retrieved via a dbref on source sequence to resolve and
-   * transfer data
+   * transfer data JBPNote: as of 2022-02-03 - this assumes retrievedSequence
+   * has dbRefs with Mapping references to a sequence congruent with
+   * sourceSequence
    * 
    * @param cf
    * @param sourceSequence
@@ -535,10 +542,11 @@ public class CrossRef
     List<DBRefEntry> dbr = retrievedSequence.getDBRefs();
     if (dbr != null)
     {
-       for (int ib = 0, nb = dbr.size(); ib < nb; ib++)
+      for (int ib = 0, nb = dbr.size(); ib < nb; ib++)
       {
 
-       DBRefEntry dbref = dbr.get(ib);
+        DBRefEntry dbref = dbr.get(ib);
+        // matched will return null if the dbref has no map
         SequenceI matched = findInDataset(dbref);
         if (matched == sourceSequence)
         {
@@ -550,7 +558,7 @@ public class CrossRef
         Mapping map = dbref.getMap();
         if (map != null)
         {
-               SequenceI ms = map.getTo();
+          SequenceI ms = map.getTo();
           if (ms != null && map.getMap() != null)
           {
             if (ms == sourceSequence)
@@ -716,7 +724,7 @@ public class CrossRef
    * Returns null or the first sequence in the dataset which is identical to
    * xref.mapTo, and has a) a primary dbref matching xref, or if none found, the
    * first one with an ID source|xrefacc
-   * 
+   * JBPNote: Could refactor this to AlignmentI/DatasetI
    * @param xref
    *          with map and mapped-to sequence
    * @return
@@ -814,7 +822,7 @@ public class CrossRef
    * Updates any empty mappings in the cross-references with one to a compatible
    * retrieved sequence if found, and adds any new mappings to the
    * AlignedCodonFrame
-   * 
+   * JBPNote: TODO: this relies on sequence IDs like UNIPROT|ACCESSION - which do not always happen.
    * @param mapFrom
    * @param xrefs
    * @param retrieved
index d52e42a..bf86a86 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import jalview.api.AlignViewportI;
 import jalview.api.FinderI;
 import jalview.datamodel.AlignmentI;
@@ -148,7 +150,7 @@ public class Finder implements FinderI
     idMatches = new ArrayList<>();
 
     String searchString = matchCase ? theSearchString
-            : theSearchString.toUpperCase();
+            : theSearchString.toUpperCase(Locale.ROOT);
     Regex searchPattern = new Regex(searchString);
     searchPattern.setIgnoreCase(!matchCase);
 
index df1dd82..a2ecdca 100644 (file)
@@ -20,8 +20,7 @@
  */
 package jalview.analysis;
 
-import jalview.bin.Cache;
-
+import java.util.Locale;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -31,6 +30,8 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.StringTokenizer;
 
+import jalview.bin.Console;
+
 /**
  * A singleton that provides instances of genetic code translation tables
  * 
@@ -160,7 +161,7 @@ public final class GeneticCodes
       }
     } catch (IOException | NullPointerException e)
     {
-      Cache.log.error(
+      Console.error(
               "Error reading genetic codes data file " + fileName + ": "
               + e.getMessage());
     }
@@ -198,13 +199,13 @@ public final class GeneticCodes
       while (line != null)
       {
         line = readLine(dataIn);
-        if (line != null && !"DNA".equals(line.toUpperCase()))
+        if (line != null && !"DNA".equals(line.toUpperCase(Locale.ROOT)))
         {
           String[] tokens = line.split("\\t");
           if (tokens.length == 2)
           {
-          ambiguityCodes.put(tokens[0].toUpperCase(),
-                  tokens[1].toUpperCase());
+          ambiguityCodes.put(tokens[0].toUpperCase(Locale.ROOT),
+                  tokens[1].toUpperCase(Locale.ROOT));
           }
           else
           {
@@ -215,7 +216,7 @@ public final class GeneticCodes
       }
     } catch (IOException e)
     {
-      Cache.log.error(
+      Console.error(
               "Error reading nucleotide ambiguity codes data file: "
                       + e.getMessage());
     }
@@ -292,7 +293,7 @@ public final class GeneticCodes
                 line.lastIndexOf(QUOTE));
         if (aminos.length() != NUCS_COUNT_CUBED) // 4 * 4 * 4 combinations
         {
-          Cache.log.error("wrong data length in code table: " + line);
+          Console.error("wrong data length in code table: " + line);
         }
         else
         {
@@ -341,13 +342,13 @@ public final class GeneticCodes
       @Override
       public String translateCanonical(String codon)
       {
-        return codons.get(codon.toUpperCase());
+        return codons.get(codon.toUpperCase(Locale.ROOT));
       }
 
       @Override
       public String translate(String codon)
       {
-        String upper = codon.toUpperCase();
+        String upper = codon.toUpperCase(Locale.ROOT);
         String peptide = translateCanonical(upper);
 
         /*
index d51f00e..4a3cfec 100755 (executable)
@@ -22,7 +22,7 @@ package jalview.analysis;
 
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Point;
 import jalview.math.MatrixI;
@@ -220,7 +220,7 @@ public class PCA implements Runnable
       eigenMatrix.tqli();
     } catch (Exception q)
     {
-      Cache.log.error("Error computing PCA:  " + q.getMessage());
+      Console.error("Error computing PCA:  " + q.getMessage());
       q.printStackTrace();
     }
   }
index a85c7f3..3ec162d 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
 
@@ -289,7 +291,7 @@ public class SequenceIdMatcher
     {
       if (s != null)
       {
-        id = s.toLowerCase();
+        id = s.toLowerCase(Locale.ROOT);
       }
       else
       {
@@ -319,7 +321,7 @@ public class SequenceIdMatcher
       {
         if (s instanceof String)
         {
-          return this.stringequals(((String) s).toLowerCase());
+          return this.stringequals(((String) s).toLowerCase(Locale.ROOT));
         }
       }
 
index a50634e..4d5e4b2 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.analysis;
 
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.BinaryNode;
 import jalview.datamodel.NodeTransformI;
@@ -155,8 +156,8 @@ public class TreeModel
         if (one2many.contains(nam))
         {
           // countOne2Many++;
-          // if (jalview.bin.Cache.log.isDebugEnabled())
-          // jalview.bin.Cache.log.debug("One 2 many relationship for
+          // if (Cache.isDebugEnabled())
+          // Cache.debug("One 2 many relationship for
           // "+nam.getName());
         }
         else
@@ -171,8 +172,8 @@ public class TreeModel
         j.setPlaceholder(true);
       }
     }
-    // if (jalview.bin.Cache.log.isDebugEnabled() && countOne2Many>0) {
-    // jalview.bin.Cache.log.debug("There were "+countOne2Many+" alignment
+    // if (Cache.isDebugEnabled() && countOne2Many>0) {
+    // Cache.debug("There were "+countOne2Many+" alignment
     // sequence ids (out of "+one2many.size()+" unique ids) linked to two or
     // more leaves.");
     // }
index 672d6b4..ed6358e 100644 (file)
@@ -112,4 +112,6 @@ public interface DBRefEntryI
    *         associated sequence object
    */
   public boolean isPrimaryCandidate();
+
+  public boolean isCanonical();
 }
index 8aa2858..fff3b38 100644 (file)
@@ -297,4 +297,11 @@ public interface FeatureRenderer
    * @return
    */
   MappedFeatures findComplementFeaturesAtResidue(SequenceI sequence, int pos);
+
+  /**
+   * Sends a message to let any registered parties know that something about
+   * feature rendering has changed
+   */
+  void notifyFeaturesChanged();
+
 }
index c0fc523..c8a835a 100644 (file)
@@ -35,7 +35,8 @@ public interface FeatureSettingsModelI extends Comparator<String>
   // interface, simplifying instantiating classes
 
   /**
-   * Answers true if the specified feature type is displayed
+   * Answers true if the specified feature type is to be displayed, false if no
+   * preference
    * 
    * @param type
    * @return
@@ -43,6 +44,15 @@ public interface FeatureSettingsModelI extends Comparator<String>
   boolean isFeatureDisplayed(String type);
 
   /**
+   * Answers true if the specified feature type is to be hidden, false if no
+   * preference
+   * 
+   * @param type
+   * @return
+   */
+  boolean isFeatureHidden(String type);
+
+  /**
    * Answers true if the specified feature group is displayed
    * 
    * @param group
index e69785f..9387e3f 100644 (file)
@@ -39,6 +39,8 @@ public interface FeaturesDisplayedI
 
   void setVisible(String featureType);
 
+  void setHidden(String featureType);
+
   /**
    * Sets all the specified feature types to visible. Visibility of other
    * feature types is not changed.
index d8c8371..d0351a8 100644 (file)
@@ -161,4 +161,10 @@ public interface JalviewStructureDisplayI
    */
   void stopProgressBar(String msg, long handle);
 
+  /**
+   * 
+   * @return true if the actions menu is shown for this viewer
+   */
+  boolean hasViewerActionsMenu();
+
 }
index 353f449..4d1a453 100755 (executable)
@@ -47,14 +47,10 @@ import java.util.regex.Pattern;
 import javax.swing.LookAndFeel;
 import javax.swing.UIManager;
 
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.SimpleLayout;
-
 import jalview.datamodel.PDBEntry;
 import jalview.gui.Preferences;
 import jalview.gui.UserDefinedColours;
+import jalview.log.JLoggerLog4j;
 import jalview.schemes.ColourSchemeLoader;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.UserColourScheme;
@@ -182,8 +178,8 @@ import jalview.ws.sifts.SiftsSettings;
  * when shading by annotation</li>
  * <li>ANNOTATIONCOLOUR_MAX (red) Shade used for maximum value of annotation
  * when shading by annotation</li>
- * <li>www.jalview.org (http://www.jalview.org) a property enabling all HTTP
- * requests to be redirected to a mirror of http://www.jalview.org</li>
+ * <li>www.jalview.org (https://www.jalview.org) a property enabling all HTTP
+ * requests to be redirected to a mirror of https://www.jalview.org</li>
  * <li>FIGURE_AUTOIDWIDTH (false) Expand the left hand column of an exported
  * alignment figure to accommodate even the longest sequence ID or annotation
  * label.</li>
@@ -275,7 +271,8 @@ public class Cache
   /**
    * Initialises the Jalview Application Log
    */
-  public static Logger log;
+
+  public final static String JALVIEW_LOGGER_NAME = "JalviewLogger";
 
   // save the proxy properties set at startup
   public final static String[] startupProxyProperties = {
@@ -320,55 +317,6 @@ public class Cache
 
   private final static String JS_PROPERTY_PREFIX = "jalview_";
 
-  public static void initLogger()
-  {
-    if (log != null)
-    {
-      return;
-    }
-    try
-    {
-      // TODO: redirect stdout and stderr here in order to grab the output of
-      // the log
-
-      ConsoleAppender ap = new ConsoleAppender(new SimpleLayout(),
-              "System.err");
-      ap.setName("JalviewLogger");
-      org.apache.log4j.Logger.getRootLogger().addAppender(ap); // catch all for
-      // log output
-      Logger laxis = Logger.getLogger("org.apache.axis");
-      Logger lcastor = Logger.getLogger("org.exolab.castor");
-      jalview.bin.Cache.log = Logger.getLogger("jalview.bin.Jalview");
-
-      laxis.setLevel(Level.toLevel(
-              Cache.getDefault("logs.Axis.Level", Level.INFO.toString())));
-      lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
-              Level.INFO.toString())));
-      lcastor = Logger.getLogger("org.exolab.castor.xml");
-      lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
-              Level.INFO.toString())));
-      // lcastor = Logger.getLogger("org.exolab.castor.xml.Marshaller");
-      // lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
-      // Level.INFO.toString())));
-      // we shouldn't need to do this
-      org.apache.log4j.Logger.getRootLogger()
-              .setLevel(org.apache.log4j.Level.INFO);
-
-      jalview.bin.Cache.log.setLevel(Level.toLevel(Cache
-              .getDefault("logs.Jalview.level", Level.INFO.toString())));
-      // laxis.addAppender(ap);
-      // lcastor.addAppender(ap);
-      // jalview.bin.Cache.log.addAppender(ap);
-      // Tell the user that debug is enabled
-      jalview.bin.Cache.log.debug(ChannelProperties.getProperty("app_name")
-              + " Debugging Output Follows.");
-    } catch (Exception ex)
-    {
-      System.err.println("Problems initializing the log4j system\n");
-      ex.printStackTrace(System.err);
-    }
-  }
-
   /**
    * Loads properties from the given properties file. Any existing properties
    * are first cleared.
@@ -479,7 +427,7 @@ public class Cache
     default:
       String message = "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): "
               + proxyType;
-      Cache.warn(message);
+      Console.warn(message);
     }
 
     // LOAD THE AUTHORS FROM THE authors.props file
@@ -511,27 +459,27 @@ public class Cache
     SiftsSettings
             .setMapWithSifts(Cache.getDefault("MAP_WITH_SIFTS", false));
 
-    SiftsSettings.setSiftDownloadDirectory(jalview.bin.Cache
+    SiftsSettings.setSiftDownloadDirectory(Cache
             .getDefault("sifts_download_dir", DEFAULT_SIFTS_DOWNLOAD_DIR));
 
     SiftsSettings.setFailSafePIDThreshold(
-            jalview.bin.Cache.getDefault("sifts_fail_safe_pid_threshold",
+            Cache.getDefault("sifts_fail_safe_pid_threshold",
                     DEFAULT_FAIL_SAFE_PID_THRESHOLD));
 
     SiftsSettings.setCacheThresholdInDays(
-            jalview.bin.Cache.getDefault("sifts_cache_threshold_in_days",
+            Cache.getDefault("sifts_cache_threshold_in_days",
                     DEFAULT_CACHE_THRESHOLD_IN_DAYS));
 
     IdOrgSettings.setUrl(getDefault("ID_ORG_HOSTURL",
-            "http://www.jalview.org/services/identifiers"));
+            "https://www.jalview.org/services/identifiers"));
     IdOrgSettings.setDownloadLocation(ID_ORG_FILE);
 
-    StructureImportSettings.setDefaultStructureFileFormat(jalview.bin.Cache
-            .getDefault("PDB_DOWNLOAD_FORMAT", PDB_DOWNLOAD_FORMAT));
+    StructureImportSettings.setDefaultStructureFileFormat(
+            Cache.getDefault("PDB_DOWNLOAD_FORMAT", PDB_DOWNLOAD_FORMAT));
     StructureImportSettings
             .setDefaultPDBFileParser(DEFAULT_PDB_FILE_PARSER);
     // StructureImportSettings
-    // .setDefaultPDBFileParser(jalview.bin.Cache.getDefault(
+    // .setDefaultPDBFileParser(Cache.getDefault(
     // "DEFAULT_PDB_FILE_PARSER", DEFAULT_PDB_FILE_PARSER));
 
     String jnlpVersion = System.getProperty("jalview.version");
@@ -852,14 +800,11 @@ public class Cache
         if (jalview.jbgui.GDesktop.class.getClassLoader()
                 .loadClass("uk.ac.vamsas.client.VorbaId") != null)
         {
-          jalview.bin.Cache.log.debug(
-                  "Found Vamsas Classes (uk.ac..vamsas.client.VorbaId can be loaded)");
+          Console.debug("Found Vamsas Classes (uk.ac..vamsas.client.VorbaId can be loaded)");
           vamsasJarsArePresent = 1;
-          Logger lvclient = Logger.getLogger("uk.ac.vamsas");
-          lvclient.setLevel(Level.toLevel(Cache
-                  .getDefault("logs.Vamsas.Level", Level.INFO.toString())));
-
-          lvclient.addAppender(log.getAppender("JalviewLogger"));
+          JLoggerLog4j lvclient = JLoggerLog4j.getLogger("uk.ac.vamsas",
+                  Console.getCachedLogLevel("logs.Vamsas.Level"));
+          JLoggerLog4j.addAppender(lvclient, Console.log, JALVIEW_LOGGER_NAME);
           // Tell the user that debug is enabled
           lvclient.debug(ChannelProperties.getProperty("app_name")
                   + " Vamsas Client Debugging Output Follows.");
@@ -867,7 +812,7 @@ public class Cache
       } catch (Exception e)
       {
         vamsasJarsArePresent = 0;
-        jalview.bin.Cache.log.debug("Vamsas Classes are not present");
+        Console.debug("Vamsas Classes are not present");
       }
     }
     return (vamsasJarsArePresent > 0);
@@ -892,14 +837,11 @@ public class Cache
         if (Cache.class.getClassLoader()
                 .loadClass("groovy.lang.GroovyObject") != null)
         {
-          jalview.bin.Cache.log.debug(
-                  "Found Groovy (groovy.lang.GroovyObject can be loaded)");
+          Console.debug("Found Groovy (groovy.lang.GroovyObject can be loaded)");
           groovyJarsArePresent = 1;
-          Logger lgclient = Logger.getLogger("groovy");
-          lgclient.setLevel(Level.toLevel(Cache
-                  .getDefault("logs.Groovy.Level", Level.INFO.toString())));
-
-          lgclient.addAppender(log.getAppender("JalviewLogger"));
+          JLoggerLog4j lgclient = JLoggerLog4j.getLogger("groovy",
+                  Console.getCachedLogLevel("logs.Groovy.Level"));
+          JLoggerLog4j.addAppender(lgclient, Console.log, JALVIEW_LOGGER_NAME);
           // Tell the user that debug is enabled
           lgclient.debug(ChannelProperties.getProperty("app_name")
                   + " Groovy Client Debugging Output Follows.");
@@ -907,11 +849,11 @@ public class Cache
       } catch (Error e)
       {
         groovyJarsArePresent = 0;
-        jalview.bin.Cache.log.debug("Groovy Classes are not present", e);
+        Console.debug("Groovy Classes are not present", e);
       } catch (Exception e)
       {
         groovyJarsArePresent = 0;
-        jalview.bin.Cache.log.debug("Groovy Classes are not present");
+        Console.debug("Groovy Classes are not present");
       }
     }
     return (groovyJarsArePresent > 0);
@@ -945,8 +887,7 @@ public class Cache
                   .loadClass("com.boxysystems.jgoogleanalytics.FocusPoint");
         } catch (Exception e)
         {
-          log.debug(
-                  "com.boxysystems.jgoogleanalytics package is not present - tracking not enabled.");
+          Console.debug("com.boxysystems.jgoogleanalytics package is not present - tracking not enabled.");
           tracker = null;
           jgoogleanalyticstracker = null;
           trackerfocus = null;
@@ -965,9 +906,8 @@ public class Cache
                 { String.class, String.class, String.class })
                 .newInstance(new Object[]
                 { ChannelProperties.getProperty("app_name") + " Desktop",
-                    (vrs = jalview.bin.Cache.getProperty("VERSION") + "_"
-                            + jalview.bin.Cache.getDefault("BUILD_DATE",
-                                    "unknown")),
+                    (vrs = Cache.getProperty("VERSION") + "_"
+                            + Cache.getDefault("BUILD_DATE", "unknown")),
                     "UA-9060947-1" });
         jgoogleanalyticstracker
                 .getMethod("trackAsynchronously", new Class[]
@@ -988,57 +928,24 @@ public class Cache
       }
       if (re != null || ex != null || err != null)
       {
-        if (log != null)
+        if (re != null)
         {
-          if (re != null)
-          {
-            log.debug("Caught runtime exception in googletracker init:",
-                    re);
-          }
-          if (ex != null)
-          {
-            log.warn(
-                    "Failed to initialise GoogleTracker for Jalview Desktop with version "
-                            + vrs,
-                    ex);
-          }
-          if (err != null)
-          {
-            log.error(
-                    "Whilst initing GoogleTracker for Jalview Desktop version "
-                            + vrs,
-                    err);
-          }
+          Console.debug("Caught runtime exception in googletracker init:", re);
         }
-        else
+        if (ex != null)
         {
-          if (re != null)
-          {
-            System.err.println(
-                    "Debug: Caught runtime exception in googletracker init:"
-                            + vrs);
-            re.printStackTrace();
-          }
-          if (ex != null)
-          {
-            System.err.println(
-                    "Warning:  Failed to initialise GoogleTracker for Jalview Desktop with version "
-                            + vrs);
-            ex.printStackTrace();
-          }
-
-          if (err != null)
-          {
-            System.err.println(
-                    "ERROR: Whilst initing GoogleTracker for Jalview Desktop version "
-                            + vrs);
-            err.printStackTrace();
-          }
+          Console.warn("Failed to initialise GoogleTracker for Jalview Desktop with version "
+                  + vrs, ex);
+        }
+        if (err != null)
+        {
+          Console.error("Whilst initing GoogleTracker for Jalview Desktop version "
+                  + vrs, err);
         }
       }
       else
       {
-        log.debug("Successfully initialised tracker.");
+        Console.debug("Successfully initialised tracker.");
       }
     }
   }
@@ -1060,8 +967,7 @@ public class Cache
     Color col = ColorUtils.parseColourString(colprop);
     if (col == null)
     {
-      log.warn("Couldn't parse '" + colprop + "' as a colour for "
-              + property);
+      Console.warn("Couldn't parse '" + colprop + "' as a colour for " + property);
     }
     return (col == null) ? defcolour : col;
   }
@@ -1242,14 +1148,14 @@ public class Cache
     StringBuilder sb = new StringBuilder();
     sb.append(ChannelProperties.getProperty("app_name"))
             .append(" Version: ");
-    sb.append(jalview.bin.Cache.getDefault("VERSION", "TEST"));
+    sb.append(Cache.getDefault("VERSION", "TEST"));
     sb.append("\n");
     sb.append(ChannelProperties.getProperty("app_name"))
             .append(" Installation: ");
-    sb.append(jalview.bin.Cache.getDefault("INSTALLATION", "unknown"));
+    sb.append(Cache.getDefault("INSTALLATION", "unknown"));
     sb.append("\n");
     sb.append("Build Date: ");
-    sb.append(jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
+    sb.append(Cache.getDefault("BUILD_DATE", "unknown"));
     sb.append("\n");
     sb.append("Java version: ");
     sb.append(System.getProperty("java.version"));
@@ -1277,7 +1183,7 @@ public class Cache
     // Not displayed in release version ( determined by possible version number
     // regex 9[9.]*9[.-_a9]* )
     if (Pattern.matches("^\\d[\\d\\.]*\\d[\\.\\-\\w]*$",
-            jalview.bin.Cache.getDefault("VERSION", "TEST")))
+            Cache.getDefault("VERSION", "TEST")))
     {
       appendIfNotNull(sb, "Getdown appdir: ",
               System.getProperty("getdownappdir"), "\n", null);
@@ -1297,7 +1203,7 @@ public class Cache
   {
     // consider returning more human friendly info
     // eg 'built from Source' or update channel
-    return jalview.bin.Cache.getDefault("INSTALLATION", "unknown");
+    return Cache.getDefault("INSTALLATION", "unknown");
   }
 
   public static String getStackTraceString(Throwable t)
@@ -1341,7 +1247,7 @@ public class Cache
                             ? " [" + startupProxyProperties[6] + "]"
                             : "");
 
-    Cache.debug(sb.toString());
+    Console.debug(sb.toString());
   }
 
   public static void setProxyPropertiesFromPreferences()
@@ -1367,7 +1273,7 @@ public class Cache
     case Cache.PROXYTYPE_NONE:
       if (!previousProxyType.equals(proxyType))
       {
-        Cache.log.info("Setting no proxy settings");
+        Console.info("Setting no proxy settings");
         Cache.setProxyProperties(null, null, null, null, null, null, null,
                 null, null);
       }
@@ -1375,7 +1281,7 @@ public class Cache
     case Cache.PROXYTYPE_CUSTOM:
       // always re-set a custom proxy -- it might have changed, particularly
       // password
-      Cache.log.info("Setting custom proxy settings");
+      Console.info("Setting custom proxy settings");
       boolean proxyAuthSet = Cache.getDefault("PROXY_AUTH", false);
       Cache.setProxyProperties(Cache.getDefault("PROXY_SERVER", null),
               Cache.getDefault("PROXY_PORT", null),
@@ -1389,7 +1295,7 @@ public class Cache
               proxyAuthSet ? Cache.proxyAuthPassword : null, "localhost");
       break;
     default: // system proxy settings by default
-      Cache.log.info("Setting system proxy settings");
+      Console.info("Setting system proxy settings");
       Cache.resetProxyProperties();
     }
   }
@@ -1441,7 +1347,7 @@ public class Cache
         char[] displayHttpPw = new char[httpPassword == null ? 0
                 : httpPassword.length];
         Arrays.fill(displayHttpPw, '*');
-        Cache.debug("CACHE Proxy: setting new Authenticator with httpUser='"
+        Console.debug("CACHE Proxy: setting new Authenticator with httpUser='"
                 + httpUser + "' httpPassword='" + displayHttpPw + "'");
         if (!Platform.isJS())
         /* *
@@ -1476,8 +1382,8 @@ public class Cache
                   // open Preferences -> Connections
                   String message = MessageManager
                           .getString("label.proxy_password_required");
-                  Preferences.openPreferences(Preferences.CONNECTIONS_TAB,
-                          message);
+                  Preferences.openPreferences(
+                          Preferences.TabRef.CONNECTIONS_TAB, message);
                   Preferences.getInstance()
                           .proxyAuthPasswordCheckHighlight(true, true);
                 }
@@ -1491,7 +1397,7 @@ public class Cache
                             && getRequestingPort() == Integer
                                     .valueOf(httpPort))
                     {
-                      Cache.debug(
+                      Console.debug(
                               "AUTHENTICATOR returning PasswordAuthentication(\""
                                       + httpUser + "\", '"
                                       + new String(displayHttpPw) + "')");
@@ -1506,7 +1412,7 @@ public class Cache
                     {
                       char[] displayHttpsPw = new char[httpPassword.length];
                       Arrays.fill(displayHttpsPw, '*');
-                      Cache.debug(
+                      Console.debug(
                               "AUTHENTICATOR returning PasswordAuthentication(\""
                                       + httpsUser + "\", '" + displayHttpsPw
                                       + "'");
@@ -1515,15 +1421,15 @@ public class Cache
                     }
                   } catch (NumberFormatException e)
                   {
-                    Cache.error("Problem with proxy port values [http:"
+                    Console.error("Problem with proxy port values [http:"
                             + httpPort + ", https:" + httpsPort + "]");
                   }
-                  Cache.debug(
+                  Console.debug(
                           "AUTHENTICATOR after trying to get PasswordAuthentication");
                 }
               }
               // non proxy request
-              Cache.debug("AUTHENTICATOR returning null");
+              Console.debug("AUTHENTICATOR returning null");
               return null;
             }
           });
@@ -1531,13 +1437,13 @@ public class Cache
 
         // required to re-enable basic authentication (should be okay for a
         // local proxy)
-        Cache.debug(
+        Console.debug(
                 "AUTHENTICATOR setting property 'jdk.http.auth.tunneling.disabledSchemes' to \"\"");
         System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
       } catch (SecurityException e)
       {
-        Cache.error("Could not set default Authenticator");
-        Cache.debug(getStackTraceString(e));
+        Console.error("Could not set default Authenticator");
+        Console.debug(getStackTraceString(e));
       }
     }
     else
@@ -1555,13 +1461,13 @@ public class Cache
        * 
        */
       {
-        Cache.debug("AUTHENTICATOR setting default Authenticator to null");
+        Console.debug("AUTHENTICATOR setting default Authenticator to null");
         Authenticator.setDefault(null);
       }
     }
 
     // nonProxyHosts not currently configurable in Preferences
-    Cache.debug("AUTHENTICATOR setting property 'http.nonProxyHosts' to \""
+    Console.debug("AUTHENTICATOR setting property 'http.nonProxyHosts' to \""
             + nonProxyHosts + "\"");
     setOrClearSystemProperty("http.nonProxyHosts", nonProxyHosts);
   }
@@ -1588,75 +1494,6 @@ public class Cache
     }
   }
 
-  public final static int TRACE = 10;
-
-  public final static int DEBUG = 20;
-
-  public final static int INFO = 30;
-
-  public final static int WARN = 40;
-
-  public final static int ERROR = 50;
-
-  public static boolean println(int level, String message)
-  {
-    if (Cache.log == null)
-    {
-      if (level >= WARN)
-        System.err.println(message);
-      else if (level >= INFO)
-        System.out.println(message);
-      // not printing debug or trace messages
-      return false;
-    }
-    if (level >= ERROR)
-    {
-      Cache.log.error(message);
-    }
-    else if (level >= WARN)
-    {
-      Cache.log.warn(message);
-    }
-    else if (level >= INFO)
-    {
-      Cache.log.info(message);
-    }
-    else if (level >= DEBUG)
-    {
-      Cache.log.debug(message);
-    }
-    else
-    {
-      Cache.log.trace(message);
-    }
-    return true;
-  }
-
-  public static void trace(String message)
-  {
-    println(TRACE, message);
-  }
-
-  public static void debug(String message)
-  {
-    println(DEBUG, message);
-  }
-
-  public static void info(String message)
-  {
-    println(INFO, message);
-  }
-
-  public static void warn(String message)
-  {
-    println(WARN, message);
-  }
-
-  public static void error(String message)
-  {
-    println(ERROR, message);
-  }
-
   /**
    * Getdown appbase methods
    */
diff --git a/src/jalview/bin/Console.java b/src/jalview/bin/Console.java
new file mode 100644 (file)
index 0000000..0b5a38a
--- /dev/null
@@ -0,0 +1,240 @@
+package jalview.bin;
+
+import jalview.log.JLogger;
+import jalview.log.JLoggerI.LogLevel;
+import jalview.log.JLoggerLog4j;
+import jalview.util.ChannelProperties;
+import jalview.util.Log4j;
+import jalview.util.Platform;
+
+public class Console
+{
+
+  public static JLoggerLog4j log;
+
+  public static void debug(String message, Throwable t)
+  {
+    if (Console.initLogger())
+    {
+      log.debug(message, t);
+    }
+    else
+    {
+      System.out.println(message);
+      t.printStackTrace();
+    }
+  
+  }
+
+  public static void info(String message)
+  {
+    if (Console.initLogger())
+    {
+      log.info(message, null);
+    }
+    else
+    {
+      System.out.println(message);
+    }
+  
+  }
+
+  public static void trace(String message, Throwable t)
+  {
+    if (Console.initLogger())
+    {
+      log.trace(message, t);
+    }
+    else
+    {
+      System.out.println(message);
+      t.printStackTrace();
+    }
+  }
+
+  public static void debug(String message)
+  {
+    if (Console.initLogger())
+    {
+      log.debug(message, null);
+    }
+    else
+    {
+      System.out.println(message);
+    }
+  
+  }
+
+  public static void info(String message, Throwable t)
+  {
+    if (Console.initLogger())
+    {
+      log.info(message, t);
+    }
+    else
+    {
+      System.out.println(message);
+      t.printStackTrace();
+    }
+  
+  }
+
+  public static void warn(String message)
+  {
+    if (Console.initLogger())
+    {
+      log.warn(message, null);
+    }
+    else
+    {
+      System.out.println(message);
+    }
+  
+  }
+
+  public static void trace(String message)
+  {
+    if (Console.initLogger())
+    {
+      log.trace(message, null);
+    }
+    else
+    {
+      System.out.println(message);
+    }
+  }
+
+  public static void warn(String message, Throwable t)
+  {
+    if (Console.initLogger())
+    {
+      log.warn(message, t);
+    }
+    else
+    {
+      System.out.println(message);
+      t.printStackTrace();
+    }
+  
+  }
+
+  public static void error(String message)
+  {
+    if (Console.initLogger())
+    {
+      log.error(message, null);
+    }
+    else
+    {
+      System.err.println(message);
+    }
+  
+  }
+
+  public static void error(String message, Throwable t)
+  {
+    if (Console.initLogger())
+    {
+      log.error(message, t);
+    }
+    else
+    {
+      System.err.println(message);
+      t.printStackTrace(System.err);
+    }
+  
+  }
+
+  public static void fatal(String message)
+  {
+    if (Console.initLogger())
+    {
+      log.fatal(message, null);
+    }
+    else
+    {
+      System.err.println(message);
+    }
+  
+  }
+
+  public static void fatal(String message, Throwable t)
+  {
+    if (Console.initLogger())
+    {
+      log.fatal(message, t);
+    }
+    else
+    {
+      System.err.println(message);
+      t.printStackTrace(System.err);
+    }
+  
+  }
+
+  public static boolean isDebugEnabled()
+  {
+    return log == null ? false : log.isDebugEnabled();
+  }
+
+  public static boolean isTraceEnabled()
+  {
+    return log == null ? false : log.isTraceEnabled();
+  }
+
+  public static JLogger.LogLevel getCachedLogLevel()
+  {
+    return Console.getCachedLogLevel(Cache.JALVIEWLOGLEVEL);
+  }
+
+  public static JLogger.LogLevel getCachedLogLevel(String key)
+  {
+    return JLogger.toLevel(Cache.getDefault(key, "INFO"));
+  }
+
+  public static boolean initLogger()
+  {
+    if (log != null)
+    {
+      return true;
+    }
+    try
+    {
+      JLogger.LogLevel cachedLevel = getCachedLogLevel();
+      if (!Platform.isJS())
+      {
+        Log4j.init(cachedLevel);
+      }
+      // log output
+      // is laxis used? Does getLogger do anything without a Logger object?
+      // Logger laxis = Log4j.getLogger("org.apache.axis", myLevel);
+      JLoggerLog4j.getLogger("org.apache.axis", cachedLevel);
+  
+      // The main application logger
+      log = JLoggerLog4j.getLogger(Cache.JALVIEW_LOGGER_NAME, cachedLevel);
+    } catch (NoClassDefFoundError e)
+    {
+      System.err.println("Could not initialise the logger framework");
+      e.printStackTrace();
+    }
+  
+    // Test message
+    if (log != null)
+    {
+      // Logging test message should got through the logger object
+      if (log.loggerExists())
+        log.debug(Console.LOGGING_TEST_MESSAGE);
+      // Tell the user that debug is enabled
+      debug(ChannelProperties.getProperty("app_name")
+              + " Debugging Output Follows.");
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  public final static String LOGGING_TEST_MESSAGE = "Logging to STDERR";
+
+}
index 38b7587..6219179 100644 (file)
@@ -1,5 +1,7 @@
 package jalview.bin;
 
+import java.util.Locale;
+
 import java.awt.HeadlessException;
 
 public class HiDPISetting
@@ -45,7 +47,7 @@ public class HiDPISetting
   static
   {
     String system = System.getProperty("os.name") == null ? null
-            : System.getProperty("os.name").toLowerCase();
+            : System.getProperty("os.name").toLowerCase(Locale.ROOT);
     if (system != null)
     {
       isLinux = system.indexOf("linux") > -1;
index 4c21624..0c11808 100755 (executable)
@@ -37,6 +37,7 @@ import java.security.PermissionCollection;
 import java.security.Permissions;
 import java.security.Policy;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Vector;
 import java.util.logging.ConsoleHandler;
@@ -317,6 +318,9 @@ public class Jalview
       }
       // anything else!
 
+      // allow https handshakes to download intermediate certs if necessary
+      System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
+
       final String jabawsUrl = aparser.getValue("jabaws");
       if (jabawsUrl != null)
       {
@@ -361,9 +365,10 @@ public class Jalview
     }
     System.setProperty("http.agent",
             "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
+
     try
     {
-      Cache.initLogger();
+      Console.initLogger();
     } catch (NoClassDefFoundError error)
     {
       error.printStackTrace();
@@ -397,13 +402,13 @@ public class Jalview
         JalviewTaskbar.setTaskbar(this);
       } catch (Exception e)
       {
-        Cache.log.info("Cannot set Taskbar");
-        Cache.log.error(e.getMessage());
+        Console.info("Cannot set Taskbar");
+        Console.error(e.getMessage());
         // e.printStackTrace();
       } catch (Throwable t)
       {
-        Cache.log.info("Cannot set Taskbar");
-        Cache.log.error(t.getMessage());
+        Console.info("Cannot set Taskbar");
+        Console.error(t.getMessage());
         // t.printStackTrace();
       }
 
@@ -439,7 +444,7 @@ public class Jalview
           {
             // Start the desktop questionnaire prompter with the specified
             // questionnaire
-            Cache.log.debug("Starting questionnaire url at " + url);
+            Console.debug("Starting questionnaire url at " + url);
             desktop.checkForQuestionnaire(url);
             System.out.println("CMD questionnaire[-" + url
                     + "] executed successfully!");
@@ -453,8 +458,8 @@ public class Jalview
               // String defurl =
               // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
               // //
-              String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
-              Cache.log.debug(
+              String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
+              Console.debug(
                       "Starting questionnaire with default url: " + defurl);
               desktop.checkForQuestionnaire(defurl);
             }
@@ -783,13 +788,16 @@ public class Jalview
      */
     {
       file = Cache.getDefault("STARTUP_FILE",
-              Cache.getDefault("www.jalview.org", "http://www.jalview.org")
-                      + "/examples/exampleFile_2_7.jar");
-      if (file.equals(
-              "http://www.jalview.org/examples/exampleFile_2_3.jar"))
+              Cache.getDefault("www.jalview.org", "https://www.jalview.org")
+                      + "/examples/exampleFile_2_7.jvp");
+      if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
+              || file.equals(
+                      "http://www.jalview.org/examples/exampleFile_2_7.jar"))
       {
+        file.replace("http:", "https:");
         // hardwire upgrade of the startup file
-        file.replace("_2_3.jar", "_2_7.jar");
+        file.replace("_2_3", "_2_7");
+        file.replace("2_7.jar", "2_7.jvp");
         // and remove the stale setting
         Cache.removeProperty("STARTUP_FILE");
       }
@@ -866,62 +874,62 @@ public class Jalview
       lafSet = setCrossPlatformLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "system":
       lafSet = setSystemLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "gtk":
       lafSet = setGtkLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "metal":
       lafSet = setMetalLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "nimbus":
       lafSet = setNimbusLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "quaqua":
       lafSet = setQuaquaLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "vaqua":
       lafSet = setVaquaLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "mac":
       lafSet = setMacLookAndFeel();
       if (!lafSet)
       {
-        Cache.log.error("Could not set requested laf=" + laf);
+        Console.error("Could not set requested laf=" + laf);
       }
       break;
     case "none":
       break;
     default:
-      Cache.log.error("Requested laf=" + laf + " not implemented");
+      Console.error("Requested laf=" + laf + " not implemented");
     }
     if (!lafSet)
     {
@@ -947,9 +955,9 @@ public class Jalview
       set = true;
     } catch (Exception ex)
     {
-      Cache.log.error("Unexpected Look and Feel Exception");
-      Cache.log.error(ex.getMessage());
-      Cache.log.debug(Cache.getStackTraceString(ex));
+      Console.error("Unexpected Look and Feel Exception");
+      Console.error(ex.getMessage());
+      Console.debug(Cache.getStackTraceString(ex));
     }
     return set;
   }
@@ -963,9 +971,9 @@ public class Jalview
       set = true;
     } catch (Exception ex)
     {
-      Cache.log.error("Unexpected Look and Feel Exception");
-      Cache.log.error(ex.getMessage());
-      Cache.log.debug(Cache.getStackTraceString(ex));
+      Console.error("Unexpected Look and Feel Exception");
+      Console.error(ex.getMessage());
+      Console.debug(Cache.getStackTraceString(ex));
     }
     return set;
   }
@@ -979,9 +987,10 @@ public class Jalview
       for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
       {
         if (info.getName() != null && nameStartsWith
-                ? info.getName().toLowerCase()
-                        .startsWith(name.toLowerCase())
-                : info.getName().toLowerCase().equals(name.toLowerCase()))
+                ? info.getName().toLowerCase(Locale.ROOT)
+                        .startsWith(name.toLowerCase(Locale.ROOT))
+                : info.getName().toLowerCase(Locale.ROOT)
+                        .equals(name.toLowerCase(Locale.ROOT)))
         {
           className = info.getClassName();
           break;
@@ -991,9 +1000,9 @@ public class Jalview
       set = true;
     } catch (Exception ex)
     {
-      Cache.log.error("Unexpected Look and Feel Exception");
-      Cache.log.error(ex.getMessage());
-      Cache.log.debug(Cache.getStackTraceString(ex));
+      Console.error("Unexpected Look and Feel Exception");
+      Console.error(ex.getMessage());
+      Console.debug(Cache.getStackTraceString(ex));
     }
     return set;
   }
@@ -1038,7 +1047,7 @@ public class Jalview
     System.setProperty("apple.laf.useScreenMenuBar", "true");
     set = setQuaquaLookAndFeel();
     if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
-            .toLowerCase().contains("quaqua"))
+            .toLowerCase(Locale.ROOT).contains("quaqua"))
     {
       set = setVaquaLookAndFeel();
     }
@@ -1085,7 +1094,7 @@ public class Jalview
                     + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
                     + "-jvmmempc=PERCENT\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
                     + "-jvmmemmax=MAXMEMORY\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to MAXMEMORY. MAXMEMORY can be specified in bytes, kilobytes(k), megabytes(m), gigabytes(g) or if you're lucky enough, terabytes(t). This defaults to 32g if total physical memory can be detected, or to 8g if total physical memory cannot be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
-                    + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
+                    + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
   }
 
   private static void startUsageStats(final Desktop desktop)
@@ -1103,17 +1112,16 @@ public class Jalview
               @Override
               public void run()
               {
-                Cache.log.debug(
-                        "Initialising googletracker for usage stats.");
+                Console.debug("Initialising googletracker for usage stats.");
                 Cache.initGoogleTracker();
-                Cache.log.debug("Tracking enabled.");
+                Console.debug("Tracking enabled.");
               }
             }, new Runnable()
             {
               @Override
               public void run()
               {
-                Cache.log.debug("Not enabling Google Tracking.");
+                Console.debug("Not enabling Google Tracking.");
               }
             }, null, true);
     desktop.addDialogThread(prompter);
index e7f2a53..871ca54 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.bin;
 
+import java.util.Locale;
+
 import jalview.analysis.AlignmentUtils;
 import jalview.api.StructureSelectionManagerProvider;
 import jalview.appletgui.AlignFrame;
@@ -208,7 +210,7 @@ public class JalviewLite extends Applet
       final int pos = apos;
       // use vamsas listener to broadcast to all listeners in scope
       if (alignedPosition != null && (alignedPosition.trim().length() == 0
-              || alignedPosition.toLowerCase().indexOf("false") > -1))
+              || alignedPosition.toLowerCase(Locale.ROOT).indexOf("false") > -1))
       {
         java.awt.EventQueue.invokeLater(new Runnable()
         {
@@ -412,7 +414,7 @@ public class JalviewLite extends Applet
             r--;
           } catch (NumberFormatException ex)
           {
-            if (cl.toLowerCase().equals("sequence"))
+            if (cl.toLowerCase(Locale.ROOT).equals("sequence"))
             {
               // we are in the dataset sequence's coordinate frame.
               inseqpos = true;
@@ -1440,7 +1442,7 @@ public class JalviewLite extends Applet
     String externalsviewer = getParameter("externalstructureviewer");
     if (externalsviewer != null)
     {
-      useXtrnalSviewer = externalsviewer.trim().toLowerCase().equals(TRUE);
+      useXtrnalSviewer = externalsviewer.trim().toLowerCase(Locale.ROOT).equals(TRUE);
     }
     /**
      * if true disable the check for jmol
@@ -2691,7 +2693,7 @@ public class JalviewLite extends Applet
           final String groups, boolean state)
   {
     final boolean st = state;// !(state==null || state.equals("") ||
-    // state.toLowerCase().equals("false"));
+    // state.toLowerCase(Locale.ROOT).equals("false"));
     java.awt.EventQueue.invokeLater(new Runnable()
     {
       @Override
index b8d31c2..1ea17d6 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.bin;
 
+import java.util.Locale;
+
 import java.io.File;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
@@ -27,6 +29,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import jalview.util.ChannelProperties;
+import jalview.util.LaunchUtils;
 
 /**
  * A Launcher class for Jalview. This class is used to launch Jalview from the
@@ -104,6 +107,23 @@ public class Launcher
       }
     }
 
+    // use saved preferences if no cmdline args
+    boolean useCustomisedSettings = LaunchUtils
+            .getBooleanUserPreference(MemorySetting.CUSTOMISED_SETTINGS);
+    if (useCustomisedSettings)
+    {
+      if (jvmmempc == null)
+      {
+        jvmmempc = LaunchUtils
+                .getUserPreference(MemorySetting.MEMORY_JVMMEMPC);
+      }
+      if (jvmmemmax == null)
+      {
+        jvmmemmax = LaunchUtils
+                .getUserPreference(MemorySetting.MEMORY_JVMMEMMAX);
+      }
+    }
+
     // add memory setting if not specified
     boolean memSet = false;
     boolean dockIcon = false;
@@ -190,7 +210,7 @@ public class Launcher
       process.waitFor();
     } catch (IOException e)
     {
-      if (e.getMessage().toLowerCase().contains("memory"))
+      if (e.getMessage().toLowerCase(Locale.ROOT).contains("memory"))
       {
         System.out.println("Caught a memory exception: " + e.getMessage());
         // Probably the "Cannot allocate memory" error, try without the memory
@@ -226,7 +246,6 @@ public class Launcher
       e.printStackTrace();
     }
     // System.exit(0);
-
   }
 
 }
index 5d7f14c..56713b0 100644 (file)
@@ -1,4 +1,6 @@
 /*
+
+  private static String ADJUSTMENT_MESSAGE = null;
  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
@@ -49,13 +51,33 @@ public class MemorySetting
 
   private static final long NOMEM_MAX_HEAPSIZE_GB_DEFAULT = 8;
 
+  public static final String NS = "MEMORY";
+
+  public static final String CUSTOMISED_SETTINGS = NS
+          + "_CUSTOMISED_SETTINGS";
+
+  public static final String MEMORY_JVMMEMPC = NS + "_"
+          + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.toUpperCase();
+
+  public static final String MEMORY_JVMMEMMAX = NS + "_"
+          + MAX_HEAPSIZE_PROPERTY_NAME.toUpperCase();
+
   protected static boolean logToClassChecked = false;
 
+  public static String memorySuffixes = "bkmgt"; // order of the suffixes is
+                                                 // important!
+
   public static long getMemorySetting()
   {
     return getMemorySetting(null, null);
   }
 
+  public static long getMemorySetting(String jvmmemmaxarg,
+          String jvmmempcarg)
+  {
+    return getMemorySetting(jvmmemmaxarg, jvmmempcarg, true, false);
+  }
+
   /**
    * Decide on appropriate memory setting for Jalview based on the two arguments
    * values: jvmmempc - the maximum percentage of total physical memory to
@@ -83,99 +105,66 @@ public class MemorySetting
    * @param jvmmempcarg
    *          Max percentage of physical memory to use. Defaults to "90".
    * 
+   * @param useProps
+   *          boolean to decide whether to look at System properties.
+   * 
    * @return The amount of memory (in bytes) to allocate to Jalview
    */
   public static long getMemorySetting(String jvmmemmaxarg,
-          String jvmmempcarg)
+          String jvmmempcarg, boolean useProps, boolean quiet)
   {
     // actual Xmx value-to-be
     long maxMemLong = -1;
+    clearAdjustmentMessage();
 
     // (absolute) jvmmaxmem setting, start with default
     long memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
-    if (jvmmemmaxarg == null)
+    if (jvmmemmaxarg == null && useProps)
     {
       jvmmemmaxarg = System.getProperty(MAX_HEAPSIZE_PROPERTY_NAME);
     }
     String jvmmemmax = jvmmemmaxarg;
     if (jvmmemmax != null && jvmmemmax.length() > 0)
     {
-      long multiplier = 1;
-      switch (jvmmemmax.toLowerCase().substring(jvmmemmax.length() - 1))
-      {
-      case "t":
-        multiplier = 1099511627776L; // 2^40
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "g":
-        multiplier = 1073741824; // 2^30
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "m":
-        multiplier = 1048576; // 2^20
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "k":
-        multiplier = 1024; // 2^10
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      case "b":
-        multiplier = 1; // 2^0
-        jvmmemmax = jvmmemmax.substring(0, jvmmemmax.length() - 1);
-        break;
-      default:
-        break;
-      }
-
       // parse the arg
       try
       {
-        memmax = Long.parseLong(jvmmemmax);
+        memmax = memoryStringToLong(jvmmemmax);
+        if (memmax == 0)
+        {
+          throw (new NumberFormatException("Not allowing 0"));
+        }
       } catch (NumberFormatException e)
       {
         memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
-        System.out.println("MemorySetting Property '"
+        setAdjustmentMessage("MemorySetting Property '"
                 + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
-                + "') badly formatted, using default ("
-                + MAX_HEAPSIZE_GB_DEFAULT + "g).");
-      }
-
-      // apply multiplier if not too big (i.e. bigger than a long)
-      if (Long.MAX_VALUE / memmax < multiplier)
-      {
-        memmax = MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
-        System.out.println("MemorySetting Property '"
-                + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
-                + ") too big, using default (" + MAX_HEAPSIZE_GB_DEFAULT
-                + "g).");
-      }
-      else
-      {
-        memmax = multiplier * memmax;
+                + "') badly formatted or 0, using default ("
+                + MAX_HEAPSIZE_GB_DEFAULT + "g).", quiet);
       }
 
       // check at least minimum value (this accounts for negatives too)
       if (memmax < APPLICATION_MIN_MEMORY)
       {
         memmax = APPLICATION_MIN_MEMORY;
-        System.out.println("MemorySetting Property '"
+        setAdjustmentMessage("MemorySetting Property '"
                 + MAX_HEAPSIZE_PROPERTY_NAME + "' (" + jvmmemmaxarg
                 + ") too small, using minimum (" + APPLICATION_MIN_MEMORY
-                + ").");
+                + ").", quiet);
       }
 
     }
     else
     {
       // no need to warn if no setting
-      // System.out.println("MemorySetting Property '" + maxHeapSizeProperty
+      // adjustmentMessage("MemorySetting Property '" + maxHeapSizeProperty
       // + "' not
       // set.");
     }
 
     // get max percent of physical memory, starting with default
     float percent = MAX_HEAPSIZE_PERCENT_DEFAULT;
-    if (jvmmempcarg == null)
+    if (jvmmempcarg == null && useProps)
     {
       jvmmempcarg = System.getProperty(MAX_HEAPSIZE_PERCENT_PROPERTY_NAME);
     }
@@ -185,24 +174,24 @@ public class MemorySetting
     {
       if (jvmmempc != null)
       {
-        float trypercent = Float.parseFloat(jvmmempc);
-        if (0 < trypercent && trypercent <= 100f)
+        int trypercent = Integer.parseInt(jvmmempc);
+        if (0 <= trypercent && trypercent <= 100)
         {
           percent = trypercent;
         }
         else
         {
-          System.out.println("MemorySetting Property '"
+          setAdjustmentMessage("MemorySetting Property '"
                   + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME
-                  + "' should be in range 1..100. Using default " + percent
-                  + "%");
+                  + "' should be in range 0..100. Using default " + percent
+                  + "%", quiet);
         }
       }
     } catch (NumberFormatException e)
     {
-      System.out.println("MemorySetting property '"
+      setAdjustmentMessage("MemorySetting property '"
               + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' (" + jvmmempcarg
-              + ") badly formatted");
+              + ") badly formatted", quiet);
     }
 
     // catch everything in case of no com.sun.management.OperatingSystemMXBean
@@ -223,10 +212,10 @@ public class MemorySetting
         {
           mempc = physicalMem - LEAVE_FREE_MIN_MEMORY;
           reducedmempc = true;
-          System.out.println("MemorySetting Property '"
+          setAdjustmentMessage("MemorySetting Property '"
                   + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' (" + jvmmempcarg
                   + ") too large. Leaving free space for OS and reducing to ("
-                  + mempc + ").");
+                  + mempc + ").", quiet);
         }
 
         // check for minimum application memsize
@@ -234,16 +223,16 @@ public class MemorySetting
         {
           if (reducedmempc)
           {
-            System.out.println("Reduced MemorySetting (" + mempc
+            setAdjustmentMessage("Reduced MemorySetting (" + mempc
                     + ") too small. Increasing to application minimum ("
-                    + APPLICATION_MIN_MEMORY + ").");
+                    + APPLICATION_MIN_MEMORY + ").", quiet);
           }
           else
           {
-            System.out.println("MemorySetting Property '"
+            setAdjustmentMessage("MemorySetting Property '"
                     + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' ("
                     + jvmmempcarg + ") too small. Using minimum ("
-                    + APPLICATION_MIN_MEMORY + ").");
+                    + APPLICATION_MIN_MEMORY + ").", quiet);
           }
           mempc = APPLICATION_MIN_MEMORY;
         }
@@ -252,19 +241,21 @@ public class MemorySetting
       {
         // not enough memory for application, just try and grab what we can!
         mempc = physicalMem;
-        System.out.println(
+        setAdjustmentMessage(
                 "Not enough physical memory for application. Ignoring MemorySetting Property '"
                         + MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "' ("
                         + jvmmempcarg
                         + "). Using maximum memory available ("
-                        + physicalMem + ").");
+                        + physicalMem + ").",
+                quiet);
       }
 
     } catch (Throwable t)
     {
       memoryPercentError = true;
-      System.out.println(
-              "Problem calling GetMemory.getPhysicalMemory(). Likely to be problem with com.sun.management.OperatingSystemMXBean");
+      setAdjustmentMessage(
+              "Problem calling GetMemory.getPhysicalMemory(). Likely to be problem with com.sun.management.OperatingSystemMXBean",
+              quiet);
       t.printStackTrace();
     }
 
@@ -281,9 +272,10 @@ public class MemorySetting
                                                               // == null))
             && memmax > NOMEM_MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE)
     {
-      System.out.println(
+      setAdjustmentMessage(
               "Capping maximum memory to " + NOMEM_MAX_HEAPSIZE_GB_DEFAULT
-                      + "g due to failure to read physical memory size.");
+                      + "g due to failure to read physical memory size.",
+              quiet);
       memmax = NOMEM_MAX_HEAPSIZE_GB_DEFAULT * GIGABYTE;
     }
 
@@ -299,4 +291,120 @@ public class MemorySetting
     return maxMemLong;
   }
 
-}
\ No newline at end of file
+  public static boolean isValidMemoryString(String text)
+  {
+    if (text.length() > 0)
+    {
+      char lastChar = text.charAt(text.length() - 1);
+      char[] otherChars = text.substring(0, text.length() - 1)
+              .toCharArray();
+      for (char c : otherChars)
+      {
+        if (c < '0' || c > '9')
+        {
+          return false;
+        }
+      }
+      if ((lastChar < '0' || lastChar > '9') && memorySuffixes
+              .indexOf(Character.toLowerCase(lastChar)) == -1)
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static long memoryStringToLong(String memString)
+          throws NumberFormatException
+  {
+    if (!isValidMemoryString(memString)) // not valid
+    {
+      throw (new NumberFormatException("Not a valid memory string"));
+    }
+    char suffix = Character
+            .toLowerCase(memString.charAt(memString.length() - 1));
+    if ('0' <= suffix && suffix <= '9') // no suffix
+    {
+      return Long.valueOf(memString);
+    }
+    if (memorySuffixes.indexOf(suffix) == -1) // suffix is unknown
+    {
+      return -1;
+    }
+
+    long multiplier = (long) Math.pow(2,
+            memorySuffixes.indexOf(suffix) * 10); // note order of suffixes in
+                                                  // memorySuffixes important
+                                                  // here!
+    // parse the arg. NumberFormatExceptions passed on to calling method
+    long mem = Long
+            .parseLong(memString.substring(0, memString.length() - 1));
+    if (mem == 0)
+    {
+      return 0;
+    }
+
+    // apply multiplier only if result is not too big (i.e. bigger than a long)
+    if (Long.MAX_VALUE / mem > multiplier)
+    {
+      return multiplier * mem;
+    }
+    else
+    {
+      // number too big for a Long. Limit to Long.MAX_VALUE
+      System.out.println("Memory parsing of '" + memString
+              + "' produces number too big.  Limiting to Long.MAX_VALUE="
+              + Long.MAX_VALUE);
+      return Long.MAX_VALUE;
+    }
+  }
+
+  public static String memoryLongToString(long mem)
+  {
+    return memoryLongToString(mem, "%.3f");
+  }
+
+  public static String memoryLongToString(long mem, String format)
+  {
+    int exponent = 0;
+    float num = mem;
+    char suffix = 'b';
+
+    for (int i = 0; i < memorySuffixes.length(); i++)
+    {
+      char s = Character.toUpperCase(memorySuffixes.charAt(i));
+      if (mem < (long) Math.pow(2, exponent + 10)
+              || i == memorySuffixes.length() - 1) // last suffix
+      {
+        suffix = s;
+        num = (float) (mem / Math.pow(2, exponent));
+        break;
+      }
+      exponent += 10;
+    }
+
+    return String.format(format, num) + suffix;
+  }
+
+  private static String ADJUSTMENT_MESSAGE = null;
+
+  private static void setAdjustmentMessage(String reason, boolean quiet)
+  {
+    ADJUSTMENT_MESSAGE = reason;
+    if (!quiet)
+    {
+      System.out.println(reason);
+    }
+  }
+
+  public static void clearAdjustmentMessage()
+  {
+    ADJUSTMENT_MESSAGE = null;
+  }
+
+  public static String getAdjustmentMessage()
+  {
+    return ADJUSTMENT_MESSAGE;
+  }
+
+}
index 7f7142f..2d61705 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.commands;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 
@@ -101,13 +103,13 @@ public class ChangeCaseCommand implements CommandI
         if ((caseChange == TO_UPPER && doCommand)
                 || (caseChange == TO_LOWER && !doCommand))
         {
-          newSeq.append(sequence.substring(start, end).toUpperCase());
+          newSeq.append(sequence.substring(start, end).toUpperCase(Locale.ROOT));
         }
 
         else if ((caseChange == TO_LOWER && doCommand)
                 || (caseChange == TO_UPPER && !doCommand))
         {
-          newSeq.append(sequence.substring(start, end).toLowerCase());
+          newSeq.append(sequence.substring(start, end).toLowerCase(Locale.ROOT));
         }
 
         else
index d0790c8..30595bc 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.commands;
 
+import java.util.Locale;
+
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -789,7 +791,7 @@ public class EditCommand implements CommandI
       String nogapold = AlignSeq.extractGaps(Comparison.GapChars,
               new String(command.string[i]));
 
-      if (!nogaprep.toLowerCase().equals(nogapold.toLowerCase()))
+      if (!nogaprep.toLowerCase(Locale.ROOT).equals(nogapold.toLowerCase(Locale.ROOT)))
       {
         // we may already have dataset and limits stashed...
         if (newDSWasNeeded || newStartEndWasNeeded)
@@ -838,7 +840,7 @@ public class EditCommand implements CommandI
             // old ds and edited ds are different, so
             // create the new dataset sequence
             SequenceI newds = new Sequence(oldds);
-            newds.setSequence(fullseq.toUpperCase());
+            newds.setSequence(fullseq.toUpperCase(Locale.ROOT));
 
             if (command.oldds == null)
             {
@@ -891,7 +893,7 @@ public class EditCommand implements CommandI
               // new
               // start/end
               String nogapalseq = AlignSeq.extractGaps(Comparison.GapChars,
-                      command.seqs[i].getSequenceAsString().toUpperCase());
+                      command.seqs[i].getSequenceAsString().toUpperCase(Locale.ROOT));
               int newStart = command.seqs[i].getDatasetSequence()
                       .getSequenceAsString().indexOf(nogapalseq);
               if (newStart == -1)
index fffa137..b376c80 100644 (file)
  */
 package jalview.datamodel;
 
-import jalview.util.MapList;
-import jalview.util.MappingUtils;
-
 import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.List;
 
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
+
 /**
  * Stores mapping between the columns of a protein alignment and a DNA alignment
  * and a list of individual codon to amino acid mappings between sequences.
@@ -107,6 +107,143 @@ public class AlignedCodonFrame
     {
       return mapping;
     }
+
+    /**
+     * Returns true if the mapping covers the full length of the given sequence.
+     * This allows us to distinguish the CDS that codes for a protein from
+     * another overlapping CDS in the parent dna sequence.
+     * 
+     * @param seq
+     * @return
+     */
+    public boolean covers(SequenceI seq)
+    {
+      return covers(seq,false,false);
+    }
+    /**
+     * 
+     * @param seq
+     * @param localCover - when true - compare extent of seq's dataset sequence rather than the local extent
+     * @param either - when true coverage is required for either seq or the mapped sequence 
+     * @return true if mapping covers full length of given sequence (or the other if either==true)
+     */
+    public boolean covers(SequenceI seq, boolean localCover,boolean either)
+    {
+      List<int[]> mappedRanges = null,otherRanges=null;
+      MapList mapList = mapping.getMap();
+      int mstart=seq.getStart(),mend=seq.getEnd(),ostart,oend;
+              ;
+      if (fromSeq == seq || fromSeq == seq.getDatasetSequence())
+      {
+        if (localCover && fromSeq !=seq)
+        {
+          mstart=fromSeq.getStart();
+          mend=fromSeq.getEnd();
+        }
+        mappedRanges = mapList.getFromRanges();
+        otherRanges=mapList.getToRanges();
+        ostart=mapping.to.getStart();
+        oend=mapping.to.getEnd();
+      }
+      else if (mapping.to == seq || mapping.to == seq.getDatasetSequence())
+      {
+        if (localCover && mapping.to !=seq)
+        {
+          mstart=mapping.to.getStart();
+          mend=mapping.to.getEnd();
+        }
+        mappedRanges = mapList.getToRanges();
+        otherRanges=mapList.getFromRanges();
+        ostart=fromSeq.getStart();
+        oend=fromSeq.getEnd();
+      }
+      else
+      {
+        return false;
+      }
+
+      /*
+       * check that each mapped range lies within the sequence range
+       * (necessary for circular CDS - example EMBL:J03321:AAA91567)
+       * and mapped length covers (at least) sequence length
+       */
+      int length = countRange(mappedRanges,mstart,mend);
+
+      if (length != -1)
+      {
+        // add 3 to mapped length to allow for a mapped stop codon
+        if (length + 3 >= (mend - mstart + 1))
+        {
+          return true;
+        }
+      }
+      if (either)
+      {
+        // also check coverage of the other range
+        length = countRange(otherRanges, ostart, oend);
+        if (length != -1)
+        {
+          if (length + 1 >= (oend - ostart + 1))
+          {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+    private int countRange(List<int[]> mappedRanges,int mstart,int mend)
+    {
+      int length=0;
+      for (int[] range : mappedRanges)
+      {
+        int from = Math.min(range[0], range[1]);
+        int to = Math.max(range[0], range[1]);
+        if (from < mstart || to > mend)
+        {
+          return -1;
+        }
+        length += (to - from + 1);
+      }
+      return length;
+    }
+
+    /**
+     * Adds any regions mapped to or from position {@code pos} in sequence
+     * {@code seq} to the given search results
+     * Note: recommend first using the .covers(,true,true) to ensure mapping covers both sequences
+     * @param seq
+     * @param pos
+     * @param sr
+     */
+    public void markMappedRegion(SequenceI seq, int pos, SearchResultsI sr)
+    {
+      int[] codon = null;
+      SequenceI mappedSeq = null;
+      SequenceI ds = seq.getDatasetSequence();
+      if (ds == null)
+      {
+        ds = seq;
+      }
+      
+      if (this.fromSeq == seq || this.fromSeq == ds)
+      {
+        codon = this.mapping.map.locateInTo(pos, pos);
+        mappedSeq = this.mapping.to;
+      }
+      else if (this.mapping.to == seq || this.mapping.to == ds)
+      {
+        codon = this.mapping.map.locateInFrom(pos, pos);
+        mappedSeq = this.fromSeq;
+      }
+
+      if (codon != null)
+      {
+        for (int i = 0; i < codon.length; i += 2)
+        {
+          sr.addResult(mappedSeq, codon[i], codon[i + 1]);
+        }
+      }
+    }
   }
 
   private List<SequenceToSequenceMapping> mappings;
@@ -261,9 +398,12 @@ public class AlignedCodonFrame
   }
 
   /**
+   * Return the corresponding aligned or dataset dna sequence for given amino
+   * acid sequence, or null if not found. returns the sequence from the first
+   * mapping found that involves the protein sequence.
    * 
-   * @param sequenceRef
-   * @return null or corresponding aaSeq entry for dnaSeq entry
+   * @param aaSeqRef
+   * @return
    */
   public SequenceI getDnaForAaSeq(SequenceI aaSeqRef)
   {
@@ -293,7 +433,8 @@ public class AlignedCodonFrame
 
   /**
    * Add search results for regions in other sequences that translate or are
-   * translated from a particular position in seq
+   * translated from a particular position in seq (which may be an aligned or
+   * dataset sequence)
    * 
    * @param seq
    * @param index
@@ -304,69 +445,17 @@ public class AlignedCodonFrame
   public void markMappedRegion(SequenceI seq, int index,
           SearchResultsI results)
   {
-    int[] codon;
     SequenceI ds = seq.getDatasetSequence();
-    for (SequenceToSequenceMapping ssm : mappings)
+    if (ds == null)
     {
-      if (ssm.fromSeq == seq || ssm.fromSeq == ds)
-      {
-        codon = ssm.mapping.map.locateInTo(index, index);
-        if (codon != null)
-        {
-          for (int i = 0; i < codon.length; i += 2)
-          {
-            results.addResult(ssm.mapping.to, codon[i], codon[i + 1]);
-          }
-        }
-      }
-      else if (ssm.mapping.to == seq || ssm.mapping.to == ds)
-      {
-        {
-          codon = ssm.mapping.map.locateInFrom(index, index);
-          if (codon != null)
-          {
-            for (int i = 0; i < codon.length; i += 2)
-            {
-              results.addResult(ssm.fromSeq, codon[i], codon[i + 1]);
-            }
-          }
-        }
-      }
+      ds = seq;
     }
-  }
-
-  /**
-   * Returns the DNA codon positions (base 1) for the given position (base 1) in
-   * a mapped protein sequence, or null if no mapping is found.
-   * 
-   * Intended for use in aligning cDNA to match aligned protein. Only the first
-   * mapping found is returned, so not suitable for use if multiple protein
-   * sequences are mapped to the same cDNA (but aligning cDNA as protein is
-   * ill-defined for this case anyway).
-   * 
-   * @param seq
-   *          the DNA dataset sequence
-   * @param aaPos
-   *          residue position (base 1) in a protein sequence
-   * @return
-   */
-  public int[] getDnaPosition(SequenceI seq, int aaPos)
-  {
-    /*
-     * Adapted from markMappedRegion().
-     */
-    MapList ml = null;
-    int i = 0;
     for (SequenceToSequenceMapping ssm : mappings)
     {
-      if (ssm.fromSeq == seq)
-      {
-        ml = getdnaToProt()[i];
-        break;
+      if (ssm.covers(seq,true,true)) {
+        ssm.markMappedRegion(ds, index, results);
       }
-      i++;
     }
-    return ml == null ? null : ml.locateInFrom(aaPos, aaPos);
   }
 
   /**
@@ -767,7 +856,7 @@ public class AlignedCodonFrame
    * Two AlignedCodonFrame objects are equal if they hold the same ordered list
    * of mappings
    * 
-   * @see SequenceToSequenceMapping#
+   * @see SequenceToSequenceMapping#equals
    */
   @Override
   public boolean equals(Object obj)
@@ -783,4 +872,55 @@ public class AlignedCodonFrame
   {
     return mappings;
   }
+
+  /**
+   * Returns the first mapping found which is between the two given sequences,
+   * and covers the full extent of both.
+   * 
+   * @param seq1
+   * @param seq2
+   * @return
+   */
+  public SequenceToSequenceMapping getCoveringMapping(SequenceI seq1,
+          SequenceI seq2)
+  {
+    for (SequenceToSequenceMapping mapping : mappings)
+    {
+      if (mapping.covers(seq2) && mapping.covers(seq1))
+      {
+        return mapping;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Returns the first mapping found which is between the given dataset sequence
+   * and another, is a triplet mapping (3:1 or 1:3), and covers the full extent
+   * of both sequences involved
+   * 
+   * @param seq
+   * @return
+   */
+  public SequenceToSequenceMapping getCoveringCodonMapping(SequenceI seq)
+  {
+    for (SequenceToSequenceMapping mapping : mappings)
+    {
+      if (mapping.getMapping().getMap().isTripletMap()
+              && mapping.covers(seq))
+      {
+        if (mapping.fromSeq == seq
+                && mapping.covers(mapping.getMapping().getTo()))
+        {
+          return mapping;
+        }
+        else if (mapping.getMapping().getTo() == seq
+                && mapping.covers(mapping.fromSeq))
+        {
+          return mapping;
+        }
+      }
+    }
+    return null;
+  }
 }
index 5708f01..5f27ea7 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import java.util.Locale;
+
 import jalview.analysis.Rna;
 import jalview.analysis.SecStrConsensus.SimpleBP;
 import jalview.analysis.WUSSParseException;
@@ -1227,7 +1229,7 @@ public class AlignmentAnnotation
   {
     if (seqname && this.sequenceRef != null)
     {
-      int i = description.toLowerCase().indexOf("<html>");
+      int i = description.toLowerCase(Locale.ROOT).indexOf("<html>");
       if (i > -1)
       {
         // move the html tag to before the sequence reference.
index f557ff8..93a5460 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import java.util.Locale;
+
 import jalview.api.DBRefEntryI;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
@@ -39,6 +41,8 @@ public class DBRefEntry implements DBRefEntryI
   int sourceKey = Integer.MIN_VALUE;
 
   String canonicalSourceName;
+  
+  boolean isCanonicalAccession=false;
 
   /*
    * maps from associated sequence to the database sequence's coordinate system
@@ -61,12 +65,25 @@ public class DBRefEntry implements DBRefEntryI
    */
   public DBRefEntry(String source, String version, String accessionId)
   {
-    this(source, version, accessionId, null);
+    this(source, version, accessionId, null,false);
   }
 
   /**
    * 
    * @param source
+   *                      may not be null
+   * @param version
+   *                      may be null
+   * @param accessionId
+   *                      may be null
+   */
+  public DBRefEntry(String source, String version, String accessionId, Mapping map)
+  {
+    this(source, version, accessionId, map,false);
+  }
+  /**
+   * 
+   * @param source
    *          canonical source (turned to uppercase; cannot be null)
    * @param version
    *          (source dependent version string or null)
@@ -77,13 +94,14 @@ public class DBRefEntry implements DBRefEntryI
    *          numbering or null)
    */
   public DBRefEntry(String source, String version, String accessionId,
-          Mapping map)
+          Mapping map,boolean isCanonical)
   {
        
-    this.source = source.toUpperCase();
+    this.source = source.toUpperCase(Locale.ROOT);
     setVersion(version);
     this.accessionId = accessionId;
     this.map = map;
+    this.isCanonicalAccession=isCanonical;
   }
 
   /**
@@ -97,7 +115,7 @@ public class DBRefEntry implements DBRefEntryI
                     : new String(entry.getVersion())),
             (entry.getAccessionId() == null ? ""
                     : new String(entry.getAccessionId())),
-            (entry.getMap() == null ? null : new Mapping(entry.getMap())));
+            (entry.getMap() == null ? null : new Mapping(entry.getMap())),entry.isCanonical());
   }
 
   @Override
@@ -156,6 +174,7 @@ public class DBRefEntry implements DBRefEntryI
       return true;
     }
 
+    boolean improved=false;
     /*
      * source must either match or be both null
      */
@@ -179,6 +198,19 @@ public class DBRefEntry implements DBRefEntryI
       return false;
     }
 
+    if (!isCanonicalAccession && other.isCanonical())
+    {
+      isCanonicalAccession = true;
+      improved = true;
+    }
+    else
+    {
+      if (isCanonicalAccession && !other.isCanonical())
+      {
+        // other is not an authoritative source of canonical accessions
+        return false;
+      }
+    }
     /*
      * if my version is null, "0" or "source:0" then replace with other version,
      * otherwise the versions have to match
@@ -195,12 +227,15 @@ public class DBRefEntry implements DBRefEntryI
       if (version != null && (otherVersion == null
               || !version.equalsIgnoreCase(otherVersion)))
       {
-        return false;
+        // FIXME: there may be a problem with old version strings not allowing
+        // updating of dbrefentries
+        return improved;
       }
     }
 
     /*
-     * if I have no mapping, take that of the other dbref
+     * if I have no mapping, take that of the other dbref 
+     * - providing it had a version and so do I
      */
     if (map == null)
     {
@@ -273,7 +308,7 @@ public class DBRefEntry implements DBRefEntryI
   public void setAccessionId(String accessionId)
   {
          this.accessionId = accessionId;
-//    this.accessionId = (accessionId == null ? "" : accessionId).toUpperCase();
+//    this.accessionId = (accessionId == null ? "" : accessionId).toUpperCase(Locale.ROOT);
   }
 
   /**
@@ -284,7 +319,7 @@ public class DBRefEntry implements DBRefEntryI
   {
          this.source = source;
          
-//    this.source = (source == null ? "" : source).toUpperCase();
+//    this.source = (source == null ? "" : source).toUpperCase(Locale.ROOT);
 //    this.canonicalSourceName =       DBRefUtils.getCanonicalName(this.source);
 //    this.sourceKey = DBRefSource.getSourceKey(this.canonicalSourceName);
   }
@@ -293,7 +328,7 @@ public class DBRefEntry implements DBRefEntryI
   public void setVersion(String version)
   {
     this.version = version;
-    this.ucversion = (version == null ? null : version.toUpperCase());
+    this.ucversion = (version == null ? null : version.toUpperCase(Locale.ROOT));
   }
 
   @Override
@@ -383,4 +418,22 @@ public class DBRefEntry implements DBRefEntryI
   public String getCanonicalSourceName() {
        return (canonicalSourceName == null ? (canonicalSourceName = DBRefUtils.getCanonicalName(this.source)) : canonicalSourceName);
   }
+
+  /**
+   * 
+   * @param canonical
+   */
+  public void setCanonical(boolean canonical)
+  {
+    isCanonicalAccession = canonical;
+  }
+  /**
+   * 
+   * @return true if this is the primary canonical accession for the database source
+   */
+  public boolean isCanonical()
+  {
+    // TODO Auto-generated method stub
+    return isCanonicalAccession;
+  }
 }
index 2f94884..2d2ae4f 100755 (executable)
@@ -36,29 +36,31 @@ package jalview.datamodel;
  * @author JimP
  * 
  */
+import java.util.Locale;
+
 public class DBRefSource
 {
   
   
   
   public static final String UNIPROT = "UNIPROT";
-  public static final String UP_NAME = "UNIPROT_NAME".toUpperCase();
+  public static final String UP_NAME = "UNIPROT_NAME".toUpperCase(Locale.ROOT);
   /**
    * Uniprot Knowledgebase/TrEMBL as served from EMBL protein products.
    */
-  public static final String UNIPROTKB = "UniProtKB/TrEMBL".toUpperCase();
+  public static final String UNIPROTKB = "UniProtKB/TrEMBL".toUpperCase(Locale.ROOT);
 
   public static final String ENSEMBL        = "ENSEMBL";
   public static final String ENSEMBLGENOMES = "ENSEMBLGENOMES";
   
   public static final String EMBL           = "EMBL";
   public static final String EMBLCDS        = "EMBLCDS";
-  public static final String EMBLCDSProduct = "EMBLCDSProtein".toUpperCase();
+  public static final String EMBLCDSProduct = "EMBLCDSProtein".toUpperCase(Locale.ROOT);
 
   public static final String PDB    = "PDB";
   public static final String PFAM   = "PFAM";
   public static final String RFAM   = "RFAM";
-  public static final String GENEDB = "GeneDB".toUpperCase();
+  public static final String GENEDB = "GeneDB".toUpperCase(Locale.ROOT);
 
   public static final String PDB_CANONICAL_NAME = PDB;
 
@@ -146,7 +148,7 @@ public class DBRefSource
     // see if there is a primary reference that derived this reference.
     for (int i = allSources.length; --i >= 0;)
     {
-      if (ucversion.startsWith(allSources[i])) // BH 2019.01.25 .toUpperCase() unnecessary here for allSources
+      if (ucversion.startsWith(allSources[i])) // BH 2019.01.25 .toUpperCase(Locale.ROOT) unnecessary here for allSources
       {
         // by convention, many secondary references inherit the primary
         // reference's
index d652a97..ca6db1b 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import java.util.Locale;
+
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -199,12 +201,12 @@ public class MappedFeatures
      * e.g. C,G,T gives variants G and T for base C
      */
     Set<String> variantPeptides = new HashSet<>();
-    String[] alleles = alls.toUpperCase().split(",");
+    String[] alleles = alls.toUpperCase(Locale.ROOT).split(",");
     StringBuilder vars = new StringBuilder();
 
     for (String allele : alleles)
     {
-      allele = allele.trim().toUpperCase();
+      allele = allele.trim().toUpperCase(Locale.ROOT);
       if (allele.length() > 1 || "-".equals(allele))
       {
         continue; // multi-locus variant
@@ -220,7 +222,7 @@ public class MappedFeatures
        */
       final int i = cdsPos == codonPos[0] ? 0
               : (cdsPos == codonPos[1] ? 1 : 2);
-      variantCodon[i] = allele.toUpperCase().charAt(0);
+      variantCodon[i] = allele.toUpperCase(Locale.ROOT).charAt(0);
       if (variantCodon[i] == baseCodon[i])
       {
         continue;
@@ -294,8 +296,8 @@ public class MappedFeatures
   public int[] getMappedPositions(int begin, int end)
   {
     MapList map = mapping.getMap();
-    return mapping.to == featureSequence ? map.locateInFrom(begin, end)
-            : map.locateInTo(begin, end);
+    return mapping.to == featureSequence ? map.getOverlapsInFrom(begin, end)
+            : map.getOverlapsInTo(begin, end);
   }
 
   /**
index b5184fb..4d90e3e 100644 (file)
  */
 package jalview.datamodel;
 
-import jalview.util.Comparison;
-import jalview.util.MapList;
-
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Vector;
 
+import jalview.util.Comparison;
+import jalview.util.MapList;
+
 public class Mapping
 {
   /**
@@ -433,23 +433,6 @@ public class Mapping
   }
 
   /**
-   * gets boundary in direction of mapping
-   * 
-   * @param position
-   *          in mapped reference frame
-   * @return int{start, end} positions in associated sequence (in direction of
-   *         mapped word)
-   */
-  public int[] getWord(int mpos)
-  {
-    if (map != null)
-    {
-      return map.getToWord(mpos);
-    }
-    return null;
-  }
-
-  /**
    * width of mapped unit in associated sequence
    * 
    */
index c1dc77c..741ef07 100755 (executable)
@@ -38,6 +38,15 @@ public class PDBEntry
 
   private static final int PDB_ID_LENGTH = 4;
 
+  /**
+   * property set when id is a 'manufactured' identifier from the structure data's filename
+   */
+  private static final String FAKED_ID = "faked_pdbid";
+  /**
+   * property set when the id is authoritative, and should be used in preference to any identifiers in the structure data
+   */
+  private static final String AUTHORITATIVE_ID = "authoritative_pdbid";
+
   private String file;
 
   private String type;
@@ -48,7 +57,7 @@ public class PDBEntry
   {
     // TODO is FILE needed; if not is this enum needed, or can we
     // use FileFormatI for PDB, MMCIF?
-    PDB("pdb", "pdb"), MMCIF("mmcif", "cif"), FILE("?", "?");
+    PDB("pdb", "pdb"), MMCIF("mmcif", "cif"), BCIF("bcif","bcif"),FILE("?", "?");
 
     /*
      * file extension for cached structure file; must be one that
@@ -384,21 +393,40 @@ public class PDBEntry
       return false; // shouldn't happen
     }
 
-    /*
-     * id has to match (ignoring case)
-     */
-    if (!getId().equalsIgnoreCase(newId))
-    {
-      return false;
-    }
+    boolean idMatches = getId().equalsIgnoreCase(newId);
 
     /*
      * Don't update if associated with different structure files
      */
     String newFile = newEntry.getFile();
-    if (newFile != null && getFile() != null && !newFile.equals(getFile()))
+    if (newFile != null && getFile() != null)
     {
-      return false;
+      if (!newFile.equals(getFile()))
+      {
+        return false;
+      }
+      else
+      {
+        // files match.
+        if (!idMatches)
+        {
+          // this shouldn't happen, but could do if the id from the
+          // file is not the same as the id from the authority that provided
+          // the file
+          if (!newEntry.fakedPDBId() && !isAuthoritative())
+          {
+            return false;
+          } // otherwise we can update
+        }
+      }
+    }
+    else
+    {
+      // one has data, one doesn't ..
+      if (!idMatches)
+      {
+        return false;
+      } // otherwise maybe can update
     }
 
     /*
@@ -453,6 +481,11 @@ public class PDBEntry
        */
       String key = newProps.nextElement();
       Object value = newEntry.getProperty(key);
+      if (FAKED_ID.equals(key) || AUTHORITATIVE_ID.equals(key))
+      {
+        // we never update the fake ID property
+        continue;
+      }
       if (!value.equals(getProperty(key)))
       {
         setProperty(key, value);
@@ -460,4 +493,130 @@ public class PDBEntry
     }
     return true;
   }
+  
+  public void setAuthoritative(boolean isAuthoritative)
+  {
+    setProperty(AUTHORITATIVE_ID, Boolean.valueOf(isAuthoritative));
+  }
+  
+  /**
+   * 
+   * @return true if the identifier should be preferred over any identifiers
+   *         embedded in the structure data
+   */
+  public boolean isAuthoritative()
+  {
+    if (_hasProperty(AUTHORITATIVE_ID))
+    {
+      return ((Boolean)getProperty(AUTHORITATIVE_ID));
+    }
+    return false;
+  }
+
+  /**
+   * set when Jalview has manufactured the ID using a local filename
+   * @return
+   */
+  public boolean fakedPDBId()
+  {
+    if (_hasProperty(FAKED_ID))
+    {
+      return true;
+    }
+    return false;
+  }
+  public void setFakedPDBId(boolean faked)
+  {
+    if (faked)
+    {
+      setProperty(FAKED_ID, Boolean.TRUE);
+    }
+    else 
+    {
+      if (properties!=null) {
+        properties.remove(FAKED_ID);
+      }
+    }
+  }
+
+  private boolean _hasProperty(final String key)
+  {
+    return (properties != null && properties.containsKey(key));
+  }
+
+  private static final String RETRIEVE_FROM = "RETRIEVE_FROM";
+
+  private static final String PROVIDER = "PROVIDER";
+
+  private static final String MODELPAGE = "PROVIDERPAGE";
+
+  /**
+   * Permanent URI for retrieving the original structure data
+   * 
+   * @param urlStr
+   */
+  public void setRetrievalUrl(String urlStr)
+  {
+    setProperty(RETRIEVE_FROM, urlStr);
+  }
+
+  public boolean hasRetrievalUrl()
+  {
+    return _hasProperty(RETRIEVE_FROM);
+  }
+
+  /**
+   * get the Permanent URI for retrieving the original structure data
+   */
+  public String getRetrievalUrl()
+  {
+    return (String) getProperty(RETRIEVE_FROM);
+  }
+
+  /**
+   * Data provider name - from 3D Beacons
+   * 
+   * @param provider
+   */
+  public void setProvider(String provider)
+  {
+    setProperty(PROVIDER, provider);
+  }
+
+  /**
+   * Get Data provider name - from 3D Beacons
+   * 
+   */
+  public String getProvider()
+  {
+    return (String) getProperty(PROVIDER);
+  }
+
+  /**
+   * Permanent URI for retrieving the original structure data
+   * 
+   * @param urlStr
+   */
+  public void setProviderPage(String urlStr)
+  {
+    setProperty(MODELPAGE, urlStr);
+  }
+
+  /**
+   * get the Permanent URI for retrieving the original structure data
+   */
+  public String getProviderPage()
+  {
+    return (String) getProperty(MODELPAGE);
+  }
+
+  public boolean hasProviderPage()
+  {
+    return _hasProperty(MODELPAGE);
+  }
+
+  public boolean hasProvider()
+  {
+    return _hasProperty(PROVIDER);
+  }
 }
index 7c3bba7..5c929fc 100755 (executable)
@@ -349,8 +349,10 @@ public class SearchResults implements SearchResultsI
   }
 
   /**
-   * Two SearchResults are considered equal if they contain the same matches in
-   * the same order.
+   * Two SearchResults are considered equal if they contain the same matches
+   * (Sequence, start position, end position) in the same order
+   * 
+   * @see Match#equals(Object)
    */
   @Override
   public boolean equals(Object obj)
index 552349f..d52e049 100755 (executable)
@@ -1799,13 +1799,30 @@ public class Sequence extends ASequence implements SequenceI
   public List<AlignmentAnnotation> getAlignmentAnnotations(String calcId,
           String label)
   {
+    return getAlignmentAnnotations(calcId, label, null, true);
+  }
+
+  @Override
+  public List<AlignmentAnnotation> getAlignmentAnnotations(String calcId,
+          String label, String description)
+  {
+    return getAlignmentAnnotations(calcId, label, description, false);
+  }
+
+  private List<AlignmentAnnotation> getAlignmentAnnotations(String calcId,
+          String label, String description, boolean ignoreDescription)
+  {
     List<AlignmentAnnotation> result = new ArrayList<>();
     if (this.annotation != null)
     {
       for (AlignmentAnnotation ann : annotation)
       {
-        if (ann.calcId != null && ann.calcId.equals(calcId)
-                && ann.label != null && ann.label.equals(label))
+        if ((ann.calcId != null && ann.calcId.equals(calcId))
+                && (ann.label != null && ann.label.equals(label))
+                && ((ignoreDescription && description == null)
+                        || (ann.description != null
+                                && ann.description.equals(description))))
+
         {
           result.add(ann);
         }
index 6eeba2f..bbf1b45 100755 (executable)
@@ -612,10 +612,9 @@ public class SequenceFeature implements FeatureLocationI
     String consequence = "";
     if (mf != null)
     {
-      int[] beginRange = mf.getMappedPositions(begin, begin);
-      int[] endRange = mf.getMappedPositions(end, end);
-      int from = beginRange[0];
-      int to = endRange[endRange.length - 1];
+      int[] localRange = mf.getMappedPositions(begin, end);
+      int from = localRange[0];
+      int to = localRange[localRange.length - 1];
       String s = mf.isFromCds() ? "Peptide Location" : "Coding location";
       sb.append(String.format(ROW_DATA, s, seqName, from == to ? from
               : from + (isContactFeature() ? ":" : "-") + to));
index 933f332..7c3eb41 100755 (executable)
@@ -446,6 +446,17 @@ public interface SequenceI extends ASequenceI
           String label);
 
   /**
+   * Returns a (possibly empty) list of any annotations that match on given
+   * calcId (source), label (type) and description (observation instance).
+   * Null values do not match.
+   * 
+   * @param calcId
+   * @param label
+   * @param description
+   */
+  public List<AlignmentAnnotation> getAlignmentAnnotations(String calcId,
+          String label, String description);
+  /**
    * create a new dataset sequence (if necessary) for this sequence and sets
    * this sequence to refer to it. This call will move any features or
    * references on the sequence onto the dataset. It will also make a duplicate
index e9fb9b2..69f80f2 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel.features;
 
+import java.util.Locale;
+
 import jalview.datamodel.SequenceFeature;
 import jalview.util.MessageManager;
 import jalview.util.matcher.Condition;
@@ -163,12 +165,12 @@ public class FeatureMatcher implements FeatureMatcherI
       firstField = descriptor.substring(0, nextSpacePos);
       leftToParse = descriptor.substring(nextSpacePos + 1).trim();
     }
-    String lower = firstField.toLowerCase();
-    if (lower.startsWith(LABEL.toLowerCase()))
+    String lower = firstField.toLowerCase(Locale.ROOT);
+    if (lower.startsWith(LABEL.toLowerCase(Locale.ROOT)))
     {
       byLabel = true;
     }
-    else if (lower.startsWith(SCORE.toLowerCase()))
+    else if (lower.startsWith(SCORE.toLowerCase(Locale.ROOT)))
     {
       byScore = true;
     }
@@ -351,7 +353,7 @@ public class FeatureMatcher implements FeatureMatcherI
     }
 
     Condition condition = matcher.getCondition();
-    sb.append(SPACE).append(condition.toString().toLowerCase());
+    sb.append(SPACE).append(condition.toString().toLowerCase(Locale.ROOT));
     if (condition.isNumeric())
     {
       sb.append(SPACE).append(matcher.getPattern());
index 3743278..ee4bf12 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel.features;
 
+import java.util.Locale;
+
 import jalview.datamodel.SequenceFeature;
 import jalview.util.MessageManager;
 
@@ -257,7 +259,7 @@ public class FeatureMatcherSet implements FeatureMatcherSetI
       if (!first)
       {
         String joiner = andConditions ? AND_18N : OR_I18N;
-        sb.append(SPACE).append(joiner.toLowerCase()).append(SPACE);
+        sb.append(SPACE).append(joiner.toLowerCase(Locale.ROOT)).append(SPACE);
       }
       first = false;
       if (multiple)
index 0e3d84b..ac756fc 100644 (file)
@@ -628,10 +628,10 @@ public class EnsemblGene extends EnsemblSeqProxy
       SequenceOntologyI so = SequenceOntologyFactory.getInstance();
 
       @Override
-      public boolean isFeatureDisplayed(String type)
+      public boolean isFeatureHidden(String type)
       {
-        return (so.isA(type, SequenceOntologyI.EXON)
-                || so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT));
+        return (!so.isA(type, SequenceOntologyI.EXON)
+                && !so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT));
       }
 
       @Override
index 97ad242..e2d2725 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ext.ensembl;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefSource;
 import jalview.util.JSONUtils;
@@ -94,7 +96,7 @@ public class EnsemblInfo extends EnsemblRestClient
     {
       fetchDivisions();
     }
-    return divisions.get(division.toUpperCase());
+    return divisions.get(division.toUpperCase(Locale.ROOT));
   }
 
   /**
@@ -108,7 +110,7 @@ public class EnsemblInfo extends EnsemblRestClient
     /*
      * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL"
      */
-    divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain);
+    divisions.put(DBRefSource.ENSEMBL.toUpperCase(Locale.ROOT), ensemblDomain);
     try
     {
       @SuppressWarnings("unchecked")
@@ -118,7 +120,7 @@ public class EnsemblInfo extends EnsemblRestClient
       while (rvals.hasNext())
       {
         String division = rvals.next().toString();
-        divisions.put(division.toUpperCase(), ensemblGenomesDomain);
+        divisions.put(division.toUpperCase(Locale.ROOT), ensemblGenomesDomain);
       }
     } catch (IOException | ParseException | NumberFormatException e)
     {
index 9b56d6b..3dca1b7 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ext.ensembl;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.GeneLociI;
 import jalview.datamodel.GeneLocus;
@@ -276,7 +276,7 @@ public class EnsemblLookup extends EnsemblRestClient
               chromosome, map);
     } catch (NullPointerException | NumberFormatException e)
     {
-      Cache.log.error("Error looking up gene loci: " + e.getMessage());
+      Console.error("Error looking up gene loci: " + e.getMessage());
       e.printStackTrace();
     }
     return null;
index fd8800f..e4fa53d 100644 (file)
@@ -33,7 +33,7 @@ import org.json.simple.parser.ParseException;
 
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.Dna;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
@@ -312,7 +312,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
 
               if (upx.size() > 1)
               {
-                Cache.log.warn(
+                Console.warn(
                         "Implementation issue - multiple uniprot acc on product sequence.");
               }
             }
index 16ff41b..e91164a 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.ext.htsjdk;
 
-import jalview.bin.Cache;
-
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
@@ -30,6 +28,7 @@ import htsjdk.samtools.util.CloseableIterator;
 import htsjdk.variant.variantcontext.VariantContext;
 import htsjdk.variant.vcf.VCFFileReader;
 import htsjdk.variant.vcf.VCFHeader;
+import jalview.bin.Console;
 
 /**
  * A thin wrapper for htsjdk classes to read either plain, or compressed, or
@@ -85,7 +84,7 @@ public class VCFReader implements Closeable, Iterable<VariantContext>
     }
     else
     {
-      Cache.log.error("File not found: " + filePath);
+      Console.error("File not found: " + filePath);
     }
   }
 
index eee48df..895db9a 100644 (file)
@@ -31,6 +31,8 @@ import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
+import javax.swing.SwingUtilities;
+
 import org.jmol.adapter.smarter.SmarterJmolAdapter;
 import org.jmol.api.JmolAppConsoleInterface;
 import org.jmol.api.JmolSelectionListener;
@@ -41,10 +43,12 @@ import org.jmol.viewer.Viewer;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
+import jalview.api.FeatureSettingsModelI;
 import jalview.api.SequenceRenderer;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.gui.AppJmol;
 import jalview.gui.IProgressIndicator;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
@@ -54,6 +58,7 @@ import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
 import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
+import jalview.ws.dbsources.Pdb;
 import javajs.util.BS;
 
 public abstract class JalviewJmolBinding extends AAStructureBindingModel
@@ -86,8 +91,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     setStructureCommands(new JmolCommands());
     /*
      * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
-     * "jalviewJmol", ap.av.applet .getDocumentBase(),
-     * ap.av.applet.getCodeBase(), "", this);
+     * "jalviewJmol", ap.av.applet .getDocumentBase(), ap.av.applet.getCodeBase(),
+     * "", this);
      * 
      * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
      */
@@ -117,9 +122,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   private String jmolScript(String script)
   {
-    Cache.log.debug(">>Jmol>> " + script);
+    Console.debug(">>Jmol>> " + script);
     String s = jmolViewer.evalStringQuiet(script); // scriptWait(script); BH
-    Cache.log.debug("<<Jmol<< " + s);
+    Console.debug("<<Jmol<< " + s);
 
     return s;
   }
@@ -204,8 +209,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       for (int i = 0; i < modelCount; ++i)
       {
         /*
-         * defensive check for null as getModelFileName can return null
-         * even when model count ms.mc is > 0
+         * defensive check for null as getModelFileName can return null even when model
+         * count ms.mc is > 0
          */
         filePath = jmolViewer.ms.getModelFileName(i);
         if (filePath != null && !mset.contains(filePath))
@@ -398,8 +403,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     }
 
     /*
-     * highlight position on alignment(s); if some text is returned, 
-     * show this as a second line on the structure hover tooltip
+     * highlight position on alignment(s); if some text is returned, show this as a
+     * second line on the structure hover tooltip
      */
     String label = getSsm().mouseOverStructure(pdbResNum, chainId,
             pdbfilename);
@@ -435,8 +440,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   /*
    * { if (history != null && strStatus != null &&
-   * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
-   * } }
+   * !strStatus.equals("Script completed")) { history.append("\n" + strStatus); }
+   * }
    */
 
   public void notifyAtomPicked(int atomIndex, String strInfo,
@@ -497,6 +502,28 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   @Override
   public void notifyCallback(CBK type, Object[] data)
   {
+    /*
+     * ensure processed in AWT thread to avoid risk of deadlocks
+     */
+    SwingUtilities.invokeLater(new Runnable()
+    {
+
+      @Override
+      public void run()
+      {
+        processCallback(type, data);
+      }
+    });
+  }
+
+  /**
+   * Processes one callback notification from Jmol
+   * 
+   * @param type
+   * @param data
+   */
+  protected void processCallback(CBK type, Object[] data)
+  {
     try
     {
       switch (type)
@@ -745,7 +772,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       FeatureRenderer fr = getFeatureRenderer(null);
       if (fr != null)
       {
-        fr.featuresAdded();
+        FeatureSettingsModelI colours = new Pdb().getFeatureColourScheme();
+        ((AppJmol) getViewer()).getAlignmentPanel().av
+                .applyFeaturesStyle(colours);
       }
       refreshGUI();
       loadNotifiesHandled++;
@@ -774,8 +803,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   public abstract void sendConsoleEcho(String strEcho); /*
                                                          * { showConsole(true);
                                                          * 
-                                                         * history.append("\n" +
-                                                         * strEcho); }
+                                                         * history.append("\n" + strEcho); }
                                                          */
 
   // /End JmolStatusListener
index 25f6aec..8b67ad9 100644 (file)
@@ -40,6 +40,7 @@ import jalview.structure.StructureCommandI;
 import jalview.structure.StructureCommandsBase;
 import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 import jalview.util.Comparison;
 import jalview.util.Platform;
 
@@ -178,7 +179,7 @@ public class JmolCommands extends StructureCommandsBase
    */
   @Override
   public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
-          AtomSpecModel atomSpec)
+          AtomSpecModel atomSpec, AtomSpecType backbone)
   {
     StringBuilder sb = new StringBuilder(64);
     String refModel = refAtoms.getModels().iterator().next();
@@ -190,16 +191,16 @@ public class JmolCommands extends StructureCommandsBase
      * command examples don't include modelspec with atoms, getAtomSpec does;
      * it works, so leave it as it is for simplicity
      */
-    sb.append(getAtomSpec(atomSpec, true)).append("}{");
-    sb.append(getAtomSpec(refAtoms, true)).append("}");
+    sb.append(getAtomSpec(atomSpec, backbone)).append("}{");
+    sb.append(getAtomSpec(refAtoms, backbone)).append("}");
     sb.append(" ROTATE TRANSLATE ");
     sb.append(getCommandSeparator());
 
     /*
      * show residues used for superposition as ribbon
      */
-    sb.append("select ").append(getAtomSpec(atomSpec, false)).append("|");
-    sb.append(getAtomSpec(refAtoms, false)).append(getCommandSeparator())
+    sb.append("select ").append(getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY)).append("|");
+    sb.append(getAtomSpec(refAtoms, AtomSpecType.RESIDUE_ONLY)).append(getCommandSeparator())
             .append("cartoons");
 
     return Arrays.asList(new StructureCommand(sb.toString()));
@@ -250,7 +251,7 @@ public class JmolCommands extends StructureCommandsBase
    * a separate clause in the {@code compare} (superposition) command.
    */
   @Override
-  public String getAtomSpec(AtomSpecModel model, boolean alphaOnly)
+  public String getAtomSpec(AtomSpecModel model, AtomSpecType specType)
   {
     StringBuilder sb = new StringBuilder(128);
 
index a9c5f5c..2a43244 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ext.jmol;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.PDBEntry;
@@ -45,6 +47,8 @@ import org.jmol.c.STR;
 import org.jmol.modelset.ModelSet;
 import org.jmol.viewer.Viewer;
 
+import com.stevesoft.pat.Regex;
+
 import mc_view.Atom;
 import mc_view.PDBChain;
 import mc_view.Residue;
@@ -59,6 +63,8 @@ public class JmolParser extends StructureFile implements JmolStatusListener
 {
   Viewer viewer = null;
 
+  private boolean alphaFoldModel;
+
   public JmolParser(boolean immediate, Object inFile,
           DataSourceType sourceType) throws IOException
   {
@@ -111,7 +117,7 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       // }
       // ;
       // instead, we distinguish .cif from non-.cif by filename
-      setStructureFileType(getDataName().toLowerCase().endsWith(".cif")
+      setStructureFileType(getDataName().toLowerCase(Locale.ROOT).endsWith(".cif")
               ? PDBEntry.Type.MMCIF.toString()
               : "PDB");
 
@@ -148,17 +154,58 @@ public class JmolParser extends StructureFile implements JmolStatusListener
     }
     return viewer;
   }
+  
+  public static Regex getNewAlphafoldValidator()
+  {
+    Regex validator =  new Regex("(AF-[A-Z]+[0-9]+[A-Z0-9]+-F1)");
+    validator.setIgnoreCase(true);
+    return validator;
+  }
 
+  PDBEntry.Type jmolFiletype=null;
+  /**
+   * resolve a jmol filetype string and update the jmolFiletype field accordingly
+   * @param jmolIdentifiedFileType
+   * @return true if filetype was identified as MMCIF, PDB
+   */
+  public boolean updateFileType(String jmolIdentifiedFileType)
+  {
+    if (jmolIdentifiedFileType == null 
+            || jmolIdentifiedFileType.trim().equals(""))
+    {
+      return false;
+    }
+    if ("mmcif".equalsIgnoreCase(jmolIdentifiedFileType)) {
+      jmolFiletype = PDBEntry.Type.MMCIF;
+      return true;
+    }
+    if ("pdb".equalsIgnoreCase(jmolIdentifiedFileType))
+    {
+      jmolFiletype = PDBEntry.Type.PDB;
+      return true;
+    } 
+    return false;
+  }
+  
   public void transformJmolModelToJalview(ModelSet ms) throws IOException
   {
     try
     {
+      Regex alphaFold = getNewAlphafoldValidator();
       String lastID = "";
       List<SequenceI> rna = new ArrayList<SequenceI>();
       List<SequenceI> prot = new ArrayList<SequenceI>();
       PDBChain tmpchain;
       String pdbId = (String) ms.getInfo(0, "title");
-
+      boolean isMMCIF = false;
+      String jmolFileType_String = (String) ms.getInfo(0, "fileType");
+      if (updateFileType(jmolFileType_String))
+      {
+        setStructureFileType(jmolFiletype.toString());
+      }
+      
+      isMMCIF = PDBEntry.Type.MMCIF.equals(jmolFiletype);
+      
       if (pdbId == null)
       {
         setId(safeName(getDataName()));
@@ -168,6 +215,8 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       {
         setId(pdbId);
         setPDBIdAvailable(true);
+        alphaFoldModel = alphaFold.search(pdbId) && isMMCIF;  
+
       }
       List<Atom> significantAtoms = convertSignificantAtoms(ms);
       for (Atom tmpatom : significantAtoms)
@@ -183,7 +232,13 @@ public class JmolParser extends StructureFile implements JmolStatusListener
           tmpchain.atoms.addElement(tmpatom);
         } else
         {
-          tmpchain = new PDBChain(getId(), tmpatom.chain);
+          String tempFString=null;
+          if (isAlphafoldModel())
+          {
+            tempFString = "Alphafold Reliability";
+          }
+
+          tmpchain = new PDBChain(getId(), tmpatom.chain,tempFString);
           getChains().add(tmpchain);
           tmpchain.atoms.addElement(tmpatom);
         }
@@ -225,6 +280,11 @@ public class JmolParser extends StructureFile implements JmolStatusListener
     }
   }
 
+  private boolean isAlphafoldModel()
+  {
+    return alphaFoldModel;
+  }
+
   private List<Atom> convertSignificantAtoms(ModelSet ms)
   {
     List<Atom> significantAtoms = new ArrayList<Atom>();
@@ -351,7 +411,7 @@ public class JmolParser extends StructureFile implements JmolStatusListener
 
   /**
    * Helper method that adds an AlignmentAnnotation for secondary structure to
-   * the sequence, provided at least one secondary structure prediction has been
+   * the sequence, provided at least one secondary structure assignment has been
    * made
    * 
    * @param modelTitle
index 36957f5..ed64c00 100644 (file)
@@ -106,20 +106,22 @@ public class PymolCommands extends StructureCommandsBase
 
   @Override
   public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
-          AtomSpecModel atomSpec)
+          AtomSpecModel atomSpec, AtomSpecType specType)
   {
+             
     // https://pymolwiki.org/index.php/Super
     List<StructureCommandI> commands = new ArrayList<>();
-    String refAtomsAlphaOnly = getAtomSpec(refAtoms, true);
-    String atomSpec2AlphaOnly = getAtomSpec(atomSpec, true);
-    commands.add(new StructureCommand("super", refAtomsAlphaOnly,
-            atomSpec2AlphaOnly));
+    String refAtomsAlphaOnly = "("+getAtomSpec(refAtoms, specType)+" and (altloc '' or altloc 'a'))";
+    String atomSpec2AlphaOnly = "("+getAtomSpec(atomSpec, specType)+" and (altloc '' or altloc 'a'))";
+    // pair_fit mobile -> reference
+    commands.add(new StructureCommand("pair_fit", 
+            atomSpec2AlphaOnly, refAtomsAlphaOnly));
 
     /*
      * and show superposed residues as cartoon
      */
-    String refAtomsAll = getAtomSpec(refAtoms, false);
-    String atomSpec2All = getAtomSpec(atomSpec, false);
+    String refAtomsAll = getAtomSpec(refAtoms, AtomSpecType.RESIDUE_ONLY);
+    String atomSpec2All = getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY);
     commands.add(new StructureCommand("show", "cartoon",
             refAtomsAll + " " + atomSpec2All));
 
@@ -153,7 +155,7 @@ public class PymolCommands extends StructureCommandsBase
    * @see https://pymolwiki.org/index.php/Selection_Macros
    */
   @Override
-  public String getAtomSpec(AtomSpecModel model, boolean alphaOnly)
+  public String getAtomSpec(AtomSpecModel model, AtomSpecType specType)
   {
     StringBuilder sb = new StringBuilder(64);
     boolean first = true;
@@ -184,10 +186,14 @@ public class PymolCommands extends StructureCommandsBase
           }
         }
         sb.append("/");
-        if (alphaOnly)
+        if (specType == AtomSpecType.ALPHA)
         {
           sb.append("CA");
         }
+        if (specType == AtomSpecType.PHOSPHATE)
+        {
+          sb.append("P");
+        }
       }
     }
     return sb.toString();
@@ -261,7 +267,7 @@ public class PymolCommands extends StructureCommandsBase
     StringBuilder sb = new StringBuilder(128);
     sb.append("p.").append(attributeName).append("='")
             .append(attributeValue).append("'");
-    String atomSpec = getAtomSpec(atomSpecModel, false);
+    String atomSpec = getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY);
     return new StructureCommand("iterate", atomSpec, sb.toString());
   }
 
index 26c780d..db71269 100644 (file)
@@ -14,6 +14,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.Preferences;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
@@ -140,7 +141,7 @@ public class PymolManager
       int rc = conn.getResponseCode();
       if (rc != HttpURLConnection.HTTP_OK)
       {
-        Cache.log.error(
+        Console.error(
                 String.format("Error status from %s: %d", rpcUrl, rc));
         return result;
       }
@@ -158,7 +159,7 @@ public class PymolManager
     } catch (SocketException e)
     {
       // thrown when 'quit' command is sent to PyMol
-      Cache.log.warn(String.format("Request to %s returned %s", rpcUrl,
+      Console.warn(String.format("Request to %s returned %s", rpcUrl,
               e.toString()));
     } catch (Exception e)
     {
@@ -169,6 +170,14 @@ public class PymolManager
       {
         out.close();
       }
+      if (Console.isTraceEnabled())
+      {
+        Console.trace("Sent: " + command.toString());
+        if (result != null)
+        {
+          Console.trace("Received: " + result);
+        }
+      }
     }
     return result;
   }
@@ -243,12 +252,12 @@ public class PymolManager
       this.pymolXmlRpcPort = getPortNumber();
       if (pymolXmlRpcPort > 0)
       {
-        Cache.log.info("PyMOL XMLRPC started on port " + pymolXmlRpcPort);
+        Console.info("PyMOL XMLRPC started on port " + pymolXmlRpcPort);
       }
       else
       {
         error += "Failed to read PyMOL XMLRPC port number";
-        Cache.log.error(error);
+        Console.error(error);
         pymolProcess.destroy();
         pymolProcess = null;
       }
@@ -292,7 +301,7 @@ public class PymolManager
       }
     } catch (Exception e)
     {
-      Cache.log.error("Failed to get REST port number from " + responses
+      Console.error("Failed to get REST port number from " + responses
               + ": " + e.getMessage());
       // logger.error("Failed to get REST port number from " + responses + ": "
       // + e.getMessage());
@@ -307,10 +316,10 @@ public class PymolManager
     }
     if (port == 0)
     {
-      Cache.log.error("Failed to start PyMOL with XMLRPC, response was: "
+      Console.error("Failed to start PyMOL with XMLRPC, response was: "
               + responses);
     }
-    Cache.log.error("PyMOL started with XMLRPC on port " + port);
+    Console.error("PyMOL started with XMLRPC on port " + port);
     return port;
   }
 
index ced22fa..6d4caa2 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ext.rbvi.chimera;
 
+import java.util.Locale;
+
 import java.awt.Color;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -30,6 +32,7 @@ import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
 import jalview.structure.StructureCommandsBase;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 import jalview.util.ColorUtils;
 
 /**
@@ -159,7 +162,7 @@ public class ChimeraCommands extends StructureCommandsBase
     StringBuilder sb = new StringBuilder(128);
     sb.append("setattr res ").append(attributeName).append(" '")
             .append(attributeValue).append("' ");
-    sb.append(getAtomSpec(atomSpecModel, false));
+    sb.append(getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY));
     return new StructureCommand(sb.toString());
   }
 
@@ -181,7 +184,7 @@ public class ChimeraCommands extends StructureCommandsBase
      * Chimera treats an attribute name ending in 'color' as colour-valued;
      * Jalview doesn't, so prevent this by appending an underscore
      */
-    if (attName.toUpperCase().endsWith("COLOR"))
+    if (attName.toUpperCase(Locale.ROOT).endsWith("COLOR"))
     {
       attName += "_";
     }
@@ -257,7 +260,7 @@ public class ChimeraCommands extends StructureCommandsBase
 
   @Override
   public List<StructureCommandI> superposeStructures(AtomSpecModel ref,
-          AtomSpecModel spec)
+          AtomSpecModel spec, AtomSpecType backbone)
   {
     /*
      * Form Chimera match command to match spec to ref
@@ -268,15 +271,15 @@ public class ChimeraCommands extends StructureCommandsBase
      * @see https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
      */
     StringBuilder cmd = new StringBuilder();
-    String atomSpecAlphaOnly = getAtomSpec(spec, true);
-    String refSpecAlphaOnly = getAtomSpec(ref, true);
+    String atomSpecAlphaOnly = getAtomSpec(spec, backbone);
+    String refSpecAlphaOnly = getAtomSpec(ref, backbone);
     cmd.append("match ").append(atomSpecAlphaOnly).append(" ").append(refSpecAlphaOnly);
 
     /*
      * show superposed residues as ribbon
      */
-    String atomSpec = getAtomSpec(spec, false);
-    String refSpec = getAtomSpec(ref, false);
+    String atomSpec = getAtomSpec(spec, AtomSpecType.RESIDUE_ONLY);
+    String refSpec = getAtomSpec(ref, AtomSpecType.RESIDUE_ONLY);
     cmd.append("; ribbon ");
     cmd.append(atomSpec).append("|").append(refSpec).append("; focus");
 
@@ -317,12 +320,12 @@ public class ChimeraCommands extends StructureCommandsBase
    * <pre>
    * 
    * @param model
-   * @param alphaOnly
+   * @param specType
    * @return
    * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
    */
   @Override
-  public String getAtomSpec(AtomSpecModel atomSpec, boolean alphaOnly)
+  public String getAtomSpec(AtomSpecModel atomSpec, AtomSpecType specType)
   {
     StringBuilder sb = new StringBuilder(128);
     boolean firstModel = true;
@@ -333,7 +336,7 @@ public class ChimeraCommands extends StructureCommandsBase
         sb.append("|");
       }
       firstModel = false;
-      appendModel(sb, model, atomSpec, alphaOnly);
+      appendModel(sb, model, atomSpec, specType);
     }
     return sb.toString();
   }
@@ -347,7 +350,7 @@ public class ChimeraCommands extends StructureCommandsBase
    * @param alphaOnly
    */
   protected void appendModel(StringBuilder sb, String model,
-          AtomSpecModel atomSpec, boolean alphaOnly)
+          AtomSpecModel atomSpec, AtomSpecType specType)
   {
     sb.append("#").append(model).append(":");
 
@@ -365,15 +368,18 @@ public class ChimeraCommands extends StructureCommandsBase
         firstPositionForModel = false;
       }
     }
-    if (alphaOnly)
+    if (specType == AtomSpecType.ALPHA)
     {
       /*
        * restrict to alpha carbon, no alternative locations
        * (needed to ensuring matching atom counts for superposition)
        */
-      // TODO @P instead if RNA - add nucleotide flag to AtomSpecModel?
       sb.append("@CA").append(NO_ALTLOCS);
     }
+    if (specType == AtomSpecType.PHOSPHATE)
+    {
+      sb.append("@P").append(NO_ALTLOCS);
+    }
   }
 
   @Override
index ad04fc9..780d292 100644 (file)
@@ -28,6 +28,7 @@ import java.util.List;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 
 /**
  * Routines for generating ChimeraX commands for Jalview/ChimeraX binding
@@ -35,15 +36,19 @@ import jalview.structure.StructureCommandI;
 public class ChimeraXCommands extends ChimeraCommands
 {
   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#resattr
-  private static final StructureCommand LIST_RESIDUE_ATTRIBUTES = new StructureCommand("info resattr");
+  private static final StructureCommand LIST_RESIDUE_ATTRIBUTES = new StructureCommand(
+          "info resattr");
 
   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/exit.html
-  private static final StructureCommand CLOSE_CHIMERAX = new StructureCommand("exit");
+  private static final StructureCommand CLOSE_CHIMERAX = new StructureCommand(
+          "exit");
 
   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#notify
-  private static final StructureCommand STOP_NOTIFY_SELECTION = new StructureCommand("info notify stop selection jalview");
+  private static final StructureCommand STOP_NOTIFY_SELECTION = new StructureCommand(
+          "info notify stop selection jalview");
 
-  private static final StructureCommand STOP_NOTIFY_MODELS = new StructureCommand("info notify stop models jalview");
+  private static final StructureCommand STOP_NOTIFY_MODELS = new StructureCommand(
+          "info notify stop models jalview");
 
   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#selection
   private static final StructureCommand GET_SELECTION = new StructureCommand(
@@ -98,8 +103,8 @@ public class ChimeraXCommands extends ChimeraCommands
   }
 
   /**
-   * Returns a viewer command to set the given residue attribute value on
-   * residues specified by the AtomSpecModel, for example
+   * Returns a viewer command to set the given residue attribute value on residues
+   * specified by the AtomSpecModel, for example
    * 
    * <pre>
    * setattr #0/A:3-9,14-20,39-43 res jv_strand 'strand' create true
@@ -115,7 +120,7 @@ public class ChimeraXCommands extends ChimeraCommands
           String attributeValue, AtomSpecModel atomSpecModel)
   {
     StringBuilder sb = new StringBuilder(128);
-    sb.append("setattr ").append(getAtomSpec(atomSpecModel, false));
+    sb.append("setattr ").append(getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY));
     sb.append(" res ").append(attributeName).append(" '")
             .append(attributeValue).append("'");
     sb.append(" create true");
@@ -141,11 +146,15 @@ public class ChimeraXCommands extends ChimeraCommands
    * Returns the range(s) formatted as a ChimeraX atomspec, for example
    * <p>
    * #1/A:2-20,30-40/B:10-20|#2/A:12-30
+   * <p>
+   * Note there is no need to explicitly exclude ALTLOC atoms when
+   * {@code alphaOnly == true}, as this is the default behaviour of ChimeraX (a
+   * change from Chimera)
    * 
    * @return
    */
   @Override
-  public String getAtomSpec(AtomSpecModel atomSpec, boolean alphaOnly)
+  public String getAtomSpec(AtomSpecModel atomSpec, AtomSpecType specType)
   {
     StringBuilder sb = new StringBuilder(128);
     boolean firstModel = true;
@@ -157,12 +166,14 @@ public class ChimeraXCommands extends ChimeraCommands
       }
       firstModel = false;
       appendModel(sb, model, atomSpec);
-      if (alphaOnly)
+      if (specType == AtomSpecType.ALPHA)
       {
-        // TODO @P if RNA - add nucleotide flag to AtomSpecModel?
         sb.append("@CA");
       }
-      // todo: is there ChimeraX syntax to exclude altlocs?
+      if (specType == AtomSpecType.PHOSPHATE)
+      {
+        sb.append("@P");
+      }
     }
     return sb.toString();
   }
@@ -206,7 +217,7 @@ public class ChimeraXCommands extends ChimeraCommands
 
   @Override
   public List<StructureCommandI> superposeStructures(AtomSpecModel ref,
-          AtomSpecModel spec)
+          AtomSpecModel spec, AtomSpecType backbone)
   {
     /*
      * Form ChimeraX match command to match spec to ref
@@ -216,8 +227,8 @@ public class ChimeraXCommands extends ChimeraCommands
      * @see https://www.cgl.ucsf.edu/chimerax/docs/user/commands/align.html
      */
     StringBuilder cmd = new StringBuilder();
-    String atomSpec = getAtomSpec(spec, true);
-    String refSpec = getAtomSpec(ref, true);
+    String atomSpec = getAtomSpec(spec, backbone);
+    String refSpec = getAtomSpec(ref, backbone);
     cmd.append("align ").append(atomSpec).append(" toAtoms ")
             .append(refSpec);
 
@@ -225,8 +236,8 @@ public class ChimeraXCommands extends ChimeraCommands
      * show superposed residues as ribbon, others as chain
      */
     cmd.append("; ribbon ");
-    cmd.append(getAtomSpec(spec, false)).append("|");
-    cmd.append(getAtomSpec(ref, false)).append("; view");
+    cmd.append(getAtomSpec(spec, AtomSpecType.RESIDUE_ONLY)).append("|");
+    cmd.append(getAtomSpec(ref, AtomSpecType.RESIDUE_ONLY)).append("; view");
 
     return Arrays.asList(new StructureCommand(cmd.toString()));
   }
@@ -249,8 +260,12 @@ public class ChimeraXCommands extends ChimeraCommands
   public List<StructureCommandI> startNotifications(String uri)
   {
     List<StructureCommandI> cmds = new ArrayList<>();
-    cmds.add(new StructureCommand("info notify start models jalview prefix ModelChanged url " + uri));
-    cmds.add(new StructureCommand("info notify start selection jalview prefix SelectionChanged url " + uri));
+    cmds.add(new StructureCommand(
+            "info notify start models jalview prefix ModelChanged url "
+                    + uri));
+    cmds.add(new StructureCommand(
+            "info notify start selection jalview prefix SelectionChanged url "
+                    + uri));
     return cmds;
   }
 
index 66420b0..c78a82b 100644 (file)
@@ -36,7 +36,7 @@ import ext.edu.ucsf.rbvi.strucviz2.ChimeraModel;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
 import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
@@ -337,11 +337,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     if (getResponse)
     {
       reply = lastReply;
-      if (Cache.log.isDebugEnabled()) {
-        Cache.log.debug(
+      if (Console.isDebugEnabled()) {
+        Console.debug(
               "Response from command ('" + cmd + "') was:\n" + lastReply); 
       }
     }
+    else
+    {
+      if (Console.isDebugEnabled())
+      {
+        Console.debug("Command executed: " + cmd);
+      }
+    }
 
     return reply;
   }
@@ -418,19 +425,29 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     {
       return;
     }
-
+    if (!found)
+    {
+      // not a valid residue label command, so clear
+      cmd.setLength(0);
+    }
     /*
-     * unshow the label for the previous residue
+     * prepend with command
+     * to unshow the label for the previous residue
      */
     if (lastHighlightCommand != null)
     {
-      executeCommand(false,  null,  new StructureCommand("~" + lastHighlightCommand));
+      cmd.insert(0, ";");
+      cmd.insert(0,lastHighlightCommand);
+      cmd.insert(0,"~");
+      
     }
-    if (found)
-    {
-      executeCommand(false,  null,  new StructureCommand(command));
+    if (cmd.length()>0) {
+      executeCommand(true,  null,  new StructureCommand(cmd.toString()));
+    }
+    
+    if (found) {
+      this.lastHighlightCommand = command;
     }
-    this.lastHighlightCommand = command;
   }
 
   /**
@@ -510,7 +527,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
         atomSpecs.add(spec);
       } catch (IllegalArgumentException e)
       {
-        Cache.log.error("Failed to parse atomspec: " + atomSpec);
+        Console.error("Failed to parse atomspec: " + atomSpec);
       }
     }
     return atomSpecs;
@@ -662,7 +679,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
         spec = parseAtomSpec(atomSpec);
       } catch (IllegalArgumentException e)
       {
-        Cache.log.error("Problem parsing atomspec " + atomSpec);
+        Console.error("Problem parsing atomspec " + atomSpec);
         continue;
       }
 
index 138aa58..38d98d0 100644 (file)
@@ -42,7 +42,7 @@ import org.biojava.nbio.ontology.Triple;
 import org.biojava.nbio.ontology.io.OboParser;
 import org.biojava.nbio.ontology.utils.Annotation;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.io.gff.SequenceOntologyI;
 
 /**
@@ -115,7 +115,7 @@ public class SequenceOntology implements SequenceOntologyI
         }
       }
       long elapsed = System.currentTimeMillis() - now;
-      Cache.log.info("Loaded Sequence Ontology from " + zipFile + " ("
+      Console.info("Loaded Sequence Ontology from " + zipFile + " ("
               + elapsed + "ms)");
     } catch (Exception e)
     {
@@ -184,19 +184,19 @@ public class SequenceOntology implements SequenceOntologyI
             boolean oldTermIsObsolete = isObsolete(replaced);
             if (newTermIsObsolete && !oldTermIsObsolete)
             {
-              Cache.log.debug("Ignoring " + term.getName()
+              Console.debug("Ignoring " + term.getName()
                       + " as obsolete and duplicated by "
                       + replaced.getName());
               term = replaced;
             }
             else if (!newTermIsObsolete && oldTermIsObsolete)
             {
-              Cache.log.debug("Ignoring " + replaced.getName()
+              Console.debug("Ignoring " + replaced.getName()
                       + " as obsolete and duplicated by " + term.getName());
             }
             else
             {
-              Cache.log.debug("Warning: " + term.getName()
+              Console.debug("Warning: " + term.getName()
                       + " has replaced " + replaced.getName()
                       + " for lookup of '" + description + "'");
             }
@@ -337,7 +337,7 @@ public class SequenceOntology implements SequenceOntologyI
     {
       if (!termsNotFound.contains(term))
       {
-        Cache.log.error("SO term " + term + " invalid");
+        Console.error("SO term " + term + " invalid");
         termsNotFound.add(term);
       }
     }
index 33b0ed6..31d5c7c 100644 (file)
@@ -22,6 +22,7 @@
 package jalview.fts.api;
 
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 
@@ -88,7 +89,7 @@ public interface FTSRestClientI
 
   /**
    * Fetch index of the primary key column for the dynamic table
-   * 
+   * TODO: consider removing 'hasRefSeq' - never used in code
    * @param wantedFields
    *          the available table columns
    * @param hasRefSeq
@@ -136,4 +137,6 @@ public interface FTSRestClientI
    * @return the default response page size
    */
   public int getDefaultResponsePageSize();
+
+  public String[] getPreferencesColumnsFor(PreferenceSource source);
 }
diff --git a/src/jalview/fts/api/StructureFTSRestClientI.java b/src/jalview/fts/api/StructureFTSRestClientI.java
new file mode 100644 (file)
index 0000000..4974b80
--- /dev/null
@@ -0,0 +1,10 @@
+package jalview.fts.api;
+
+import java.util.Collection;
+
+public interface StructureFTSRestClientI
+{
+
+  Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns();
+
+}
index e5042ae..0335d65 100644 (file)
@@ -23,6 +23,7 @@ package jalview.fts.core;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.api.StructureFTSRestClientI;
 import jalview.fts.service.pdb.PDBFTSRestClient;
 
 import java.util.ArrayList;
@@ -39,7 +40,13 @@ import javax.swing.SortOrder;
 import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
-
+/**
+ * Helps render GUI allowing control of which columns to show for entries returned from an FTS query.
+ * TODO: push down FTSClient specific code
+ * 
+ * @author tcofoegbu
+ *
+ */
 @SuppressWarnings("serial")
 public class FTSDataColumnPreferences extends JScrollPane
 {
@@ -70,7 +77,7 @@ public class FTSDataColumnPreferences extends JScrollPane
     if (source.equals(PreferenceSource.STRUCTURE_CHOOSER)
             || source.equals(PreferenceSource.PREFERENCES))
     {
-      structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
+      structSummaryColumns = ((StructureFTSRestClientI) ftsRestClient)
               .getAllDefaultDisplayedStructureDataColumns();
     }
     allFTSDataColumns.addAll(ftsRestClient.getAllFTSDataColumns());
@@ -79,28 +86,14 @@ public class FTSDataColumnPreferences extends JScrollPane
     this.getViewport().add(tbl_FTSDataColumnPrefs);
     this.currentSource = source;
 
-    String[] columnNames = null;
-    switch (source)
-    {
-    case SEARCH_SUMMARY:
-      columnNames = new String[] { "", "Display", "Group" };
-      break;
-    case STRUCTURE_CHOOSER:
-      columnNames = new String[] { "", "Display", "Group" };
-      break;
-    case PREFERENCES:
-      columnNames = new String[] { "PDB Field", "Show in search summary",
-          "Show in structure summary" };
-      break;
-    default:
-      break;
-    }
+    String[] columnNames = ftsRestClient.getPreferencesColumnsFor(source);
 
-    Object[][] data = new Object[allFTSDataColumns.size() - 1][3];
+    Object[][] data = new Object[allFTSDataColumns.size()][3];
 
     int x = 0;
     for (FTSDataColumnI field : allFTSDataColumns)
-    {
+    {   
+      //System.out.println("allFTSDataColumns==" + allFTSDataColumns);
       if (field.getName().equalsIgnoreCase("all"))
       {
         continue;
@@ -112,6 +105,7 @@ public class FTSDataColumnPreferences extends JScrollPane
         data[x++] = new Object[] { ftsRestClient
                 .getAllDefaultDisplayedFTSDataColumns().contains(field),
             field.getName(), field.getGroup() };
+        //System.out.println(" PUIS " + field.getName() + " ET AUSSI " + field.getGroup() + "X = " + x);
         break;
       case STRUCTURE_CHOOSER:
         data[x++] = new Object[] { structSummaryColumns.contains(field),
index 7a8a695..0bca070 100644 (file)
  */
 package jalview.fts.core;
 
+import java.util.Locale;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Objects;
 
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
 import jalview.fts.api.FTSRestClientI;
 
 /**
@@ -56,6 +61,8 @@ public abstract class FTSRestClient implements FTSRestClientI
 
   private int defaultResponsePageSize = 100;
 
+  protected HashMap<String,String> mockQueries = null;
+
   protected FTSRestClient()
   {
 
@@ -166,7 +173,7 @@ public abstract class FTSRestClient implements FTSRestClientI
               public DataTypeI getDataType()
               {
                 final String[] dataTypeString = lineData[2].split("\\|");
-                final String classString = dataTypeString[0].toUpperCase();
+                final String classString = dataTypeString[0].toUpperCase(Locale.ROOT);
 
                 return new DataTypeI()
                 {
@@ -177,7 +184,7 @@ public abstract class FTSRestClient implements FTSRestClientI
                     if (dataTypeString.length > 1
                             && dataTypeString[1] != null)
                     {
-                      switch (dataTypeString[1].toUpperCase())
+                      switch (dataTypeString[1].toUpperCase(Locale.ROOT))
                       {
                       case "T":
                       case "TRUE":
@@ -427,6 +434,16 @@ public abstract class FTSRestClient implements FTSRestClientI
             "Couldn't find data column with name : " + nameOrCode);
   }
 
+  /**
+   * 
+   * @param instance
+   * @param mocks {{working query, working response}, ...}
+   */
+  public static void createMockFTSRestClient(FTSRestClient instance,String[][] mocks)
+  {
+    instance.setMock(mocks);
+  }
+
   @Override
   public FTSDataColumnGroupI getDataColumnGroupById(String id)
           throws Exception
@@ -480,6 +497,11 @@ public abstract class FTSRestClient implements FTSRestClientI
     return String.valueOf(code) + " " + message;
   }
 
+  public static void unMock(FTSRestClient instance)
+  {
+    instance.mockQueries=null;
+  }
+
   protected String getResourceFile(String fileName)
   {
     String result = "";
@@ -504,4 +526,37 @@ public abstract class FTSRestClient implements FTSRestClientI
     return defaultResponsePageSize;
   }
 
+  protected void setMock(String[][] mocks)
+  {
+    if (mocks==null) {
+      mockQueries=null;
+      return;
+    }
+    mockQueries=new HashMap<String,String>();
+    for (String[] mock:mocks)
+    {
+      mockQueries.put(mock[0],mock[1]);
+    }
+  }
+
+  protected boolean isMocked()
+  {
+    return mockQueries!=null;
+  }
+
+  @Override
+  public String[] getPreferencesColumnsFor(PreferenceSource source)
+  {
+    String[] columnNames = null;
+    switch (source)
+    {
+    case SEARCH_SUMMARY:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    default:
+      // non structure sources don't return any other kind of preferences columns
+      break;
+    }
+    return columnNames;
+  }
 }
index 2d9eeb6..bf88d2d 100644 (file)
@@ -188,4 +188,23 @@ public class FTSRestRequest
   {
     this.offSet = offSet;
   }
+
+  /**
+   * locate column given field name
+   * @param string - field name
+   * @return -1 if not located
+   */
+  public int getFieldIndex(String string)
+  {
+    int i=associatedSequence!=null ? 1 : 0;
+    for (FTSDataColumnI field:wantedFields)
+    {
+      if (field.getName().equals(string))
+      {
+        return i; 
+      }
+      i++;
+    }
+    return -1;
+  }
 }
index 597bb89..ae50233 100644 (file)
@@ -41,7 +41,7 @@ import javax.swing.table.DefaultTableModel;
 public class FTSRestResponse
 {
   private int numberOfItemsFound;
-
+  
   private String responseTime;
 
   private Collection<FTSData> searchSummary;
index 0dccc0c..da43bea 100644 (file)
@@ -377,14 +377,15 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     btn_autosearch.setText(MessageManager.getString("option.autosearch"));
     btn_autosearch.setToolTipText(
             MessageManager.getString("option.enable_disable_autosearch"));
+    // disable autosearch by default
     btn_autosearch.setSelected(!Platform.isJS()
-            && Cache.getDefault(getAutosearchPreference(), true));
+            && Cache.getDefault(getAutosearchPreference(), false));
     btn_autosearch.addActionListener(new java.awt.event.ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        jalview.bin.Cache.setProperty(getAutosearchPreference(),
+        Cache.setProperty(getAutosearchPreference(),
                 Boolean.toString(btn_autosearch.isSelected()));
       }
     });
index 6b855fc..5ee7aaa 100644 (file)
@@ -8,6 +8,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import jalview.bin.Console;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceI;
@@ -56,7 +57,7 @@ public class AlphafoldRestClient
         }
       } catch (Exception mfe)
       {
-        jalview.bin.Cache.log.debug("Exception accessing urls", mfe);
+        Console.debug("Exception accessing urls", mfe);
         continue;
       }
       int colCounter = 0;
index 963778c..796bc0e 100644 (file)
  */
 package jalview.fts.service.pdb;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
 import java.net.URI;
+import java.nio.CharBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -41,6 +45,9 @@ import jalview.datamodel.SequenceI;
 import jalview.fts.api.FTSData;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.api.StructureFTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
 import jalview.fts.core.FTSRestClient;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
@@ -55,6 +62,7 @@ import jalview.util.Platform;
  * @author tcnofoegbu
  */
 public class PDBFTSRestClient extends FTSRestClient
+        implements StructureFTSRestClientI
 {
 
   private static FTSRestClientI instance = null;
@@ -122,8 +130,9 @@ public class PDBFTSRestClient extends FTSRestClient
 
       // Build request parameters for the REST Request
 
-      // BH 2018 the trick here is to coerce the classes in Javascript to be 
-      // different from the ones in Java yet still allow this to be correct for Java
+      // BH 2018 the trick here is to coerce the classes in Javascript to be
+      // different from the ones in Java yet still allow this to be correct for
+      // Java
       Client client;
       Class<ClientResponse> clientResponseClass;
       if (Platform.isJS())
@@ -166,35 +175,61 @@ public class PDBFTSRestClient extends FTSRestClient
 
       URI uri = webResource.getURI();
 
-      // System.out.println(uri);
-
-      // Execute the REST request
-      ClientResponse clientResponse = webResource
-              .accept(MediaType.APPLICATION_JSON).get(clientResponseClass );
-
+      System.out.println(uri);
+      ClientResponse clientResponse = null;
+      int responseStatus = -1;
       // Get the JSON string from the response object or directly from the
       // client (JavaScript)
       Map<String, Object> jsonObj = null;
       String responseString = null;
 
-      // System.out.println("query >>>>>>> " + pdbRestRequest.toString());
+      System.out.println("query >>>>>>> " + pdbRestRequest.toString());
+
+      if (!isMocked())
+      {
+        // Execute the REST request
+        clientResponse = webResource.accept(MediaType.APPLICATION_JSON)
+                .get(clientResponseClass);
+        responseStatus = clientResponse.getStatus();
+      }
+      else
+      {
+        // mock response
+        if (mockQueries.containsKey(uri.toString()))
+        {
+          responseStatus = 200;
+        }
+        else
+        {
+          // FIXME - may cause unexpected exceptions for callers when mocked
+          responseStatus = 400;
+        }
+      }
 
       // Check the response status and report exception if one occurs
-      int responseStatus = clientResponse.getStatus();
       switch (responseStatus)
       {
       case 200:
-        if (Platform.isJS())
+
+        if (isMocked())
         {
-          jsonObj = clientResponse.getEntity(Map.class);
+          responseString = mockQueries.get(uri.toString());
         }
         else
         {
-          responseString = clientResponse.getEntity(String.class);
+          if (Platform.isJS())
+          {
+            jsonObj = clientResponse.getEntity(Map.class);
+          }
+          else
+          {
+            responseString = clientResponse.getEntity(String.class);
+          }
         }
         break;
       case 400:
-        throw new Exception(parseJsonExceptionString(responseString));
+        throw new Exception(isMocked() ? "400 response (Mocked)"
+                : parseJsonExceptionString(responseString));
       default:
         throw new Exception(
                 getMessageByHTTPStatusCode(responseStatus, "PDB"));
@@ -204,6 +239,10 @@ public class PDBFTSRestClient extends FTSRestClient
       return parsePDBJsonResponse(responseString, jsonObj, pdbRestRequest);
     } catch (Exception e)
     {
+      if (e.getMessage() == null)
+      {
+        throw (e);
+      }
       String exceptionMsg = e.getMessage();
       if (exceptionMsg.contains("SocketException"))
       {
@@ -232,39 +271,42 @@ public class PDBFTSRestClient extends FTSRestClient
    * @return the processed error message from the JSON string
    */
   @SuppressWarnings("unchecked")
-public static String parseJsonExceptionString(String jsonErrorResponse)
+  public static String parseJsonExceptionString(String jsonErrorResponse)
   {
     StringBuilder errorMessage = new StringBuilder(
             "\n============= PDB Rest Client RunTime error =============\n");
 
-    
-//    {
-//      "responseHeader":{
-//        "status":0,
-//        "QTime":0,
-//        "params":{
-//          "q":"(text:q93xj9_soltu) AND molecule_sequence:['' TO *] AND status:REL",
-//          "fl":"pdb_id,title,experimental_method,resolution",
-//          "start":"0",
-//          "sort":"overall_quality desc",
-//          "rows":"500",
-//          "wt":"json"}},
-//      "response":{"numFound":1,"start":0,"docs":[
-//          {
-//            "experimental_method":["X-ray diffraction"],
-//            "pdb_id":"4zhp",
-//            "resolution":2.46,
-//            "title":"The crystal structure of Potato ferredoxin I with 2Fe-2S cluster"}]
-//      }}
-//    
+    // {
+    // "responseHeader":{
+    // "status":0,
+    // "QTime":0,
+    // "params":{
+    // "q":"(text:q93xj9_soltu) AND molecule_sequence:['' TO *] AND status:REL",
+    // "fl":"pdb_id,title,experimental_method,resolution",
+    // "start":"0",
+    // "sort":"overall_quality desc",
+    // "rows":"500",
+    // "wt":"json"}},
+    // "response":{"numFound":1,"start":0,"docs":[
+    // {
+    // "experimental_method":["X-ray diffraction"],
+    // "pdb_id":"4zhp",
+    // "resolution":2.46,
+    // "title":"The crystal structure of Potato ferredoxin I with 2Fe-2S
+    // cluster"}]
+    // }}
+    //
     try
     {
-      Map<String, Object> jsonObj = (Map<String, Object>) JSONUtils.parse(jsonErrorResponse);
-      Map<String, Object> errorResponse = (Map<String, Object>) jsonObj.get("error");
+      Map<String, Object> jsonObj = (Map<String, Object>) JSONUtils
+              .parse(jsonErrorResponse);
+      Map<String, Object> errorResponse = (Map<String, Object>) jsonObj
+              .get("error");
 
       Map<String, Object> responseHeader = (Map<String, Object>) jsonObj
               .get("responseHeader");
-      Map<String, Object> paramsObj = (Map<String, Object>) responseHeader.get("params");
+      Map<String, Object> paramsObj = (Map<String, Object>) responseHeader
+              .get("params");
       String status = responseHeader.get("status").toString();
       String message = errorResponse.get("msg").toString();
       String query = paramsObj.get("q").toString();
@@ -312,27 +354,30 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
     {
       if (jsonObj == null)
       {
-        jsonObj = (Map<String, Object>) JSONUtils.parse(pdbJsonResponseString);
+        jsonObj = (Map<String, Object>) JSONUtils
+                .parse(pdbJsonResponseString);
       }
-      Map<String, Object> pdbResponse = (Map<String, Object>) jsonObj.get("response");
-      String queryTime = ((Map<String, Object>) jsonObj.get("responseHeader"))
-              .get("QTime").toString();
+      Map<String, Object> pdbResponse = (Map<String, Object>) jsonObj
+              .get("response");
+      String queryTime = ((Map<String, Object>) jsonObj
+              .get("responseHeader")).get("QTime").toString();
       int numFound = Integer
               .valueOf(pdbResponse.get("numFound").toString());
       List<Object> docs = (List<Object>) pdbResponse.get("docs");
-      // add in any alphafold bits at the top
-      result = AlphafoldRestClient.getFTSData(pdbRestRequest);
+
+      result = new ArrayList<FTSData>();
       if (numFound > 0)
       {
 
-        for (Iterator<Object> docIter = docs.iterator(); docIter
-                .hasNext();)
+        for (Iterator<Object> docIter = docs.iterator(); docIter.hasNext();)
         {
           Map<String, Object> doc = (Map<String, Object>) docIter.next();
           result.add(getFTSData(doc, pdbRestRequest));
         }
       }
-      searchResult.setNumberOfItemsFound(result.size());
+      // this is the total number found by the query,
+      // rather than the set returned in SearchSummary
+      searchResult.setNumberOfItemsFound(numFound);
       searchResult.setResponseTime(queryTime);
       searchResult.setSearchSummary(result);
 
@@ -368,8 +413,10 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
 
     for (FTSDataColumnI field : diplayFields)
     {
+      // System.out.println("Field " + field);
       String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? ""
               : pdbJsonDoc.get(field.getCode()).toString();
+      // System.out.println("Field Data : " + fieldData);
       if (field.isPrimaryKeyColumn())
       {
         primaryKey = fieldData;
@@ -473,6 +520,7 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
 
   private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
 
+  @Override
   public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
   {
     if (allDefaultDisplayedStructureDataColumns == null
@@ -484,6 +532,26 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
     }
     return allDefaultDisplayedStructureDataColumns;
   }
-  
-  
+
+  @Override
+  public String[] getPreferencesColumnsFor(PreferenceSource source)
+  {
+    String[] columnNames = null;
+    switch (source)
+    {
+    case SEARCH_SUMMARY:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case STRUCTURE_CHOOSER:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case PREFERENCES:
+      columnNames = new String[] { "PDB Field", "Show in search summary",
+          "Show in structure summary" };
+      break;
+    default:
+      break;
+    }
+    return columnNames;
+  }
 }
diff --git a/src/jalview/fts/service/threedbeacons/.gitignore b/src/jalview/fts/service/threedbeacons/.gitignore
new file mode 100644 (file)
index 0000000..9a003b7
--- /dev/null
@@ -0,0 +1 @@
+/tdbresttest2.java
diff --git a/src/jalview/fts/service/threedbeacons/TDB_FTSData.java b/src/jalview/fts/service/threedbeacons/TDB_FTSData.java
new file mode 100644 (file)
index 0000000..6745bb8
--- /dev/null
@@ -0,0 +1,120 @@
+package jalview.fts.service.threedbeacons;
+
+import java.util.Map;
+import java.util.Objects;
+
+import jalview.fts.api.FTSData;
+
+/**
+ * TDB result bean - holds filtered fields for GUI and essential metadata fields
+ * for back end
+ * 
+ * @author jprocter
+ *
+ */
+public class TDB_FTSData implements FTSData
+{
+  String primaryKey;
+
+  Object[] summaryRowData;
+
+  /*
+   * fields in the JSON object 
+   */
+  public static String Uniprot_Id= "id";
+  public static String Uniprot_Start= "uniprot_start";
+  public static String Uniprot_End= "uniprot_end";
+  public static String Provider= "provider";
+  public static String Model_id= "model_identifier";
+  public static String Model_Category= "model_category";
+  public static String Model_Type= "model_type";
+  public static String Model_Title="model_title";
+  public static String Resolution= "resolution";
+  public static String Confidence= "confidence_avg_local_score";
+  public static String Confidence_Score_Type= "confidence_type";
+  public static String Confidence_Score_Version= "confidence_version";
+  public static String Coverage= "coverage";
+  public static String Sequence_Identity= "sequence_identity";
+  public static String Created_Date= "created";
+  public static String UniProt_Accession= "uniprot_accession";
+  public static String Url= "model_url";
+  public static String Page_URL= "model_page_url";
+  public static String Ensemble_Sample_Url= "ensembl_sample_url";
+
+  /**
+   * original response from server
+   */
+  Map<String, Object> tdb_entry;
+
+  public TDB_FTSData(String primaryKey,
+          Map<String, Object> tdbJsonStructure, Object[] summaryData)
+  {
+    this.primaryKey = primaryKey;
+    tdb_entry = tdbJsonStructure;
+    this.summaryRowData = summaryData;
+  }
+
+  public Object getField(String key)
+  {
+    return tdb_entry.get(key);
+  }
+
+  @Override
+  public Object[] getSummaryData()
+  {
+    return summaryRowData;
+  }
+
+  @Override
+  public Object getPrimaryKey()
+  {
+    return primaryKey;
+  }
+
+  /**
+   * Returns a string representation of this object;
+   */
+  @Override
+  public String toString()
+  {
+    StringBuilder summaryFieldValues = new StringBuilder();
+    for (Object summaryField : summaryRowData)
+    {
+      summaryFieldValues
+              .append(summaryField == null ? " " : summaryField.toString())
+              .append("\t");
+    }
+    return summaryFieldValues.toString();
+  }
+
+  /**
+   * Returns hash code value for this object
+   */
+  @Override
+  public int hashCode()
+  {
+    return Objects.hash(primaryKey, this.toString());
+  }
+
+  @Override
+  public boolean equals(Object that)
+  {
+    return this.toString().equals(that.toString());
+  }
+
+  public String getProvider()
+  {
+    return (String) getField(Provider);
+  }
+
+  public String getModelViewUrl()
+  {
+    return (String) getField(Page_URL);
+  }
+
+  public String getModelId()
+  {
+    return (String) getField(Model_id);
+  }
+
+}
diff --git a/src/jalview/fts/service/threedbeacons/TDBeaconsFTSPanel.java b/src/jalview/fts/service/threedbeacons/TDBeaconsFTSPanel.java
new file mode 100644 (file)
index 0000000..99f1a71
--- /dev/null
@@ -0,0 +1,280 @@
+package jalview.fts.service.threedbeacons;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.swing.SwingUtilities;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import jalview.bin.Console;
+import jalview.datamodel.AlignmentI;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.core.GFTSPanel;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.gui.SequenceFetcher;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileFormatI;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.util.MessageManager;
+
+@SuppressWarnings("serial")
+public class TDBeaconsFTSPanel extends GFTSPanel
+{
+  private static String defaultFTSFrameTitle = MessageManager
+          .getString("label.pdb_sequence_fetcher");
+
+  private static Map<String, Integer> tempUserPrefs = new HashMap<>();
+
+  private static final String THREEDB_FTS_CACHE_KEY = "CACHE.THREEDB_FTS";
+
+  private static final String THREEDB_AUTOSEARCH = "FTS.THREEDB.AUTOSEARCH";
+
+  private static HttpURLConnection connection;
+
+  public TDBeaconsFTSPanel(SequenceFetcher fetcher)
+  {
+    // no ID retrieval option for TD Beacons just now
+    super(null);
+    pageLimit = TDBeaconsFTSRestClient.getInstance()
+            .getDefaultResponsePageSize();
+    this.seqFetcher = fetcher;
+    this.progressIndicator = (fetcher == null) ? null
+            : fetcher.getProgressIndicator();
+  }
+
+  @Override
+  public void searchAction(boolean isFreshSearch)
+  {
+    mainFrame.requestFocusInWindow();
+    if (isFreshSearch)
+    {
+      offSet = 0;
+    }
+    new Thread()
+    {
+      @Override
+      public void run()
+      {
+        reset();
+        boolean allowEmptySequence = false;
+        if (getTypedText().length() > 0)
+        {
+          setSearchInProgress(true);
+          long startTime = System.currentTimeMillis();
+
+          String searchTarget = ((FTSDataColumnI) cmb_searchTarget
+                  .getSelectedItem()).getCode();
+          wantedFields = TDBeaconsFTSRestClient.getInstance()
+                  .getAllDefaultDisplayedFTSDataColumns();
+          String searchTerm = getTypedText(); // to add : decodeSearchTerm
+
+          FTSRestRequest request = new FTSRestRequest();
+          request.setAllowEmptySeq(allowEmptySequence);
+          request.setResponseSize(100);
+          // expect it to be uniprot accesssion
+          request.setSearchTerm(searchTerm + ".json");
+          request.setOffSet(offSet);
+          request.setWantedFields(wantedFields);
+          FTSRestClientI tdbRestClient = TDBeaconsFTSRestClient
+                  .getInstance();
+          FTSRestResponse resultList;
+          try
+          {
+            resultList = tdbRestClient.executeRequest(request);
+          } catch (Exception e)
+          {
+            setErrorMessage(e.getMessage());
+            checkForErrors();
+            setSearchInProgress(false);
+            return;
+          }
+
+          if (resultList.getSearchSummary() != null
+                  && resultList.getSearchSummary().size() > 0)
+          {
+            getResultTable().setModel(FTSRestResponse.getTableModel(request,
+                    resultList.getSearchSummary()));
+            FTSRestResponse.configureTableColumn(getResultTable(),
+                    wantedFields, tempUserPrefs);
+            getResultTable().setVisible(true);
+          }
+
+          long endTime = System.currentTimeMillis();
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
+          String result = (resultSetCount > 0)
+                  ? MessageManager.getString("label.results")
+                  : MessageManager.getString("label.result");
+
+          if (isPaginationEnabled() && resultSetCount > 0)
+          {
+            String f1 = totalNumberformatter
+                    .format(Integer.valueOf(offSet + 1));
+            String f2 = totalNumberformatter
+                    .format(Integer.valueOf(offSet + resultSetCount));
+            String f3 = totalNumberformatter
+                    .format(Integer.valueOf(totalResultSetCount));
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
+                    + " " + f1 + " to " + f2 + " of " + f3 + " " + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+          else
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - "
+                    + resultSetCount + " " + result + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+
+          setSearchInProgress(false);
+          refreshPaginatorState();
+          updateSummaryTableSelections();
+        }
+        txt_search.updateCache();
+      }
+    }.start();
+  }
+
+  @Override
+  public void okAction()
+  {
+    // mainFrame.dispose();
+    disableActionButtons();
+    StringBuilder selectedIds = new StringBuilder();
+    final HashSet<String> selectedIdsSet = new HashSet<>();
+    int primaryKeyColIndex = 0;
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient()
+              .getPrimaryKeyColumIndex(wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    int[] selectedRows = getResultTable().getSelectedRows();
+    String searchTerm = getTypedText();
+    for (int summaryRow : selectedRows)
+    {
+      String idStr = getResultTable()
+              .getValueAt(summaryRow, primaryKeyColIndex).toString();
+      selectedIdsSet.add(idStr);
+    }
+
+    for (String idStr : paginatorCart)
+    {
+      selectedIdsSet.add(idStr);
+    }
+
+    for (String selectedId : selectedIdsSet)
+    {
+      selectedIds.append(selectedId).append(";");
+    }
+
+    SwingUtilities.invokeLater(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        AlignmentI allSeqs = null;
+        FormatAdapter fl = new jalview.io.FormatAdapter();
+        for (String tdbURL : selectedIdsSet)
+        {
+          try
+          {
+            // retrieve the structure via its URL
+            AlignmentI tdbAl = fl.readFile(tdbURL, DataSourceType.URL,
+                    FileFormat.MMCif);
+
+            // TODO: pad structure according to its Uniprot Start so all line up w.r.t. the Uniprot reference sequence
+            // TODO: give the structure a sensible name (not the giant URL *:o) )
+            if (tdbAl != null)
+            {
+              if (allSeqs != null)
+              {
+                allSeqs.append(tdbAl);
+              }
+              else
+              {
+                allSeqs = tdbAl;
+              }
+            }
+          } catch (Exception x)
+          {
+            Console.warn(
+                    "Couldn't retrieve 3d-beacons model for uniprot id"
+                            + searchTerm + " : " + tdbURL,
+                    x);
+          }
+        }
+        seqFetcher.parseResult(allSeqs,
+                "3D-Beacons models for " + searchTerm, FileFormat.MMCif,
+                null);
+
+      }
+    });
+    delayAndEnableActionButtons();
+  }
+
+  @Override
+  public FTSRestClientI getFTSRestClient()
+  {
+    return TDBeaconsFTSRestClient.getInstance();
+  }
+
+  @Override
+  public String getFTSFrameTitle()
+  {
+    return defaultFTSFrameTitle;
+  }
+
+  @Override
+  public boolean isPaginationEnabled()
+  {
+    return true;
+  }
+
+  @Override
+  public Map<String, Integer> getTempUserPrefs()
+  {
+    return tempUserPrefs;
+  }
+
+  @Override
+  public String getCacheKey()
+  {
+    return THREEDB_FTS_CACHE_KEY;
+  }
+
+  @Override
+  public String getAutosearchPreference()
+  {
+    return THREEDB_AUTOSEARCH;
+  }
+
+  @Override
+  protected void showHelp()
+  {
+    System.out.println("No help implemented yet.");
+
+  }
+
+  public static String decodeSearchTerm(String enteredText)
+  {
+    // no multiple query support yet
+    return enteredText;
+  }
+}
diff --git a/src/jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.java b/src/jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.java
new file mode 100644 (file)
index 0000000..ccdc525
--- /dev/null
@@ -0,0 +1,350 @@
+package jalview.fts.service.threedbeacons;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.ws.rs.core.MediaType;
+
+import org.json.simple.parser.ParseException;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.api.StructureFTSRestClientI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.util.JSONUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
+public class TDBeaconsFTSRestClient extends FTSRestClient
+        implements StructureFTSRestClientI
+{
+  /**
+   * production server URI
+   */
+  private static String TDB_PROD_API="https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
+  /**
+   * dev server URI
+   */
+  private static String TDB_DEV_API="https://wwwdev.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
+  private static String DEFAULT_THREEDBEACONS_DOMAIN = TDB_PROD_API; 
+
+  public static FTSRestClientI instance = null;
+
+  protected TDBeaconsFTSRestClient()
+  {
+  }
+  @SuppressWarnings("unchecked")
+  @Override
+  public FTSRestResponse executeRequest(FTSRestRequest tdbRestRequest)
+          throws Exception
+  {
+    try
+    {
+      String query = tdbRestRequest.getSearchTerm();
+      Client client;
+      Class<ClientResponse> clientResponseClass;
+      if (Platform.isJS())
+      {
+        // JavaScript only
+        client = (Client) (Object) new jalview.javascript.web.Client();
+        clientResponseClass = (Class<ClientResponse>) (Object) jalview.javascript.web.ClientResponse.class;
+      }
+      else
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
+      {
+        client = Client.create(new DefaultClientConfig());
+        clientResponseClass = ClientResponse.class;
+      }
+
+      WebResource webResource;
+      webResource = client.resource(DEFAULT_THREEDBEACONS_DOMAIN+query);
+
+      URI uri = webResource.getURI();
+      System.out.println(uri.toString());
+
+      // Execute the REST request
+      ClientResponse clientResponse;
+      if (isMocked()) { 
+        clientResponse = null;
+      }
+      else
+      {
+        clientResponse = webResource.accept(MediaType.APPLICATION_JSON)
+                .get(clientResponseClass);
+      }
+
+      // Get the JSON string from the response object or directly from the
+      // client (JavaScript)
+      Map<String, Object> jsonObj = null;
+      String responseString = null;
+
+      // Check the response status and report exception if one occurs
+      int responseStatus = isMocked() ? (mockQueries.containsKey(query) ? 200 : 404) : clientResponse.getStatus();
+      switch (responseStatus)
+      {
+      // if success
+      case 200:
+        if (Platform.isJS())
+        {
+          jsonObj = clientResponse.getEntity(Map.class);
+        }
+        else
+        {
+          responseString = isMocked() ? mockQueries.get(query): clientResponse.getEntity(String.class);
+        }
+        break;
+      case 400:
+        throw new Exception(parseJsonExceptionString(responseString));
+      case 404:
+        return emptyTDBeaconsJsonResponse();
+      default:
+        throw new Exception(
+                getMessageByHTTPStatusCode(responseStatus, "3DBeacons"));
+      }
+      // Process the response and return the result to the caller.
+      return parseTDBeaconsJsonResponse(responseString, jsonObj,
+              tdbRestRequest);
+    } catch (Exception e)
+    {
+      String exceptionMsg = e.getMessage();
+      if (exceptionMsg != null)
+      {
+        if (exceptionMsg.contains("SocketException"))
+        {
+          // No internet connection
+          throw new Exception(MessageManager.getString(
+                  "exception.unable_to_detect_internet_connection"));
+        }
+        else if (exceptionMsg.contains("UnknownHostException"))
+        {
+          // The server is unreachable
+          throw new Exception(MessageManager.formatMessage(
+                  "exception.fts_server_unreachable", "3DB Hub"));
+        }
+      }
+      throw e;
+      
+    }
+
+  }
+
+  /**
+   * returns response for when the 3D-Beacons service doesn't have a record for
+   * the given query - in 2.11.2 this triggers a failover to the PDBe FTS 
+   * 
+   * @return null
+   */
+  private FTSRestResponse emptyTDBeaconsJsonResponse()
+  {
+    return null;
+  }
+
+  public String setSearchTerm(String term)
+  {
+    return term;
+  }
+
+  public static FTSRestResponse parseTDBeaconsJsonResponse(
+          String tdbJsonResponseString, FTSRestRequest tdbRestRequest)
+  {
+    return parseTDBeaconsJsonResponse(tdbJsonResponseString,
+            (Map<String, Object>) null, tdbRestRequest);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static FTSRestResponse parseTDBeaconsJsonResponse(
+          String tdbJsonResponseString, Map<String, Object> jsonObj,
+          FTSRestRequest tdbRestRequest)
+  {
+    FTSRestResponse searchResult = new FTSRestResponse();
+    List<FTSData> result = null;
+
+    try
+    {
+      if (jsonObj == null)
+      {
+        jsonObj = (Map<String, Object>) JSONUtils
+                .parse(tdbJsonResponseString);
+      }
+
+      Object uniprot_entry = jsonObj.get("uniprot_entry");
+      // TODO: decide if anything from uniprot_entry needs to be reported via
+      // the FTSRestResponse object
+      // Arnaud added seqLength = (Long) ((Map<String, Object>)
+      // jsonObj.get("uniprot_entry")).get("sequence_length");
+
+      List<Object> structures = (List<Object>) jsonObj.get("structures");
+      result = new ArrayList<>();
+
+      int numFound = 0;
+      for (Iterator<Object> strucIter = structures.iterator(); strucIter
+              .hasNext();)
+      {
+        Map<String, Object> structure = (Map<String, Object>) strucIter
+                .next();
+        result.add(getFTSData(structure, tdbRestRequest));
+        numFound++;
+      }
+
+      searchResult.setNumberOfItemsFound(numFound);
+      searchResult.setSearchSummary(result);
+
+    } catch (ParseException e)
+    {
+      e.printStackTrace();
+    }
+    return searchResult;
+  }
+
+  private static FTSData getFTSData(Map<String, Object> tdbJsonStructure,
+          FTSRestRequest tdbRequest)
+  {
+    String primaryKey = null;
+    Object[] summaryRowData;
+
+    SequenceI associatedSequence;
+
+    Collection<FTSDataColumnI> displayFields = tdbRequest.getWantedFields();
+    SequenceI associatedSeq = tdbRequest.getAssociatedSequence();
+    int colCounter = 0;
+    summaryRowData = new Object[(associatedSeq != null)
+                                ? displayFields.size() + 1
+                                : displayFields.size()];
+                        if (associatedSeq != null)
+                        {
+                          associatedSequence = associatedSeq;
+                          summaryRowData[0] = associatedSequence;
+                          colCounter = 1;
+                        }
+
+    for (FTSDataColumnI field : displayFields)
+    {
+      String fieldData = (tdbJsonStructure.get(field.getCode()) == null)
+              ? " "
+              : tdbJsonStructure.get(field.getCode()).toString();
+      // System.out.println("Field : " + field + " Data : " + fieldData);
+      if (field.isPrimaryKeyColumn())
+      {
+        primaryKey = fieldData;
+        summaryRowData[colCounter++] = primaryKey;
+      }
+      else if (fieldData == null || fieldData.trim().isEmpty())
+      {
+        summaryRowData[colCounter++] = null;
+      }
+      else
+      {
+        try
+        {
+          summaryRowData[colCounter++] = (field.getDataType()
+                  .getDataTypeClass() == Integer.class)
+                          ? Integer.valueOf(fieldData)
+                          : (field.getDataType()
+                                  .getDataTypeClass() == Double.class)
+                                          ? Double.valueOf(fieldData)
+                                          : fieldData;
+        } catch (Exception e)
+        {
+          // e.printStackTrace();
+          System.out.println("offending value:" + fieldData + fieldData);
+        }
+      }
+    }
+    final String primaryKey1 = primaryKey;
+    final Object[] summaryRowData1 = summaryRowData;
+
+    return new TDB_FTSData(primaryKey, tdbJsonStructure, summaryRowData1);
+  }
+
+  // private static FTSData getFTSData(Map<String, Object> doc,
+  // FTSRestRequest tdbRestRequest)
+  // {
+  // String primaryKey = null;
+  //
+  // Object[] summaryRowData;
+  //
+  // Collection<FTSDataColumnI> displayFields =
+  // tdbRestRequest.getWantedFields();
+  // int colCounter = 0;
+  // summaryRowData = new Object[displayFields.size() + 1];
+  //
+  // return null;
+  // }
+
+  private String parseJsonExceptionString(String jsonErrorString)
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String getColumnDataConfigFileName()
+  {
+    return "/fts/tdbeacons_data_columns.txt";
+  }
+
+  public static FTSRestClientI getInstance()
+  {
+    if (instance == null)
+    {
+      instance = new TDBeaconsFTSRestClient();
+    }
+    return instance;
+  }
+
+  private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
+
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
+  {
+    if (allDefaultDisplayedStructureDataColumns == null
+            || allDefaultDisplayedStructureDataColumns.isEmpty())
+    {
+      allDefaultDisplayedStructureDataColumns = new ArrayList<>();
+      allDefaultDisplayedStructureDataColumns
+              .addAll(super.getAllDefaultDisplayedFTSDataColumns());
+    }
+    return allDefaultDisplayedStructureDataColumns;
+  }
+
+  @Override
+  public String[] getPreferencesColumnsFor(PreferenceSource source)
+  {
+    String[] columnNames = null;
+    switch (source)
+    {
+    case SEARCH_SUMMARY:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case STRUCTURE_CHOOSER:
+      columnNames = new String[] { "", "Display", "Group" };
+      break;
+    case PREFERENCES:
+      columnNames = new String[] { "3DB Beacons Field", "Show in search summary",
+          "Show in structure summary" };
+      break;
+    default:
+      break;
+    }
+    return columnNames;
+  }
+}
index fb9b707..4d3a3f3 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.bin.Cache;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
@@ -105,7 +106,7 @@ public class APQHandlers
                 public void handleQuitRequestWith(
                         QuitEvent e, QuitResponse r)
                 {
-                  boolean confirmQuit = jalview.bin.Cache
+                  boolean confirmQuit = Cache
                           .getDefault(
                                   jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT,
                                   true);
index 5370437..07baa2e 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -91,6 +93,7 @@ import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
@@ -366,7 +369,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // modifyPID.setEnabled(false);
     }
 
-    String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",
+    String sortby = Cache.getDefault("SORT_ALIGNMENT",
             "No sort");
 
     if (sortby.equals("Id"))
@@ -409,7 +412,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       wrapMenuItem_actionPerformed(null);
     }
 
-    if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))
+    if (Cache.getDefault("SHOW_OVERVIEW", false))
     {
       this.overviewMenuItem_actionPerformed(null);
     }
@@ -484,9 +487,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
               }
             });
-    if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase()
+    if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase(Locale.ROOT)
             .indexOf("devel") > -1
-            || Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase()
+            || Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase(Locale.ROOT)
                     .indexOf("test") > -1)
     {
       formatMenu.add(vsel);
@@ -565,7 +568,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().moveCursor(0, 1);
+            alignPanel.getSeqPanel().moveCursor(0, 1, evt.isShiftDown());
           }
           break;
 
@@ -576,7 +579,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().moveCursor(0, -1);
+            alignPanel.getSeqPanel().moveCursor(0, -1,evt.isShiftDown());
           }
 
           break;
@@ -589,7 +592,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().moveCursor(-1, 0);
+            alignPanel.getSeqPanel().moveCursor(-1, 0, evt.isShiftDown());
           }
 
           break;
@@ -601,7 +604,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().moveCursor(1, 0);
+            alignPanel.getSeqPanel().moveCursor(1, 0, evt.isShiftDown());
           }
           break;
 
@@ -1012,7 +1015,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public String getVersion()
   {
-    return jalview.bin.Cache.getProperty("VERSION");
+    return Cache.getProperty("VERSION");
   }
 
   public FeatureRenderer getFeatureRenderer()
@@ -1214,7 +1217,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       }
       else
       {
-        Cache.log.error(MessageManager
+        Console.error(MessageManager
                 .formatMessage("label.couldnt_save_file", new Object[]
                 { lastFilenameSaved }));
       }
@@ -1297,7 +1300,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           BackupFiles backupfiles = null;
           if (doBackup)
           {
-            Cache.log.trace(
+            Console.trace(
                     "ALIGNFRAME making backupfiles object for " + file);
             backupfiles = new BackupFiles(file);
           }
@@ -1305,19 +1308,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           {
             String tempFilePath = doBackup ? backupfiles.getTempFilePath()
                     : file;
-            Cache.log.trace("ALIGNFRAME setting PrintWriter");
+            Console.trace("ALIGNFRAME setting PrintWriter");
             PrintWriter out = new PrintWriter(new FileWriter(tempFilePath));
 
             if (backupfiles != null)
             {
-              Cache.log.trace("ALIGNFRAME about to write to temp file "
+              Console.trace("ALIGNFRAME about to write to temp file "
                       + backupfiles.getTempFilePath());
             }
 
             out.print(output);
-            Cache.log.trace("ALIGNFRAME about to close file");
+            Console.trace("ALIGNFRAME about to close file");
             out.close();
-            Cache.log.trace("ALIGNFRAME closed file");
+            Console.trace("ALIGNFRAME closed file");
             AlignFrame.this.setTitle(file);
             statusBar.setText(MessageManager.formatMessage(
                     "label.successfully_saved_to_file_in_format",
@@ -1327,29 +1330,29 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           } catch (IOException e)
           {
             lastSaveSuccessful = false;
-            Cache.log.error(
+            Console.error(
                     "ALIGNFRAME Something happened writing the temp file");
-            Cache.log.error(e.getMessage());
-            Cache.log.debug(Cache.getStackTraceString(e));
+            Console.error(e.getMessage());
+            Console.debug(Cache.getStackTraceString(e));
           } catch (Exception ex)
           {
             lastSaveSuccessful = false;
-            Cache.log.error(
+            Console.error(
                     "ALIGNFRAME Something unexpected happened writing the temp file");
-            Cache.log.error(ex.getMessage());
-            Cache.log.debug(Cache.getStackTraceString(ex));
+            Console.error(ex.getMessage());
+            Console.debug(Cache.getStackTraceString(ex));
           }
 
           if (doBackup)
           {
             backupfiles.setWriteSuccess(lastSaveSuccessful);
-            Cache.log.debug("ALIGNFRAME writing temp file was "
+            Console.debug("ALIGNFRAME writing temp file was "
                     + (lastSaveSuccessful ? "" : "NOT ") + "successful");
             // do the backup file roll and rename the temp file to actual file
-            Cache.log.trace(
+            Console.trace(
                     "ALIGNFRAME about to rollBackupsAndRenameTempFile");
             lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile();
-            Cache.log.debug(
+            Console.debug(
                     "ALIGNFRAME performed rollBackupsAndRenameTempFile "
                             + (lastSaveSuccessful ? "" : "un")
                             + "successfully");
@@ -1532,7 +1535,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void associatedData_actionPerformed(ActionEvent e)
   {
     final JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
     String tooltip = MessageManager
             .getString("label.load_jalview_annotations");
@@ -1544,7 +1547,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       public void run()
       {
         String choice = chooser.getSelectedFile().getPath();
-        jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
+        Cache.setProperty("LAST_DIRECTORY", choice);
         loadJalviewDataFile(chooser.getSelectedFile(), null, null, null);
       }
     });
@@ -1731,7 +1734,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       if (originalSource != viewport)
       {
-        Cache.log.warn(
+        Console.warn(
                 "Implementation worry: mismatch of viewport origin for undo");
       }
       originalSource.updateHiddenColumns();
@@ -1771,7 +1774,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       if (originalSource != viewport)
       {
-        Cache.log.warn(
+        Console.warn(
                 "Implementation worry: mismatch of viewport origin for redo");
       }
       originalSource.updateHiddenColumns();
@@ -2825,7 +2828,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void findMenuItem_actionPerformed(ActionEvent e)
   {
-    new Finder(alignPanel);
+    new Finder(alignPanel, false, null);
   }
 
   /**
@@ -4067,7 +4070,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     // Pick the tree file
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.select_newick_like_tree_file"));
@@ -4297,7 +4300,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       jws2servs.attachWSMenuEntry(webService, me);
                       for (Jws2Instance sv : jws2servs.getServices())
                       {
-                        if (sv.description.toLowerCase().contains("jpred"))
+                        if (sv.description.toLowerCase(Locale.ROOT).contains("jpred"))
                         {
                           for (JMenuItem jmi : legacyItems)
                           {
@@ -4331,7 +4334,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
               } catch (Exception e)
               {
-                Cache.log.debug(
+                Console.debug(
                         "Exception during web service menu building process.",
                         e);
               }
@@ -4428,7 +4431,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showProducts.setEnabled(showp);
     } catch (Exception e)
     {
-      Cache.log.warn(
+      Console.warn(
               "canShowProducts threw an exception - please report to help@jalview.org",
               e);
       return false;
@@ -4469,7 +4472,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       al = dna.translateCdna(codeTable);
     } catch (Exception ex)
     {
-      jalview.bin.Cache.log.error(
+      Console.error(
               "Exception during translation. Please report this !", ex);
       final String msg = MessageManager.getString(
               "label.error_when_translating_sequences_submit_bug_report");
@@ -4832,7 +4835,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
         } catch (Exception x)
         {
-          Cache.log.debug(
+          Console.debug(
                   "Exception when processing data source as T-COFFEE score file",
                   x);
           tcf = null;
index 0125f0d..092d7e7 100644 (file)
@@ -29,6 +29,7 @@ import jalview.api.FeatureSettingsModelI;
 import jalview.api.FeaturesDisplayedI;
 import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
@@ -123,14 +124,14 @@ public class AlignViewport extends AlignmentViewport
     sequenceSetID = seqsetid;
     viewId = viewid;
     // TODO remove these once 2.4.VAMSAS release finished
-    if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null)
+    if (seqsetid != null)
     {
-      Cache.log.debug(
+      Console.debug(
               "Setting viewport's sequence set id : " + sequenceSetID);
     }
-    if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null)
+    if (viewId != null)
     {
-      Cache.log.debug("Setting viewport's view id : " + viewId);
+      Console.debug("Setting viewport's view id : " + viewId);
     }
     init();
 
@@ -185,14 +186,14 @@ public class AlignViewport extends AlignmentViewport
     sequenceSetID = seqsetid;
     viewId = viewid;
     // TODO remove these once 2.4.VAMSAS release finished
-    if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null)
+    if (seqsetid != null)
     {
-      Cache.log.debug(
+      Console.debug(
               "Setting viewport's sequence set id : " + sequenceSetID);
     }
-    if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null)
+    if (viewId != null)
     {
-      Cache.log.debug("Setting viewport's view id : " + viewId);
+      Console.debug("Setting viewport's view id : " + viewId);
     }
 
     if (hiddenColumns != null)
@@ -594,7 +595,7 @@ public class AlignViewport extends AlignmentViewport
     // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass())
     if (needsUpdate)
     {
-      Cache.log.debug("trigger update for " + calcId);
+      Console.debug("trigger update for " + calcId);
     }
   }
 
@@ -824,7 +825,7 @@ public class AlignViewport extends AlignmentViewport
     try
     {
       newAlignFrame.setMaximum(
-              jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));
+              Cache.getDefault("SHOW_FULLSCREEN", false));
     } catch (java.beans.PropertyVetoException ex)
     {
     }
@@ -1022,8 +1023,8 @@ public class AlignViewport extends AlignmentViewport
     
     FeatureRenderer fr = getAlignPanel().getSeqPanel().seqCanvas
             .getFeatureRenderer();
-    List<String> origRenderOrder = new ArrayList(),
-            origGroups = new ArrayList();
+    List<String> origRenderOrder = new ArrayList<>();
+    List<String> origGroups = new ArrayList<>();
     // preserve original render order - allows differentiation between user configured colours and autogenerated ones
     origRenderOrder.addAll(fr.getRenderOrder());
     origGroups.addAll(fr.getFeatureGroups());
@@ -1034,7 +1035,7 @@ public class AlignViewport extends AlignmentViewport
     if (!mergeOnly)
     {
       // only clear displayed features if we are mergeing
-      displayed.clear();
+      // displayed.clear();
     }
     // TODO this clears displayed.featuresRegistered - do we care?
     //
@@ -1066,6 +1067,10 @@ public class AlignViewport extends AlignmentViewport
         {
           displayed.setVisible(type);
         }
+        else if (featureSettings.isFeatureHidden(type))
+        {
+          displayed.setHidden(type);
+        }
       }
     }
 
@@ -1094,6 +1099,8 @@ public class AlignViewport extends AlignmentViewport
       fr.orderFeatures(featureSettings);
     }
     fr.setTransparency(featureSettings.getTransparency());
+
+    fr.notifyFeaturesChanged();
   }
 
   public String getViewName()
index 45e4b95..5366913 100644 (file)
@@ -24,6 +24,7 @@ import jalview.analysis.AnnotationSorter;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenColumns;
@@ -806,7 +807,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           // could not be validated and it is not clear if it is now being
           // called. Log warning here in case it is called and unforeseen
           // problems occur
-          Cache.log.warn(
+          Console.warn(
                   "Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences");
 
           // scroll to start of panel
@@ -1464,9 +1465,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
     else
     {
-      if (Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        Cache.log.warn("Closing alignment panel which is already closed.");
+        Console.warn("Closing alignment panel which is already closed.");
       }
     }
   }
@@ -1541,13 +1542,16 @@ public class AlignmentPanel extends GAlignmentPanel implements
     } catch (Exception ex)
     {
     }
-
     if (b)
     {
-      alignFrame.setDisplayedView(this);
+      setAlignFrameView();
     }
   }
-
+  public void setAlignFrameView()
+  {
+    alignFrame.setDisplayedView(this);
+  }
+  
   @Override
   public StructureSelectionManager getStructureSelectionManager()
   {
index d84287f..568ca47 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import jalview.api.FeatureRenderer;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
@@ -337,7 +339,7 @@ public class AnnotationExporter extends JPanel
 
     boolean nucleotide = ap.av.isNucleotide();
     String complement = nucleotide
-            ? MessageManager.getString("label.protein").toLowerCase()
+            ? MessageManager.getString("label.protein").toLowerCase(Locale.ROOT)
             : "CDS";
     JLabel label = new JLabel(
             MessageManager.formatMessage("label.include_linked_features",
index 5a681f1..21c45e9 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import jalview.analysis.AlignSeq;
 import jalview.analysis.AlignmentUtils;
 import jalview.datamodel.Alignment;
@@ -754,12 +756,12 @@ public class AnnotationLabels extends JPanel
       // jalview.gui.SeqPanel.mouseMoved(..) that formats sequence feature
       // tooltips
       String desc = aa.getDescription(true).trim();
-      if (!desc.toLowerCase().startsWith(HTML_START_TAG))
+      if (!desc.toLowerCase(Locale.ROOT).startsWith(HTML_START_TAG))
       {
         tooltip.append(HTML_START_TAG);
         desc = desc.replace("<", "&lt;");
       }
-      else if (desc.toLowerCase().endsWith(HTML_END_TAG))
+      else if (desc.toLowerCase(Locale.ROOT).endsWith(HTML_END_TAG))
       {
         desc = desc.substring(0, desc.length() - HTML_END_TAG.length());
       }
index d085117..16d0dd7 100644 (file)
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -37,12 +38,12 @@ import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
 import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentI;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.StructureViewerModel;
 import jalview.datamodel.StructureViewerModel.StructureData;
+import jalview.fts.service.alphafold.AlphafoldRestClient;
 import jalview.gui.ImageExporter.ImageWriterI;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.structure.StructureCommand;
@@ -51,8 +52,6 @@ import jalview.util.BrowserLauncher;
 import jalview.util.ImageMaker;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
-import jalview.ws.dbsources.EBIAlfaFold;
-import jalview.ws.dbsources.Pdb;
 
 public class AppJmol extends StructureViewerBase
 {
@@ -272,7 +271,7 @@ public class AppJmol extends StructureViewerBase
     _started = true;
     try
     {
-      List<String> files = fetchPdbFiles();
+      List<String> files = jmb.fetchPdbFiles(this);
       if (files.size() > 0)
       {
         showFilesInViewer(files);
@@ -310,10 +309,10 @@ public class AppJmol extends StructureViewerBase
       } catch (OutOfMemoryError oomerror)
       {
         new OOMWarning("When trying to open the Jmol viewer!", oomerror);
-        Cache.log.debug("File locations are " + filesString);
+        Console.debug("File locations are " + filesString);
       } catch (Exception ex)
       {
-        Cache.log.error("Couldn't open Jmol viewer!", ex);
+        Console.error("Couldn't open Jmol viewer!", ex);
         ex.printStackTrace();
         return;
       }
@@ -334,11 +333,11 @@ public class AppJmol extends StructureViewerBase
       {
         new OOMWarning("When trying to add structures to the Jmol viewer!",
                 oomerror);
-        Cache.log.debug("File locations are " + filesString);
+        Console.debug("File locations are " + filesString);
         return;
       } catch (Exception ex)
       {
-        Cache.log.error("Couldn't add files to Jmol viewer!", ex);
+        Console.error("Couldn't add files to Jmol viewer!", ex);
         ex.printStackTrace();
         return;
       }
@@ -354,7 +353,7 @@ public class AppJmol extends StructureViewerBase
     {
       try
       {
-        Cache.log.debug("Waiting around for jmb notify.");
+        Console.debug("Waiting around for jmb notify.");
         waitTotal += waitFor;
 
         // Thread.sleep() throws an exception in JS
@@ -418,117 +417,6 @@ public class AppJmol extends StructureViewerBase
   }
 
   /**
-   * Retrieves and saves as file any modelled PDB entries for which we do not
-   * already have a file saved. Returns a list of absolute paths to structure
-   * files which were either retrieved, or already stored but not modelled in
-   * the structure viewer (i.e. files to add to the viewer display).
-   * 
-   * @return
-   */
-  List<String> fetchPdbFiles()
-  {
-    // todo - record which pdbids were successfully imported.
-    StringBuilder errormsgs = new StringBuilder();
-
-    List<String> files = new ArrayList<>();
-    String pdbid = "";
-    try
-    {
-      String[] filesInViewer = jmb.getStructureFiles();
-      // TODO: replace with reference fetching/transfer code (validate PDBentry
-      // as a DBRef?)
-      Pdb pdbclient = new Pdb();
-      EBIAlfaFold afclient = new EBIAlfaFold();
-      
-      for (int pi = 0; pi < jmb.getPdbCount(); pi++)
-      {
-        String file = jmb.getPdbEntry(pi).getFile();
-        if (file == null)
-        {
-          // todo: extract block as method and pull up (also ChimeraViewFrame)
-          // retrieve the pdb and store it locally
-          AlignmentI pdbseq = null;
-          pdbid = jmb.getPdbEntry(pi).getId();
-          long hdl = pdbid.hashCode() - System.currentTimeMillis();
-          setProgressMessage(MessageManager
-                  .formatMessage("status.fetching_pdb", new String[]
-                  { pdbid }), hdl);
-          try
-          {
-            if (afclient.isValidReference(pdbid))
-            {
-              pdbseq = afclient.getSequenceRecords(pdbid);
-            } else {
-              pdbseq = pdbclient.getSequenceRecords(pdbid);
-            }
-          } catch (OutOfMemoryError oomerror)
-          {
-            new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
-          } catch (Exception ex)
-          {
-            ex.printStackTrace();
-            errormsgs.append("'").append(pdbid).append("'");
-          } finally
-          {
-            setProgressMessage(
-                    MessageManager.getString("label.state_completed"), hdl);
-          }
-          if (pdbseq != null)
-          {
-            // just transfer the file name from the first sequence's first
-            // PDBEntry
-            file = new File(pdbseq.getSequenceAt(0).getAllPDBEntries()
-                    .elementAt(0).getFile()).getAbsolutePath();
-            jmb.getPdbEntry(pi).setFile(file);
-            files.add(file);
-          }
-          else
-          {
-            errormsgs.append("'").append(pdbid).append("' ");
-          }
-        }
-        else
-        {
-          if (filesInViewer != null && filesInViewer.length > 0)
-          {
-            addingStructures = true; // already files loaded.
-            for (int c = 0; c < filesInViewer.length; c++)
-            {
-              if (Platform.pathEquals(filesInViewer[c], file))
-              {
-                file = null;
-                break;
-              }
-            }
-          }
-          if (file != null)
-          {
-            files.add(file);
-          }
-        }
-      }
-    } catch (OutOfMemoryError oomerror)
-    {
-      new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
-    } catch (Exception ex)
-    {
-      ex.printStackTrace();
-      errormsgs.append("When retrieving pdbfiles : current was: '")
-              .append(pdbid).append("'");
-    }
-    if (errormsgs.length() > 0)
-    {
-      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
-              MessageManager.formatMessage(
-                      "label.pdb_entries_couldnt_be_retrieved", new String[]
-                      { errormsgs.toString() }),
-              MessageManager.getString("label.couldnt_load_file"),
-              JvOptionPane.ERROR_MESSAGE);
-    }
-    return files;
-  }
-
-  /**
    * Outputs the Jmol viewer image as an image file, after prompting the user to
    * choose a file and (for EPS) choice of Text or Lineart character rendering
    * (unless a preference for this is set)
@@ -548,7 +436,7 @@ public class AppJmol extends StructureViewerBase
         jmb.jmolViewer.renderScreenImage(g, width, height);
       }
     };
-    String view = MessageManager.getString("action.view").toLowerCase();
+    String view = MessageManager.getString("action.view").toLowerCase(Locale.ROOT);
     ImageExporter exporter = new ImageExporter(writer,
             getProgressIndicator(), type, getTitle());
     exporter.doExport(null, this, width, height, view);
index 98787cb..34d930d 100644 (file)
@@ -22,6 +22,7 @@ package jalview.gui;
 
 import java.awt.Container;
 import java.io.File;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -32,13 +33,18 @@ import org.openscience.jmol.app.jmolpanel.console.AppConsole;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.api.structures.JalviewStructureDisplayI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JalviewJmolBinding;
 import jalview.io.DataSourceType;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.ws.dbsources.EBIAlfaFold;
+import jalview.ws.dbsources.Pdb;
+import jalview.ws.utils.UrlDownloadClient;
 import javajs.util.BS;
 
 public class AppJmolBinding extends JalviewJmolBinding
@@ -85,7 +91,7 @@ public class AppJmolBinding extends JalviewJmolBinding
       jalview.util.BrowserLauncher.openURL(url);
     } catch (Exception e)
     {
-      Cache.log.error("Failed to launch Jmol-associated url " + url, e);
+      Console.error("Failed to launch Jmol-associated url " + url, e);
       // TODO: 2.6 : warn user if browser was not configured.
     }
   }
@@ -189,4 +195,101 @@ public class AppJmolBinding extends JalviewJmolBinding
       Platform.cacheFileData(f);
     }
   }
+
+  /**
+   * Retrieves and saves as file any modelled PDB entries for which we do not
+   * already have a file saved. Returns a list of absolute paths to structure
+   * files which were either retrieved, or already stored but not modelled in
+   * the structure viewer (i.e. files to add to the viewer display).
+   * 
+   * Currently only used by Jmol - similar but different code used for Chimera/X
+   * and Pymol so still need to refactor
+   * 
+   * @param structureViewer
+   *          UI proxy for the structure viewer
+   * @return list of absolute paths to structures retrieved that need to be
+   *         added to the display
+   */
+  public List<String> fetchPdbFiles(StructureViewerBase structureViewer)
+  {
+    // todo - record which pdbids were successfully imported.
+    StringBuilder errormsgs = new StringBuilder();
+  
+    List<String> files = new ArrayList<>();
+    String pdbid = "";
+    try
+    {
+      String[] filesInViewer = getStructureFiles();
+      // TODO: replace with reference fetching/transfer code (validate PDBentry
+      // as a DBRef?)
+      
+      for (int pi = 0; pi < getPdbCount(); pi++)
+      {
+        PDBEntry strucEntry = getPdbEntry(pi);
+
+        String file = strucEntry.getFile();
+        if (file == null)
+        {
+          pdbid = strucEntry.getId();
+          try{ 
+            file = structureViewer.fetchPdbFile(strucEntry);
+          } catch (OutOfMemoryError oomerror)
+          {
+            new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
+          } catch (Exception ex)
+          {
+            ex.printStackTrace();
+            errormsgs.append("'").append(pdbid).append("'");
+          }
+          if (file!=null)
+          {
+            // success
+            files.add(file);
+          }
+          else
+          {
+            errormsgs.append("'").append(pdbid).append("' ");
+          }
+        }
+        else
+        {
+          if (filesInViewer != null && filesInViewer.length > 0)
+          {
+            structureViewer.setAddingStructures(true); // already files loaded.
+            for (int c = 0; c < filesInViewer.length; c++)
+            {
+              if (Platform.pathEquals(filesInViewer[c], file))
+              {
+                file = null;
+                break;
+              }
+            }
+          }
+          if (file != null)
+          {
+            files.add(file);
+          }
+        }
+      }
+    } catch (OutOfMemoryError oomerror)
+    {
+      new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+      errormsgs.append("When retrieving pdbfiles : current was: '")
+              .append(pdbid).append("'");
+    }
+    if (errormsgs.length() > 0)
+    {
+      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+              MessageManager.formatMessage(
+                      "label.pdb_entries_couldnt_be_retrieved", new String[]
+                      { errormsgs.toString() }),
+              MessageManager.getString("label.couldnt_load_file"),
+              JvOptionPane.ERROR_MESSAGE);
+    }
+    return files;
+  }
+
 }
index 757bb01..3dc51ce 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -199,7 +200,7 @@ public class BlogReader extends JPanel
       {
         if (parent != null)
         {
-          Cache.log.debug("News window closed.");
+          Console.debug("News window closed.");
           jd = null;
           parent.showNews(false);
         }
@@ -247,16 +248,16 @@ public class BlogReader extends JPanel
 
   public BlogReader(Desktop desktop)
   {
-    Cache.log.debug("Constructing news reader.");
+    Console.debug("Constructing news reader.");
 
     parent = desktop;
     _channelModel = new ChannelListModel();
     // Construct our jalview news channel
     Channel chan = new Channel();
     chan.setURL(
-            jalview.bin.Cache.getDefault("JALVIEW_NEWS_RSS",
-                    jalview.bin.Cache.getDefault("www.jalview.org",
-                            "http://www.jalview.org")
+            Cache.getDefault("JALVIEW_NEWS_RSS",
+                    Cache.getDefault("www.jalview.org",
+                            "https://www.jalview.org")
                             + "/feeds/desktop/rss"));
     loadLastM();
     _channelModel.addChannel(chan);
@@ -277,10 +278,10 @@ public class BlogReader extends JPanel
     if (setvisible)
     {
 
-      Cache.log.debug("Will show jalview news automatically");
+      Console.debug("Will show jalview news automatically");
       showNews();
     }
-    Cache.log.debug("Completed construction of reader.");
+    Console.debug("Completed construction of reader.");
 
   }
 
@@ -340,7 +341,7 @@ public class BlogReader extends JPanel
                   MessageManager.getString("label.news_from_jalview"),
                   bounds.width, bounds.height);
           jd.frame.setModalExclusionType(ModalExclusionType.NO_EXCLUDE);
-          Cache.log.debug("Displaying news.");
+          Console.debug("Displaying news.");
           jd.waitForInput();
         }
       }
@@ -367,7 +368,7 @@ public class BlogReader extends JPanel
     }
     if (chan != null && chan.getItems() != null)
     {
-      Cache.log.debug("Scanning news items: newsnew=" + newsnew
+      Console.debug("Scanning news items: newsnew=" + newsnew
               + " and lastDate is " + lastDate);
       for (Item i : (List<Item>) chan.getItems())
       {
@@ -426,7 +427,7 @@ public class BlogReader extends JPanel
       {
         String formatted = Cache
                 .setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", lastDate);
-        Cache.log.debug("Saved last read date as " + formatted);
+        Console.debug("Saved last read date as " + formatted);
       }
     }
   }
@@ -759,8 +760,8 @@ public class BlogReader extends JPanel
   {
     // this tests the detection of new news based on the last read date stored
     // in jalview properties
-    jalview.bin.Cache.loadProperties(null);
-    jalview.bin.Cache.initLogger();
+    Cache.loadProperties(null);
+    Console.initLogger();
     // test will advance read date each time
     Calendar today = Calendar.getInstance(),
             lastread = Calendar.getInstance();
@@ -773,16 +774,16 @@ public class BlogReader extends JPanel
       System.out.println("Set last date to " + formattedDate);
       if (me.isNewsNew())
       {
-        Cache.log.debug("There is news to read.");
+        Console.debug("There is news to read.");
       }
       else
       {
-        Cache.log.debug("There is no new news.");
+        Console.debug("There is no new news.");
         me.xf.setTitle("Testing : Last read is " + me.lastDate);
         me.showNews();
         me.xf.toFront();
       }
-      Cache.log.debug("Waiting for closure.");
+      Console.debug("Waiting for closure.");
       do
       {
         try
@@ -795,11 +796,11 @@ public class BlogReader extends JPanel
 
       if (me.isNewsNew())
       {
-        Cache.log.debug("Still new news after reader displayed.");
+        Console.debug("Still new news after reader displayed.");
       }
       if (lastread.getTime().before(me.lastDate))
       {
-        Cache.log.debug("The news was read.");
+        Console.debug("The news was read.");
         lastread.setTime(me.lastDate);
       }
       else
index 810f40d..9d98585 100644 (file)
@@ -38,7 +38,7 @@ import javax.swing.event.InternalFrameEvent;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.StructureViewerModel;
@@ -73,7 +73,10 @@ public class ChimeraViewFrame extends StructureViewerBase
 
   private int myHeight = 150;
 
-  /**
+  private JMenuItem writeFeatures=null;
+
+  private JMenu fetchAttributes=null;
+/**
    * Initialise menu options.
    */
   @Override
@@ -84,7 +87,7 @@ public class ChimeraViewFrame extends StructureViewerBase
     savemenu.setVisible(false); // not yet implemented
     viewMenu.add(fitToWindow);
 
-    JMenuItem writeFeatures = new JMenuItem(
+    writeFeatures = new JMenuItem(
             MessageManager.getString("label.create_viewer_attributes"));
     writeFeatures.setToolTipText(MessageManager
             .getString("label.create_viewer_attributes_tip"));
@@ -98,10 +101,10 @@ public class ChimeraViewFrame extends StructureViewerBase
     });
     viewerActionMenu.add(writeFeatures);
 
-    final JMenu fetchAttributes = new JMenu(
-            MessageManager.getString("label.fetch_chimera_attributes"));
+    fetchAttributes = new JMenu(
+            MessageManager.formatMessage("label.fetch_viewer_attributes",getViewerName()));
     fetchAttributes.setToolTipText(
-            MessageManager.getString("label.fetch_chimera_attributes_tip"));
+            MessageManager.formatMessage("label.fetch_viewer_attributes_tip",getViewerName()));
     fetchAttributes.addMouseListener(new MouseAdapter()
     {
 
@@ -113,7 +116,15 @@ public class ChimeraViewFrame extends StructureViewerBase
     });
     viewerActionMenu.add(fetchAttributes);
   }
-
+  @Override
+  protected void buildActionMenu()
+  {
+    super.buildActionMenu();
+    // add these back in after menu is refreshed
+    viewerActionMenu.add(writeFeatures);
+    viewerActionMenu.add(fetchAttributes);
+    
+  };
   /**
    * Query the structure viewer for its residue attribute names and add them as
    * items off the attributes menu
@@ -153,7 +164,7 @@ public class ChimeraViewFrame extends StructureViewerBase
     // todo pull up?
     int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
     statusBar.setText(
-            MessageManager.formatMessage("label.attributes_set", count));
+            MessageManager.formatMessage("label.attributes_set", count, getViewerName()));
   }
 
   /**
@@ -430,7 +441,7 @@ public class ChimeraViewFrame extends StructureViewerBase
           initChimera();
         } catch (Exception ex)
         {
-          Cache.log.error("Couldn't open Chimera viewer!", ex);
+          Console.error("Couldn't open Chimera viewer!", ex);
         }
       }
       int num = -1;
@@ -475,12 +486,12 @@ public class ChimeraViewFrame extends StructureViewerBase
                     oomerror);
           } catch (Exception ex)
           {
-            Cache.log.error(
+            Console.error(
                     "Couldn't open " + pe.getFile() + " in Chimera viewer!",
                     ex);
           } finally
           {
-            Cache.log.debug("File locations are " + files);
+            Console.debug("File locations are " + files);
           }
         }
       }
@@ -491,7 +502,8 @@ public class ChimeraViewFrame extends StructureViewerBase
 
       /*
        * ensure that any newly discovered features (e.g. RESNUM)
-       * are added to any open feature settings dialog
+       * are notified to the FeatureRenderer (and added to any 
+       * open feature settings dialog)
        */
       FeatureRenderer fr = getBinding().getFeatureRenderer(null);
       if (fr != null)
index 050523e..d9d729a 100644 (file)
@@ -42,6 +42,7 @@ import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 import java.io.PrintStream;
 
+import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JFrame;
@@ -49,13 +50,15 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
+import javax.swing.border.Border;
+import javax.swing.text.DefaultCaret;
 
-import org.apache.log4j.Level;
-import org.apache.log4j.SimpleLayout;
-
-import jalview.bin.Cache;
+import jalview.log.JLoggerI.LogLevel;
+import jalview.log.JLoggerLog4j;
+import jalview.log.JalviewAppender;
 import jalview.util.ChannelProperties;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 /**
  * Simple Jalview Java Console. Version 1 - allows viewing of console output
@@ -101,9 +104,9 @@ public class Console extends WindowAdapter
 
   private int MIN_HEIGHT = 250;
 
-  private JComboBox<Level> logLevelCombo = new JComboBox<Level>();
+  private JComboBox<LogLevel> logLevelCombo = new JComboBox<LogLevel>();
 
-  protected Level startingLogLevel = Level.INFO;
+  protected LogLevel startingLogLevel = LogLevel.INFO;
 
   public Console()
   {
@@ -132,6 +135,36 @@ public class Console extends WindowAdapter
     // textArea = cpt.getTextArea();
     textArea = new JTextArea();
     textArea.setEditable(false);
+    // autoscroll
+    DefaultCaret caret = (DefaultCaret) textArea.getCaret();
+    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
+    // toggle autoscroll by clicking on the text area
+    Border pausedBorder = BorderFactory.createMatteBorder(2, 2, 2, 2,
+            textArea.getForeground());
+    Border noBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2);
+    JScrollPane scrollPane = new JScrollPane(textArea);
+    scrollPane.setBorder(noBorder);
+    textArea.addMouseListener(new MouseAdapter()
+    {
+      public void mouseClicked(MouseEvent e)
+      {
+        if (e.getButton() == MouseEvent.BUTTON1)
+        {
+          if (caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE)
+          {
+            caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
+            scrollPane.setBorder(pausedBorder);
+          }
+          else
+          {
+            caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
+            textArea.setCaretPosition(textArea.getDocument().getLength());
+            scrollPane.setBorder(noBorder);
+          }
+        }
+      }
+    });
+
     JButton clearButton = new JButton(
             MessageManager.getString("action.clear"));
     JButton copyToClipboardButton = new JButton(
@@ -168,25 +201,26 @@ public class Console extends WindowAdapter
     JLabel logLevelLabel = new JLabel(
             MessageManager.getString("label.log_level") + ":");
 
-    // logLevelCombo.addItem(Level.ALL);
-    logLevelCombo.addItem(Level.TRACE);
-    logLevelCombo.addItem(Level.DEBUG);
-    logLevelCombo.addItem(Level.INFO);
-    logLevelCombo.addItem(Level.WARN);
-    // logLevelCombo.addItem(Level.ERROR);
-    // logLevelCombo.addItem(Level.FATAL);
-    // logLevelCombo.addItem(Level.OFF);
+    // logLevelCombo.addItem(LogLevel.ALL);
+    logLevelCombo.addItem(LogLevel.TRACE);
+    logLevelCombo.addItem(LogLevel.DEBUG);
+    logLevelCombo.addItem(LogLevel.INFO);
+    logLevelCombo.addItem(LogLevel.WARN);
+    // logLevelCombo.addItem(LogLevel.ERROR);
+    // logLevelCombo.addItem(LogLevel.FATAL);
+    // logLevelCombo.addItem(LogLevel.ERROR);
+    // logLevelCombo.addItem(LogLevel.OFF);
     // set startingLogLevel
-    startingLogLevel = Cache.log == null ? Level.INFO
-            : Cache.log.getLevel();
+    startingLogLevel = jalview.bin.Console.log == null ? LogLevel.INFO
+            : jalview.bin.Console.log.getLevel();
     setChosenLogLevelCombo();
     logLevelCombo.addActionListener(new ActionListener()
     {
       public void actionPerformed(ActionEvent e)
       {
-        if (Cache.log != null)
+        if (jalview.bin.Console.log != null)
         {
-          Cache.log.setLevel((Level) logLevelCombo.getSelectedItem());
+          jalview.bin.Console.log.setLevel((LogLevel) logLevelCombo.getSelectedItem());
         }
       }
 
@@ -194,8 +228,7 @@ public class Console extends WindowAdapter
 
     // frame = cpt;
     frame.getContentPane().setLayout(new BorderLayout());
-    frame.getContentPane().add(new JScrollPane(textArea),
-            BorderLayout.CENTER);
+    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
     JPanel southPanel = new JPanel();
     southPanel.setLayout(new GridBagLayout());
 
@@ -266,20 +299,20 @@ public class Console extends WindowAdapter
     setChosenLogLevelCombo(startingLogLevel);
   }
 
-  private void setChosenLogLevelCombo(Level setLogLevel)
+  private void setChosenLogLevelCombo(LogLevel setLogLevel)
   {
     logLevelCombo.setSelectedItem(setLogLevel);
     if (!logLevelCombo.getSelectedItem().equals(setLogLevel))
     {
       // setLogLevel not (yet) in list
-      if (setLogLevel != null && setLogLevel instanceof Level)
+      if (setLogLevel != null && setLogLevel instanceof LogLevel)
       {
         // add new item to list (might be set via .jalview_properties)
         boolean added = false;
         for (int i = 0; i < logLevelCombo.getItemCount(); i++)
         {
-          Level l = (Level) logLevelCombo.getItemAt(i);
-          if (l.isGreaterOrEqual(setLogLevel))
+          LogLevel l = (LogLevel) logLevelCombo.getItemAt(i);
+          if (l.compareTo(setLogLevel) >= 0)
           {
             logLevelCombo.insertItemAt(setLogLevel, i);
             added = true;
@@ -295,7 +328,7 @@ public class Console extends WindowAdapter
       }
       else
       {
-        logLevelCombo.setSelectedItem(Level.INFO);
+        logLevelCombo.setSelectedItem(LogLevel.INFO);
       }
     }
   }
@@ -471,10 +504,17 @@ public class Console extends WindowAdapter
     frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
     // desktop.add(frame);
     initConsole(false);
-    JalviewAppender jappender = new JalviewAppender();
-    jappender.setLayout(new SimpleLayout());
-    JalviewAppender.setTextArea(textArea);
-    org.apache.log4j.Logger.getRootLogger().addAppender(jappender);
+    LogLevel level = (LogLevel) logLevelCombo.getSelectedItem();
+    if (!Platform.isJS())
+    {
+      JalviewAppender jappender = new JalviewAppender(level);
+      JalviewAppender.setTextArea(textArea);
+      jappender.start();
+      if (jalview.bin.Console.log != null && jalview.bin.Console.log instanceof JLoggerLog4j)
+      {
+        JLoggerLog4j.addAppender(jalview.bin.Console.log, jappender);
+      }
+    }
   }
 
   public synchronized void stopConsole()
@@ -815,9 +855,9 @@ public class Console extends WindowAdapter
     else
     {
       // reset log level to what it was before
-      if (Cache.log != null)
+      if (jalview.bin.Console.log != null)
       {
-        Cache.log.setLevel(startingLogLevel);
+        jalview.bin.Console.log.setLevel(startingLogLevel);
       }
 
       unredirectStreams();
index 2ada4d2..b04661e 100644 (file)
@@ -25,6 +25,7 @@ import jalview.analysis.CrossRef;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsModelI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
@@ -229,7 +230,7 @@ public class CrossRefAction implements Runnable
       new OOMWarning("whilst fetching crossreferences", e);
     } catch (Throwable e)
     {
-      Cache.log.error("Error when finding crossreferences", e);
+      Console.error("Error when finding crossreferences", e);
     } finally
     {
       alignFrame.setProgressBar(MessageManager.formatMessage(
index fc19695..6e0032f 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.bin.Cache;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.jbgui.GCutAndPasteHtmlTransfer;
@@ -152,7 +153,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
     // TODO: JAL-3048 JalviewFileChooser - Save option
 
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
 
     chooser.setAcceptAllFileFilterUsed(false);
     chooser.setFileView(new JalviewFileView());
index d328a0d..5e36500 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.bin.Cache;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.ComplexAlignFile;
@@ -138,7 +139,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
     // TODO: JAL-3048 JalviewFileChooser - Save option
 
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
 
     chooser.setAcceptAllFileFilterUsed(false);
     chooser.setFileView(new JalviewFileView());
@@ -274,11 +275,8 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
        */
       if (viewport != null && viewport.getAlignment() != null)
       {
-        if (proxyColourScheme != null)
-        {
-          viewport.applyFeaturesStyle(proxyColourScheme);
-        }
         ((AlignViewport) viewport).addAlignment(al, title);
+        viewport.applyFeaturesStyle(proxyColourScheme);
       }
       else
       {
@@ -330,7 +328,7 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
         try
         {
           af.setMaximum(
-                  jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));
+                  Cache.getDefault("SHOW_FULLSCREEN", false));
         } catch (Exception ex)
         {
         }
index 195a313..ad36492 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -136,36 +138,26 @@ import jalview.ws.utils.UrlDownloadClient;
  * @version $Revision: 1.155 $
  */
 public class Desktop extends jalview.jbgui.GDesktop
-        implements DropTargetListener, ClipboardOwner, IProgressIndicator,
-        jalview.api.StructureSelectionManagerProvider
-{
+    implements DropTargetListener, ClipboardOwner, IProgressIndicator, jalview.api.StructureSelectionManagerProvider {
   private static final String CITATION;
-  static
-  {
-    URL bg_logo_url = ChannelProperties.getImageURL(
-            "bg_logo." + String.valueOf(SplashScreen.logoSize));
-    URL uod_logo_url = ChannelProperties.getImageURL(
-            "uod_banner." + String.valueOf(SplashScreen.logoSize));
+  static {
+    URL bg_logo_url = ChannelProperties.getImageURL("bg_logo." + String.valueOf(SplashScreen.logoSize));
+    URL uod_logo_url = ChannelProperties.getImageURL("uod_banner." + String.valueOf(SplashScreen.logoSize));
     boolean logo = (bg_logo_url != null || uod_logo_url != null);
     StringBuilder sb = new StringBuilder();
-    sb.append(
-            "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.");
-    if (logo)
-    {
+    sb.append("<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.");
+    if (logo) {
       sb.append("<br>");
     }
-    sb.append(bg_logo_url == null ? ""
-            : "<img alt=\"Barton Group logo\" src=\""
-                    + bg_logo_url.toString() + "\">");
+    sb.append(bg_logo_url == null ? "" : "<img alt=\"Barton Group logo\" src=\"" + bg_logo_url.toString() + "\">");
     sb.append(uod_logo_url == null ? ""
-            : "&nbsp;<img alt=\"University of Dundee shield\" src=\""
-                    + uod_logo_url.toString() + "\">");
+        : "&nbsp;<img alt=\"University of Dundee shield\" src=\"" + uod_logo_url.toString() + "\">");
     sb.append(
-            "<br><br>For help, see the FAQ at <a href=\"https://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list");
+        "<br><br>For help, see the FAQ at <a href=\"https://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list");
     sb.append("<br><br>If  you use Jalview, please cite:"
-            + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
-            + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
-            + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033");
+        + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
+        + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
+        + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033");
     CITATION = sb.toString();
   }
 
@@ -200,9 +192,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @param listener
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
    */
-  public void addJalviewPropertyChangeListener(
-          PropertyChangeListener listener)
-  {
+  public void addJalviewPropertyChangeListener(PropertyChangeListener listener) {
     changeSupport.addJalviewPropertyChangeListener(listener);
   }
 
@@ -212,9 +202,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
    *      java.beans.PropertyChangeListener)
    */
-  public void addJalviewPropertyChangeListener(String propertyName,
-          PropertyChangeListener listener)
-  {
+  public void addJalviewPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
     changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
   }
 
@@ -224,11 +212,8 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
    *      java.beans.PropertyChangeListener)
    */
-  public void removeJalviewPropertyChangeListener(String propertyName,
-          PropertyChangeListener listener)
-  {
-    changeSupport.removeJalviewPropertyChangeListener(propertyName,
-            listener);
+  public void removeJalviewPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+    changeSupport.removeJalviewPropertyChangeListener(propertyName, listener);
   }
 
   /** Singleton Desktop instance */
@@ -236,8 +221,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static MyDesktopPane desktop;
 
-  public static MyDesktopPane getDesktop()
-  {
+  public static MyDesktopPane getDesktop() {
     // BH 2018 could use currentThread() here as a reference to a
     // Hashtable<Thread, MyDesktopPane> in JavaScript
     return desktop;
@@ -257,122 +241,99 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   static int fileLoadingCount = 0;
 
-  class MyDesktopManager implements DesktopManager
-  {
+  class MyDesktopManager implements DesktopManager {
 
     private DesktopManager delegate;
 
-    public MyDesktopManager(DesktopManager delegate)
-    {
+    public MyDesktopManager(DesktopManager delegate) {
       this.delegate = delegate;
     }
 
     @Override
-    public void activateFrame(JInternalFrame f)
-    {
-      try
-      {
+    public void activateFrame(JInternalFrame f) {
+      try {
         delegate.activateFrame(f);
-      } catch (NullPointerException npe)
-      {
+      } catch (NullPointerException npe) {
         Point p = getMousePosition();
         instance.showPasteMenu(p.x, p.y);
       }
     }
 
     @Override
-    public void beginDraggingFrame(JComponent f)
-    {
+    public void beginDraggingFrame(JComponent f) {
       delegate.beginDraggingFrame(f);
     }
 
     @Override
-    public void beginResizingFrame(JComponent f, int direction)
-    {
+    public void beginResizingFrame(JComponent f, int direction) {
       delegate.beginResizingFrame(f, direction);
     }
 
     @Override
-    public void closeFrame(JInternalFrame f)
-    {
+    public void closeFrame(JInternalFrame f) {
       delegate.closeFrame(f);
     }
 
     @Override
-    public void deactivateFrame(JInternalFrame f)
-    {
+    public void deactivateFrame(JInternalFrame f) {
       delegate.deactivateFrame(f);
     }
 
     @Override
-    public void deiconifyFrame(JInternalFrame f)
-    {
+    public void deiconifyFrame(JInternalFrame f) {
       delegate.deiconifyFrame(f);
     }
 
     @Override
-    public void dragFrame(JComponent f, int newX, int newY)
-    {
-      if (newY < 0)
-      {
+    public void dragFrame(JComponent f, int newX, int newY) {
+      if (newY < 0) {
         newY = 0;
       }
       delegate.dragFrame(f, newX, newY);
     }
 
     @Override
-    public void endDraggingFrame(JComponent f)
-    {
+    public void endDraggingFrame(JComponent f) {
       delegate.endDraggingFrame(f);
       desktop.repaint();
     }
 
     @Override
-    public void endResizingFrame(JComponent f)
-    {
+    public void endResizingFrame(JComponent f) {
       delegate.endResizingFrame(f);
       desktop.repaint();
     }
 
     @Override
-    public void iconifyFrame(JInternalFrame f)
-    {
+    public void iconifyFrame(JInternalFrame f) {
       delegate.iconifyFrame(f);
     }
 
     @Override
-    public void maximizeFrame(JInternalFrame f)
-    {
+    public void maximizeFrame(JInternalFrame f) {
       delegate.maximizeFrame(f);
     }
 
     @Override
-    public void minimizeFrame(JInternalFrame f)
-    {
+    public void minimizeFrame(JInternalFrame f) {
       delegate.minimizeFrame(f);
     }
 
     @Override
-    public void openFrame(JInternalFrame f)
-    {
+    public void openFrame(JInternalFrame f) {
       delegate.openFrame(f);
     }
 
     @Override
-    public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
-            int newHeight)
-    {
-      if (newY < 0)
-      {
+    public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
+      if (newY < 0) {
         newY = 0;
       }
       delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
     }
 
     @Override
-    public void setBoundsForFrame(JComponent f, int newX, int newY,
-            int newWidth, int newHeight)
-    {
+    public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
       delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
     }
 
@@ -383,83 +344,72 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * Creates a new Desktop object.
    */
-  public Desktop()
-  {
+  public Desktop() {
     super();
     /**
-     * A note to implementors. It is ESSENTIAL that any activities that might
-     * block are spawned off as threads rather than waited for during this
-     * constructor.
+     * A note to implementors. It is ESSENTIAL that any activities that might block
+     * are spawned off as threads rather than waited for during this constructor.
      */
     instance = this;
 
     doConfigureStructurePrefs();
-    setTitle(ChannelProperties.getProperty("app_name") + " "
-            + Cache.getProperty("VERSION"));
+    setTitle(ChannelProperties.getProperty("app_name") + " " + Cache.getProperty("VERSION"));
 
     /**
-     * Set taskbar "grouped windows" name for linux desktops (works in GNOME and KDE).
-     * This uses sun.awt.X11.XToolkit.awtAppClassName which is not officially documented or
-     * guaranteed to exist, so we access it via reflection.
-     * There appear to be unfathomable criteria about what this string can contain, and it if doesn't
-     * meet those criteria then "java" (KDE) or "jalview-bin-Jalview" (GNOME) is used.
-     * "Jalview", "Jalview Develop" and "Jalview Test" seem okay, but "Jalview non-release" does not.
-     * The reflection access may generate a warning:
-     * WARNING: An illegal reflective access operation has occurred
-     * WARNING: Illegal reflective access by jalview.gui.Desktop () to field sun.awt.X11.XToolkit.awtAppClassName
-     * which I don't think can be avoided.
+     * Set taskbar "grouped windows" name for linux desktops (works in GNOME and
+     * KDE). This uses sun.awt.X11.XToolkit.awtAppClassName which is not officially
+     * documented or guaranteed to exist, so we access it via reflection. There
+     * appear to be unfathomable criteria about what this string can contain, and it
+     * if doesn't meet those criteria then "java" (KDE) or "jalview-bin-Jalview"
+     * (GNOME) is used. "Jalview", "Jalview Develop" and "Jalview Test" seem okay,
+     * but "Jalview non-release" does not. The reflection access may generate a
+     * warning: WARNING: An illegal reflective access operation has occurred
+     * WARNING: Illegal reflective access by jalview.gui.Desktop () to field
+     * sun.awt.X11.XToolkit.awtAppClassName which I don't think can be avoided.
      */
-    if (Platform.isLinux())
-    {
-      try
-      {
+    if (Platform.isLinux()) {
+      try {
         Toolkit xToolkit = Toolkit.getDefaultToolkit();
         Field[] declaredFields = xToolkit.getClass().getDeclaredFields();
         Field awtAppClassNameField = null;
 
-        if (Arrays.stream(declaredFields).anyMatch(f -> f.getName().equals("awtAppClassName")))
-        {
-          awtAppClassNameField = xToolkit.getClass()
-                  .getDeclaredField("awtAppClassName");
+        if (Arrays.stream(declaredFields).anyMatch(f -> f.getName().equals("awtAppClassName"))) {
+          awtAppClassNameField = xToolkit.getClass().getDeclaredField("awtAppClassName");
         }
 
         String title = ChannelProperties.getProperty("app_name");
-        if (awtAppClassNameField != null)
-        {
+        if (awtAppClassNameField != null) {
           awtAppClassNameField.setAccessible(true);
           awtAppClassNameField.set(xToolkit, title);
+        } else {
+          jalview.bin.Console.debug("XToolkit: awtAppClassName not found");
         }
-        else
-        {
-          Cache.log.debug("XToolkit: awtAppClassName not found");
-        }
-      } catch (Exception e)
-      {
-        Cache.debug("Error setting awtAppClassName");
-        Cache.trace(Cache.getStackTraceString(e));
+      } catch (Exception e) {
+        jalview.bin.Console.debug("Error setting awtAppClassName");
+        jalview.bin.Console.trace(Cache.getStackTraceString(e));
       }
     }
 
     /**
-     * APQHandlers sets handlers for About, Preferences and Quit actions peculiar to macOS's application menu.
-     * APQHandlers will check to see if a handler is supported before setting it.
+     * APQHandlers sets handlers for About, Preferences and Quit actions peculiar to
+     * macOS's application menu. APQHandlers will check to see if a handler is
+     * supported before setting it.
      */
-    try
-    {
+    try {
       APQHandlers.setAPQHandlers(this);
-    } catch (Throwable t)
-    {
-      Cache.warn("Error setting APQHandlers: " + t.toString());
-      Cache.trace(Cache.getStackTraceString(t));
+    } catch (Exception e) {
+      System.out.println("Cannot set APQHandlers");
+      // e.printStackTrace();
+    } catch (Throwable t) {
+      jalview.bin.Console.warn("Error setting APQHandlers: " + t.toString());
+      jalview.bin.Console.trace(Cache.getStackTraceString(t));
     }
     setIconImages(ChannelProperties.getIconList());
 
-    addWindowListener(new WindowAdapter()
-    {
+    addWindowListener(new WindowAdapter() {
 
       @Override
-      public void windowClosing(WindowEvent ev)
-      {
+      public void windowClosing(WindowEvent ev) {
         quit();
       }
     });
@@ -472,8 +422,6 @@ public class Desktop extends jalview.jbgui.GDesktop
     showMemusage.setSelected(selmemusage);
     desktop.setBackground(Color.white);
 
-    this.setIconImages(ChannelProperties.getIconList());
-
     getContentPane().setLayout(new BorderLayout());
     // alternate config - have scrollbars - see notes in JAL-153
     // JScrollPane sp = new JScrollPane();
@@ -481,8 +429,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     // getContentPane().add(sp, BorderLayout.CENTER);
 
     // BH 2018 - just an experiment to try unclipped JInternalFrames.
-    if (Platform.isJS())
-    {
+    if (Platform.isJS()) {
       getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
     }
 
@@ -491,20 +438,14 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     // This line prevents Windows Look&Feel resizing all new windows to maximum
     // if previous window was maximised
-    desktop.setDesktopManager(new MyDesktopManager(
-            (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
-                    : Platform.isAMacAndNotJS()
-                            ? new AquaInternalFrameManager(
-                                    desktop.getDesktopManager())
-                            : desktop.getDesktopManager())));
+    desktop.setDesktopManager(new MyDesktopManager((Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
+        : Platform.isAMacAndNotJS() ? new AquaInternalFrameManager(desktop.getDesktopManager())
+            : desktop.getDesktopManager())));
 
     Rectangle dims = getLastKnownDimensions("");
-    if (dims != null)
-    {
+    if (dims != null) {
       setBounds(dims);
-    }
-    else
-    {
+    } else {
       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
       int xPos = Math.max(5, (screenSize.width - 900) / 2);
       int yPos = Math.max(5, (screenSize.height - 650) / 2);
@@ -531,13 +472,10 @@ public class Desktop extends jalview.jbgui.GDesktop
       checkURLLinks();
 
       // Spawn a thread that shows the splashscreen
-      if (!nosplash)
-      {
-        SwingUtilities.invokeLater(new Runnable()
-        {
+      if (!nosplash) {
+        SwingUtilities.invokeLater(new Runnable() {
           @Override
-          public void run()
-          {
+          public void run() {
             new SplashScreen(true);
           }
         });
@@ -546,50 +484,39 @@ public class Desktop extends jalview.jbgui.GDesktop
       // Thread off a new instance of the file chooser - this reduces the time
       // it
       // takes to open it later on.
-      new Thread(new Runnable()
-      {
+      new Thread(new Runnable() {
         @Override
-        public void run()
-        {
-          Cache.log.debug("Filechooser init thread started.");
+        public void run() {
+          jalview.bin.Console.debug("Filechooser init thread started.");
           String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
-          JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
-                  fileFormat);
-          Cache.log.debug("Filechooser init thread finished.");
+          JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
+          jalview.bin.Console.debug("Filechooser init thread finished.");
         }
       }).start();
       // Add the service change listener
-      changeSupport.addJalviewPropertyChangeListener("services",
-              new PropertyChangeListener()
-              {
+      changeSupport.addJalviewPropertyChangeListener("services", new PropertyChangeListener() {
 
-                @Override
-                public void propertyChange(PropertyChangeEvent evt)
-                {
-                  Cache.log.debug("Firing service changed event for "
-                          + evt.getNewValue());
-                  JalviewServicesChanged(evt);
-                }
-              });
+        @Override
+        public void propertyChange(PropertyChangeEvent evt) {
+          jalview.bin.Console.debug("Firing service changed event for " + evt.getNewValue());
+          JalviewServicesChanged(evt);
+        }
+      });
     }
 
     this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
 
-    this.addWindowListener(new WindowAdapter()
-    {
+    this.addWindowListener(new WindowAdapter() {
       @Override
-      public void windowClosing(WindowEvent evt)
-      {
+      public void windowClosing(WindowEvent evt) {
         quit();
       }
     });
 
     MouseAdapter ma;
-    this.addMouseListener(ma = new MouseAdapter()
-    {
+    this.addMouseListener(ma = new MouseAdapter() {
       @Override
-      public void mousePressed(MouseEvent evt)
-      {
+      public void mousePressed(MouseEvent evt) {
         if (evt.isPopupTrigger()) // Mac
         {
           showPasteMenu(evt.getX(), evt.getY());
@@ -597,8 +524,7 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
 
       @Override
-      public void mouseReleased(MouseEvent evt)
-      {
+      public void mouseReleased(MouseEvent evt) {
         if (evt.isPopupTrigger()) // Windows
         {
           showPasteMenu(evt.getX(), evt.getY());
@@ -614,95 +540,71 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return
    */
-  public boolean showExperimental()
-  {
-    String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
-            Boolean.FALSE.toString());
+  public boolean showExperimental() {
+    String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES, Boolean.FALSE.toString());
     return Boolean.valueOf(experimental).booleanValue();
   }
 
-  public void doConfigureStructurePrefs()
-  {
+  public void doConfigureStructurePrefs() {
     // configure services
-    StructureSelectionManager ssm = StructureSelectionManager
-            .getStructureSelectionManager(this);
-    if (Cache.getDefault(Preferences.ADD_SS_ANN, true))
-    {
-      ssm.setAddTempFacAnnot(
-              Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true));
-      ssm.setProcessSecondaryStructure(
-              Cache.getDefault(Preferences.STRUCT_FROM_PDB, true));
-      ssm.setSecStructServices(
-              Cache.getDefault(Preferences.USE_RNAVIEW, true));
-    }
-    else
-    {
+    StructureSelectionManager ssm = StructureSelectionManager.getStructureSelectionManager(this);
+    if (Cache.getDefault(Preferences.ADD_SS_ANN, true)) {
+      ssm.setAddTempFacAnnot(Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true));
+      ssm.setProcessSecondaryStructure(Cache.getDefault(Preferences.STRUCT_FROM_PDB, true));
+      // JAL-3915 - RNAView is no longer an option so this has no effect
+      ssm.setSecStructServices(Cache.getDefault(Preferences.USE_RNAVIEW, false));
+    } else {
       ssm.setAddTempFacAnnot(false);
       ssm.setProcessSecondaryStructure(false);
       ssm.setSecStructServices(false);
     }
   }
 
-  public void checkForNews()
-  {
+  public void checkForNews() {
     final Desktop me = this;
     // Thread off the news reader, in case there are connection problems.
-    new Thread(new Runnable()
-    {
+    new Thread(new Runnable() {
       @Override
-      public void run()
-      {
-        Cache.log.debug("Starting news thread.");
+      public void run() {
+        jalview.bin.Console.debug("Starting news thread.");
         jvnews = new BlogReader(me);
         showNews.setVisible(true);
-        Cache.log.debug("Completed news thread.");
+        jalview.bin.Console.debug("Completed news thread.");
       }
     }).start();
   }
 
-  public void getIdentifiersOrgData()
-  {
-    // Thread off the identifiers fetcher
-    new Thread(new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        Cache.log.debug("Downloading data from identifiers.org");
-        try
-        {
-          UrlDownloadClient.download(IdOrgSettings.getUrl(),
-                  IdOrgSettings.getDownloadLocation());
-        } catch (IOException e)
-        {
-          Cache.log.debug("Exception downloading identifiers.org data"
-                  + e.getMessage());
+  public void getIdentifiersOrgData() {
+    if (Cache.getProperty("NOIDENTIFIERSSERVICE") == null) {
+      // Thread off the identifiers fetcher
+      new Thread(new Runnable() {
+        @Override
+        public void run() {
+          jalview.bin.Console.debug("Downloading data from identifiers.org");
+          try {
+            UrlDownloadClient.download(IdOrgSettings.getUrl(), IdOrgSettings.getDownloadLocation());
+          } catch (IOException e) {
+            jalview.bin.Console.debug("Exception downloading identifiers.org data" + e.getMessage());
+          }
         }
-      }
-    }).start();
-
+      }).start();
+    }
   }
 
   @Override
-  protected void showNews_actionPerformed(ActionEvent e)
-  {
+  protected void showNews_actionPerformed(ActionEvent e) {
     showNews(showNews.isSelected());
   }
 
-  void showNews(boolean visible)
-  {
-    Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
+  void showNews(boolean visible) {
+    jalview.bin.Console.debug((visible ? "Showing" : "Hiding") + " news.");
     showNews.setSelected(visible);
-    if (visible && !jvnews.isVisible())
-    {
-      new Thread(new Runnable()
-      {
+    if (visible && !jvnews.isVisible()) {
+      new Thread(new Runnable() {
         @Override
-        public void run()
-        {
+        public void run() {
           long now = System.currentTimeMillis();
-          Desktop.instance.setProgressBar(
-                  MessageManager.getString("status.refreshing_news"), now);
+          Desktop.instance.setProgressBar(MessageManager.getString("status.refreshing_news"), now);
           jvnews.refreshNews();
           Desktop.instance.setProgressBar(null, now);
           jvnews.showNews();
@@ -714,52 +616,42 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * recover the last known dimensions for a jalview window
    * 
-   * @param windowName
-   *          - empty string is desktop, all other windows have unique prefix
+   * @param windowName - empty string is desktop, all other windows have unique
+   *                   prefix
    * @return null or last known dimensions scaled to current geometry (if last
    *         window geom was known)
    */
-  Rectangle getLastKnownDimensions(String windowName)
-  {
+  Rectangle getLastKnownDimensions(String windowName) {
     // TODO: lock aspect ratio for scaling desktop Bug #0058199
     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
     String x = Cache.getProperty(windowName + "SCREEN_X");
     String y = Cache.getProperty(windowName + "SCREEN_Y");
     String width = Cache.getProperty(windowName + "SCREEN_WIDTH");
     String height = Cache.getProperty(windowName + "SCREEN_HEIGHT");
-    if ((x != null) && (y != null) && (width != null) && (height != null))
-    {
-      int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
-              iw = Integer.parseInt(width), ih = Integer.parseInt(height);
-      if (Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
-      {
+    if ((x != null) && (y != null) && (width != null) && (height != null)) {
+      int ix = Integer.parseInt(x), iy = Integer.parseInt(y), iw = Integer.parseInt(width),
+          ih = Integer.parseInt(height);
+      if (Cache.getProperty("SCREENGEOMETRY_WIDTH") != null) {
         // attempt #1 - try to cope with change in screen geometry - this
         // version doesn't preserve original jv aspect ratio.
         // take ratio of current screen size vs original screen size.
-        double sw = ((1f * screenSize.width) / (1f * Integer
-                .parseInt(Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
-        double sh = ((1f * screenSize.height) / (1f * Integer
-                .parseInt(Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
+        double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
+        double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
         // rescale the bounds depending upon the current screen geometry.
         ix = (int) (ix * sw);
         iw = (int) (iw * sw);
         iy = (int) (iy * sh);
         ih = (int) (ih * sh);
-        while (ix >= screenSize.width)
-        {
-          Cache.log.debug(
-                  "Window geometry location recall error: shifting horizontal to within screenbounds.");
+        while (ix >= screenSize.width) {
+          jalview.bin.Console.debug("Window geometry location recall error: shifting horizontal to within screenbounds.");
           ix -= screenSize.width;
         }
-        while (iy >= screenSize.height)
-        {
-          Cache.log.debug(
-                  "Window geometry location recall error: shifting vertical to within screenbounds.");
+        while (iy >= screenSize.height) {
+          jalview.bin.Console.debug("Window geometry location recall error: shifting vertical to within screenbounds.");
           iy -= screenSize.height;
         }
-        Cache.log.debug(
-                "Got last known dimensions for " + windowName + ": x:" + ix
-                        + " y:" + iy + " width:" + iw + " height:" + ih);
+        jalview.bin.Console.debug("Got last known dimensions for " + windowName + ": x:" + ix + " y:" + iy + " width:" + iw
+            + " height:" + ih);
       }
       // return dimensions for new instance
       return new Rectangle(ix, iy, iw, ih);
@@ -767,16 +659,12 @@ public class Desktop extends jalview.jbgui.GDesktop
     return null;
   }
 
-  void showPasteMenu(int x, int y)
-  {
+  void showPasteMenu(int x, int y) {
     JPopupMenu popup = new JPopupMenu();
-    JMenuItem item = new JMenuItem(
-            MessageManager.getString("label.paste_new_window"));
-    item.addActionListener(new ActionListener()
-    {
+    JMenuItem item = new JMenuItem(MessageManager.getString("label.paste_new_window"));
+    item.addActionListener(new ActionListener() {
       @Override
-      public void actionPerformed(ActionEvent evt)
-      {
+      public void actionPerformed(ActionEvent evt) {
         paste();
       }
     });
@@ -785,115 +673,79 @@ public class Desktop extends jalview.jbgui.GDesktop
     popup.show(this, x, y);
   }
 
-  public void paste()
-  {
-    try
-    {
+  public void paste() {
+    try {
       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
       Transferable contents = c.getContents(this);
 
-      if (contents != null)
-      {
-        String file = (String) contents
-                .getTransferData(DataFlavor.stringFlavor);
+      if (contents != null) {
+        String file = (String) contents.getTransferData(DataFlavor.stringFlavor);
 
-        FileFormatI format = new IdentifyFile().identify(file,
-                DataSourceType.PASTE);
+        FileFormatI format = new IdentifyFile().identify(file, DataSourceType.PASTE);
 
         new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
 
       }
-    } catch (Exception ex)
-    {
-      System.out.println(
-              "Unable to paste alignment from system clipboard:\n" + ex);
+    } catch (Exception ex) {
+      System.out.println("Unable to paste alignment from system clipboard:\n" + ex);
     }
   }
 
   /**
    * Adds and opens the given frame to the desktop
    * 
-   * @param frame
-   *          Frame to show
-   * @param title
-   *          Visible Title
-   * @param w
-   *          width
-   * @param h
-   *          height
-   */
-  public static synchronized void addInternalFrame(
-          final JInternalFrame frame, String title, int w, int h)
-  {
+   * @param frame Frame to show
+   * @param title Visible Title
+   * @param w     width
+   * @param h     height
+   */
+  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, int w, int h) {
     addInternalFrame(frame, title, true, w, h, true, false);
   }
 
   /**
    * Add an internal frame to the Jalview desktop
    * 
-   * @param frame
-   *          Frame to show
-   * @param title
-   *          Visible Title
-   * @param makeVisible
-   *          When true, display frame immediately, otherwise, caller must call
-   *          setVisible themselves.
-   * @param w
-   *          width
-   * @param h
-   *          height
-   */
-  public static synchronized void addInternalFrame(
-          final JInternalFrame frame, String title, boolean makeVisible,
-          int w, int h)
-  {
+   * @param frame       Frame to show
+   * @param title       Visible Title
+   * @param makeVisible When true, display frame immediately, otherwise, caller
+   *                    must call setVisible themselves.
+   * @param w           width
+   * @param h           height
+   */
+  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, boolean makeVisible, int w,
+      int h) {
     addInternalFrame(frame, title, makeVisible, w, h, true, false);
   }
 
   /**
    * Add an internal frame to the Jalview desktop and make it visible
    * 
-   * @param frame
-   *          Frame to show
-   * @param title
-   *          Visible Title
-   * @param w
-   *          width
-   * @param h
-   *          height
-   * @param resizable
-   *          Allow resize
-   */
-  public static synchronized void addInternalFrame(
-          final JInternalFrame frame, String title, int w, int h,
-          boolean resizable)
-  {
+   * @param frame     Frame to show
+   * @param title     Visible Title
+   * @param w         width
+   * @param h         height
+   * @param resizable Allow resize
+   */
+  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, int w, int h,
+      boolean resizable) {
     addInternalFrame(frame, title, true, w, h, resizable, false);
   }
 
   /**
    * Add an internal frame to the Jalview desktop
    * 
-   * @param frame
-   *          Frame to show
-   * @param title
-   *          Visible Title
-   * @param makeVisible
-   *          When true, display frame immediately, otherwise, caller must call
-   *          setVisible themselves.
-   * @param w
-   *          width
-   * @param h
-   *          height
-   * @param resizable
-   *          Allow resize
-   * @param ignoreMinSize
-   *          Do not set the default minimum size for frame
-   */
-  public static synchronized void addInternalFrame(
-          final JInternalFrame frame, String title, boolean makeVisible,
-          int w, int h, boolean resizable, boolean ignoreMinSize)
-  {
+   * @param frame         Frame to show
+   * @param title         Visible Title
+   * @param makeVisible   When true, display frame immediately, otherwise, caller
+   *                      must call setVisible themselves.
+   * @param w             width
+   * @param h             height
+   * @param resizable     Allow resize
+   * @param ignoreMinSize Do not set the default minimum size for frame
+   */
+  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, boolean makeVisible, int w,
+      int h, boolean resizable, boolean ignoreMinSize) {
 
     // TODO: allow callers to determine X and Y position of frame (eg. via
     // bounds object).
@@ -901,8 +753,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     // the current window title
 
     frame.setTitle(title);
-    if (frame.getWidth() < 1 || frame.getHeight() < 1)
-    {
+    if (frame.getWidth() < 1 || frame.getHeight() < 1) {
       frame.setSize(w, h);
     }
     // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
@@ -910,26 +761,21 @@ public class Desktop extends jalview.jbgui.GDesktop
     // IF JALVIEW IS RUNNING HEADLESS
     // ///////////////////////////////////////////////
     if (instance == null || (System.getProperty("java.awt.headless") != null
-            && System.getProperty("java.awt.headless").equals("true")))
-    {
+        && System.getProperty("java.awt.headless").equals("true"))) {
       return;
     }
 
     openFrameCount++;
 
-    if (!ignoreMinSize)
-    {
-      frame.setMinimumSize(
-              new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
+    if (!ignoreMinSize) {
+      frame.setMinimumSize(new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
 
       // Set default dimension for Alignment Frame window.
       // The Alignment Frame window could be added from a number of places,
       // hence,
       // I did this here in order not to miss out on any Alignment frame.
-      if (frame instanceof AlignFrame)
-      {
-        frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
-                ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
+      if (frame instanceof AlignFrame) {
+        frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH, ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
       }
     }
 
@@ -940,27 +786,21 @@ public class Desktop extends jalview.jbgui.GDesktop
     frame.setIconifiable(resizable);
     frame.setOpaque(Platform.isJS());
 
-    if (frame.getX() < 1 && frame.getY() < 1)
-    {
-      frame.setLocation(xOffset * openFrameCount,
-              yOffset * ((openFrameCount - 1) % 10) + yOffset);
+    if (frame.getX() < 1 && frame.getY() < 1) {
+      frame.setLocation(xOffset * openFrameCount, yOffset * ((openFrameCount - 1) % 10) + yOffset);
     }
 
     /*
-     * add an entry for the new frame in the Window menu 
-     * (and remove it when the frame is closed)
+     * add an entry for the new frame in the Window menu (and remove it when the
+     * frame is closed)
      */
     final JMenuItem menuItem = new JMenuItem(title);
-    frame.addInternalFrameListener(new InternalFrameAdapter()
-    {
+    frame.addInternalFrameListener(new InternalFrameAdapter() {
       @Override
-      public void internalFrameActivated(InternalFrameEvent evt)
-      {
+      public void internalFrameActivated(InternalFrameEvent evt) {
         JInternalFrame itf = desktop.getSelectedFrame();
-        if (itf != null)
-        {
-          if (itf instanceof AlignFrame)
-          {
+        if (itf != null) {
+          if (itf instanceof AlignFrame) {
             Jalview.setCurrentAlignFrame((AlignFrame) itf);
           }
           itf.requestFocus();
@@ -968,42 +808,34 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
 
       @Override
-      public void internalFrameClosed(InternalFrameEvent evt)
-      {
+      public void internalFrameClosed(InternalFrameEvent evt) {
         PaintRefresher.RemoveComponent(frame);
 
         /*
-         * defensive check to prevent frames being
-         * added half off the window
+         * defensive check to prevent frames being added half off the window
          */
-        if (openFrameCount > 0)
-        {
+        if (openFrameCount > 0) {
           openFrameCount--;
         }
 
         /*
          * ensure no reference to alignFrame retained by menu item listener
          */
-        if (menuItem.getActionListeners().length > 0)
-        {
+        if (menuItem.getActionListeners().length > 0) {
           menuItem.removeActionListener(menuItem.getActionListeners()[0]);
         }
         windowMenu.remove(menuItem);
       }
     });
 
-    menuItem.addActionListener(new ActionListener()
-    {
+    menuItem.addActionListener(new ActionListener() {
       @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        try
-        {
+      public void actionPerformed(ActionEvent e) {
+        try {
           frame.setSelected(true);
           frame.setIcon(false);
-        } catch (java.beans.PropertyVetoException ex)
-        {
-          // System.err.println(ex.toString());
+        } catch (java.beans.PropertyVetoException ex) {
+
         }
       }
     });
@@ -1015,34 +847,28 @@ public class Desktop extends jalview.jbgui.GDesktop
     windowMenu.add(menuItem);
 
     frame.toFront();
-    try
-    {
+    try {
       frame.setSelected(true);
       frame.requestFocus();
-    } catch (java.beans.PropertyVetoException ve)
-    {
-    } catch (java.lang.ClassCastException cex)
-    {
-      Cache.log.warn(
-              "Squashed a possible GUI implementation error. If you can recreate this, please look at https://issues.jalview.org/browse/JAL-869",
-              cex);
+    } catch (java.beans.PropertyVetoException ve) {
+    } catch (java.lang.ClassCastException cex) {
+      jalview.bin.Console.warn(
+          "Squashed a possible GUI implementation error. If you can recreate this, please look at https://issues.jalview.org/browse/JAL-869",
+          cex);
     }
   }
 
   /**
-   * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
-   * the window
+   * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
+   * window
    * 
    * @param frame
    */
-  private static void setKeyBindings(JInternalFrame frame)
-  {
+  private static void setKeyBindings(JInternalFrame frame) {
     @SuppressWarnings("serial")
-    final Action closeAction = new AbstractAction()
-    {
+    final Action closeAction = new AbstractAction() {
       @Override
-      public void actionPerformed(ActionEvent e)
-      {
+      public void actionPerformed(ActionEvent e) {
         frame.dispose();
       }
     };
@@ -1050,13 +876,10 @@ public class Desktop extends jalview.jbgui.GDesktop
     /*
      * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
      */
-    KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-            InputEvent.CTRL_DOWN_MASK);
-    KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-            ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
+    KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK);
+    KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
 
-    InputMap inputMap = frame
-            .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+    InputMap inputMap = frame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
     String ctrlW = ctrlWKey.toString();
     inputMap.put(ctrlWKey, ctrlW);
     inputMap.put(cmdWKey, ctrlW);
@@ -1066,10 +889,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void lostOwnership(Clipboard clipboard, Transferable contents)
-  {
-    if (!internalCopy)
-    {
+  public void lostOwnership(Clipboard clipboard, Transferable contents) {
+    if (!internalCopy) {
       Desktop.jalviewClipboard = null;
     }
 
@@ -1077,34 +898,28 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void dragEnter(DropTargetDragEvent evt)
-  {
+  public void dragEnter(DropTargetDragEvent evt) {
   }
 
   @Override
-  public void dragExit(DropTargetEvent evt)
-  {
+  public void dragExit(DropTargetEvent evt) {
   }
 
   @Override
-  public void dragOver(DropTargetDragEvent evt)
-  {
+  public void dragOver(DropTargetDragEvent evt) {
   }
 
   @Override
-  public void dropActionChanged(DropTargetDragEvent evt)
-  {
+  public void dropActionChanged(DropTargetDragEvent evt) {
   }
 
   /**
    * DOCUMENT ME!
    * 
-   * @param evt
-   *          DOCUMENT ME!
+   * @param evt DOCUMENT ME!
    */
   @Override
-  public void drop(DropTargetDropEvent evt)
-  {
+  public void drop(DropTargetDropEvent evt) {
     boolean success = true;
     // JAL-1552 - acceptDrop required before getTransferable call for
     // Java's Transferable for native dnd
@@ -1113,47 +928,35 @@ public class Desktop extends jalview.jbgui.GDesktop
     List<Object> files = new ArrayList<>();
     List<DataSourceType> protocols = new ArrayList<>();
 
-    try
-    {
+    try {
       Desktop.transferFromDropTarget(files, protocols, evt, t);
-    } catch (Exception e)
-    {
+    } catch (Exception e) {
       e.printStackTrace();
       success = false;
     }
 
-    if (files != null)
-    {
-      try
-      {
-        for (int i = 0; i < files.size(); i++)
-        {
+    if (files != null) {
+      try {
+        for (int i = 0; i < files.size(); i++) {
           // BH 2018 File or String
           Object file = files.get(i);
           String fileName = file.toString();
-          DataSourceType protocol = (protocols == null)
-                  ? DataSourceType.FILE
-                  : protocols.get(i);
+          DataSourceType protocol = (protocols == null) ? DataSourceType.FILE : protocols.get(i);
           FileFormatI format = null;
 
-          if (fileName.endsWith(".jar"))
-          {
+          if (fileName.endsWith(".jar")) {
             format = FileFormat.Jalview;
 
-          }
-          else
-          {
+          } else {
             format = new IdentifyFile().identify(file, protocol);
           }
-          if (file instanceof File)
-          {
+          if (file instanceof File) {
             Platform.cacheFileData((File) file);
           }
           new FileLoader().LoadFile(null, file, protocol, format);
 
         }
-      } catch (Exception ex)
-      {
+      } catch (Exception ex) {
         success = false;
       }
     }
@@ -1164,27 +967,21 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * DOCUMENT ME!
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param e DOCUMENT ME!
    */
   @Override
-  public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
-  {
+  public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport) {
     String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
-    JalviewFileChooser chooser = JalviewFileChooser.forRead(
-            Cache.getProperty("LAST_DIRECTORY"), fileFormat,
-            BackupFiles.getEnabled());
+    JalviewFileChooser chooser = JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat,
+        BackupFiles.getEnabled());
 
     chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(
-            MessageManager.getString("label.open_local_file"));
+    chooser.setDialogTitle(MessageManager.getString("label.open_local_file"));
     chooser.setToolTipText(MessageManager.getString("action.open"));
 
-    chooser.setResponseHandler(0, new Runnable()
-    {
+    chooser.setResponseHandler(0, new Runnable() {
       @Override
-      public void run()
-      {
+      public void run() {
         File selectedFile = chooser.getSelectedFile();
         Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
 
@@ -1192,23 +989,18 @@ public class Desktop extends jalview.jbgui.GDesktop
 
         /*
          * Call IdentifyFile to verify the file contains what its extension implies.
-         * Skip this step for dynamically added file formats, because
-         * IdentifyFile does not know how to recognise them.
+         * Skip this step for dynamically added file formats, because IdentifyFile does
+         * not know how to recognise them.
          */
-        if (FileFormats.getInstance().isIdentifiable(format))
-        {
-          try
-          {
-            format = new IdentifyFile().identify(selectedFile,
-                    DataSourceType.FILE);
-          } catch (FileFormatException e)
-          {
+        if (FileFormats.getInstance().isIdentifiable(format)) {
+          try {
+            format = new IdentifyFile().identify(selectedFile, DataSourceType.FILE);
+          } catch (FileFormatException e) {
             // format = null; //??
           }
         }
 
-        new FileLoader().LoadFile(viewport, selectedFile,
-                DataSourceType.FILE, format);
+        new FileLoader().LoadFile(viewport, selectedFile, DataSourceType.FILE, format);
       }
     });
     chooser.showOpenDialog(this);
@@ -1220,28 +1012,23 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @param viewport
    */
   @Override
-  public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
-  {
+  public void inputURLMenuItem_actionPerformed(AlignViewport viewport) {
     // This construct allows us to have a wider textfield
     // for viewing
-    JLabel label = new JLabel(
-            MessageManager.getString("label.input_file_url"));
+    JLabel label = new JLabel(MessageManager.getString("label.input_file_url"));
 
     JPanel panel = new JPanel(new GridLayout(2, 1));
     panel.add(label);
 
     /*
-     * the URL to fetch is input in
-     * Java: an editable combobox with history
-     * JS: (pending JAL-3038) a plain text field
+     * the URL to fetch is input in Java: an editable combobox with history JS:
+     * (pending JAL-3038) a plain text field
      */
     JComponent history;
     String urlBase = "https://www.";
-    if (Platform.isJS())
-    {
+    if (Platform.isJS()) {
       history = new JTextField(urlBase, 35);
-    }
-    else
+    } else
     /**
      * Java only
      * 
@@ -1253,10 +1040,8 @@ public class Desktop extends jalview.jbgui.GDesktop
       asCombo.setEditable(true);
       asCombo.addItem(urlBase);
       String historyItems = Cache.getProperty("RECENT_URL");
-      if (historyItems != null)
-      {
-        for (String token : historyItems.split("\\t"))
-        {
+      if (historyItems != null) {
+        for (String token : historyItems.split("\\t")) {
           asCombo.addItem(token);
         }
       }
@@ -1266,122 +1051,87 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     Object[] options = new Object[] { MessageManager.getString("action.ok"),
         MessageManager.getString("action.cancel") };
-    Runnable action = new Runnable()
-    {
+    Runnable action = new Runnable() {
       @Override
-      public void run()
-      {
+      public void run() {
         @SuppressWarnings("unchecked")
-        String url = (history instanceof JTextField
-                ? ((JTextField) history).getText()
-                : ((JComboBox<String>) history).getEditor().getItem()
-                        .toString().trim());
-
-        if (url.toLowerCase().endsWith(".jar"))
-        {
-          if (viewport != null)
-          {
-            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
-                    FileFormat.Jalview);
+        String url = (history instanceof JTextField ? ((JTextField) history).getText()
+            : ((JComboBox<String>) history).getEditor().getItem().toString().trim());
+
+        if (url.toLowerCase(Locale.ROOT).endsWith(".jar")) {
+          if (viewport != null) {
+            new FileLoader().LoadFile(viewport, url, DataSourceType.URL, FileFormat.Jalview);
+          } else {
+            new FileLoader().LoadFile(url, DataSourceType.URL, FileFormat.Jalview);
           }
-          else
-          {
-            new FileLoader().LoadFile(url, DataSourceType.URL,
-                    FileFormat.Jalview);
-          }
-        }
-        else
-        {
+        } else {
           FileFormatI format = null;
-          try
-          {
+          try {
             format = new IdentifyFile().identify(url, DataSourceType.URL);
-          } catch (FileFormatException e)
-          {
+          } catch (FileFormatException e) {
             // TODO revise error handling, distinguish between
             // URL not found and response not valid
           }
 
-          if (format == null)
-          {
-            String msg = MessageManager
-                    .formatMessage("label.couldnt_locate", url);
+          if (format == null) {
+            String msg = MessageManager.formatMessage("label.couldnt_locate", url);
             JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
-                    MessageManager.getString("label.url_not_found"),
-                    JvOptionPane.WARNING_MESSAGE);
+                MessageManager.getString("label.url_not_found"), JvOptionPane.WARNING_MESSAGE);
 
             return;
           }
 
-          if (viewport != null)
-          {
-            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
-                    format);
-          }
-          else
-          {
+          if (viewport != null) {
+            new FileLoader().LoadFile(viewport, url, DataSourceType.URL, format);
+          } else {
             new FileLoader().LoadFile(url, DataSourceType.URL, format);
           }
         }
       }
     };
-    String dialogOption = MessageManager
-            .getString("label.input_alignment_from_url");
-    JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
-            .showInternalDialog(panel, dialogOption,
-                    JvOptionPane.YES_NO_CANCEL_OPTION,
-                    JvOptionPane.PLAIN_MESSAGE, null, options,
-                    MessageManager.getString("action.ok"));
+    String dialogOption = MessageManager.getString("label.input_alignment_from_url");
+    JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action).showInternalDialog(panel, dialogOption,
+        JvOptionPane.YES_NO_CANCEL_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options,
+        MessageManager.getString("action.ok"));
   }
 
   /**
    * Opens the CutAndPaste window for the user to paste an alignment in to
    * 
-   * @param viewPanel
-   *          - if not null, the pasted alignment is added to the current
-   *          alignment; if null, to a new alignment window
+   * @param viewPanel - if not null, the pasted alignment is added to the current
+   *                  alignment; if null, to a new alignment window
    */
   @Override
-  public void inputTextboxMenuItem_actionPerformed(
-          AlignmentViewPanel viewPanel)
-  {
+  public void inputTextboxMenuItem_actionPerformed(AlignmentViewPanel viewPanel) {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     cap.setForInput(viewPanel);
-    Desktop.addInternalFrame(cap,
-            MessageManager.getString("label.cut_paste_alignmen_file"), true,
-            600, 500);
+    Desktop.addInternalFrame(cap, MessageManager.getString("label.cut_paste_alignmen_file"), true, 600, 500);
   }
 
   /*
    * Exit the program
    */
   @Override
-  public void quit()
-  {
+  public void quit() {
     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
     Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
     Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
-    storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
-            getWidth(), getHeight()));
+    storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y, getWidth(), getHeight()));
 
-    if (jconsole != null)
-    {
+    if (jconsole != null) {
       storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
       jconsole.stopConsole();
     }
-    if (jvnews != null)
-    {
+    if (jvnews != null) {
       storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
 
     }
-    if (dialogExecutor != null)
-    {
+    if (dialogExecutor != null) {
       dialogExecutor.shutdownNow();
     }
     closeAll_actionPerformed(null);
 
-    if (groovyConsole != null)
-    {
+    if (groovyConsole != null) {
       // suppress a possible repeat prompt to save script
       groovyConsole.setDirty(false);
       groovyConsole.exit();
@@ -1389,11 +1139,9 @@ public class Desktop extends jalview.jbgui.GDesktop
     System.exit(0);
   }
 
-  private void storeLastKnownDimensions(String string, Rectangle jc)
-  {
-    Cache.log.debug("Storing last known dimensions for " + string + ": x:"
-            + jc.x + " y:" + jc.y + " width:" + jc.width + " height:"
-            + jc.height);
+  private void storeLastKnownDimensions(String string, Rectangle jc) {
+    jalview.bin.Console.debug("Storing last known dimensions for " + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
+        + " height:" + jc.height);
 
     Cache.setProperty(string + "SCREEN_X", jc.x + "");
     Cache.setProperty(string + "SCREEN_Y", jc.y + "");
@@ -1404,17 +1152,13 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * DOCUMENT ME!
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param e DOCUMENT ME!
    */
   @Override
-  public void aboutMenuItem_actionPerformed(ActionEvent e)
-  {
-    new Thread(new Runnable()
-    {
+  public void aboutMenuItem_actionPerformed(ActionEvent e) {
+    new Thread(new Runnable() {
       @Override
-      public void run()
-      {
+      public void run() {
         new SplashScreen(false);
       }
     }).start();
@@ -1422,48 +1166,35 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   /**
    * Returns the html text for the About screen, including any available version
-   * number, build details, author details and citation reference, but without
-   * the enclosing {@code html} tags
+   * number, build details, author details and citation reference, but without the
+   * enclosing {@code html} tags
    * 
    * @return
    */
-  public String getAboutMessage()
-  {
+  public String getAboutMessage() {
     StringBuilder message = new StringBuilder(1024);
-    message.append("<div style=\"font-family: sans-serif;\">")
-            .append("<h1><strong>Version: ")
-            .append(Cache.getProperty("VERSION")).append("</strong></h1>")
-            .append("<strong>Built: <em>")
-            .append(Cache.getDefault("BUILD_DATE", "unknown"))
-            .append("</em> from ").append(Cache.getBuildDetailsForSplash())
-            .append("</strong>");
+    message.append("<div style=\"font-family: sans-serif;\">").append("<h1><strong>Version: ")
+        .append(Cache.getProperty("VERSION")).append("</strong></h1>").append("<strong>Built: <em>")
+        .append(Cache.getDefault("BUILD_DATE", "unknown")).append("</em> from ")
+        .append(Cache.getBuildDetailsForSplash()).append("</strong>");
 
     String latestVersion = Cache.getDefault("LATEST_VERSION", "Checking");
-    if (latestVersion.equals("Checking"))
-    {
+    if (latestVersion.equals("Checking")) {
       // JBP removed this message for 2.11: May be reinstated in future version
       // message.append("<br>...Checking latest version...</br>");
-    }
-    else if (!latestVersion.equals(Cache.getProperty("VERSION")))
-    {
+    } else if (!latestVersion.equals(Cache.getProperty("VERSION"))) {
       boolean red = false;
-      if (Cache.getProperty("VERSION").toLowerCase()
-              .indexOf("automated build") == -1)
-      {
+      if (Cache.getProperty("VERSION").toLowerCase(Locale.ROOT).indexOf("automated build") == -1) {
         red = true;
         // Displayed when code version and jnlp version do not match and code
         // version is not a development build
         message.append("<div style=\"color: #FF0000;font-style: bold;\">");
       }
 
-      message.append("<br>!! Version ")
-              .append(Cache.getDefault("LATEST_VERSION", "..Checking.."))
-              .append(" is available for download from ")
-              .append(Cache.getDefault("www.jalview.org",
-                      "https://www.jalview.org"))
-              .append(" !!");
-      if (red)
-      {
+      message.append("<br>!! Version ").append(Cache.getDefault("LATEST_VERSION", "..Checking.."))
+          .append(" is available for download from ")
+          .append(Cache.getDefault("www.jalview.org", "https://www.jalview.org")).append(" !!");
+      if (red) {
         message.append("</div>");
       }
     }
@@ -1480,15 +1211,11 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Action on requesting Help documentation
    */
   @Override
-  public void documentationMenuItem_actionPerformed()
-  {
-    try
-    {
-      if (Platform.isJS())
-      {
+  public void documentationMenuItem_actionPerformed() {
+    try {
+      if (Platform.isJS()) {
         BrowserLauncher.openURL("https://www.jalview.org/help.html");
-      }
-      else
+      } else
       /**
        * Java only
        * 
@@ -1497,24 +1224,19 @@ public class Desktop extends jalview.jbgui.GDesktop
       {
         Help.showHelpWindow();
       }
-    } catch (Exception ex)
-    {
+    } catch (Exception ex) {
       System.err.println("Error opening help: " + ex.getMessage());
     }
   }
 
   @Override
-  public void closeAll_actionPerformed(ActionEvent e)
-  {
+  public void closeAll_actionPerformed(ActionEvent e) {
     // TODO show a progress bar while closing?
     JInternalFrame[] frames = desktop.getAllFrames();
-    for (int i = 0; i < frames.length; i++)
-    {
-      try
-      {
+    for (int i = 0; i < frames.length; i++) {
+      try {
         frames[i].setClosed(true);
-      } catch (java.beans.PropertyVetoException ex)
-      {
+      } catch (java.beans.PropertyVetoException ex) {
       }
     }
     Jalview.setCurrentAlignFrame(null);
@@ -1524,28 +1246,23 @@ public class Desktop extends jalview.jbgui.GDesktop
      * reset state of singleton objects as appropriate (clear down session state
      * when all windows are closed)
      */
-    StructureSelectionManager ssm = StructureSelectionManager
-            .getStructureSelectionManager(this);
-    if (ssm != null)
-    {
+    StructureSelectionManager ssm = StructureSelectionManager.getStructureSelectionManager(this);
+    if (ssm != null) {
       ssm.resetAll();
     }
   }
 
   @Override
-  public void raiseRelated_actionPerformed(ActionEvent e)
-  {
+  public void raiseRelated_actionPerformed(ActionEvent e) {
     reorderAssociatedWindows(false, false);
   }
 
   @Override
-  public void minimizeAssociated_actionPerformed(ActionEvent e)
-  {
+  public void minimizeAssociated_actionPerformed(ActionEvent e) {
     reorderAssociatedWindows(true, false);
   }
 
-  void closeAssociatedWindows()
-  {
+  void closeAssociatedWindows() {
     reorderAssociatedWindows(false, true);
   }
 
@@ -1556,24 +1273,21 @@ public class Desktop extends jalview.jbgui.GDesktop
    * ActionEvent)
    */
   @Override
-  protected void garbageCollect_actionPerformed(ActionEvent e)
-  {
+  protected void garbageCollect_actionPerformed(ActionEvent e) {
     // We simply collect the garbage
-    Cache.log.debug("Collecting garbage...");
+    jalview.bin.Console.debug("Collecting garbage...");
     System.gc();
-    Cache.log.debug("Finished garbage collection.");
+    jalview.bin.Console.debug("Finished garbage collection.");
   }
 
   /*
    * (non-Javadoc)
    * 
-   * @see
-   * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
-   * )
+   * @see jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.
+   * ActionEvent )
    */
   @Override
-  protected void showMemusage_actionPerformed(ActionEvent e)
-  {
+  protected void showMemusage_actionPerformed(ActionEvent e) {
     desktop.showMemoryUsage(showMemusage.isSelected());
   }
 
@@ -1585,8 +1299,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    * )
    */
   @Override
-  protected void showConsole_actionPerformed(ActionEvent e)
-  {
+  protected void showConsole_actionPerformed(ActionEvent e) {
     showConsole(showConsole.isSelected());
   }
 
@@ -1597,89 +1310,61 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param selected
    */
-  void showConsole(boolean selected)
-  {
+  void showConsole(boolean selected) {
     // TODO: decide if we should update properties file
     if (jconsole != null) // BH 2018
     {
       showConsole.setSelected(selected);
-      Cache.setProperty("SHOW_JAVA_CONSOLE",
-              Boolean.valueOf(selected).toString());
+      Cache.setProperty("SHOW_JAVA_CONSOLE", Boolean.valueOf(selected).toString());
       jconsole.setVisible(selected);
     }
   }
 
-  void reorderAssociatedWindows(boolean minimize, boolean close)
-  {
+  void reorderAssociatedWindows(boolean minimize, boolean close) {
     JInternalFrame[] frames = desktop.getAllFrames();
-    if (frames == null || frames.length < 1)
-    {
+    if (frames == null || frames.length < 1) {
       return;
     }
 
     AlignmentViewport source = null, target = null;
-    if (frames[0] instanceof AlignFrame)
-    {
+    if (frames[0] instanceof AlignFrame) {
       source = ((AlignFrame) frames[0]).getCurrentView();
-    }
-    else if (frames[0] instanceof TreePanel)
-    {
+    } else if (frames[0] instanceof TreePanel) {
       source = ((TreePanel) frames[0]).getViewPort();
-    }
-    else if (frames[0] instanceof PCAPanel)
-    {
+    } else if (frames[0] instanceof PCAPanel) {
       source = ((PCAPanel) frames[0]).av;
-    }
-    else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
-    {
+    } else if (frames[0].getContentPane() instanceof PairwiseAlignPanel) {
       source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
     }
 
-    if (source != null)
-    {
-      for (int i = 0; i < frames.length; i++)
-      {
+    if (source != null) {
+      for (int i = 0; i < frames.length; i++) {
         target = null;
-        if (frames[i] == null)
-        {
+        if (frames[i] == null) {
           continue;
         }
-        if (frames[i] instanceof AlignFrame)
-        {
+        if (frames[i] instanceof AlignFrame) {
           target = ((AlignFrame) frames[i]).getCurrentView();
-        }
-        else if (frames[i] instanceof TreePanel)
-        {
+        } else if (frames[i] instanceof TreePanel) {
           target = ((TreePanel) frames[i]).getViewPort();
-        }
-        else if (frames[i] instanceof PCAPanel)
-        {
+        } else if (frames[i] instanceof PCAPanel) {
           target = ((PCAPanel) frames[i]).av;
-        }
-        else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
-        {
+        } else if (frames[i].getContentPane() instanceof PairwiseAlignPanel) {
           target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
         }
 
-        if (source == target)
-        {
-          try
-          {
-            if (close)
-            {
+        if (source == target) {
+          try {
+            if (close) {
               frames[i].setClosed(true);
-            }
-            else
-            {
+            } else {
               frames[i].setIcon(minimize);
-              if (!minimize)
-              {
+              if (!minimize) {
                 frames[i].toFront();
               }
             }
 
-          } catch (java.beans.PropertyVetoException ex)
-          {
+          } catch (java.beans.PropertyVetoException ex) {
           }
         }
       }
@@ -1689,12 +1374,10 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * DOCUMENT ME!
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param e DOCUMENT ME!
    */
   @Override
-  protected void preferences_actionPerformed(ActionEvent e)
-  {
+  protected void preferences_actionPerformed(ActionEvent e) {
     Preferences.openPreferences();
   }
 
@@ -1703,86 +1386,66 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Jalview project file
    */
   @Override
-  public void saveState_actionPerformed()
-  {
+  public void saveState_actionPerformed() {
     saveState_actionPerformed(false);
   }
 
-  public void saveState_actionPerformed(boolean saveAs)
-  {
+  public void saveState_actionPerformed(boolean saveAs) {
     java.io.File projectFile = getProjectFile();
     // autoSave indicates we already have a file and don't need to ask
-    boolean autoSave = projectFile != null && !saveAs
-            && BackupFiles.getEnabled();
+    boolean autoSave = projectFile != null && !saveAs && BackupFiles.getEnabled();
 
     // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
     // saveAs="+saveAs+", Backups
     // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
 
     boolean approveSave = false;
-    if (!autoSave)
-    {
-      JalviewFileChooser chooser = new JalviewFileChooser("jvp",
-              "Jalview Project");
+    if (!autoSave) {
+      JalviewFileChooser chooser = new JalviewFileChooser("jvp", "Jalview Project");
 
       chooser.setFileView(new JalviewFileView());
       chooser.setDialogTitle(MessageManager.getString("label.save_state"));
 
       int value = chooser.showSaveDialog(this);
 
-      if (value == JalviewFileChooser.APPROVE_OPTION)
-      {
+      if (value == JalviewFileChooser.APPROVE_OPTION) {
         projectFile = chooser.getSelectedFile();
         setProjectFile(projectFile);
         approveSave = true;
       }
     }
 
-    if (approveSave || autoSave)
-    {
+    if (approveSave || autoSave) {
       final Desktop me = this;
       final java.io.File chosenFile = projectFile;
-      new Thread(new Runnable()
-      {
+      new Thread(new Runnable() {
         @Override
-        public void run()
-        {
+        public void run() {
           // TODO: refactor to Jalview desktop session controller action.
-          setProgressBar(MessageManager.formatMessage(
-                  "label.saving_jalview_project", new Object[]
-                  { chosenFile.getName() }), chosenFile.hashCode());
+          setProgressBar(
+              MessageManager.formatMessage("label.saving_jalview_project", new Object[] { chosenFile.getName() }),
+              chosenFile.hashCode());
           Cache.setProperty("LAST_DIRECTORY", chosenFile.getParent());
           // TODO catch and handle errors for savestate
           // TODO prevent user from messing with the Desktop whilst we're saving
-          try
-          {
+          try {
             boolean doBackup = BackupFiles.getEnabled();
-            BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile)
-                    : null;
+            BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
 
-            new Jalview2XML().saveState(
-                    doBackup ? backupfiles.getTempFile() : chosenFile);
+            new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
 
-            if (doBackup)
-            {
+            if (doBackup) {
               backupfiles.setWriteSuccess(true);
               backupfiles.rollBackupsAndRenameTempFile();
             }
-          } catch (OutOfMemoryError oom)
-          {
-            new OOMWarning("Whilst saving current state to "
-                    + chosenFile.getName(), oom);
-          } catch (Exception ex)
-          {
-            Cache.log.error("Problems whilst trying to save to "
-                    + chosenFile.getName(), ex);
+          } catch (OutOfMemoryError oom) {
+            new OOMWarning("Whilst saving current state to " + chosenFile.getName(), oom);
+          } catch (Exception ex) {
+            jalview.bin.Console.error("Problems whilst trying to save to " + chosenFile.getName(), ex);
             JvOptionPane.showMessageDialog(me,
-                    MessageManager.formatMessage(
-                            "label.error_whilst_saving_current_state_to",
-                            new Object[]
-                            { chosenFile.getName() }),
-                    MessageManager.getString("label.couldnt_save_project"),
-                    JvOptionPane.WARNING_MESSAGE);
+                MessageManager.formatMessage("label.error_whilst_saving_current_state_to",
+                    new Object[] { chosenFile.getName() }),
+                MessageManager.getString("label.couldnt_save_project"), JvOptionPane.WARNING_MESSAGE);
           }
           setProgressBar(null, chosenFile.hashCode());
         }
@@ -1791,18 +1454,15 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void saveAsState_actionPerformed(ActionEvent e)
-  {
+  public void saveAsState_actionPerformed(ActionEvent e) {
     saveState_actionPerformed(true);
   }
 
-  private void setProjectFile(File choice)
-  {
+  private void setProjectFile(File choice) {
     this.projectFile = choice;
   }
 
-  public File getProjectFile()
-  {
+  public File getProjectFile() {
     return this.projectFile;
   }
 
@@ -1811,51 +1471,35 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Jalview project
    */
   @Override
-  public void loadState_actionPerformed()
-  {
+  public void loadState_actionPerformed() {
     final String[] suffix = new String[] { "jvp", "jar" };
-    final String[] desc = new String[] { "Jalview Project",
-        "Jalview Project (old)" };
-    JalviewFileChooser chooser = new JalviewFileChooser(
-            Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
-            "Jalview Project", true, BackupFiles.getEnabled()); // last two
-                                                                // booleans:
-                                                                // allFiles,
+    final String[] desc = new String[] { "Jalview Project", "Jalview Project (old)" };
+    JalviewFileChooser chooser = new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
+        "Jalview Project", true, BackupFiles.getEnabled()); // last two
+                                                            // booleans:
+                                                            // allFiles,
     // allowBackupFiles
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
-    chooser.setResponseHandler(0, new Runnable()
-    {
+    chooser.setResponseHandler(0, new Runnable() {
       @Override
-      public void run()
-      {
+      public void run() {
         File selectedFile = chooser.getSelectedFile();
         setProjectFile(selectedFile);
         String choice = selectedFile.getAbsolutePath();
         Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
-        new Thread(new Runnable()
-        {
+        new Thread(new Runnable() {
           @Override
-          public void run()
-          {
-            try
-            {
+          public void run() {
+            try {
               new Jalview2XML().loadJalviewAlign(selectedFile);
-            } catch (OutOfMemoryError oom)
-            {
+            } catch (OutOfMemoryError oom) {
               new OOMWarning("Whilst loading project from " + choice, oom);
-            } catch (Exception ex)
-            {
-              Cache.log.error(
-                      "Problems whilst loading project from " + choice, ex);
+            } catch (Exception ex) {
+              jalview.bin.Console.error("Problems whilst loading project from " + choice, ex);
               JvOptionPane.showMessageDialog(Desktop.desktop,
-                      MessageManager.formatMessage(
-                              "label.error_whilst_loading_project_from",
-                              new Object[]
-                              { choice }),
-                      MessageManager
-                              .getString("label.couldnt_load_project"),
-                      JvOptionPane.WARNING_MESSAGE);
+                  MessageManager.formatMessage("label.error_whilst_loading_project_from", new Object[] { choice }),
+                  MessageManager.getString("label.couldnt_load_project"), JvOptionPane.WARNING_MESSAGE);
             }
           }
         }, "Project Loader").start();
@@ -1866,8 +1510,7 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void inputSequence_actionPerformed(ActionEvent e)
-  {
+  public void inputSequence_actionPerformed(ActionEvent e) {
     new SequenceFetcher(this);
   }
 
@@ -1875,21 +1518,16 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
 
-  public void startLoading(final Object fileName)
-  {
-    if (fileLoadingCount == 0)
-    {
-      fileLoadingPanels.add(addProgressPanel(MessageManager
-              .formatMessage("label.loading_file", new Object[]
-              { fileName })));
+  public void startLoading(final Object fileName) {
+    if (fileLoadingCount == 0) {
+      fileLoadingPanels
+          .add(addProgressPanel(MessageManager.formatMessage("label.loading_file", new Object[] { fileName })));
     }
     fileLoadingCount++;
   }
 
-  private JPanel addProgressPanel(String string)
-  {
-    if (progressPanel == null)
-    {
+  private JPanel addProgressPanel(String string) {
+    if (progressPanel == null) {
       progressPanel = new JPanel(new GridLayout(1, 1));
       totalProgressCount = 0;
       instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
@@ -1902,8 +1540,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     thisprogress.add(progressBar, BorderLayout.CENTER);
     progressPanel.add(thisprogress);
-    ((GridLayout) progressPanel.getLayout()).setRows(
-            ((GridLayout) progressPanel.getLayout()).getRows() + 1);
+    ((GridLayout) progressPanel.getLayout()).setRows(((GridLayout) progressPanel.getLayout()).getRows() + 1);
     ++totalProgressCount;
     instance.validate();
     return thisprogress;
@@ -1911,17 +1548,13 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   int totalProgressCount = 0;
 
-  private void removeProgressPanel(JPanel progbar)
-  {
-    if (progressPanel != null)
-    {
-      synchronized (progressPanel)
-      {
+  private void removeProgressPanel(JPanel progbar) {
+    if (progressPanel != null) {
+      synchronized (progressPanel) {
         progressPanel.remove(progbar);
         GridLayout gl = (GridLayout) progressPanel.getLayout();
         gl.setRows(gl.getRows() - 1);
-        if (--totalProgressCount < 1)
-        {
+        if (--totalProgressCount < 1) {
           this.getContentPane().remove(progressPanel);
           progressPanel = null;
         }
@@ -1930,13 +1563,10 @@ public class Desktop extends jalview.jbgui.GDesktop
     validate();
   }
 
-  public void stopLoading()
-  {
+  public void stopLoading() {
     fileLoadingCount--;
-    if (fileLoadingCount < 1)
-    {
-      while (fileLoadingPanels.size() > 0)
-      {
+    if (fileLoadingCount < 1) {
+      while (fileLoadingPanels.size() > 0) {
         removeProgressPanel(fileLoadingPanels.remove(0));
       }
       fileLoadingPanels.clear();
@@ -1945,45 +1575,35 @@ public class Desktop extends jalview.jbgui.GDesktop
     validate();
   }
 
-  public static int getViewCount(String alignmentId)
-  {
+  public static int getViewCount(String alignmentId) {
     AlignmentViewport[] aps = getViewports(alignmentId);
     return (aps == null) ? 0 : aps.length;
   }
 
   /**
    * 
-   * @param alignmentId
-   *          - if null, all sets are returned
+   * @param alignmentId - if null, all sets are returned
    * @return all AlignmentPanels concerning the alignmentId sequence set
    */
-  public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
-  {
-    if (Desktop.desktop == null)
-    {
+  public static AlignmentPanel[] getAlignmentPanels(String alignmentId) {
+    if (Desktop.desktop == null) {
       // no frames created and in headless mode
       // TODO: verify that frames are recoverable when in headless mode
       return null;
     }
     List<AlignmentPanel> aps = new ArrayList<>();
     AlignFrame[] frames = getAlignFrames();
-    if (frames == null)
-    {
+    if (frames == null) {
       return null;
     }
-    for (AlignFrame af : frames)
-    {
-      for (AlignmentPanel ap : af.alignPanels)
-      {
-        if (alignmentId == null
-                || alignmentId.equals(ap.av.getSequenceSetId()))
-        {
+    for (AlignFrame af : frames) {
+      for (AlignmentPanel ap : af.alignPanels) {
+        if (alignmentId == null || alignmentId.equals(ap.av.getSequenceSetId())) {
           aps.add(ap);
         }
       }
     }
-    if (aps.size() == 0)
-    {
+    if (aps.size() == 0) {
       return null;
     }
     AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
@@ -1993,42 +1613,29 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * get all the viewports on an alignment.
    * 
-   * @param sequenceSetId
-   *          unique alignment id (may be null - all viewports returned in that
-   *          case)
+   * @param sequenceSetId unique alignment id (may be null - all viewports
+   *                      returned in that case)
    * @return all viewports on the alignment bound to sequenceSetId
    */
-  public static AlignmentViewport[] getViewports(String sequenceSetId)
-  {
+  public static AlignmentViewport[] getViewports(String sequenceSetId) {
     List<AlignmentViewport> viewp = new ArrayList<>();
-    if (desktop != null)
-    {
+    if (desktop != null) {
       AlignFrame[] frames = Desktop.getAlignFrames();
 
-      for (AlignFrame afr : frames)
-      {
-        if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
-                .equals(sequenceSetId))
-        {
-          if (afr.alignPanels != null)
-          {
-            for (AlignmentPanel ap : afr.alignPanels)
-            {
-              if (sequenceSetId == null
-                      || sequenceSetId.equals(ap.av.getSequenceSetId()))
-              {
+      for (AlignFrame afr : frames) {
+        if (sequenceSetId == null || afr.getViewport().getSequenceSetId().equals(sequenceSetId)) {
+          if (afr.alignPanels != null) {
+            for (AlignmentPanel ap : afr.alignPanels) {
+              if (sequenceSetId == null || sequenceSetId.equals(ap.av.getSequenceSetId())) {
                 viewp.add(ap.av);
               }
             }
-          }
-          else
-          {
+          } else {
             viewp.add(afr.getViewport());
           }
         }
       }
-      if (viewp.size() > 0)
-      {
+      if (viewp.size() > 0) {
         return viewp.toArray(new AlignmentViewport[viewp.size()]);
       }
     }
@@ -2040,56 +1647,47 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param af
    */
-  public static void explodeViews(AlignFrame af)
-  {
+  public static void explodeViews(AlignFrame af) {
     int size = af.alignPanels.size();
-    if (size < 2)
-    {
+    if (size < 2) {
       return;
     }
 
     // FIXME: ideally should use UI interface API
-    FeatureSettings viewFeatureSettings = (af.featureSettings != null
-            && af.featureSettings.isOpen()) ? af.featureSettings : null;
+    FeatureSettings viewFeatureSettings = (af.featureSettings != null && af.featureSettings.isOpen())
+        ? af.featureSettings
+        : null;
     Rectangle fsBounds = af.getFeatureSettingsGeometry();
-    for (int i = 0; i < size; i++)
-    {
+    for (int i = 0; i < size; i++) {
       AlignmentPanel ap = af.alignPanels.get(i);
 
       AlignFrame newaf = new AlignFrame(ap);
 
       // transfer reference for existing feature settings to new alignFrame
-      if (ap == af.alignPanel)
-      {
-        if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap)
-        {
+      if (ap == af.alignPanel) {
+        if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap) {
           newaf.featureSettings = viewFeatureSettings;
         }
         newaf.setFeatureSettingsGeometry(fsBounds);
       }
 
       /*
-       * Restore the view's last exploded frame geometry if known. Multiple
-       * views from one exploded frame share and restore the same (frame)
-       * position and size.
+       * Restore the view's last exploded frame geometry if known. Multiple views from
+       * one exploded frame share and restore the same (frame) position and size.
        */
       Rectangle geometry = ap.av.getExplodedGeometry();
-      if (geometry != null)
-      {
+      if (geometry != null) {
         newaf.setBounds(geometry);
       }
 
       ap.av.setGatherViewsHere(false);
 
-      addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
-              AlignFrame.DEFAULT_HEIGHT);
+      addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
       // and materialise a new feature settings dialog instance for the new
       // alignframe
       // (closes the old as if 'OK' was pressed)
-      if (ap == af.alignPanel && newaf.featureSettings != null
-              && newaf.featureSettings.isOpen()
-              && af.alignPanel.getAlignViewport().isShowSequenceFeatures())
-      {
+      if (ap == af.alignPanel && newaf.featureSettings != null && newaf.featureSettings.isOpen()
+          && af.alignPanel.getAlignViewport().isShowSequenceFeatures()) {
         newaf.showFeatureSettingsUI();
       }
     }
@@ -2102,29 +1700,24 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   /**
    * Gather expanded views (separate AlignFrame's) with the same sequence set
-   * identifier back in to this frame as additional views, and close the
-   * expanded views. Note the expanded frames may themselves have multiple
-   * views. We take the lot.
+   * identifier back in to this frame as additional views, and close the expanded
+   * views. Note the expanded frames may themselves have multiple views. We take
+   * the lot.
    * 
    * @param source
    */
-  public void gatherViews(AlignFrame source)
-  {
+  public void gatherViews(AlignFrame source) {
     source.viewport.setGatherViewsHere(true);
     source.viewport.setExplodedGeometry(source.getBounds());
     JInternalFrame[] frames = desktop.getAllFrames();
     String viewId = source.viewport.getSequenceSetId();
-    for (int t = 0; t < frames.length; t++)
-    {
-      if (frames[t] instanceof AlignFrame && frames[t] != source)
-      {
+    for (int t = 0; t < frames.length; t++) {
+      if (frames[t] instanceof AlignFrame && frames[t] != source) {
         AlignFrame af = (AlignFrame) frames[t];
         boolean gatherThis = false;
-        for (int a = 0; a < af.alignPanels.size(); a++)
-        {
+        for (int a = 0; a < af.alignPanels.size(); a++) {
           AlignmentPanel ap = af.alignPanels.get(a);
-          if (viewId.equals(ap.av.getSequenceSetId()))
-          {
+          if (viewId.equals(ap.av.getSequenceSetId())) {
             gatherThis = true;
             ap.av.setGatherViewsHere(false);
             ap.av.setExplodedGeometry(af.getBounds());
@@ -2132,19 +1725,13 @@ public class Desktop extends jalview.jbgui.GDesktop
           }
         }
 
-        if (gatherThis)
-        {
-          if (af.featureSettings != null && af.featureSettings.isOpen())
-          {
-            if (source.featureSettings == null)
-            {
+        if (gatherThis) {
+          if (af.featureSettings != null && af.featureSettings.isOpen()) {
+            if (source.featureSettings == null) {
               // preserve the feature settings geometry for this frame
               source.featureSettings = af.featureSettings;
-              source.setFeatureSettingsGeometry(
-                      af.getFeatureSettingsGeometry());
-            }
-            else
-            {
+              source.setFeatureSettingsGeometry(af.getFeatureSettingsGeometry());
+            } else {
               // close it and forget
               af.featureSettings.close();
             }
@@ -2156,14 +1743,13 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
 
     // refresh the feature setting UI for the source frame if it exists
-    if (source.featureSettings != null && source.featureSettings.isOpen())
-    {
+    if (source.featureSettings != null && source.featureSettings.isOpen()) {
       source.showFeatureSettingsUI();
     }
+
   }
 
-  public JInternalFrame[] getAllFrames()
-  {
+  public JInternalFrame[] getAllFrames() {
     return desktop.getAllFrames();
   }
 
@@ -2173,49 +1759,37 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param url
    */
-  public void checkForQuestionnaire(String url)
-  {
+  public void checkForQuestionnaire(String url) {
     UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
     // javax.swing.SwingUtilities.invokeLater(jvq);
     new Thread(jvq).start();
   }
 
-  public void checkURLLinks()
-  {
+  public void checkURLLinks() {
     // Thread off the URL link checker
-    addDialogThread(new Runnable()
-    {
+    addDialogThread(new Runnable() {
       @Override
-      public void run()
-      {
-        if (Cache.getDefault("CHECKURLLINKS", true))
-        {
+      public void run() {
+        if (Cache.getDefault("CHECKURLLINKS", true)) {
           // check what the actual links are - if it's just the default don't
           // bother with the warning
-          List<String> links = Preferences.sequenceUrlLinks
-                  .getLinksForMenu();
+          List<String> links = Preferences.sequenceUrlLinks.getLinksForMenu();
 
           // only need to check links if there is one with a
           // SEQUENCE_ID which is not the default EMBL_EBI link
           ListIterator<String> li = links.listIterator();
           boolean check = false;
           List<JLabel> urls = new ArrayList<>();
-          while (li.hasNext())
-          {
+          while (li.hasNext()) {
             String link = li.next();
-            if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
-                    && !UrlConstants.isDefaultString(link))
-            {
+            if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID) && !UrlConstants.isDefaultString(link)) {
               check = true;
               int barPos = link.indexOf("|");
-              String urlMsg = barPos == -1 ? link
-                      : link.substring(0, barPos) + ": "
-                              + link.substring(barPos + 1);
+              String urlMsg = barPos == -1 ? link : link.substring(0, barPos) + ": " + link.substring(barPos + 1);
               urls.add(new JLabel(urlMsg));
             }
           }
-          if (!check)
-          {
+          if (!check) {
             return;
           }
 
@@ -2224,36 +1798,27 @@ public class Desktop extends jalview.jbgui.GDesktop
           JPanel msgPanel = new JPanel();
           msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
           msgPanel.add(Box.createVerticalGlue());
-          JLabel msg = new JLabel(MessageManager
-                  .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
-          JLabel msg2 = new JLabel(MessageManager
-                  .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
+          JLabel msg = new JLabel(MessageManager.getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
+          JLabel msg2 = new JLabel(MessageManager.getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
           msgPanel.add(msg);
-          for (JLabel url : urls)
-          {
+          for (JLabel url : urls) {
             msgPanel.add(url);
           }
           msgPanel.add(msg2);
 
-          final JCheckBox jcb = new JCheckBox(
-                  MessageManager.getString("label.do_not_display_again"));
-          jcb.addActionListener(new ActionListener()
-          {
+          final JCheckBox jcb = new JCheckBox(MessageManager.getString("label.do_not_display_again"));
+          jcb.addActionListener(new ActionListener() {
             @Override
-            public void actionPerformed(ActionEvent e)
-            {
+            public void actionPerformed(ActionEvent e) {
               // update Cache settings for "don't show this again"
               boolean showWarningAgain = !jcb.isSelected();
-              Cache.setProperty("CHECKURLLINKS",
-                      Boolean.valueOf(showWarningAgain).toString());
+              Cache.setProperty("CHECKURLLINKS", Boolean.valueOf(showWarningAgain).toString());
             }
           });
           msgPanel.add(jcb);
 
           JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
-                  MessageManager
-                          .getString("label.SEQUENCE_ID_no_longer_used"),
-                  JvOptionPane.WARNING_MESSAGE);
+              MessageManager.getString("label.SEQUENCE_ID_no_longer_used"), JvOptionPane.WARNING_MESSAGE);
         }
       }
     });
@@ -2261,13 +1826,11 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   /**
    * Proxy class for JDesktopPane which optionally displays the current memory
-   * usage and highlights the desktop area with a red bar if free memory runs
-   * low.
+   * usage and highlights the desktop area with a red bar if free memory runs low.
    * 
    * @author AMW
    */
-  public class MyDesktopPane extends JDesktopPane implements Runnable
-  {
+  public class MyDesktopPane extends JDesktopPane implements Runnable {
     private static final float ONE_MB = 1048576f;
 
     boolean showMemoryUsage = false;
@@ -2276,41 +1839,33 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     java.text.NumberFormat df;
 
-    float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
-            percentUsage;
+    float maxMemory, allocatedMemory, freeMemory, totalFreeMemory, percentUsage;
 
-    public MyDesktopPane(boolean showMemoryUsage)
-    {
+    public MyDesktopPane(boolean showMemoryUsage) {
       showMemoryUsage(showMemoryUsage);
     }
 
-    public void showMemoryUsage(boolean showMemory)
-    {
+    public void showMemoryUsage(boolean showMemory) {
       this.showMemoryUsage = showMemory;
-      if (showMemory)
-      {
+      if (showMemory) {
         Thread worker = new Thread(this);
         worker.start();
       }
       repaint();
     }
 
-    public boolean isShowMemoryUsage()
-    {
+    public boolean isShowMemoryUsage() {
       return showMemoryUsage;
     }
 
     @Override
-    public void run()
-    {
+    public void run() {
       df = java.text.NumberFormat.getNumberInstance();
       df.setMaximumFractionDigits(2);
       runtime = Runtime.getRuntime();
 
-      while (showMemoryUsage)
-      {
-        try
-        {
+      while (showMemoryUsage) {
+        try {
           maxMemory = runtime.maxMemory() / ONE_MB;
           allocatedMemory = runtime.totalMemory() / ONE_MB;
           freeMemory = runtime.freeMemory() / ONE_MB;
@@ -2327,30 +1882,24 @@ public class Desktop extends jalview.jbgui.GDesktop
           repaint();
           // sleep after showing usage
           Thread.sleep(3000);
-        } catch (Exception ex)
-        {
+        } catch (Exception ex) {
           ex.printStackTrace();
         }
       }
     }
 
     @Override
-    public void paintComponent(Graphics g)
-    {
-      if (showMemoryUsage && g != null && df != null)
-      {
-        if (percentUsage < 20)
-        {
+    public void paintComponent(Graphics g) {
+      if (showMemoryUsage && g != null && df != null) {
+        if (percentUsage < 20) {
           g.setColor(Color.red);
         }
         FontMetrics fm = g.getFontMetrics();
-        if (fm != null)
-        {
-          g.drawString(MessageManager.formatMessage("label.memory_stats",
-                  new Object[]
-                  { df.format(totalFreeMemory), df.format(maxMemory),
-                      df.format(percentUsage) }),
-                  10, getHeight() - fm.getHeight());
+        if (fm != null) {
+          g.drawString(
+              MessageManager.formatMessage("label.memory_stats",
+                  new Object[] { df.format(totalFreeMemory), df.format(maxMemory), df.format(percentUsage) }),
+              10, getHeight() - fm.getHeight());
         }
       }
 
@@ -2364,46 +1913,36 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return an array of AlignFrame, or null if none found
    */
-  public static AlignFrame[] getAlignFrames()
-  {
-    if (Jalview.isHeadlessMode())
-    {
+  public static AlignFrame[] getAlignFrames() {
+    if (Jalview.isHeadlessMode()) {
       // Desktop.desktop is null in headless mode
       return new AlignFrame[] { Jalview.currentAlignFrame };
     }
 
     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
 
-    if (frames == null)
-    {
+    if (frames == null) {
       return null;
     }
     List<AlignFrame> avp = new ArrayList<>();
     // REVERSE ORDER
-    for (int i = frames.length - 1; i > -1; i--)
-    {
-      if (frames[i] instanceof AlignFrame)
-      {
+    for (int i = frames.length - 1; i > -1; i--) {
+      if (frames[i] instanceof AlignFrame) {
         avp.add((AlignFrame) frames[i]);
-      }
-      else if (frames[i] instanceof SplitFrame)
-      {
+      } else if (frames[i] instanceof SplitFrame) {
         /*
          * Also check for a split frame containing an AlignFrame
          */
         GSplitFrame sf = (GSplitFrame) frames[i];
-        if (sf.getTopFrame() instanceof AlignFrame)
-        {
+        if (sf.getTopFrame() instanceof AlignFrame) {
           avp.add((AlignFrame) sf.getTopFrame());
         }
-        if (sf.getBottomFrame() instanceof AlignFrame)
-        {
+        if (sf.getBottomFrame() instanceof AlignFrame) {
           avp.add((AlignFrame) sf.getBottomFrame());
         }
       }
     }
-    if (avp.size() == 0)
-    {
+    if (avp.size() == 0) {
       return null;
     }
     AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
@@ -2415,26 +1954,21 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return
    */
-  public GStructureViewer[] getJmols()
-  {
+  public GStructureViewer[] getJmols() {
     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
 
-    if (frames == null)
-    {
+    if (frames == null) {
       return null;
     }
     List<GStructureViewer> avp = new ArrayList<>();
     // REVERSE ORDER
-    for (int i = frames.length - 1; i > -1; i--)
-    {
-      if (frames[i] instanceof AppJmol)
-      {
+    for (int i = frames.length - 1; i > -1; i--) {
+      if (frames[i] instanceof AppJmol) {
         GStructureViewer af = (GStructureViewer) frames[i];
         avp.add(af);
       }
     }
-    if (avp.size() == 0)
-    {
+    if (avp.size() == 0) {
       return null;
     }
     GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
@@ -2445,45 +1979,37 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Add Groovy Support to Jalview
    */
   @Override
-  public void groovyShell_actionPerformed()
-  {
-    try
-    {
+  public void groovyShell_actionPerformed() {
+    try {
       openGroovyConsole();
-    } catch (Exception ex)
-    {
-      Cache.log.error("Groovy Shell Creation failed.", ex);
+    } catch (Exception ex) {
+      jalview.bin.Console.error("Groovy Shell Creation failed.", ex);
       JvOptionPane.showInternalMessageDialog(Desktop.desktop,
 
-              MessageManager.getString("label.couldnt_create_groovy_shell"),
-              MessageManager.getString("label.groovy_support_failed"),
-              JvOptionPane.ERROR_MESSAGE);
+          MessageManager.getString("label.couldnt_create_groovy_shell"),
+          MessageManager.getString("label.groovy_support_failed"), JvOptionPane.ERROR_MESSAGE);
     }
   }
 
   /**
    * Open the Groovy console
    */
-  void openGroovyConsole()
-  {
-    if (groovyConsole == null)
-    {
+  void openGroovyConsole() {
+    if (groovyConsole == null) {
       groovyConsole = new groovy.ui.Console();
       groovyConsole.setVariable("Jalview", this);
       groovyConsole.run();
 
       /*
        * We allow only one console at a time, so that AlignFrame menu option
-       * 'Calculate | Run Groovy script' is unambiguous.
-       * Disable 'Groovy Console', and enable 'Run script', when the console is 
-       * opened, and the reverse when it is closed
+       * 'Calculate | Run Groovy script' is unambiguous. Disable 'Groovy Console', and
+       * enable 'Run script', when the console is opened, and the reverse when it is
+       * closed
        */
       Window window = (Window) groovyConsole.getFrame();
-      window.addWindowListener(new WindowAdapter()
-      {
+      window.addWindowListener(new WindowAdapter() {
         @Override
-        public void windowClosed(WindowEvent e)
-        {
+        public void windowClosed(WindowEvent e) {
           /*
            * rebind CMD-Q from Groovy Console to Jalview Quit
            */
@@ -2499,30 +2025,23 @@ public class Desktop extends jalview.jbgui.GDesktop
     ((Window) groovyConsole.getFrame()).setVisible(true);
 
     /*
-     * if we got this far, enable 'Run Groovy' in AlignFrame menus
-     * and disable opening a second console
+     * if we got this far, enable 'Run Groovy' in AlignFrame menus and disable
+     * opening a second console
      */
     enableExecuteGroovy(true);
   }
 
   /**
-   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
-   * binding when opened
-   */
-  protected void addQuitHandler()
-  {
-    getRootPane()
-            .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                    KeyStroke
-                            .getKeyStroke(KeyEvent.VK_Q,
-                                    jalview.util.ShortcutKeyMaskExWrapper
-                                            .getMenuShortcutKeyMaskEx()),
-                    "Quit");
-    getRootPane().getActionMap().put("Quit", new AbstractAction()
-    {
+   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
+   * when opened
+   */
+  protected void addQuitHandler() {
+    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+        KeyStroke.getKeyStroke(KeyEvent.VK_Q, jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
+        "Quit");
+    getRootPane().getActionMap().put("Quit", new AbstractAction() {
       @Override
-      public void actionPerformed(ActionEvent e)
-      {
+      public void actionPerformed(ActionEvent e) {
         quit();
       }
     });
@@ -2531,22 +2050,18 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
    * 
-   * @param enabled
-   *          true if Groovy console is open
+   * @param enabled true if Groovy console is open
    */
-  public void enableExecuteGroovy(boolean enabled)
-  {
+  public void enableExecuteGroovy(boolean enabled) {
     /*
-     * disable opening a second Groovy console
-     * (or re-enable when the console is closed)
+     * disable opening a second Groovy console (or re-enable when the console is
+     * closed)
      */
     groovyShell.setEnabled(!enabled);
 
     AlignFrame[] alignFrames = getAlignFrames();
-    if (alignFrames != null)
-    {
-      for (AlignFrame af : alignFrames)
-      {
+    if (alignFrames != null) {
+      for (AlignFrame af : alignFrames) {
         af.setGroovyEnabled(enabled);
       }
     }
@@ -2565,27 +2080,19 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
    */
   @Override
-  public void setProgressBar(String message, long id)
-  {
-    // Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
-
-    if (progressBars == null)
-    {
+  public void setProgressBar(String message, long id) {
+    if (progressBars == null) {
       progressBars = new Hashtable<>();
       progressBarHandlers = new Hashtable<>();
     }
 
-    if (progressBars.get(Long.valueOf(id)) != null)
-    {
+    if (progressBars.get(Long.valueOf(id)) != null) {
       JPanel panel = progressBars.remove(Long.valueOf(id));
-      if (progressBarHandlers.contains(Long.valueOf(id)))
-      {
+      if (progressBarHandlers.contains(Long.valueOf(id))) {
         progressBarHandlers.remove(Long.valueOf(id));
       }
       removeProgressPanel(panel);
-    }
-    else
-    {
+    } else {
       progressBars.put(Long.valueOf(id), addProgressPanel(message));
     }
   }
@@ -2597,33 +2104,22 @@ public class Desktop extends jalview.jbgui.GDesktop
    * jalview.gui.IProgressIndicatorHandler)
    */
   @Override
-  public void registerHandler(final long id,
-          final IProgressIndicatorHandler handler)
-  {
-    if (progressBarHandlers == null
-            || !progressBars.containsKey(Long.valueOf(id)))
-    {
-      throw new Error(MessageManager.getString(
-              "error.call_setprogressbar_before_registering_handler"));
+  public void registerHandler(final long id, final IProgressIndicatorHandler handler) {
+    if (progressBarHandlers == null || !progressBars.containsKey(Long.valueOf(id))) {
+      throw new Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
     }
     progressBarHandlers.put(Long.valueOf(id), handler);
     final JPanel progressPanel = progressBars.get(Long.valueOf(id));
-    if (handler.canCancel())
-    {
-      JButton cancel = new JButton(
-              MessageManager.getString("action.cancel"));
+    if (handler.canCancel()) {
+      JButton cancel = new JButton(MessageManager.getString("action.cancel"));
       final IProgressIndicator us = this;
-      cancel.addActionListener(new ActionListener()
-      {
+      cancel.addActionListener(new ActionListener() {
 
         @Override
-        public void actionPerformed(ActionEvent e)
-        {
+        public void actionPerformed(ActionEvent e) {
           handler.cancelActivity(id);
-          us.setProgressBar(MessageManager
-                  .formatMessage("label.cancelled_params", new Object[]
-                  { ((JLabel) progressPanel.getComponent(0)).getText() }),
-                  id);
+          us.setProgressBar(MessageManager.formatMessage("label.cancelled_params",
+              new Object[] { ((JLabel) progressPanel.getComponent(0)).getText() }), id);
         }
       });
       progressPanel.add(cancel, BorderLayout.EAST);
@@ -2635,33 +2131,25 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @return true if any progress bars are still active
    */
   @Override
-  public boolean operationInProgress()
-  {
-    if (progressBars != null && progressBars.size() > 0)
-    {
+  public boolean operationInProgress() {
+    if (progressBars != null && progressBars.size() > 0) {
       return true;
     }
     return false;
   }
 
   /**
-   * This will return the first AlignFrame holding the given viewport instance.
-   * It will break if there are more than one AlignFrames viewing a particular
-   * av.
+   * This will return the first AlignFrame holding the given viewport instance. It
+   * will break if there are more than one AlignFrames viewing a particular av.
    * 
    * @param viewport
    * @return alignFrame for viewport
    */
-  public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
-  {
-    if (desktop != null)
-    {
-      AlignmentPanel[] aps = getAlignmentPanels(
-              viewport.getSequenceSetId());
-      for (int panel = 0; aps != null && panel < aps.length; panel++)
-      {
-        if (aps[panel] != null && aps[panel].av == viewport)
-        {
+  public static AlignFrame getAlignFrameFor(AlignViewportI viewport) {
+    if (desktop != null) {
+      AlignmentPanel[] aps = getAlignmentPanels(viewport.getSequenceSetId());
+      for (int panel = 0; aps != null && panel < aps.length; panel++) {
+        if (aps[panel] != null && aps[panel].av == viewport) {
           return aps[panel].alignFrame;
         }
       }
@@ -2669,8 +2157,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     return null;
   }
 
-  public VamsasApplication getVamsasApplication()
-  {
+  public VamsasApplication getVamsasApplication() {
     // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS
     return null;
 
@@ -2686,8 +2173,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return inBatchMode
    */
-  public boolean isInBatchMode()
-  {
+  public boolean isInBatchMode() {
     return inBatchMode;
   }
 
@@ -2696,26 +2182,42 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param inBatchMode
    */
-  public void setInBatchMode(boolean inBatchMode)
-  {
+  public void setInBatchMode(boolean inBatchMode) {
     this.inBatchMode = inBatchMode;
   }
 
-  public void startServiceDiscovery()
-  {
+  /**
+   * start service discovery and wait till it is done
+   */
+  public void startServiceDiscovery() {
     startServiceDiscovery(false);
   }
 
-  public void startServiceDiscovery(boolean blocking)
-  {
+  /**
+   * start service discovery threads - blocking or non-blocking
+   * 
+   * @param blocking
+   */
+  public void startServiceDiscovery(boolean blocking) {
+    startServiceDiscovery(blocking, false);
+  }
+
+  /**
+   * start service discovery threads
+   * 
+   * @param blocking                             - false means call returns
+   *                                             immediately
+   * @param ignore_SHOW_JWS2_SERVICES_preference - when true JABA services are
+   *                                             discovered regardless of user's
+   *                                             JWS2 discovery preference setting
+   */
+  public void startServiceDiscovery(boolean blocking, boolean ignore_SHOW_JWS2_SERVICES_preference) {
     boolean alive = true;
     Thread t0 = null, t1 = null, t2 = null;
     // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
-    if (true)
-    {
+    if (true) {
       // todo: changesupport handlers need to be transferred
-      if (discoverer == null)
-      {
+      if (discoverer == null) {
         discoverer = new jalview.ws.jws1.Discoverer();
         // register PCS handler for desktop.
         discoverer.addPropertyChangeListener(changeSupport);
@@ -2725,28 +2227,21 @@ public class Desktop extends jalview.jbgui.GDesktop
       (t0 = new Thread(discoverer)).start();
     }
 
-    if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
-    {
-      t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
-              .startDiscoverer(changeSupport);
+    if (ignore_SHOW_JWS2_SERVICES_preference || Cache.getDefault("SHOW_JWS2_SERVICES", true)) {
+      t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer().startDiscoverer(changeSupport);
     }
     Thread t3 = null;
     {
       // TODO: do rest service discovery
     }
-    if (blocking)
-    {
-      while (alive)
-      {
-        try
-        {
+    if (blocking) {
+      while (alive) {
+        try {
           Thread.sleep(15);
-        } catch (Exception e)
-        {
+        } catch (Exception e) {
         }
-        alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
-                || (t3 != null && t3.isAlive())
-                || (t0 != null && t0.isAlive());
+        alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive()) || (t3 != null && t3.isAlive())
+            || (t0 != null && t0.isAlive());
       }
     }
   }
@@ -2756,70 +2251,50 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param evt
    */
-  protected void JalviewServicesChanged(PropertyChangeEvent evt)
-  {
-    if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
-    {
-      final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
-              .getErrorMessages();
-      if (ermsg != null)
-      {
-        if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
-        {
-          if (serviceChangedDialog == null)
-          {
+  protected void JalviewServicesChanged(PropertyChangeEvent evt) {
+    if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) {
+      final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer().getErrorMessages();
+      if (ermsg != null) {
+        if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true)) {
+          if (serviceChangedDialog == null) {
             // only run if we aren't already displaying one of these.
-            addDialogThread(serviceChangedDialog = new Runnable()
-            {
+            addDialogThread(serviceChangedDialog = new Runnable() {
               @Override
-              public void run()
-              {
+              public void run() {
 
                 /*
                  * JalviewDialog jd =new JalviewDialog() {
                  * 
-                 * @Override protected void cancelPressed() { // TODO
-                 * Auto-generated method stub
+                 * @Override protected void cancelPressed() { // TODO Auto-generated method stub
                  * 
-                 * }@Override protected void okPressed() { // TODO
-                 * Auto-generated method stub
+                 * }@Override protected void okPressed() { // TODO Auto-generated method stub
                  * 
-                 * }@Override protected void raiseClosed() { // TODO
-                 * Auto-generated method stub
+                 * }@Override protected void raiseClosed() { // TODO Auto-generated method stub
                  * 
-                 * } }; jd.initDialogFrame(new
-                 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
+                 * } }; jd.initDialogFrame(new JLabel("<html><table width=\"450\"><tr><td>" +
+                 * ermsg +
                  * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
                  * + " or mis-configured HTTP proxy settings.<br/>" +
-                 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
-                 * +
-                 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
-                 * ), true, true, "Web Service Configuration Problem", 450,
-                 * 400);
+                 * "Check the <em>Connections</em> and <em>Web services</em> tab of the" +
+                 * " Tools->Preferences dialog box to change them.</td></tr></table></html>" ),
+                 * true, true, "Web Service Configuration Problem", 450, 400);
                  * 
                  * jd.waitForInput();
                  */
                 JvOptionPane.showConfirmDialog(Desktop.desktop,
-                        new JLabel("<html><table width=\"450\"><tr><td>"
-                                + ermsg + "</td></tr></table>"
-                                + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
-                                + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
-                                + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
-                                + " Tools->Preferences dialog box to change them.</p></html>"),
-                        "Web Service Configuration Problem",
-                        JvOptionPane.DEFAULT_OPTION,
-                        JvOptionPane.ERROR_MESSAGE);
+                    new JLabel("<html><table width=\"450\"><tr><td>" + ermsg + "</td></tr></table>"
+                        + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
+                        + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
+                        + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
+                        + " Tools->Preferences dialog box to change them.</p></html>"),
+                    "Web Service Configuration Problem", JvOptionPane.DEFAULT_OPTION, JvOptionPane.ERROR_MESSAGE);
                 serviceChangedDialog = null;
 
               }
             });
           }
-        }
-        else
-        {
-          Cache.log.error(
-                  "Errors reported by JABA discovery service. Check web services preferences.\n"
-                          + ermsg);
+        } else {
+          jalview.bin.Console.error("Errors reported by JABA discovery service. Check web services preferences.\n" + ermsg);
         }
       }
     }
@@ -2834,8 +2309,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param url
    */
-  public static void showUrl(final String url)
-  {
+  public static void showUrl(final String url) {
     showUrl(url, Desktop.instance);
   }
 
@@ -2843,38 +2317,26 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Like showUrl but allows progress handler to be specified
    * 
    * @param url
-   * @param progress
-   *          (null) or object implementing IProgressIndicator
+   * @param progress (null) or object implementing IProgressIndicator
    */
-  public static void showUrl(final String url,
-          final IProgressIndicator progress)
-  {
-    new Thread(new Runnable()
-    {
+  public static void showUrl(final String url, final IProgressIndicator progress) {
+    new Thread(new Runnable() {
       @Override
-      public void run()
-      {
-        try
-        {
-          if (progress != null)
-          {
-            progress.setProgressBar(MessageManager
-                    .formatMessage("status.opening_params", new Object[]
-                    { url }), this.hashCode());
+      public void run() {
+        try {
+          if (progress != null) {
+            progress.setProgressBar(MessageManager.formatMessage("status.opening_params", new Object[] { url }),
+                this.hashCode());
           }
           jalview.util.BrowserLauncher.openURL(url);
-        } catch (Exception ex)
-        {
+        } catch (Exception ex) {
           JvOptionPane.showInternalMessageDialog(Desktop.desktop,
-                  MessageManager
-                          .getString("label.web_browser_not_found_unix"),
-                  MessageManager.getString("label.web_browser_not_found"),
-                  JvOptionPane.WARNING_MESSAGE);
+              MessageManager.getString("label.web_browser_not_found_unix"),
+              MessageManager.getString("label.web_browser_not_found"), JvOptionPane.WARNING_MESSAGE);
 
           ex.printStackTrace();
         }
-        if (progress != null)
-        {
+        if (progress != null) {
           progress.setProgressBar(null, this.hashCode());
         }
       }
@@ -2883,10 +2345,8 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static WsParamSetManager wsparamManager = null;
 
-  public static ParamManager getUserParameterStore()
-  {
-    if (wsparamManager == null)
-    {
+  public static ParamManager getUserParameterStore() {
+    if (wsparamManager == null) {
       wsparamManager = new WsParamSetManager();
     }
     return wsparamManager;
@@ -2897,28 +2357,15 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param e
    */
-  public static void hyperlinkUpdate(HyperlinkEvent e)
-  {
-    if (e.getEventType() == EventType.ACTIVATED)
-    {
+  public static void hyperlinkUpdate(HyperlinkEvent e) {
+    if (e.getEventType() == EventType.ACTIVATED) {
       String url = null;
-      try
-      {
+      try {
         url = e.getURL().toString();
         Desktop.showUrl(url);
-      } catch (Exception x)
-      {
-        if (url != null)
-        {
-          if (Cache.log != null)
-          {
-            Cache.log.error("Couldn't handle string " + url + " as a URL.");
-          }
-          else
-          {
-            System.err.println(
-                    "Couldn't handle string " + url + " as a URL.");
-          }
+      } catch (Exception x) {
+        if (url != null) {
+          jalview.bin.Console.error("Couldn't handle string " + url + " as a URL.");
         }
         // ignore any exceptions due to dud links.
       }
@@ -2948,39 +2395,29 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param prompter
    */
-  public void addDialogThread(final Runnable prompter)
-  {
-    dialogExecutor.submit(new Runnable()
-    {
+  public void addDialogThread(final Runnable prompter) {
+    dialogExecutor.submit(new Runnable() {
       @Override
-      public void run()
-      {
-        if (dialogPause)
-        {
-          try
-          {
+      public void run() {
+        if (dialogPause) {
+          try {
             block.acquire();
-          } catch (InterruptedException x)
-          {
+          } catch (InterruptedException x) {
           }
         }
-        if (instance == null)
-        {
+        if (instance == null) {
           return;
         }
-        try
-        {
+        try {
           SwingUtilities.invokeAndWait(prompter);
-        } catch (Exception q)
-        {
-          Cache.log.warn("Unexpected Exception in dialog thread.", q);
+        } catch (Exception q) {
+          jalview.bin.Console.warn("Unexpected Exception in dialog thread.", q);
         }
       }
     });
   }
 
-  public void startDialogQueue()
-  {
+  public void startDialogQueue() {
     // set the flag so we don't pause waiting for another permit and semaphore
     // the current task to begin
     dialogPause = false;
@@ -2997,65 +2434,53 @@ public class Desktop extends jalview.jbgui.GDesktop
    * </pre>
    */
   @Override
-  protected void snapShotWindow_actionPerformed(ActionEvent e)
-  {
+  protected void snapShotWindow_actionPerformed(ActionEvent e) {
     // currently the menu option to do this is not shown
     invalidate();
 
     int width = getWidth();
     int height = getHeight();
-    File of = new File(
-            "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
-    ImageWriterI writer = new ImageWriterI()
-    {
+    File of = new File("Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
+    ImageWriterI writer = new ImageWriterI() {
       @Override
-      public void exportImage(Graphics g) throws Exception
-      {
+      public void exportImage(Graphics g) throws Exception {
         paintAll(g);
-        Cache.log.info("Successfully written snapshot to file "
-                + of.getAbsolutePath());
+        jalview.bin.Console.info("Successfully written snapshot to file " + of.getAbsolutePath());
       }
     };
     String title = "View of desktop";
-    ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
-            title);
+    ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS, title);
     exporter.doExport(of, this, width, height, title);
   }
 
   /**
    * Explode the views in the given SplitFrame into separate SplitFrame windows.
-   * This respects (remembers) any previous 'exploded geometry' i.e. the size
-   * and location last time the view was expanded (if any). However it does not
+   * This respects (remembers) any previous 'exploded geometry' i.e. the size and
+   * location last time the view was expanded (if any). However it does not
    * remember the split pane divider location - this is set to match the
    * 'exploding' frame.
    * 
    * @param sf
    */
-  public void explodeViews(SplitFrame sf)
-  {
+  public void explodeViews(SplitFrame sf) {
     AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
     AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
-    List<? extends AlignmentViewPanel> topPanels = oldTopFrame
-            .getAlignPanels();
-    List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
-            .getAlignPanels();
+    List<? extends AlignmentViewPanel> topPanels = oldTopFrame.getAlignPanels();
+    List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame.getAlignPanels();
     int viewCount = topPanels.size();
-    if (viewCount < 2)
-    {
+    if (viewCount < 2) {
       return;
     }
 
     /*
-     * Processing in reverse order works, forwards order leaves the first panels
-     * not visible. I don't know why!
+     * Processing in reverse order works, forwards order leaves the first panels not
+     * visible. I don't know why!
      */
-    for (int i = viewCount - 1; i >= 0; i--)
-    {
+    for (int i = viewCount - 1; i >= 0; i--) {
       /*
-       * Make new top and bottom frames. These take over the respective
-       * AlignmentPanel objects, including their AlignmentViewports, so the
-       * cdna/protein relationships between the viewports is carried over to the
-       * new split frames.
+       * Make new top and bottom frames. These take over the respective AlignmentPanel
+       * objects, including their AlignmentViewports, so the cdna/protein
+       * relationships between the viewports is carried over to the new split frames.
        * 
        * explodedGeometry holds the (x, y) position of the previously exploded
        * SplitFrame, and the (width, height) of the AlignFrame component
@@ -3064,10 +2489,8 @@ public class Desktop extends jalview.jbgui.GDesktop
       AlignFrame newTopFrame = new AlignFrame(topPanel);
       newTopFrame.setSize(oldTopFrame.getSize());
       newTopFrame.setVisible(true);
-      Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
-              .getExplodedGeometry();
-      if (geometry != null)
-      {
+      Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport()).getExplodedGeometry();
+      if (geometry != null) {
         newTopFrame.setSize(geometry.getSize());
       }
 
@@ -3075,27 +2498,23 @@ public class Desktop extends jalview.jbgui.GDesktop
       AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
       newBottomFrame.setSize(oldBottomFrame.getSize());
       newBottomFrame.setVisible(true);
-      geometry = ((AlignViewport) bottomPanel.getAlignViewport())
-              .getExplodedGeometry();
-      if (geometry != null)
-      {
+      geometry = ((AlignViewport) bottomPanel.getAlignViewport()).getExplodedGeometry();
+      if (geometry != null) {
         newBottomFrame.setSize(geometry.getSize());
       }
 
       topPanel.av.setGatherViewsHere(false);
       bottomPanel.av.setGatherViewsHere(false);
-      JInternalFrame splitFrame = new SplitFrame(newTopFrame,
-              newBottomFrame);
-      if (geometry != null)
-      {
+      JInternalFrame splitFrame = new SplitFrame(newTopFrame, newBottomFrame);
+      if (geometry != null) {
         splitFrame.setLocation(geometry.getLocation());
       }
       Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
     }
 
     /*
-     * Clear references to the panels (now relocated in the new SplitFrames)
-     * before closing the old SplitFrame.
+     * Clear references to the panels (now relocated in the new SplitFrames) before
+     * closing the old SplitFrame.
      */
     topPanels.clear();
     bottomPanels.clear();
@@ -3109,8 +2528,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param source
    */
-  public void gatherViews(GSplitFrame source)
-  {
+  public void gatherViews(GSplitFrame source) {
     /*
      * special handling of explodedGeometry for a view within a SplitFrame: - it
      * holds the (x, y) position of the enclosing SplitFrame, and the (width,
@@ -3118,46 +2536,38 @@ public class Desktop extends jalview.jbgui.GDesktop
      */
     AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
     AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
-    myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
-            source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
-    myBottomFrame.viewport
-            .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
-                    myBottomFrame.getWidth(), myBottomFrame.getHeight()));
+    myTopFrame.viewport.setExplodedGeometry(
+        new Rectangle(source.getX(), source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
+    myBottomFrame.viewport.setExplodedGeometry(
+        new Rectangle(source.getX(), source.getY(), myBottomFrame.getWidth(), myBottomFrame.getHeight()));
     myTopFrame.viewport.setGatherViewsHere(true);
     myBottomFrame.viewport.setGatherViewsHere(true);
     String topViewId = myTopFrame.viewport.getSequenceSetId();
     String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
 
     JInternalFrame[] frames = desktop.getAllFrames();
-    for (JInternalFrame frame : frames)
-    {
-      if (frame instanceof SplitFrame && frame != source)
-      {
+    for (JInternalFrame frame : frames) {
+      if (frame instanceof SplitFrame && frame != source) {
         SplitFrame sf = (SplitFrame) frame;
         AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
         AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
         boolean gatherThis = false;
-        for (int a = 0; a < topFrame.alignPanels.size(); a++)
-        {
+        for (int a = 0; a < topFrame.alignPanels.size(); a++) {
           AlignmentPanel topPanel = topFrame.alignPanels.get(a);
           AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
           if (topViewId.equals(topPanel.av.getSequenceSetId())
-                  && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
-          {
+              && bottomViewId.equals(bottomPanel.av.getSequenceSetId())) {
             gatherThis = true;
             topPanel.av.setGatherViewsHere(false);
             bottomPanel.av.setGatherViewsHere(false);
-            topPanel.av.setExplodedGeometry(
-                    new Rectangle(sf.getLocation(), topFrame.getSize()));
-            bottomPanel.av.setExplodedGeometry(
-                    new Rectangle(sf.getLocation(), bottomFrame.getSize()));
+            topPanel.av.setExplodedGeometry(new Rectangle(sf.getLocation(), topFrame.getSize()));
+            bottomPanel.av.setExplodedGeometry(new Rectangle(sf.getLocation(), bottomFrame.getSize()));
             myTopFrame.addAlignmentPanel(topPanel, false);
             myBottomFrame.addAlignmentPanel(bottomPanel, false);
           }
         }
 
-        if (gatherThis)
-        {
+        if (gatherThis) {
           topFrame.getAlignPanels().clear();
           bottomFrame.getAlignPanels().clear();
           sf.close();
@@ -3171,8 +2581,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     myTopFrame.setDisplayedView(myTopFrame.alignPanel);
   }
 
-  public static groovy.ui.Console getGroovyConsole()
-  {
+  public static groovy.ui.Console getGroovyConsole() {
     return groovyConsole;
   }
 
@@ -3181,147 +2590,88 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * TODO refactor to desktop utilities class
    * 
-   * @param files
-   *          - Data source strings extracted from the drop event
-   * @param protocols
-   *          - protocol for each data source extracted from the drop event
-   * @param evt
-   *          - the drop event
-   * @param t
-   *          - the payload from the drop event
+   * @param files     - Data source strings extracted from the drop event
+   * @param protocols - protocol for each data source extracted from the drop
+   *                  event
+   * @param evt       - the drop event
+   * @param t         - the payload from the drop event
    * @throws Exception
    */
-  public static void transferFromDropTarget(List<Object> files,
-          List<DataSourceType> protocols, DropTargetDropEvent evt,
-          Transferable t) throws Exception
-  {
-
-    // BH 2018 changed List<String> to List<Object> to allow for File from
-    // SwingJS
-
-    // DataFlavor[] flavors = t.getTransferDataFlavors();
-    // for (int i = 0; i < flavors.length; i++) {
-    // if (flavors[i].isFlavorJavaFileListType()) {
-    // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-    // List<File> list = (List<File>) t.getTransferData(flavors[i]);
-    // for (int j = 0; j < list.size(); j++) {
-    // File file = (File) list.get(j);
-    // byte[] data = getDroppedFileBytes(file);
-    // fileName.setText(file.getName() + " - " + data.length + " " +
-    // evt.getLocation());
-    // JTextArea target = (JTextArea) ((DropTarget)
-    // evt.getSource()).getComponent();
-    // target.setText(new String(data));
-    // }
-    // dtde.dropComplete(true);
-    // return;
-    // }
-    //
-
-    DataFlavor uriListFlavor = new DataFlavor(
-            "text/uri-list;class=java.lang.String"), urlFlavour = null;
-    try
-    {
-      urlFlavour = new DataFlavor(
-              "application/x-java-url; class=java.net.URL");
-    } catch (ClassNotFoundException cfe)
-    {
-      Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
+  public static void transferFromDropTarget(List<Object> files, List<DataSourceType> protocols, DropTargetDropEvent evt,
+      Transferable t) throws Exception {
+
+    DataFlavor uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String"), urlFlavour = null;
+    try {
+      urlFlavour = new DataFlavor("application/x-java-url; class=java.net.URL");
+    } catch (ClassNotFoundException cfe) {
+      jalview.bin.Console.debug("Couldn't instantiate the URL dataflavor.", cfe);
     }
 
-    if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
-    {
+    if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour)) {
 
-      try
-      {
+      try {
         java.net.URL url = (URL) t.getTransferData(urlFlavour);
         // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
         // means url may be null.
-        if (url != null)
-        {
+        if (url != null) {
           protocols.add(DataSourceType.URL);
           files.add(url.toString());
-          Cache.log.debug("Drop handled as URL dataflavor "
-                  + files.get(files.size() - 1));
+          jalview.bin.Console.debug("Drop handled as URL dataflavor " + files.get(files.size() - 1));
           return;
-        }
-        else
-        {
-          if (Platform.isAMacAndNotJS())
-          {
-            System.err.println(
-                    "Please ignore plist error - occurs due to problem with java 8 on OSX");
+        } else {
+          if (Platform.isAMacAndNotJS()) {
+            System.err.println("Please ignore plist error - occurs due to problem with java 8 on OSX");
           }
         }
-      } catch (Throwable ex)
-      {
-        Cache.log.debug("URL drop handler failed.", ex);
+      } catch (Throwable ex) {
+        jalview.bin.Console.debug("URL drop handler failed.", ex);
       }
     }
-    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
-    {
+    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
       // Works on Windows and MacOSX
-      Cache.log.debug("Drop handled as javaFileListFlavor");
-      for (Object file : (List) t
-              .getTransferData(DataFlavor.javaFileListFlavor))
-      {
+      jalview.bin.Console.debug("Drop handled as javaFileListFlavor");
+      for (Object file : (List) t.getTransferData(DataFlavor.javaFileListFlavor)) {
         files.add(file);
         protocols.add(DataSourceType.FILE);
       }
-    }
-    else
-    {
+    } else {
       // Unix like behaviour
       boolean added = false;
       String data = null;
-      if (t.isDataFlavorSupported(uriListFlavor))
-      {
-        Cache.log.debug("Drop handled as uriListFlavor");
+      if (t.isDataFlavorSupported(uriListFlavor)) {
+        jalview.bin.Console.debug("Drop handled as uriListFlavor");
         // This is used by Unix drag system
         data = (String) t.getTransferData(uriListFlavor);
       }
-      if (data == null)
-      {
+      if (data == null) {
         // fallback to text: workaround - on OSX where there's a JVM bug
-        Cache.log.debug("standard URIListFlavor failed. Trying text");
+        jalview.bin.Console.debug("standard URIListFlavor failed. Trying text");
         // try text fallback
-        DataFlavor textDf = new DataFlavor(
-                "text/plain;class=java.lang.String");
-        if (t.isDataFlavorSupported(textDf))
-        {
+        DataFlavor textDf = new DataFlavor("text/plain;class=java.lang.String");
+        if (t.isDataFlavorSupported(textDf)) {
           data = (String) t.getTransferData(textDf);
         }
 
-        Cache.log.debug("Plain text drop content returned "
-                + (data == null ? "Null - failed" : data));
+        jalview.bin.Console.debug("Plain text drop content returned " + (data == null ? "Null - failed" : data));
 
       }
-      if (data != null)
-      {
-        while (protocols.size() < files.size())
-        {
-          Cache.log.debug("Adding missing FILE protocol for "
-                  + files.get(protocols.size()));
+      if (data != null) {
+        while (protocols.size() < files.size()) {
+          jalview.bin.Console.debug("Adding missing FILE protocol for " + files.get(protocols.size()));
           protocols.add(DataSourceType.FILE);
         }
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
-                data, "\r\n"); st.hasMoreTokens();)
-        {
+        for (java.util.StringTokenizer st = new java.util.StringTokenizer(data, "\r\n"); st.hasMoreTokens();) {
           added = true;
           String s = st.nextToken();
-          if (s.startsWith("#"))
-          {
+          if (s.startsWith("#")) {
             // the line is a comment (as per the RFC 2483)
             continue;
           }
           java.net.URI uri = new java.net.URI(s);
-          if (uri.getScheme().toLowerCase().startsWith("http"))
-          {
+          if (uri.getScheme().toLowerCase(Locale.ROOT).startsWith("http")) {
             protocols.add(DataSourceType.URL);
             files.add(uri.toString());
-          }
-          else
-          {
+          } else {
             // otherwise preserve old behaviour: catch all for file objects
             java.io.File file = new java.io.File(uri);
             protocols.add(DataSourceType.FILE);
@@ -3330,69 +2680,46 @@ public class Desktop extends jalview.jbgui.GDesktop
         }
       }
 
-      if (Cache.log.isDebugEnabled())
-      {
-        if (data == null || !added)
-        {
+      if (jalview.bin.Console.isDebugEnabled()) {
+        if (data == null || !added) {
 
-          if (t.getTransferDataFlavors() != null
-                  && t.getTransferDataFlavors().length > 0)
-          {
-            Cache.log.debug(
-                    "Couldn't resolve drop data. Here are the supported flavors:");
-            for (DataFlavor fl : t.getTransferDataFlavors())
-            {
-              Cache.log.debug(
-                      "Supported transfer dataflavor: " + fl.toString());
+          if (t.getTransferDataFlavors() != null && t.getTransferDataFlavors().length > 0) {
+            jalview.bin.Console.debug("Couldn't resolve drop data. Here are the supported flavors:");
+            for (DataFlavor fl : t.getTransferDataFlavors()) {
+              jalview.bin.Console.debug("Supported transfer dataflavor: " + fl.toString());
               Object df = t.getTransferData(fl);
-              if (df != null)
-              {
-                Cache.log.debug("Retrieves: " + df);
-              }
-              else
-              {
-                Cache.log.debug("Retrieved nothing");
+              if (df != null) {
+                jalview.bin.Console.debug("Retrieves: " + df);
+              } else {
+                jalview.bin.Console.debug("Retrieved nothing");
               }
             }
-          }
-          else
-          {
-            Cache.log.debug("Couldn't resolve dataflavor for drop: "
-                    + t.toString());
+          } else {
+            jalview.bin.Console.debug("Couldn't resolve dataflavor for drop: " + t.toString());
           }
         }
       }
     }
-    if (Platform.isWindowsAndNotJS())
-    {
-      Cache.log.debug("Scanning dropped content for Windows Link Files");
+    if (Platform.isWindowsAndNotJS()) {
+      jalview.bin.Console.debug("Scanning dropped content for Windows Link Files");
 
       // resolve any .lnk files in the file drop
-      for (int f = 0; f < files.size(); f++)
-      {
-        String source = files.get(f).toString().toLowerCase();
+      for (int f = 0; f < files.size(); f++) {
+        String source = files.get(f).toString().toLowerCase(Locale.ROOT);
         if (protocols.get(f).equals(DataSourceType.FILE)
-                && (source.endsWith(".lnk") || source.endsWith(".url")
-                        || source.endsWith(".site")))
-        {
-          try
-          {
+            && (source.endsWith(".lnk") || source.endsWith(".url") || source.endsWith(".site"))) {
+          try {
             Object obj = files.get(f);
-            File lf = (obj instanceof File ? (File) obj
-                    : new File((String) obj));
+            File lf = (obj instanceof File ? (File) obj : new File((String) obj));
             // process link file to get a URL
-            Cache.log.debug("Found potential link file: " + lf);
+            jalview.bin.Console.debug("Found potential link file: " + lf);
             WindowsShortcut wscfile = new WindowsShortcut(lf);
             String fullname = wscfile.getRealFilename();
             protocols.set(f, FormatAdapter.checkProtocol(fullname));
             files.set(f, fullname);
-            Cache.log.debug("Parsed real filename " + fullname
-                    + " to extract protocol: " + protocols.get(f));
-          } catch (Exception ex)
-          {
-            Cache.log.error(
-                    "Couldn't parse " + files.get(f) + " as a link file.",
-                    ex);
+            jalview.bin.Console.debug("Parsed real filename " + fullname + " to extract protocol: " + protocols.get(f));
+          } catch (Exception ex) {
+            jalview.bin.Console.error("Couldn't parse " + files.get(f) + " as a link file.", ex);
           }
         }
       }
@@ -3404,40 +2731,30 @@ public class Desktop extends jalview.jbgui.GDesktop
    * depending on the state of the controlling menu item
    */
   @Override
-  protected void showExperimental_actionPerformed(boolean selected)
-  {
+  protected void showExperimental_actionPerformed(boolean selected) {
     Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
   }
 
   /**
-   * Answers a (possibly empty) list of any structure viewer frames (currently
-   * for either Jmol or Chimera) which are currently open. This may optionally
-   * be restricted to viewers of a specified class, or viewers linked to a
-   * specified alignment panel.
+   * Answers a (possibly empty) list of any structure viewer frames (currently for
+   * either Jmol or Chimera) which are currently open. This may optionally be
+   * restricted to viewers of a specified class, or viewers linked to a specified
+   * alignment panel.
    * 
-   * @param apanel
-   *          if not null, only return viewers linked to this panel
-   * @param structureViewerClass
-   *          if not null, only return viewers of this class
+   * @param apanel               if not null, only return viewers linked to this
+   *                             panel
+   * @param structureViewerClass if not null, only return viewers of this class
    * @return
    */
-  public List<StructureViewerBase> getStructureViewers(
-          AlignmentPanel apanel,
-          Class<? extends StructureViewerBase> structureViewerClass)
-  {
+  public List<StructureViewerBase> getStructureViewers(AlignmentPanel apanel,
+      Class<? extends StructureViewerBase> structureViewerClass) {
     List<StructureViewerBase> result = new ArrayList<>();
     JInternalFrame[] frames = Desktop.instance.getAllFrames();
 
-    for (JInternalFrame frame : frames)
-    {
-      if (frame instanceof StructureViewerBase)
-      {
-        if (structureViewerClass == null
-                || structureViewerClass.isInstance(frame))
-        {
-          if (apanel == null
-                  || ((StructureViewerBase) frame).isLinkedWith(apanel))
-          {
+    for (JInternalFrame frame : frames) {
+      if (frame instanceof StructureViewerBase) {
+        if (structureViewerClass == null || structureViewerClass.isInstance(frame)) {
+          if (apanel == null || ((StructureViewerBase) frame).isLinkedWith(apanel)) {
             result.add((StructureViewerBase) frame);
           }
         }
@@ -3450,32 +2767,25 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   private static boolean debugScaleMessageDone = false;
 
-  public static void debugScaleMessage(Graphics g)
-  {
-    if (debugScaleMessageDone)
-    {
+  public static void debugScaleMessage(Graphics g) {
+    if (debugScaleMessageDone) {
       return;
     }
     // output used by tests to check HiDPI scaling settings in action
-    try
-    {
+    try {
       Graphics2D gg = (Graphics2D) g;
-      if (gg != null)
-      {
+      if (gg != null) {
         AffineTransform t = gg.getTransform();
         double scaleX = t.getScaleX();
         double scaleY = t.getScaleY();
-        Cache.debug(debugScaleMessage + scaleX + " (X)");
-        Cache.debug(debugScaleMessage + scaleY + " (Y)");
+        jalview.bin.Console.debug(debugScaleMessage + scaleX + " (X)");
+        jalview.bin.Console.debug(debugScaleMessage + scaleY + " (Y)");
         debugScaleMessageDone = true;
+      } else {
+        jalview.bin.Console.debug("Desktop graphics null");
       }
-      else
-      {
-        Cache.debug("Desktop graphics null");
-      }
-    } catch (Exception e)
-    {
-      Cache.debug(Cache.getStackTraceString(e));
+    } catch (Exception e) {
+      jalview.bin.Console.debug(Cache.getStackTraceString(e));
     }
   }
 }
index e636455..ac04a1f 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -496,81 +498,6 @@ public class FeatureSettings extends JPanel
     JPopupMenu men = new JPopupMenu(MessageManager
             .formatMessage("label.settings_for_param", new String[]
             { type }));
-    final FeatureColourI featureColour = (FeatureColourI) typeCol;
-
-    /*
-     * menu option to select (or deselect) variable colour
-     */
-    final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
-            MessageManager.getString("label.variable_colour"));
-    variableColourCB.setSelected(!featureColour.isSimpleColour());
-    men.add(variableColourCB);
-
-    /*
-     * checkbox action listener doubles up as listener to OK
-     * from the variable colour / filters dialog
-     */
-    variableColourCB.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        if (e.getSource() == variableColourCB)
-        {
-                                       // BH 2018 for JavaScript because this is a checkbox
-                                       men.setVisible(true);
-          men.setVisible(false);
-          if (featureColour.isSimpleColour())
-          {
-            /*
-             * toggle simple colour to variable colour - show dialog
-             */
-            FeatureTypeSettings fc = new FeatureTypeSettings(fr, type);
-            fc.addActionListener(this);
-          }
-          else
-          {
-            /*
-             * toggle variable to simple colour - show colour chooser
-             */
-            String title = MessageManager
-                    .formatMessage("label.select_colour_for", type);
-            ColourChooserListener listener = new ColourChooserListener()
-            {
-              @Override
-              public void colourSelected(Color c)
-              {
-                table.setValueAt(new FeatureColour(c), rowSelected,
-                        COLOUR_COLUMN);
-                table.validate();
-                updateFeatureRenderer(
-                        ((FeatureTableModel) table.getModel()).getData(),
-                        false);
-              }
-            };
-            JalviewColourChooser.showColourChooser(FeatureSettings.this,
-                    title, featureColour.getMaxColour(), listener);
-          }
-        }
-        else
-        {
-          if (e.getSource() instanceof FeatureTypeSettings)
-          {
-            /*
-             * update after OK in feature colour dialog; the updated
-             * colour will have already been set in the FeatureRenderer
-             */
-            FeatureColourI fci = fr.getFeatureColours().get(type);
-            table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
-            // BH 2018 setting a table value does not invalidate it.
-            // System.out.println("FeatureSettings is valied" +
-            // table.validate();
-          }
-        }
-      }
-    });
-
-    men.addSeparator();
 
     JMenuItem scr = new JMenuItem(
             MessageManager.getString("label.sort_by_score"));
@@ -1529,7 +1456,7 @@ public class FeatureSettings extends JPanel
     String text = MessageManager.formatMessage("label.show_linked_features",
             nucleotide
                     ? MessageManager.getString("label.protein")
-                            .toLowerCase()
+                            .toLowerCase(Locale.ROOT)
                     : "CDS");
     showComplement = new JCheckBox(text);
     showComplement.addActionListener(new ActionListener()
index 54eeba7..a2a2700 100644 (file)
@@ -23,7 +23,7 @@ package jalview.gui;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureColourI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.features.FeatureAttributes;
 import jalview.datamodel.features.FeatureAttributes.Datatype;
@@ -1696,7 +1696,7 @@ public class FeatureTypeSettings extends JalviewDialog
       attName = (String) attCombo.getSelectedItem();
     } catch (Exception e)
     {
-      Cache.log.error("Problem casting Combo box entry to String");
+      Console.error("Problem casting Combo box entry to String");
       attName = attCombo.getSelectedItem().toString();
     }
     Condition cond = (Condition) condCombo.getSelectedItem();
index d328452..93dcadf 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.api.AlignViewportI;
-import jalview.api.FinderI;
-import jalview.datamodel.SearchResultMatchI;
-import jalview.datamodel.SearchResultsI;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceI;
-import jalview.jbgui.GFinder;
-import jalview.util.MessageManager;
+import java.util.Locale;
 
 import java.awt.Dimension;
-import java.awt.Graphics;
 import java.awt.event.ActionEvent;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -48,6 +42,15 @@ import javax.swing.KeyStroke;
 import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
+import jalview.api.AlignViewportI;
+import jalview.api.FinderI;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.jbgui.GFinder;
+import jalview.util.MessageManager;
+
 /**
  * Performs the menu option for searching the alignment, for the next or all
  * matches. If matches are found, they are highlighted, and the user has the
@@ -82,33 +85,62 @@ public class Finder extends GFinder
 
   private SearchResultsI searchResults;
 
+  /*
+   * true if Finder always acts on the same alignment,
+   * false if it acts on the alignment with focus
+   */
+  private boolean focusFixed;
+
   /**
    * Constructor given an associated alignment panel. Constructs and displays an
-   * internal frame where the user can enter a search string.
+   * internal frame where the user can enter a search string. The Finder may
+   * have 'fixed focus' (always act the panel for which it is constructed), or
+   * not (acts on the alignment that has focus). An optional 'scope' may be
+   * added to be shown in the title of the Finder frame.
    * 
    * @param alignPanel
+   * @param fixedFocus
+   * @param scope
    */
-  public Finder(AlignmentPanel alignPanel)
+  public Finder(AlignmentPanel alignPanel, boolean fixedFocus, String scope)
   {
     av = alignPanel.getAlignViewport();
     ap = alignPanel;
+    focusFixed = fixedFocus;
     finders = new HashMap<>();
     frame = new JInternalFrame();
     frame.setContentPane(this);
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
-    frame.addInternalFrameListener(
-            new InternalFrameAdapter()
-            {
-              @Override
-              public void internalFrameClosing(InternalFrameEvent e)
-              {
-                closeAction();
-              }
-            });
+    frame.addInternalFrameListener(new InternalFrameAdapter()
+    {
+      @Override
+      public void internalFrameClosing(InternalFrameEvent e)
+      {
+        closeAction();
+      }
+    });
+    frame.addFocusListener(new FocusAdapter()
+    {
+      @Override
+      public void focusGained(FocusEvent e)
+      {
+        /*
+         * ensure 'ignore hidden columns' is only enabled
+         * if the alignment with focus has hidden columns
+         */
+        getFocusedViewport();
+      }
+    });
+
     addEscapeHandler();
 
-    Desktop.addInternalFrame(frame, MessageManager.getString("label.find"),
-            true, MY_WIDTH, MY_HEIGHT, true, true);
+    String title = MessageManager.getString("label.find");
+    if (scope != null)
+    {
+      title += " " + scope;
+    }
+    Desktop.addInternalFrame(frame, title, MY_WIDTH, MY_HEIGHT);
+    frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
     searchBox.getComponent().requestFocus();
   }
 
@@ -156,17 +188,18 @@ public class Finder extends GFinder
   /**
    * if !focusfixed and not in a desktop environment, checks that av and ap are
    * valid. Otherwise, gets the topmost alignment window and sets av and ap
-   * accordingly. Also sets the 'ignore hidden' checkbox disabled if the viewport
-   * has no hidden columns.
+   * accordingly. Also sets the 'ignore hidden' checkbox disabled if the
+   * viewport has no hidden columns.
    * 
    * @return false if no alignment window was found
    */
   boolean getFocusedViewport()
   {
-    if (Desktop.desktop == null)
+    if (focusFixed || Desktop.desktop == null)
     {
       if (ap != null && av != null)
       {
+        ignoreHidden.setEnabled(av.hasHiddenColumns());
         return true;
       }
       // we aren't in a desktop environment, so give up now.
@@ -294,19 +327,25 @@ public class Finder extends GFinder
       if (doFindAll)
       {
         // then we report the matches that were found
-        String message = (idMatch.size() > 0) ? "" + idMatch.size() + " IDs"
-                : "";
+        StringBuilder message = new StringBuilder();
+        if (idMatch.size() > 0)
+        {
+          message.append(idMatch.size()).append(" IDs");
+        }
         if (searchResults != null)
         {
           if (idMatch.size() > 0 && searchResults.getCount() > 0)
           {
-            message += " and ";
+            message.append(" ").append(
+                    MessageManager.getString("label.and").toLowerCase(Locale.ROOT))
+                    .append(" ");
           }
-          message += searchResults.getCount()
-                  + " subsequence matches found.";
+          message.append(MessageManager.formatMessage(
+                  "label.subsequence_matches_found",
+                  searchResults.getCount()));
         }
-        JvOptionPane.showInternalMessageDialog(this, message, null,
-                JvOptionPane.PLAIN_MESSAGE);
+        JvOptionPane.showInternalMessageDialog(this, message.toString(),
+                null, JvOptionPane.INFORMATION_MESSAGE);
       }
     }
   }
@@ -371,15 +410,4 @@ public class Finder extends GFinder
       ap.alignFrame.requestFocus();
     }
   }
-
-  @Override
-  protected void paintComponent(Graphics g)
-  {
-    /*
-     * enable 'hidden regions' option only if
-     * 'top' viewport has hidden columns
-     */
-    getFocusedViewport();
-    super.paintComponent(g);
-  }
 }
index 8d62433..7bdcb2e 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import jalview.util.MessageManager;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
@@ -227,11 +229,11 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
         if (child.getUserObject() instanceof DbSourceProxy)
         {
           names[i] = ((DbSourceProxy) child.getUserObject()).getDbName()
-                  .toLowerCase();
+                  .toLowerCase(Locale.ROOT);
         }
         else
         {
-          names[i] = ((String) child.getUserObject()).toLowerCase();
+          names[i] = ((String) child.getUserObject()).toLowerCase(Locale.ROOT);
           sortTreeNodes(child);
         }
       }
index 02c8fe1..9bdbf61 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.bin.Console;
 import jalview.util.MessageManager;
 
 import java.awt.Component;
@@ -54,16 +55,8 @@ public class OOMWarning implements Runnable
       desktop = instance;
       if (oomex != null)
       {
-        if (jalview.bin.Cache.log != null)
-        {
-          jalview.bin.Cache.log.error("Out of Memory when " + action,
+        Console.error("Out of Memory when " + action,
                   oomex);
-        }
-        else
-        {
-          System.err.println("Out of Memory when " + action);
-          oomex.printStackTrace();
-        }
       }
       javax.swing.SwingUtilities.invokeLater(this);
       System.gc();
index 0f4d0e7..53b0305 100644 (file)
  */
 package jalview.gui;
 
-import jalview.util.MessageManager;
-import jalview.ws.params.ArgumentI;
-import jalview.ws.params.OptionI;
-import jalview.ws.params.ParameterI;
-import jalview.ws.params.ValueConstrainI;
-import jalview.ws.params.ValueConstrainI.ValueType;
-
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -35,6 +28,8 @@ import java.awt.GridLayout;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.MouseEvent;
@@ -59,6 +54,12 @@ import javax.swing.border.TitledBorder;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.ParameterI;
+import jalview.ws.params.ValueConstrainI;
+import jalview.ws.params.ValueConstrainI.ValueType;
 import net.miginfocom.swing.MigLayout;
 
 /**
@@ -92,7 +93,7 @@ public class OptsAndParamsPage
 
     JLabel optlabel = new JLabel();
 
-    JComboBox val = new JComboBox();
+    JComboBox<String> val = new JComboBox<>();
 
     public OptionBox(OptionI opt)
     {
@@ -126,7 +127,7 @@ public class OptsAndParamsPage
         }
       }
       add(enabled, BorderLayout.NORTH);
-      for (Object str : opt.getPossibleValues())
+      for (String str : opt.getPossibleValues())
       {
         val.addItem(str);
       }
@@ -588,7 +589,7 @@ public class OptsAndParamsPage
       {
         if (choice)
         {
-          choicebox = new JComboBox();
+          choicebox = new JComboBox<>();
           choicebox.addActionListener(this);
           controlPanel.add(choicebox, BorderLayout.CENTER);
         }
@@ -621,8 +622,19 @@ public class OptsAndParamsPage
             {
             }
           });
+          valueField.addFocusListener(new FocusAdapter() {
+
+            @Override
+            public void focusLost(FocusEvent e)
+            {
+              actionPerformed(null);
+            }
+            
+          });
           valueField.setPreferredSize(new Dimension(60, 25));
+          valueField.setText(parm.getValue());
           slider = makeSlider(parm.getValidValue());
+          updateSliderFromValueField();
           slider.addChangeListener(this);
 
           controlPanel.add(slider, BorderLayout.WEST);
index 6c76c3e..c0c347a 100644 (file)
@@ -24,7 +24,7 @@ import jalview.analysis.scoremodels.ScoreModels;
 import jalview.api.AlignViewportI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
@@ -297,7 +297,7 @@ public class PCAPanel extends GPCAPanel
     // JAL-2647 disabled after load from project (until save to project done)
     if (getPcaModel().getInputData() == null)
     {
-      Cache.log.info(
+      Console.info(
               "Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
       return;
     }
index 2a7fb9f..1c3ab8f 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.event.ActionEvent;
@@ -54,7 +56,7 @@ import jalview.analysis.AlignmentAnnotationUtils;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.Conservation;
 import jalview.api.AlignViewportI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.ChangeCaseCommand;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
@@ -228,13 +230,13 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         urlLink = new UrlLink(link);
       } catch (Exception foo)
       {
-        Cache.log.error("Exception for URLLink '" + link + "'", foo);
+        Console.error("Exception for URLLink '" + link + "'", foo);
         continue;
       }
 
       if (!urlLink.isValid())
       {
-        Cache.log.error(urlLink.getInvalidMessage());
+        Console.error(urlLink.getInvalidMessage());
         continue;
       }
 
@@ -837,10 +839,14 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
       /*
        * show local rather than linked feature coordinates
        */
-      int[] beginRange = mf.getMappedPositions(start, start);
-      start = beginRange[0];
-      int[] endRange = mf.getMappedPositions(end, end);
-      end = endRange[endRange.length - 1];
+      int[] localRange = mf.getMappedPositions(start, end);
+      if (localRange == null)
+      {
+        // e.g. variant extending to stop codon so not mappable
+        return;
+      }
+      start = localRange[0];
+      end = localRange[localRange.length - 1];
     }
     StringBuilder desc = new StringBuilder();
     desc.append(sf.getType()).append(" ").append(String.valueOf(start));
@@ -1125,7 +1131,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         for (int d = 0; d < nd; d++)
         {
           DBRefEntry e = dbr.get(d);
-          String src = e.getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase();
+          String src = e.getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase(Locale.ROOT);
           Object[] sarray = commonDbrefs.get(src);
           if (sarray == null)
           {
@@ -1159,19 +1165,19 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         urlLink = new GroupUrlLink(link);
       } catch (Exception foo)
       {
-        Cache.log.error("Exception for GroupURLLink '" + link + "'", foo);
+        Console.error("Exception for GroupURLLink '" + link + "'", foo);
         continue;
       }
       if (!urlLink.isValid())
       {
-        Cache.log.error(urlLink.getInvalidMessage());
+        Console.error(urlLink.getInvalidMessage());
         continue;
       }
       final String label = urlLink.getLabel();
       boolean usingNames = false;
       // Now see which parts of the group apply for this URL
       String ltarget = urlLink.getTarget(); // jalview.util.DBRefUtils.getCanonicalName(urlLink.getTarget());
-      Object[] idset = commonDbrefs.get(ltarget.toUpperCase());
+      Object[] idset = commonDbrefs.get(ltarget.toUpperCase(Locale.ROOT));
       String[] seqstr, ids; // input to makeUrl
       if (idset != null)
       {
index 6972657..b9f30e3 100755 (executable)
@@ -31,6 +31,7 @@ import java.awt.event.MouseEvent;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
 
 import javax.help.HelpSetException;
 import javax.swing.JComboBox;
@@ -53,6 +54,8 @@ import javax.swing.table.TableRowSorter;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.bin.MemorySetting;
 import jalview.ext.pymol.PymolManager;
 import jalview.gui.Help.HelpId;
 import jalview.gui.StructureViewer.ViewerType;
@@ -145,10 +148,10 @@ public class Preferences extends GPreferences
 
   /**
    * Holds name and link separated with | character. Sequence IDS and Sequences
-   * must be $SEQUENCEIDS$ or $SEQUENCEIDS=/.possible | chars ./=$ and
-   * $SEQUENCES$ or $SEQUENCES=/.possible | chars ./=$ and separation character
-   * for first and second token specified after a pipe character at end |,|.
-   * (TODO: proper escape for using | to separate ids or sequences
+   * must be $SEQUENCEIDS$ or $SEQUENCEIDS=/.possible | chars ./=$ and $SEQUENCES$
+   * or $SEQUENCES=/.possible | chars ./=$ and separation character for first and
+   * second token specified after a pipe character at end |,|. (TODO: proper
+   * escape for using | to separate ids or sequences
    */
 
   public static List<String> groupURLLinks;
@@ -219,19 +222,27 @@ public class Preferences extends GPreferences
 
   public static void openPreferences()
   {
-    openPreferences(0, null);
+    openPreferences(null, null);
   }
 
-  public static void openPreferences(int selectTab, String message)
+  public static void openPreferences(TabRef selectTab, String message)
   {
     Preferences p = getInstance();
-    p.selectTab(selectTab);
-    p.setMessage(message);
+    if (selectTab != null)
+      p.selectTab(selectTab, message);
     p.frame.show();
     p.frame.moveToFront();
     p.frame.grabFocus();
   }
 
+  public void selectTab(TabRef selectTab, String message)
+  {
+    this.selectTab(selectTab);
+    if (message != null)
+      this.setMessage(message);
+    this.frame.show();
+  }
+
   /**
    * Creates a new Preferences object.
    */
@@ -346,8 +357,8 @@ public class Preferences extends GPreferences
     startupCheckbox
             .setSelected(Cache.getDefault("SHOW_STARTUP_FILE", true));
     startupFileTextfield.setText(Cache.getDefault("STARTUP_FILE",
-            Cache.getDefault("www.jalview.org", "http://www.jalview.org")
-                    + "/examples/exampleFile_2_3.jar"));
+            Cache.getDefault("www.jalview.org", "https://www.jalview.org")
+                    + "/examples/exampleFile_2_7.jvp"));
 
     /*
      * Set Colours tab defaults
@@ -387,13 +398,11 @@ public class Preferences extends GPreferences
     /*
      * Set Structure tab defaults
      */
-    final boolean structSelected = Cache.getDefault(STRUCT_FROM_PDB, false);
+    final boolean structSelected = Cache.getDefault(STRUCT_FROM_PDB, true);
     structFromPdb.setSelected(structSelected);
-    useRnaView.setSelected(Cache.getDefault(USE_RNAVIEW, false));
-    useRnaView.setEnabled(structSelected);
-    addSecondaryStructure.setSelected(Cache.getDefault(ADD_SS_ANN, false));
+    addSecondaryStructure.setSelected(Cache.getDefault(ADD_SS_ANN, true));
     addSecondaryStructure.setEnabled(structSelected);
-    addTempFactor.setSelected(Cache.getDefault(ADD_TEMPFACT_ANN, false));
+    addTempFactor.setSelected(Cache.getDefault(ADD_TEMPFACT_ANN, true));
     addTempFactor.setEnabled(structSelected);
 
     /*
@@ -424,7 +433,7 @@ public class Preferences extends GPreferences
       }
     } catch (IllegalArgumentException e)
     {
-      Cache.log.error("Unknown structure viewer type: " + viewerType
+      Console.error("Unknown structure viewer type: " + viewerType
               + ", defaulting to Jmol");
       type = ViewerType.JMOL;
     }
@@ -437,11 +446,27 @@ public class Preferences extends GPreferences
       {
         if (validateViewerPath())
         {
-          Cache.setProperty(
-                  structViewer.getSelectedItem().equals(
-                          ViewerType.CHIMERAX.name()) ? CHIMERAX_PATH
-                                  : CHIMERA_PATH,
-                  structureViewerPath.getText());
+          String path = structureViewerPath.getText();
+          try {
+          ViewerType type = ViewerType.valueOf(viewerType);
+          switch (type)
+          {
+          case JMOL:
+            break;
+          case CHIMERA:
+            Cache.setProperty(CHIMERA_PATH, path);
+            break;
+          case CHIMERAX:
+            Cache.setProperty(CHIMERAX_PATH, path);
+            break;
+          case PYMOL:
+            Cache.setProperty(PYMOL_PATH, path);
+            break;
+          }
+        } catch (IllegalArgumentException x)
+        {
+          Console.error("Failed to set path - unknown viewer type",x);
+        }
         }
       }
     });
@@ -596,7 +621,7 @@ public class Preferences extends GPreferences
       proxyType.setSelected(customProxy.getModel(), true);
       break;
     default:
-      Cache.log.warn(
+      Console.warn(
               "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): "
                       + proxyTypeString);
     }
@@ -660,6 +685,11 @@ public class Preferences extends GPreferences
      * Set Backups tab defaults
      */
     loadLastSavedBackupsOptions();
+
+    /*
+     * Set Startup tab defaults
+     */
+
   }
 
   /**
@@ -820,8 +850,6 @@ public class Preferences extends GPreferences
             Boolean.toString(addTempFactor.isSelected()));
     Cache.applicationProperties.setProperty(ADD_SS_ANN,
             Boolean.toString(addSecondaryStructure.isSelected()));
-    Cache.applicationProperties.setProperty(USE_RNAVIEW,
-            Boolean.toString(useRnaView.isSelected()));
     Cache.applicationProperties.setProperty(STRUCT_FROM_PDB,
             Boolean.toString(structFromPdb.isSelected()));
     String viewer = structViewer.getSelectedItem().toString();
@@ -974,6 +1002,21 @@ public class Preferences extends GPreferences
     Cache.applicationProperties.setProperty(
             BackupFilesPresetEntry.SAVEDCONFIG, savedBFPE.toString());
 
+    /*
+     * Save Memory Settings
+     */
+    Cache.applicationProperties.setProperty(
+            MemorySetting.CUSTOMISED_SETTINGS,
+            Boolean.toString(customiseMemorySetting.isSelected()));
+    Cache.applicationProperties.setProperty(MemorySetting.MEMORY_JVMMEMPC,
+            Integer.toString(jvmMemoryPercentSlider.getValue()));
+    Cache.applicationProperties.setProperty(MemorySetting.MEMORY_JVMMEMMAX,
+            jvmMemoryMaxTextField.getText());
+
+    /*
+     * save and close Preferences
+     */
+
     Cache.saveProperties();
     Desktop.instance.doConfigureStructurePrefs();
     try
@@ -1009,8 +1052,8 @@ public class Preferences extends GPreferences
   }
 
   /**
-   * Do any necessary validation before saving settings. Return focus to the
-   * first tab which fails validation.
+   * Do any necessary validation before saving settings. Return focus to the first
+   * tab which fails validation.
    * 
    * @return
    */
@@ -1064,7 +1107,7 @@ public class Preferences extends GPreferences
    * DOCUMENT ME!
    * 
    * @param e
-   *          DOCUMENT ME!
+   *            DOCUMENT ME!
    */
   @Override
   public void cancel_actionPerformed(ActionEvent e)
@@ -1086,7 +1129,7 @@ public class Preferences extends GPreferences
    * DOCUMENT ME!
    * 
    * @param e
-   *          DOCUMENT ME!
+   *            DOCUMENT ME!
    */
   @Override
   public void annotations_actionPerformed(ActionEvent e)
@@ -1147,7 +1190,7 @@ public class Preferences extends GPreferences
     if (index == -1)
     {
       // button no longer enabled if row is not selected
-      Cache.log.debug("Edit with no row selected in linkUrlTable");
+      Console.debug("Edit with no row selected in linkUrlTable");
       return;
     }
 
@@ -1199,7 +1242,7 @@ public class Preferences extends GPreferences
     if (index == -1)
     {
       // button no longer enabled if row is not selected
-      Cache.log.debug("Delete with no row selected in linkUrlTable");
+      Console.debug("Delete with no row selected in linkUrlTable");
       return;
     }
     else
@@ -1349,8 +1392,8 @@ public class Preferences extends GPreferences
   }
 
   /**
-   * Returns true if structure viewer path is to a valid executable, else shows
-   * an error dialog. Does nothing if the path is empty, as is the case for Jmol
+   * Returns true if structure viewer path is to a valid executable, else shows an
+   * error dialog. Does nothing if the path is empty, as is the case for Jmol
    * (built in to Jalview) or when Jalview is left to try default paths.
    */
   private boolean validateViewerPath()
@@ -1371,8 +1414,8 @@ public class Preferences extends GPreferences
   }
 
   /**
-   * If Chimera or ChimeraX or Pymol is selected, check it can be found on
-   * default or user-specified path, if not show a warning/help dialog
+   * If Chimera or ChimeraX or Pymol is selected, check it can be found on default
+   * or user-specified path, if not show a warning/help dialog
    */
   @Override
   protected void structureViewer_actionPerformed(String selectedItem)
@@ -1439,8 +1482,10 @@ public class Preferences extends GPreferences
                       MessageManager.getString("label.viewer_missing")),
               "", JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
               null, options, options[0]);
+
       if (showHelp == JvOptionPane.NO_OPTION)
       {
+        this.selectTab(Preferences.TabRef.STRUCTURE_TAB, null);
         try
         {
           Help.showHelpWindow(HelpId.StructureViewer);
@@ -1449,6 +1494,24 @@ public class Preferences extends GPreferences
           e.printStackTrace();
         }
       }
+      else if (showHelp == JvOptionPane.OK_OPTION)
+      {
+        this.selectTab(Preferences.TabRef.STRUCTURE_TAB, null);
+        CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
+          try
+          {
+            for (int i = 0; i < 3; i++)
+            {
+              structureViewerPath.setBackground(Color.PINK);
+              Thread.sleep(500);
+              structureViewerPath.setBackground(Color.WHITE);
+              Thread.sleep(500);
+            }
+          } catch (InterruptedException e)
+          {
+          }
+        });
+      }
     }
   }
 
index cb59452..31db21d 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 
 import java.awt.Component;
 
@@ -89,7 +90,7 @@ public class PromptUserConfig implements Runnable
    * @param desktop
    *          - where the dialog box will be shown
    * @param property
-   *          - boolean property in jalview.bin.Cache
+   *          - boolean property in Cache
    * @param dialogTitle
    *          - title of prompt box
    * @param dialogText
@@ -126,14 +127,14 @@ public class PromptUserConfig implements Runnable
       return;
     }
     // First - check to see if wee have an old questionnaire/response id pair.
-    String lastq = jalview.bin.Cache.getProperty(property);
+    String lastq = Cache.getProperty(property);
 
     if (lastq == null)
     {
       raiseDialog();
-      Cache.log.debug("Got user response.");
+      Console.debug("Got user response.");
     }
-    lastq = jalview.bin.Cache.getProperty(property);
+    lastq = Cache.getProperty(property);
     String extype = "";
     Exception e = null;
     if (lastq == null)
@@ -183,7 +184,7 @@ public class PromptUserConfig implements Runnable
     // report any exceptions
     if (e != null)
     {
-      Cache.log.warn("Unexpected exception when executing the " + extype
+      Console.warn("Unexpected exception when executing the " + extype
               + " runnable for property " + property, e);
     }
   }
@@ -193,9 +194,9 @@ public class PromptUserConfig implements Runnable
    */
   private void raiseDialog()
   {
-    if (jalview.bin.Cache.log.isDebugEnabled())
+    if (Console.isDebugEnabled())
     {
-      jalview.bin.Cache.log.debug("Prompting user for " + dialogTitle
+      Console.debug("Prompting user for " + dialogTitle
               + " for Cache property " + property);
     }
     try
@@ -207,36 +208,36 @@ public class PromptUserConfig implements Runnable
               JvOptionPane.QUESTION_MESSAGE);
 
       // and finish parsing the result
-      jalview.bin.Cache.log.debug("Got response : " + reply);
+      Console.debug("Got response : " + reply);
       if (reply == JvOptionPane.YES_OPTION)
       {
-        jalview.bin.Cache.setProperty(property, "true");
+        Cache.setProperty(property, "true");
       }
       else if (reply == JvOptionPane.NO_OPTION)
       {
         if (removeifunset)
         {
-          jalview.bin.Cache.removeProperty(property);
+          Cache.removeProperty(property);
         }
         else
         {
-          jalview.bin.Cache.setProperty(property, "false");
+          Cache.setProperty(property, "false");
         }
       }
       else
       {
-        jalview.bin.Cache.log.debug("User cancelled setting " + property);
+        Console.debug("User cancelled setting " + property);
         return;
       }
       // verify the property is set for debugging
-      if (jalview.bin.Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        jalview.bin.Cache.log.debug("User set property to "
-                + jalview.bin.Cache.getProperty(property));
+        Console.debug("User set property to "
+                + Cache.getProperty(property));
       }
     } catch (Exception e)
     {
-      jalview.bin.Cache.log.warn(
+      Console.warn(
               "Unexpected exception when prompting user for yes/no setting for property "
                       + property,
               e);
index 538b101..6aba7b6 100644 (file)
@@ -6,7 +6,7 @@ import java.util.List;
 import java.util.Map;
 
 import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.ext.pymol.PymolCommands;
@@ -70,15 +70,14 @@ public class PymolBindingModel extends AAStructureBindingModel
   public void highlightAtoms(List<AtomSpec> atoms)
   {
     /*
-     * https://pymolwiki.org/index.php/Label#examples
+     * https://pymolwiki.org/index.php/indicate#examples
      */
     StringBuilder sb = new StringBuilder();
     for (AtomSpec atom : atoms)
     {
       // todo promote to StructureCommandsI.showLabel()
-      // todo handle CA|P correctly
       String modelId = getModelIdForFile(atom.getPdbFile());
-      sb.append(String.format(" %s//%s/%d/CA", modelId,
+      sb.append(String.format(" %s//%s/%d/*", modelId,
               atom.getChain(),
               atom.getPdbResNum()));
     }
@@ -87,18 +86,9 @@ public class PymolBindingModel extends AAStructureBindingModel
     {
       return;
     }
-    StructureCommandI command = new StructureCommand("label", labelSpec, LABEL_FORMAT);
+    StructureCommandI command = new StructureCommand("indicate", labelSpec);
     executeCommand(command, false);
 
-    /*
-     * and remove the label(s) previously shown
-     */
-    if (lastLabelSpec != null)
-    {
-      command = new StructureCommand("label", lastLabelSpec, "");
-      executeCommand(command, false);
-    }
-
     lastLabelSpec = labelSpec;
   }
 
@@ -156,7 +146,7 @@ public class PymolBindingModel extends AAStructureBindingModel
     }
     else
     {
-      Cache.log.error("Failed to launch PyMOL!");
+      Console.error("Failed to launch PyMOL!");
     }
     return pymol != null;
   }
@@ -171,6 +161,21 @@ public class PymolBindingModel extends AAStructureBindingModel
      * a second parameter sets the pdbid as the loaded PyMOL object name
      */
     String pdbId = pe.getId();
+    try {
+      String safePDBId = java.net.URLEncoder.encode(pdbId,"UTF-8");
+      pdbId = safePDBId.replace('%', '_');
+      pdbId = pdbId.replace("-", "__");
+      char fc = pdbId.charAt(0);
+      // put an 's' before any numerics
+      if (fc>='0' && fc<='9')
+      {
+        pdbId = 's'+pdbId;
+      }
+//      pdbId.replace('-', 0)
+    } catch (Exception x)
+    {
+      Console.error("Unxpected encoding exception for '"+pdbId+"'",x);
+    }
     cmd.addParameter(pdbId);
 
     executeCommand(cmd, false);
index c5a4c9a..d426051 100644 (file)
@@ -14,7 +14,7 @@ import javax.swing.event.InternalFrameEvent;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.StructureViewerModel;
@@ -210,7 +210,7 @@ public class PymolViewer extends StructureViewerBase
           initPymol();
         } catch (Exception ex)
         {
-          Cache.log.error("Couldn't open PyMOL viewer!", ex);
+          Console.error("Couldn't open PyMOL viewer!", ex);
         }
       }
       int num = -1;
@@ -249,12 +249,12 @@ public class PymolViewer extends StructureViewerBase
             binding.stashFoundChains(pdb, pe.getFile());
           } catch (Exception ex)
           {
-            Cache.log.error(
+            Console.error(
                     "Couldn't open " + pe.getFile() + " in Chimera viewer!",
                     ex);
           } finally
           {
-            // Cache.log.debug("File locations are " + files);
+            // Cache.debug("File locations are " + files);
           }
         }
       }
@@ -323,7 +323,7 @@ public class PymolViewer extends StructureViewerBase
       boolean opened = binding.openSession(pymolSessionFile);
       if (!opened)
       {
-        Cache.log.error(
+        Console.error(
                 "An error occurred opening PyMOL session file "
                 + pymolSessionFile);
       }
@@ -348,7 +348,7 @@ public class PymolViewer extends StructureViewerBase
   {
     return "PyMOL";
   }
-
+  JMenuItem writeFeatures = null;
   @Override
   protected void initMenus()
   {
@@ -357,7 +357,7 @@ public class PymolViewer extends StructureViewerBase
     savemenu.setVisible(false); // not yet implemented
     viewMenu.add(fitToWindow);
 
-    JMenuItem writeFeatures = new JMenuItem(
+    writeFeatures = new JMenuItem(
             MessageManager.getString("label.create_viewer_attributes"));
     writeFeatures.setToolTipText(MessageManager
             .getString("label.create_viewer_attributes_tip"));
@@ -371,12 +371,19 @@ public class PymolViewer extends StructureViewerBase
     });
     viewerActionMenu.add(writeFeatures);
   }
+  
+  @Override
+  protected void buildActionMenu()
+  {
+    super.buildActionMenu();
+    viewerActionMenu.add(writeFeatures);
+  }
 
   protected void sendFeaturesToPymol()
   {
     int count = binding.sendFeaturesToViewer(getAlignmentPanel());
     statusBar.setText(
-            MessageManager.formatMessage("label.attributes_set", count));
+            MessageManager.formatMessage("label.attributes_set", count, getViewerName())); 
   }
 
 }
index 561fb3c..d7cb78a 100755 (executable)
@@ -508,7 +508,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     }
     else if (evt.getKeyChar() == 's')
     {
-      // Cache.log.warn("DEBUG: Rectangle selection");
+      // Cache.warn("DEBUG: Rectangle selection");
       // todo not yet enabled as rectx2, recty2 are always -1
       // need to set them in mouseDragged; JAL-1124
       // if ((rectx2 != -1) && (recty2 != -1))
index 163ae25..827c315 100644 (file)
@@ -44,7 +44,7 @@ import javax.swing.Timer;
 import javax.swing.ToolTipManager;
 
 import jalview.api.AlignViewportI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
@@ -483,47 +483,80 @@ public class SeqPanel extends JPanel
 
   void moveCursor(int dx, int dy)
   {
-    seqCanvas.cursorX += dx;
-    seqCanvas.cursorY += dy;
-
+    moveCursor(dx, dy,false);
+  }
+  void moveCursor(int dx, int dy, boolean nextWord)
+  {
     HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 
-    if (av.hasHiddenColumns() && !hidden.isVisible(seqCanvas.cursorX))
+    if (nextWord)
     {
-      int original = seqCanvas.cursorX - dx;
       int maxWidth = av.getAlignment().getWidth();
-
-      if (!hidden.isVisible(seqCanvas.cursorX))
-      {
-        int visx = hidden.absoluteToVisibleColumn(seqCanvas.cursorX - dx);
-        int[] region = hidden.getRegionWithEdgeAtRes(visx);
-
-        if (region != null) // just in case
+      int maxHeight=av.getAlignment().getHeight();
+      SequenceI seqAtRow = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
+      // look for next gap or residue
+      boolean isGap = Comparison.isGap(seqAtRow.getCharAt(seqCanvas.cursorX));
+      int p = seqCanvas.cursorX,lastP,r=seqCanvas.cursorY,lastR;
+      do
+      {
+        lastP = p;
+        lastR = r;
+        if (dy != 0)
         {
-          if (dx == 1)
+          r += dy;
+          if (r < 0)
           {
-            // moving right
-            seqCanvas.cursorX = region[1] + 1;
+            r = 0;
           }
-          else if (dx == -1)
+          if (r >= maxHeight)
           {
-            // moving left
-            seqCanvas.cursorX = region[0] - 1;
+            r = maxHeight - 1;
           }
+          seqAtRow = av.getAlignment().getSequenceAt(r);
         }
-        seqCanvas.cursorX = (seqCanvas.cursorX < 0) ? 0 : seqCanvas.cursorX;
-      }
+        p = nextVisible(hidden, maxWidth, p, dx);
+      } while ((dx != 0 ? p != lastP : r != lastR)
+              && isGap == Comparison.isGap(seqAtRow.getCharAt(p)));
+      seqCanvas.cursorX=p;
+      seqCanvas.cursorY=r;
+    } else {
+      int maxWidth = av.getAlignment().getWidth();
+      seqCanvas.cursorX = nextVisible(hidden, maxWidth, seqCanvas.cursorX, dx);
+      seqCanvas.cursorY += dy;
+    }
+    scrollToVisible(false);
+  }
 
-      if (seqCanvas.cursorX >= maxWidth
-              || !hidden.isVisible(seqCanvas.cursorX))
+  private int nextVisible(HiddenColumns hidden,int maxWidth, int original, int dx)
+  {
+    int newCursorX=original+dx;
+    if (av.hasHiddenColumns() && !hidden.isVisible(newCursorX))
+    {
+      int visx = hidden.absoluteToVisibleColumn(newCursorX - dx);
+      int[] region = hidden.getRegionWithEdgeAtRes(visx);
+
+      if (region != null) // just in case
       {
-        seqCanvas.cursorX = original;
+        if (dx == 1)
+        {
+          // moving right
+          newCursorX = region[1] + 1;
+        }
+        else if (dx == -1)
+        {
+          // moving left
+          newCursorX = region[0] - 1;
+        }
       }
     }
-
-    scrollToVisible(false);
+    newCursorX = (newCursorX < 0) ? 0 : newCursorX;
+    if (newCursorX >= maxWidth
+            || !hidden.isVisible(newCursorX))
+    {
+      newCursorX = original;
+    }
+    return newCursorX;
   }
-
   /**
    * Scroll to make the cursor visible in the viewport.
    * 
@@ -2769,7 +2802,7 @@ public class SeqPanel extends JPanel
     {
       if (av.getAlignment() == null)
       {
-        Cache.log.warn("alignviewport av SeqSetId=" + av.getSequenceSetId()
+        Console.warn("alignviewport av SeqSetId=" + av.getSequenceSetId()
                 + " ViewId=" + av.getViewId()
                 + " 's alignment is NULL! returning immediately.");
         return;
index 8b5d3b7..e596fbf 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.api.FeatureSettingsModelI;
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.SequenceI;
-import jalview.fts.core.GFTSPanel;
-import jalview.fts.service.pdb.PDBFTSPanel;
-import jalview.fts.service.uniprot.UniprotFTSPanel;
-import jalview.io.FileFormatI;
-import jalview.io.gff.SequenceOntologyI;
-import jalview.util.DBRefUtils;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.ws.seqfetcher.DbSourceProxy;
-
 import java.awt.BorderLayout;
 import java.awt.Font;
 import java.awt.event.ActionEvent;
@@ -57,6 +42,23 @@ import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
 import javax.swing.SwingConstants;
 
+import jalview.api.FeatureSettingsModelI;
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.SequenceI;
+import jalview.fts.core.GFTSPanel;
+import jalview.fts.service.pdb.PDBFTSPanel;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSPanel;
+import jalview.fts.service.uniprot.UniprotFTSPanel;
+import jalview.io.FileFormatI;
+import jalview.io.gff.SequenceOntologyI;
+import jalview.util.DBRefUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.seqfetcher.DbSourceProxy;
+
 /**
  * A panel where the use may choose a database source, and enter one or more
  * accessions, to retrieve entries from the database.
@@ -66,11 +68,50 @@ import javax.swing.SwingConstants;
  */
 public class SequenceFetcher extends JPanel implements Runnable
 {
+  private class StringPair
+  {
+    private String key;
+
+    private String display;
+
+    public StringPair(String s1, String s2)
+    {
+      key = s1;
+      display = s2;
+    }
+
+    public StringPair(String s)
+    {
+      this(s, s);
+    }
+
+    public String getKey()
+    {
+      return key;
+    }
+
+    public String getDisplay()
+    {
+      return display;
+    }
+
+    @Override
+    public String toString()
+    {
+      return display;
+    }
+
+    public boolean equals(StringPair other)
+    {
+      return other.key == this.key;
+    }
+  }
+
   private static jalview.ws.SequenceFetcher sfetch = null;
 
   JLabel exampleAccession;
 
-  JComboBox<String> database;
+  JComboBox<StringPair> database;
 
   JCheckBox replacePunctuation;
 
@@ -145,8 +186,8 @@ public class SequenceFetcher extends JPanel implements Runnable
 
     frame = new JInternalFrame();
     frame.setContentPane(this);
-    Desktop.addInternalFrame(frame, getFrameTitle(), true, 400, 
-               Platform.isAMacAndNotJS() ? 240 : 180);
+    Desktop.addInternalFrame(frame, getFrameTitle(), true, 400,
+            Platform.isAMacAndNotJS() ? 240 : 180);
   }
 
   private String getFrameTitle()
@@ -163,15 +204,25 @@ public class SequenceFetcher extends JPanel implements Runnable
 
     database = new JComboBox<>();
     database.setFont(JvSwingUtils.getLabelFont());
-    database.setPrototypeDisplayValue("ENSEMBLGENOMES   ");
+    StringPair instructionItem = new StringPair(
+            MessageManager.getString("action.select_ddbb"));
+    database.setPrototypeDisplayValue(instructionItem);
     String[] sources = new jalview.ws.SequenceFetcher().getSupportedDb();
     Arrays.sort(sources, String.CASE_INSENSITIVE_ORDER);
-    database.addItem(MessageManager.getString("action.select_ddbb"));
+    database.addItem(instructionItem);
     for (String source : sources)
     {
-      database.addItem(source);
+      List<DbSourceProxy> slist = sfetch.getSourceProxy(source);
+      if (slist.size() == 1 && slist.get(0) != null)
+      {
+        database.addItem(new StringPair(source, slist.get(0).getDbName()));
+      }
+      else
+      {
+        database.addItem(new StringPair(source));
+      }
     }
-    database.setSelectedItem(selectedDb);
+    setDatabaseSelectedItem(selectedDb);
     if (database.getSelectedIndex() == -1)
     {
       database.setSelectedIndex(0);
@@ -182,7 +233,8 @@ public class SequenceFetcher extends JPanel implements Runnable
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        String currentSelection = (String) database.getSelectedItem();
+        String currentSelection = ((StringPair) database.getSelectedItem())
+                .getKey();
         updateExampleQuery(currentSelection);
 
         if ("pdb".equalsIgnoreCase(currentSelection))
@@ -195,6 +247,11 @@ public class SequenceFetcher extends JPanel implements Runnable
           frame.dispose();
           new UniprotFTSPanel(SequenceFetcher.this);
         }
+        else if ("3d-beacons".equalsIgnoreCase(currentSelection))
+        {
+          frame.dispose();
+          new TDBeaconsFTSPanel(SequenceFetcher.this);
+        }
         else
         {
           otherSourceAction();
@@ -304,6 +361,19 @@ public class SequenceFetcher extends JPanel implements Runnable
     this.add(databasePanel, BorderLayout.NORTH);
   }
 
+  private void setDatabaseSelectedItem(String db)
+  {
+    for (int i = 0; i < database.getItemCount(); i++)
+    {
+      StringPair sp = database.getItemAt(i);
+      if (sp != null && db != null && db.equals(sp.getKey()))
+      {
+        database.setSelectedIndex(i);
+        return;
+      }
+    }
+  }
+
   /**
    * Answers a semi-colon-delimited string with the example query or queries for
    * the selected database
@@ -375,7 +445,8 @@ public class SequenceFetcher extends JPanel implements Runnable
    */
   protected void example_actionPerformed()
   {
-    String eq = getExampleQueries((String) database.getSelectedItem());
+    String eq = getExampleQueries(
+            ((StringPair) database.getSelectedItem()).getKey());
     textArea.setText(eq);
     repaint();
   }
@@ -424,9 +495,9 @@ public class SequenceFetcher extends JPanel implements Runnable
       text = text.replace(",", ";");
     }
     text = text.replaceAll("(\\s|[; ])+", ";");
-    if (!t0.equals(text)) 
+    if (!t0.equals(text))
     {
-         textArea.setText(text);
+      textArea.setText(text);
     }
     if (text.isEmpty())
     {
@@ -471,8 +542,8 @@ public class SequenceFetcher extends JPanel implements Runnable
     List<String> presultTitle = new ArrayList<>();
     List<AlignmentI> presult = new ArrayList<>();
     List<AlignmentI> aresult = new ArrayList<>();
-    List<DbSourceProxy> sources = sfetch
-            .getSourceProxy((String) database.getSelectedItem());
+    List<DbSourceProxy> sources = sfetch.getSourceProxy(
+            ((StringPair) database.getSelectedItem()).getKey());
     Iterator<DbSourceProxy> proxies = sources.iterator();
     String[] qries = textArea.getText().trim().split(";");
     List<String> nextFetch = Arrays.asList(qries);
@@ -524,23 +595,25 @@ public class SequenceFetcher extends JPanel implements Runnable
       } catch (Exception e)
       {
         showErrorMessage("Error retrieving " + textArea.getText() + " from "
-                + database.getSelectedItem());
+                + ((StringPair) database.getSelectedItem()).getDisplay());
         // error
         // +="Couldn't retrieve sequences from "+database.getSelectedItem();
         System.err.println("Retrieval failed for source ='"
-                + database.getSelectedItem() + "' and query\n'"
-                + textArea.getText() + "'\n");
+                + ((StringPair) database.getSelectedItem()).getDisplay()
+                + "' and query\n'" + textArea.getText() + "'\n");
         e.printStackTrace();
       } catch (OutOfMemoryError e)
       {
         showErrorMessage("Out of Memory when retrieving "
-                + textArea.getText() + " from " + database.getSelectedItem()
+                + textArea.getText() + " from "
+                + ((StringPair) database.getSelectedItem()).getDisplay()
                 + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n");
         e.printStackTrace();
       } catch (Error e)
       {
         showErrorMessage("Serious Error retrieving " + textArea.getText()
-                + " from " + database.getSelectedItem());
+                + " from "
+                + ((StringPair) database.getSelectedItem()).getDisplay());
         e.printStackTrace();
       }
 
@@ -687,7 +760,8 @@ public class SequenceFetcher extends JPanel implements Runnable
     } catch (OutOfMemoryError oome)
     {
       new OOMWarning("fetching " + multiacc + " from "
-              + database.getSelectedItem(), oome, this);
+              + ((StringPair) database.getSelectedItem()).getDisplay(),
+              oome, this);
     }
   }
 
@@ -738,7 +812,7 @@ public class SequenceFetcher extends JPanel implements Runnable
       }
     } catch (Exception e)
     {
-      Cache.log.info("Error retrieving " + accession + " from "
+      Console.info("Error retrieving " + accession + " from "
               + proxy.getDbName(), e);
     }
     return success;
@@ -761,12 +835,12 @@ public class SequenceFetcher extends JPanel implements Runnable
 
     for (String q : queries)
     {
-       // BH 2019.01.25 dbr is never used.
-//      DBRefEntry dbr = new DBRefEntry();
-//      dbr.setSource(proxy.getDbSource());
-//      dbr.setVersion(null);
+      // BH 2019.01.25 dbr is never used.
+      // DBRefEntry dbr = new DBRefEntry();
+      // dbr.setSource(proxy.getDbSource());
+      // dbr.setVersion(null);
       String accId = proxy.getAccessionIdFromQuery(q);
-//      dbr.setAccessionId(accId);
+      // dbr.setAccessionId(accId);
       boolean rfound = false;
       for (int r = 0, nr = rs.length; r < nr; r++)
       {
@@ -795,10 +869,20 @@ public class SequenceFetcher extends JPanel implements Runnable
    */
   public String getDefaultRetrievalTitle()
   {
-    return "Retrieved from " + database.getSelectedItem();
+    return "Retrieved from "
+            + ((StringPair) database.getSelectedItem()).getDisplay();
   }
 
-  AlignmentI parseResult(AlignmentI al, String title,
+  /**
+   * constructs an alignment frame given the data and metadata
+   * 
+   * @param al
+   * @param title
+   * @param currentFileFormat
+   * @param preferredFeatureColours
+   * @return the alignment
+   */
+  public AlignmentI parseResult(AlignmentI al, String title,
           FileFormatI currentFileFormat,
           FeatureSettingsModelI preferredFeatureColours)
   {
@@ -831,10 +915,7 @@ public class SequenceFetcher extends JPanel implements Runnable
           }
         }
 
-        if (preferredFeatureColours != null)
-        {
-          af.getViewport().applyFeaturesStyle(preferredFeatureColours);
-        }
+        af.getViewport().applyFeaturesStyle(preferredFeatureColours);
         if (Cache.getDefault("HIDE_INTRONS", true))
         {
           af.hideFeatureColumns(SequenceOntologyI.EXON, false);
index 7f18461..714e770 100644 (file)
@@ -16,6 +16,12 @@ import javax.swing.JSlider;
 public class Slider extends JSlider
 {
   /*
+   * the number of nominal positions the slider represents
+   * (higher number = more fine-grained positioning)
+   */
+  private static final int SCALE_TICKS = 1000;
+
+  /*
    * 'true' value corresponding to zero on the slider
    */
   private float trueMin;
@@ -57,7 +63,7 @@ public class Slider extends JSlider
     trueMin = min;
     trueMax = max;
     setMinimum(0);
-    sliderScaleFactor = 100f / (max - min);
+    sliderScaleFactor = SCALE_TICKS / (max - min);
     int sliderMax = (int) ((max - min) * sliderScaleFactor);
     setMaximum(sliderMax);
     setSliderValue(value);
index 7ade797..7ce8673 100644 (file)
@@ -814,7 +814,11 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
         if (c != null && c instanceof AlignFrame)
         {
           AlignFrame af = (AlignFrame) c;
-          new Finder(af.alignPanel);
+          boolean dna = af.getViewport().getAlignment().isNucleotide();
+          String scope = MessageManager.getString("label.in") + " "
+                  + (dna ? MessageManager.getString("label.nucleotide")
+                          : MessageManager.getString("label.protein"));
+          new Finder(af.alignPanel, true, scope);
         }
       }
     };
index 33d8c33..34fa751 100644 (file)
 
 package jalview.gui;
 
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.Executors;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
+import javax.swing.table.AbstractTableModel;
+
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.fts.api.FTSData;
 import jalview.fts.api.FTSDataColumnI;
 import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.fts.service.threedbeacons.TDB_FTSData;
+import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
+import jalview.gui.structurechooser.StructureChooserQuerySource;
+import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
 import jalview.io.DataSourceType;
+import jalview.jbgui.FilterOption;
 import jalview.jbgui.GStructureChooser;
 import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.ws.DBRefFetcher;
+import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.seqfetcher.DbSourceProxy;
 import jalview.ws.sifts.SiftsSettings;
 
-import java.awt.event.ItemEvent;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JTable;
-import javax.swing.SwingUtilities;
-import javax.swing.table.AbstractTableModel;
-
 /**
  * Provides the behaviors for the Structure chooser Panel
  * 
@@ -71,8 +81,6 @@ public class StructureChooser extends GStructureChooser
 {
   private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
 
-  private static int MAX_QLENGTH = 7820;
-
   private SequenceI selectedSequence;
 
   private SequenceI[] selectedSequences;
@@ -81,9 +89,13 @@ public class StructureChooser extends GStructureChooser
 
   private Collection<FTSData> discoveredStructuresSet;
 
-  private FTSRestRequest lastPdbRequest;
+  private StructureChooserQuerySource data;
 
-  private FTSRestClientI pdbRestClient;
+  @Override
+  protected FTSDataColumnPreferences getFTSDocFieldPrefs()
+  {
+    return data.getDocFieldPrefs();
+  }
 
   private String selectedPdbFileName;
 
@@ -91,19 +103,78 @@ public class StructureChooser extends GStructureChooser
 
   private boolean cachedPDBExists;
 
+  private Collection<FTSData> lastDiscoveredStructuresSet;
+
+  private boolean canQueryTDB = false;
+
+  private boolean notQueriedTDBYet = true;
+
+  List<SequenceI> seqsWithoutSourceDBRef = null;
+
   private static StructureViewer lastTargetedView = null;
 
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap)
   {
+    // which FTS engine to use
+    data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
+    initDialog();
+
     this.ap = ap;
     this.selectedSequence = selectedSeq;
     this.selectedSequences = selectedSeqs;
     this.progressIndicator = (ap == null) ? null : ap.alignFrame;
     init();
+
   }
 
   /**
+   * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
+   * least one structure are discovered.
+   */
+  private void populateSeqsWithoutSourceDBRef()
+  {
+    seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
+    boolean needCanonical = false;
+    for (SequenceI seq : selectedSequences)
+    {
+      if (seq.isProtein())
+      {
+        int dbRef = ThreeDBStructureChooserQuerySource
+                .checkUniprotRefs(seq.getDBRefs());
+        if (dbRef < 0)
+        {
+          if (dbRef == -1)
+          {
+            // need to retrieve canonicals
+            needCanonical = true;
+            seqsWithoutSourceDBRef.add(seq);
+          }
+          else
+          {
+            // could be a sequence with pdb ref
+            if (seq.getAllPDBEntries() == null
+                    || seq.getAllPDBEntries().size() == 0)
+            {
+              seqsWithoutSourceDBRef.add(seq);
+            }
+          }
+        }
+      }
+    }
+    // retrieve database refs for protein sequences
+    if (!seqsWithoutSourceDBRef.isEmpty())
+    {
+      canQueryTDB = true;
+      if (needCanonical)
+      {
+        // triggers display of the 'Query TDB' button
+        notQueriedTDBYet = true;
+      }
+    }
+  };
+
+  /**
    * Initializes parameters used by the Structure Chooser Panel
    */
   protected void init()
@@ -114,31 +185,174 @@ public class StructureChooser extends GStructureChooser
     }
 
     chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
+    btn_queryTDB.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        promptForTDBFetch(false);
+      }
+    });
+
+    Executors.defaultThreadFactory().newThread(new Runnable()
+    {
+      public void run()
+      {
+        populateSeqsWithoutSourceDBRef();
+        initialStructureDiscovery();
+      }
+
+    }).start();
+
+  }
+
+  // called by init
+  private void initialStructureDiscovery()
+  {
+    // check which FTS engine to use
+    data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
 
     // ensure a filter option is in force for search
     populateFilterComboBox(true, cachedPDBExists);
-    Thread discoverPDBStructuresThread = new Thread(new Runnable()
+
+    // looks for any existing structures already loaded
+    // for the sequences (the cached ones)
+    // then queries the StructureChooserQuerySource to
+    // discover more structures.
+    //
+    // Possible optimisation is to only begin querying
+    // the structure chooser if there are no cached structures.
+
+    long startTime = System.currentTimeMillis();
+    updateProgressIndicator(
+            MessageManager.getString("status.loading_cached_pdb_entries"),
+            startTime);
+    loadLocalCachedPDBEntries();
+    updateProgressIndicator(null, startTime);
+    updateProgressIndicator(
+            MessageManager.getString("status.searching_for_pdb_structures"),
+            startTime);
+    fetchStructuresMetaData();
+    // revise filter options if no results were found
+    populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
+    discoverStructureViews();
+    updateProgressIndicator(null, startTime);
+    mainFrame.setVisible(true);
+    updateCurrentView();
+  }
+
+  /**
+   * raises dialog for Uniprot fetch followed by 3D beacons search
+   * @param ignoreGui - when true, don't ask, just fetch 
+   */
+  public void promptForTDBFetch(boolean ignoreGui)
+  {
+    final long progressId = System.currentTimeMillis();
+
+    // final action after prompting and discovering db refs
+    final Runnable strucDiscovery = new Runnable()
     {
       @Override
       public void run()
       {
-        long startTime = System.currentTimeMillis();
-        updateProgressIndicator(MessageManager
-                .getString("status.loading_cached_pdb_entries"), startTime);
-        loadLocalCachedPDBEntries();
-        updateProgressIndicator(null, startTime);
-        updateProgressIndicator(MessageManager.getString(
-                "status.searching_for_pdb_structures"), startTime);
-        fetchStructuresMetaData();
-        // revise filter options if no results were found
-        populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
-        discoverStructureViews();
-        updateProgressIndicator(null, startTime);
-        mainFrame.setVisible(true);
-        updateCurrentView();
+        mainFrame.setEnabled(false);
+        cmb_filterOption.setEnabled(false);
+        progressBar.setProgressBar(MessageManager.getString("status.searching_3d_beacons"), progressId);
+        // TODO: warn if no accessions discovered
+        populateSeqsWithoutSourceDBRef();
+        // redo initial discovery - this time with 3d beacons
+        // Executors.
+        previousWantedFields=null;
+        lastSelected=(FilterOption) cmb_filterOption.getSelectedItem();
+        cmb_filterOption.setSelectedItem(null);
+        cachedPDBExists=false; // reset to initial
+        initialStructureDiscovery();
+        if (!isStructuresDiscovered())
+        {
+          progressBar.setProgressBar(MessageManager.getString("status.no_structures_discovered_from_3d_beacons"), progressId);
+          btn_queryTDB.setToolTipText(MessageManager.getString("status.no_structures_discovered_from_3d_beacons"));
+          btn_queryTDB.setEnabled(false);
+        } else {
+          cmb_filterOption.setSelectedIndex(0); // select 'best'
+          btn_queryTDB.setVisible(false);
+          progressBar.setProgressBar(null, progressId);
+        }
+        mainFrame.setEnabled(true);
+        cmb_filterOption.setEnabled(true);
       }
-    });
-    discoverPDBStructuresThread.start();
+    };
+
+    final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
+    {
+      
+      @Override
+      public void finished()
+      {
+        // filter has been selected, so we set flag to remove ourselves
+        notQueriedTDBYet = false;
+        // new thread to discover structures - via 3d beacons
+        Executors.defaultThreadFactory().newThread(strucDiscovery).start();
+        
+      }
+    };
+    
+    // fetch db refs if OK pressed
+    final Runnable discoverCanonicalDBrefs = new Runnable() 
+    {
+      @Override
+      public void run()
+      {
+        populateSeqsWithoutSourceDBRef();
+
+        final int y = seqsWithoutSourceDBRef.size();
+        if (y > 0)
+        {
+          final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
+                  .toArray(new SequenceI[y]);
+          DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
+                  progressBar, new DbSourceProxy[]
+                  { new jalview.ws.dbsources.Uniprot() }, null, false);
+          dbRefFetcher.addListener(afterDbRefFetch);
+          // ideally this would also gracefully run with callbacks
+          dbRefFetcher.fetchDBRefs(true);
+        } else {
+          // call finished action directly
+          afterDbRefFetch.finished();
+        }
+      }
+
+    };
+    final Runnable revertview = new Runnable() {
+      public void run() {
+        if (lastSelected!=null) {
+          cmb_filterOption.setSelectedItem(lastSelected);
+        }
+      };
+    };
+    if (ignoreGui)
+    {
+      Executors.defaultThreadFactory().newThread(discoverCanonicalDBrefs).start();
+      return;
+    }
+    // need cancel and no to result in the discoverPDB action - mocked is
+    // 'cancel' TODO: mock should be OK
+    JvOptionPane.newOptionDialog(this)
+            .setResponseHandler(JvOptionPane.OK_OPTION,
+                    discoverCanonicalDBrefs)
+            .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
+            .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
+            .showDialog(
+                    MessageManager.formatMessage(
+                            "label.fetch_references_for_3dbeacons",
+                            seqsWithoutSourceDBRef.size()),
+                    MessageManager
+                            .getString("label.3dbeacons"),
+                    JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
+                    null, new Object[]
+                    { MessageManager.getString("action.ok"),
+                        MessageManager.getString("action.cancel") },
+                    MessageManager.getString("action.ok"));
   }
 
   /**
@@ -165,8 +379,7 @@ public class StructureChooser extends GStructureChooser
 
         if (view.isLinkedWith(ap))
         {
-          targetView.insertItemAt(viewHandler,
-                  linkedViewsAt++);
+          targetView.insertItemAt(viewHandler, linkedViewsAt++);
         }
         else
         {
@@ -217,36 +430,36 @@ public class StructureChooser extends GStructureChooser
   void fetchStructuresMetaData()
   {
     long startTime = System.currentTimeMillis();
-    pdbRestClient = PDBFTSRestClient.getInstance();
-    Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+    Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
             .getStructureSummaryFields();
 
     discoveredStructuresSet = new LinkedHashSet<>();
     HashSet<String> errors = new HashSet<>();
+
+    FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+            .getSelectedItem());
+
     for (SequenceI seq : selectedSequences)
     {
-      FTSRestRequest pdbRequest = new FTSRestRequest();
-      pdbRequest.setAllowEmptySeq(false);
-      pdbRequest.setResponseSize(500);
-      pdbRequest.setFieldToSearchBy("(");
-      FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
-              .getSelectedItem());
-      pdbRequest.setFieldToSortBy(selectedFilterOpt.getValue(),
-              !chk_invertFilter.isSelected());
-      pdbRequest.setWantedFields(wantedFields);
-      pdbRequest.setSearchTerm(buildQuery(seq) + ")");
-      pdbRequest.setAssociatedSequence(seq);
+
       FTSRestResponse resultList;
       try
       {
-        resultList = pdbRestClient.executeRequest(pdbRequest);
+        resultList = data.fetchStructuresMetaData(seq, wantedFields,
+                selectedFilterOpt, !chk_invertFilter.isSelected());
+        // null response means the FTSengine didn't yield a query for this
+        // consider designing a special exception if we really wanted to be
+        // OOCrazy
+        if (resultList == null)
+        {
+          continue;
+        }
       } catch (Exception e)
       {
         e.printStackTrace();
         errors.add(e.getMessage());
         continue;
       }
-      lastPdbRequest = pdbRequest;
       if (resultList.getSearchSummary() != null
               && !resultList.getSearchSummary().isEmpty())
       {
@@ -260,9 +473,11 @@ public class StructureChooser extends GStructureChooser
     if (discoveredStructuresSet != null
             && !discoveredStructuresSet.isEmpty())
     {
-      getResultTable().setModel(FTSRestResponse
-              .getTableModel(lastPdbRequest, discoveredStructuresSet));
+      getResultTable()
+              .setModel(data.getTableModel(discoveredStructuresSet));
+
       noOfStructuresFound = discoveredStructuresSet.size();
+      lastDiscoveredStructuresSet = discoveredStructuresSet;
       mainFrame.setTitle(MessageManager.formatMessage(
               "label.structure_chooser_no_of_structures",
               noOfStructuresFound, totalTime));
@@ -309,157 +524,6 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
-   * Builds a query string for a given sequences using its DBRef entries
-   * 
-   * @param seq
-   *          the sequences to build a query for
-   * @return the built query string
-   */
-
-  static String buildQuery(SequenceI seq)
-  {
-    boolean isPDBRefsFound = false;
-    boolean isUniProtRefsFound = false;
-    StringBuilder queryBuilder = new StringBuilder();
-    Set<String> seqRefs = new LinkedHashSet<>();
-    
-    /*
-     * note PDBs as DBRefEntry so they are not duplicated in query
-     */
-    Set<String> pdbids = new HashSet<>();
-
-    if (seq.getAllPDBEntries() != null
-            && queryBuilder.length() < MAX_QLENGTH)
-    {
-      for (PDBEntry entry : seq.getAllPDBEntries())
-      {
-        if (isValidSeqName(entry.getId()))
-        {
-          String id = entry.getId().toLowerCase();
-          queryBuilder.append("pdb_id:").append(id).append(" OR ");
-          isPDBRefsFound = true;
-          pdbids.add(id);
-        }
-      }
-    }
-
-    List<DBRefEntry> refs = seq.getDBRefs();
-    if (refs != null && refs.size() != 0)
-    {
-      for (int ib = 0, nb = refs.size(); ib < nb; ib++)
-      {
-         DBRefEntry dbRef = refs.get(ib);
-        if (isValidSeqName(getDBRefId(dbRef))
-                && queryBuilder.length() < MAX_QLENGTH)
-        {
-          if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
-          {
-            queryBuilder.append("uniprot_accession:")
-                    .append(getDBRefId(dbRef)).append(" OR ");
-            queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
-                    .append(" OR ");
-            isUniProtRefsFound = true;
-          }
-          else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
-          {
-
-            String id = getDBRefId(dbRef).toLowerCase();
-            if (!pdbids.contains(id))
-            {
-              queryBuilder.append("pdb_id:").append(id).append(" OR ");
-              isPDBRefsFound = true;
-              pdbids.add(id);
-            }
-          }
-          else
-          {
-            seqRefs.add(getDBRefId(dbRef));
-          }
-        }
-      }
-    }
-
-    if (!isPDBRefsFound && !isUniProtRefsFound)
-    {
-      String seqName = seq.getName();
-      seqName = sanitizeSeqName(seqName);
-      String[] names = seqName.toLowerCase().split("\\|");
-      for (String name : names)
-      {
-        // System.out.println("Found name : " + name);
-        name.trim();
-        if (isValidSeqName(name))
-        {
-          seqRefs.add(name);
-        }
-      }
-
-      for (String seqRef : seqRefs)
-      {
-        queryBuilder.append("text:").append(seqRef).append(" OR ");
-      }
-    }
-
-    int endIndex = queryBuilder.lastIndexOf(" OR ");
-    if (queryBuilder.toString().length() < 6)
-    {
-      return null;
-    }
-    String query = queryBuilder.toString().substring(0, endIndex);
-    return query;
-  }
-
-  /**
-   * Remove the following special characters from input string +, -, &, !, (, ),
-   * {, }, [, ], ^, ", ~, *, ?, :, \
-   * 
-   * @param seqName
-   * @return
-   */
-  static String sanitizeSeqName(String seqName)
-  {
-    Objects.requireNonNull(seqName);
-    return seqName.replaceAll("\\[\\d*\\]", "")
-            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
-  }
-
-  /**
-   * Ensures sequence ref names are not less than 3 characters and does not
-   * contain a database name
-   * 
-   * @param seqName
-   * @return
-   */
-  static boolean isValidSeqName(String seqName)
-  {
-    // System.out.println("seqName : " + seqName);
-    String ignoreList = "pdb,uniprot,swiss-prot";
-    if (seqName.length() < 3)
-    {
-      return false;
-    }
-    if (seqName.contains(":"))
-    {
-      return false;
-    }
-    seqName = seqName.toLowerCase();
-    for (String ignoredEntry : ignoreList.split(","))
-    {
-      if (seqName.contains(ignoredEntry))
-      {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  static String getDBRefId(DBRefEntry dbRef)
-  {
-    String ref = dbRef.getAccessionId().replaceAll("GO:", "");
-    return ref;
-  }
-
-  /**
    * Filters a given list of discovered structures based on supplied argument
    * 
    * @param fieldToFilterBy
@@ -469,54 +533,33 @@ public class StructureChooser extends GStructureChooser
   {
     Thread filterThread = new Thread(new Runnable()
     {
+
       @Override
       public void run()
       {
         long startTime = System.currentTimeMillis();
-        pdbRestClient = PDBFTSRestClient.getInstance();
         lbl_loading.setVisible(true);
-        Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+        Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
                 .getStructureSummaryFields();
         Collection<FTSData> filteredResponse = new HashSet<>();
         HashSet<String> errors = new HashSet<>();
 
         for (SequenceI seq : selectedSequences)
         {
-          FTSRestRequest pdbRequest = new FTSRestRequest();
-          if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
-          {
-            pdbRequest.setAllowEmptySeq(false);
-            pdbRequest.setResponseSize(1);
-            pdbRequest.setFieldToSearchBy("(");
-            pdbRequest.setSearchTerm(buildQuery(seq) + ")");
-            pdbRequest.setWantedFields(wantedFields);
-            pdbRequest.setAssociatedSequence(seq);
-            pdbRequest.setFacet(true);
-            pdbRequest.setFacetPivot(fieldToFilterBy + ",entry_entity");
-            pdbRequest.setFacetPivotMinCount(1);
-          }
-          else
-          {
-            pdbRequest.setAllowEmptySeq(false);
-            pdbRequest.setResponseSize(1);
-            pdbRequest.setFieldToSearchBy("(");
-            pdbRequest.setFieldToSortBy(fieldToFilterBy,
-                    !chk_invertFilter.isSelected());
-            pdbRequest.setSearchTerm(buildQuery(seq) + ")");
-            pdbRequest.setWantedFields(wantedFields);
-            pdbRequest.setAssociatedSequence(seq);
-          }
+
           FTSRestResponse resultList;
           try
           {
-            resultList = pdbRestClient.executeRequest(pdbRequest);
+            resultList = data.selectFirstRankedQuery(seq,
+                    discoveredStructuresSet, wantedFields, fieldToFilterBy,
+                    !chk_invertFilter.isSelected());
+
           } catch (Exception e)
           {
             e.printStackTrace();
             errors.add(e.getMessage());
             continue;
           }
-          lastPdbRequest = pdbRequest;
           if (resultList.getSearchSummary() != null
                   && !resultList.getSearchSummary().isEmpty())
           {
@@ -532,8 +575,8 @@ public class StructureChooser extends GStructureChooser
           Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
           reorderedStructuresSet.addAll(filteredResponse);
           reorderedStructuresSet.addAll(discoveredStructuresSet);
-          getResultTable().setModel(FTSRestResponse
-                  .getTableModel(lastPdbRequest, reorderedStructuresSet));
+          getResultTable()
+                  .setModel(data.getTableModel(reorderedStructuresSet));
 
           FTSRestResponse.configureTableColumn(getResultTable(),
                   wantedFields, tempUserPrefs);
@@ -577,10 +620,11 @@ public class StructureChooser extends GStructureChooser
   @Override
   protected void pdbFromFile_actionPerformed()
   {
-    // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and StructureChooser
+    // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
+    // StructureChooser
     // works
     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new jalview.io.JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.formatMessage("label.select_pdb_file_for",
@@ -593,7 +637,7 @@ public class StructureChooser extends GStructureChooser
     if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
     {
       selectedPdbFileName = chooser.getSelectedFile().getPath();
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
+      Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
       validateSelections();
     }
   }
@@ -605,46 +649,67 @@ public class StructureChooser extends GStructureChooser
   protected void populateFilterComboBox(boolean haveData,
           boolean cachedPDBExist)
   {
+    populateFilterComboBox(haveData, cachedPDBExist, null);
+  }
+
+  /**
+   * Populates the filter combo-box options dynamically depending on discovered
+   * structures
+   */
+  protected void populateFilterComboBox(boolean haveData,
+          boolean cachedPDBExist, FilterOption lastSel)
+  {
+
     /*
      * temporarily suspend the change listener behaviour
      */
     cmb_filterOption.removeItemListener(this);
-
+    int selSet = -1;
     cmb_filterOption.removeAllItems();
     if (haveData)
     {
-      cmb_filterOption.addItem(new FilterOption(
-              MessageManager.getString("label.best_quality"),
-              "overall_quality", VIEWS_FILTER, false));
-      cmb_filterOption.addItem(new FilterOption(
-              MessageManager.getString("label.best_resolution"),
-              "resolution", VIEWS_FILTER, false));
-      cmb_filterOption.addItem(new FilterOption(
-              MessageManager.getString("label.most_protein_chain"),
-              "number_of_protein_chains", VIEWS_FILTER, false));
-      cmb_filterOption.addItem(new FilterOption(
-              MessageManager.getString("label.most_bound_molecules"),
-              "number_of_bound_molecules", VIEWS_FILTER, false));
-      cmb_filterOption.addItem(new FilterOption(
-              MessageManager.getString("label.most_polymer_residues"),
-              "number_of_polymer_residues", VIEWS_FILTER, true));
+      List<FilterOption> filters = data
+              .getAvailableFilterOptions(VIEWS_FILTER);
+      data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
+              lastDiscoveredStructuresSet);
+      int p = 0;
+      for (FilterOption filter : filters)
+      {
+        if (lastSel != null && filter.equals(lastSel))
+        {
+          selSet = p;
+        }
+        p++;
+        cmb_filterOption.addItem(filter);
+      }
     }
+
     cmb_filterOption.addItem(
             new FilterOption(MessageManager.getString("label.enter_pdb_id"),
-                    "-", VIEWS_ENTER_ID, false));
+                    "-", VIEWS_ENTER_ID, false, null));
     cmb_filterOption.addItem(
             new FilterOption(MessageManager.getString("label.from_file"),
-                    "-", VIEWS_FROM_FILE, false));
+                    "-", VIEWS_FROM_FILE, false, null));
+    if (canQueryTDB && notQueriedTDBYet)
+    {
+      btn_queryTDB.setVisible(true);
+    }
 
     if (cachedPDBExist)
     {
       FilterOption cachedOption = new FilterOption(
-              MessageManager.getString("label.cached_structures"),
-              "-", VIEWS_LOCAL_PDB, false);
+              MessageManager.getString("label.cached_structures"), "-",
+              VIEWS_LOCAL_PDB, false, null);
       cmb_filterOption.addItem(cachedOption);
-      cmb_filterOption.setSelectedItem(cachedOption);
+      if (selSet == -1)
+      {
+        cmb_filterOption.setSelectedItem(cachedOption);
+      }
+    }
+    if (selSet > -1)
+    {
+      cmb_filterOption.setSelectedIndex(selSet);
     }
-
     cmb_filterOption.addItemListener(this);
   }
 
@@ -655,16 +720,41 @@ public class StructureChooser extends GStructureChooser
   {
     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
             .getSelectedItem());
+    
+    if (lastSelected == selectedFilterOpt)
+    {
+      // don't need to do anything, probably
+      return;
+    }
+    // otherwise, record selection
+    // and update the layout and dialog accordingly
+    lastSelected = selectedFilterOpt;
+
     layout_switchableViews.show(pnl_switchableViews,
             selectedFilterOpt.getView());
     String filterTitle = mainFrame.getTitle();
     mainFrame.setTitle(frameTitle);
     chk_invertFilter.setVisible(false);
+    
     if (selectedFilterOpt.getView() == VIEWS_FILTER)
     {
       mainFrame.setTitle(filterTitle);
-      chk_invertFilter.setVisible(true);
-      filterResultSet(selectedFilterOpt.getValue());
+      // TDB Query has no invert as yet
+      chk_invertFilter.setVisible(selectedFilterOpt
+              .getQuerySource() instanceof PDBStructureChooserQuerySource);
+
+      if (data != selectedFilterOpt.getQuerySource()
+              || data.needsRefetch(selectedFilterOpt))
+      {
+        data = selectedFilterOpt.getQuerySource();
+        // rebuild the views completely, since prefs will also change
+        tabRefresh();
+        return;
+      }
+      else
+      {
+        filterResultSet(selectedFilterOpt.getValue());
+      }
     }
     else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
             || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
@@ -730,6 +820,38 @@ public class StructureChooser extends GStructureChooser
             .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
   }
 
+  @Override
+  protected boolean showPopupFor(int selectedRow, int x, int y)
+  {
+    FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+            .getSelectedItem());
+    String currentView = selectedFilterOpt.getView();
+     
+    if (currentView == VIEWS_FILTER && data instanceof ThreeDBStructureChooserQuerySource)
+    {
+      
+      TDB_FTSData row=((ThreeDBStructureChooserQuerySource)data).getFTSDataFor(getResultTable(), selectedRow, discoveredStructuresSet);
+      String pageUrl = row.getModelViewUrl(); 
+      JPopupMenu popup = new JPopupMenu("3D Beacons");
+      JMenuItem viewUrl = new JMenuItem("View model web page");
+      viewUrl.addActionListener(
+              new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e)
+                {
+                  Desktop.showUrl(pageUrl);
+                }
+              }
+              );
+      popup.add(viewUrl);
+      SwingUtilities.invokeLater(new Runnable()  {
+        public void run() { popup.show(getResultTable(), x, y); }
+      });
+      return true;
+    }
+    // event not handled by us
+    return false;
+  }
   /**
    * Validates inputs from the Manual PDB entry panel
    */
@@ -801,7 +923,7 @@ public class StructureChooser extends GStructureChooser
   {
     validateSelections();
   }
-
+  private FilterOption lastSelected=null;
   /**
    * Handles the state change event for the 'filter' combo-box and 'invert'
    * check-box
@@ -861,7 +983,7 @@ public class StructureChooser extends GStructureChooser
     }
     return found;
   }
-  
+
   /**
    * Handles the 'New View' action
    */
@@ -906,37 +1028,12 @@ public class StructureChooser extends GStructureChooser
 
         if (currentView == VIEWS_FILTER)
         {
-          int pdbIdColIndex = restable.getColumn("PDB Id")
-                  .getModelIndex();
-          int refSeqColIndex = restable.getColumn("Ref Sequence")
-                  .getModelIndex();
           int[] selectedRows = restable.getSelectedRows();
           PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
-          int count = 0;
           List<SequenceI> selectedSeqsToView = new ArrayList<>();
-          for (int row : selectedRows)
-          {
-            String pdbIdStr = restable
-                    .getValueAt(row, pdbIdColIndex).toString();
-            SequenceI selectedSeq = (SequenceI) restable
-                    .getValueAt(row, refSeqColIndex);
-            selectedSeqsToView.add(selectedSeq);
-            PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
-            if (pdbEntry == null)
-            {
-              pdbEntry = getFindEntry(pdbIdStr,
-                      selectedSeq.getAllPDBEntries());
-            }
+          pdbEntriesToView = data.collectSelectedRows(restable,
+                  selectedRows, selectedSeqsToView);
 
-            if (pdbEntry == null)
-            {
-              pdbEntry = new PDBEntry();
-              pdbEntry.setId(pdbIdStr);
-              pdbEntry.setType(PDBEntry.Type.PDB);
-              selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
-            }
-            pdbEntriesToView[count++] = pdbEntry;
-          }
           SequenceI[] selectedSeqs = selectedSeqsToView
                   .toArray(new SequenceI[selectedSeqsToView.size()]);
           sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
@@ -954,8 +1051,9 @@ public class StructureChooser extends GStructureChooser
           List<SequenceI> selectedSeqsToView = new ArrayList<>();
           for (int row : selectedRows)
           {
-            PDBEntry pdbEntry = (PDBEntry) tbl_local_pdb.getValueAt(row,
-                    pdbIdColIndex);
+            PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
+                    .getModel()).getPDBEntryAt(row).getPdbEntry();
+
             pdbEntriesToView[count++] = pdbEntry;
             SequenceI selectedSeq = (SequenceI) tbl_local_pdb
                     .getValueAt(row, refSeqColIndex);
@@ -982,7 +1080,7 @@ public class StructureChooser extends GStructureChooser
             if (pdbIdStr.split(":").length > 1)
             {
               pdbEntry.setId(pdbIdStr.split(":")[0]);
-              pdbEntry.setChainCode(pdbIdStr.split(":")[1].toUpperCase());
+              pdbEntry.setChainCode(pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
             }
             else
             {
@@ -1010,10 +1108,8 @@ public class StructureChooser extends GStructureChooser
                           DataSourceType.FILE, selectedSequence, true,
                           Desktop.instance);
 
-          sViewer = launchStructureViewer(
-                  ssm, new PDBEntry[]
-                  { fileEntry }, ap,
-                  new SequenceI[]
+          sViewer = launchStructureViewer(ssm, new PDBEntry[] { fileEntry },
+                  ap, new SequenceI[]
                   { selectedSequence });
         }
         SwingUtilities.invokeLater(new Runnable()
@@ -1046,21 +1142,6 @@ public class StructureChooser extends GStructureChooser
     }
   }
 
-  private PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
-  {
-    Objects.requireNonNull(id);
-    Objects.requireNonNull(pdbEntries);
-    PDBEntry foundEntry = null;
-    for (PDBEntry entry : pdbEntries)
-    {
-      if (entry.getId().equalsIgnoreCase(id))
-      {
-        return entry;
-      }
-    }
-    return foundEntry;
-  }
-
   /**
    * Answers a structure viewer (new or existing) configured to superimpose
    * added structures or not according to the user's choice
@@ -1068,8 +1149,7 @@ public class StructureChooser extends GStructureChooser
    * @param ssm
    * @return
    */
-  StructureViewer getTargetedStructureViewer(
-          StructureSelectionManager ssm)
+  StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
   {
     Object sv = targetView.getSelectedItem();
 
@@ -1086,8 +1166,7 @@ public class StructureChooser extends GStructureChooser
    * @return
    */
   private StructureViewer launchStructureViewer(
-          StructureSelectionManager ssm,
-          final PDBEntry[] pdbEntriesToView,
+          StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
     long progressId = sequences.hashCode();
@@ -1150,8 +1229,9 @@ public class StructureChooser extends GStructureChooser
     }
     if (pdbEntriesToView.length > 1)
     {
-      setProgressBar(MessageManager.getString(
-              "status.fetching_3d_structures_for_selected_entries"),
+      setProgressBar(
+              MessageManager.getString(
+                      "status.fetching_3d_structures_for_selected_entries"),
               progressId);
       theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
     }
@@ -1159,7 +1239,7 @@ public class StructureChooser extends GStructureChooser
     {
       setProgressBar(MessageManager.formatMessage(
               "status.fetching_3d_structures_for",
-              pdbEntriesToView[0].getId()),progressId);
+              pdbEntriesToView[0].getId()), progressId);
       theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
     }
     setProgressBar(null, progressId);
@@ -1204,7 +1284,8 @@ public class StructureChooser extends GStructureChooser
             && !discoveredStructuresSet.isEmpty();
   }
 
-  protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes this. 
+  protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
+                               // this.
   // Doing a search for "1" or "1c" is valuable?
   // Those work but are enormously slow.
 
@@ -1212,51 +1293,54 @@ public class StructureChooser extends GStructureChooser
   protected void txt_search_ActionPerformed()
   {
     String text = txt_search.getText().trim();
-       if (text.length() >= PDB_ID_MIN) 
-    new Thread()
-    {
-
-       @Override
-      public void run()
+    if (text.length() >= PDB_ID_MIN)
+      new Thread()
       {
-        errorWarning.setLength(0);
-        isValidPBDEntry = false;
-        if (text.length() > 0)
+
+        @Override
+        public void run()
         {
-          String searchTerm = text.toLowerCase();
-          searchTerm = searchTerm.split(":")[0];
-          // System.out.println(">>>>> search term : " + searchTerm);
-          List<FTSDataColumnI> wantedFields = new ArrayList<>();
-          FTSRestRequest pdbRequest = new FTSRestRequest();
-          pdbRequest.setAllowEmptySeq(false);
-          pdbRequest.setResponseSize(1);
-          pdbRequest.setFieldToSearchBy("(pdb_id:");
-          pdbRequest.setWantedFields(wantedFields);
-          pdbRequest.setSearchTerm(searchTerm + ")");
-          pdbRequest.setAssociatedSequence(selectedSequence);
-          pdbRestClient = PDBFTSRestClient.getInstance();
-          wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
-          FTSRestResponse resultList;
-          try
+          errorWarning.setLength(0);
+          isValidPBDEntry = false;
+          if (text.length() > 0)
           {
-            resultList = pdbRestClient.executeRequest(pdbRequest);
-          } catch (Exception e)
-          {
-            errorWarning.append(e.getMessage());
-            return;
-          } finally
-          {
-            validateSelections();
-          }
-          if (resultList.getSearchSummary() != null
-                  && resultList.getSearchSummary().size() > 0)
-          {
-            isValidPBDEntry = true;
+            // TODO move this pdb id search into the PDB specific
+            // FTSSearchEngine
+            // for moment, it will work fine as is because it is self-contained
+            String searchTerm = text.toLowerCase(Locale.ROOT);
+            searchTerm = searchTerm.split(":")[0];
+            // System.out.println(">>>>> search term : " + searchTerm);
+            List<FTSDataColumnI> wantedFields = new ArrayList<>();
+            FTSRestRequest pdbRequest = new FTSRestRequest();
+            pdbRequest.setAllowEmptySeq(false);
+            pdbRequest.setResponseSize(1);
+            pdbRequest.setFieldToSearchBy("(pdb_id:");
+            pdbRequest.setWantedFields(wantedFields);
+            pdbRequest.setSearchTerm(searchTerm + ")");
+            pdbRequest.setAssociatedSequence(selectedSequence);
+            FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
+            wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
+            FTSRestResponse resultList;
+            try
+            {
+              resultList = pdbRestClient.executeRequest(pdbRequest);
+            } catch (Exception e)
+            {
+              errorWarning.append(e.getMessage());
+              return;
+            } finally
+            {
+              validateSelections();
+            }
+            if (resultList.getSearchSummary() != null
+                    && resultList.getSearchSummary().size() > 0)
+            {
+              isValidPBDEntry = true;
+            }
           }
+          validateSelections();
         }
-        validateSelections();
-      }
-    }.start();
+      }.start();
   }
 
   @Override
@@ -1270,6 +1354,8 @@ public class StructureChooser extends GStructureChooser
         public void run()
         {
           fetchStructuresMetaData();
+          // populateFilterComboBox(true, cachedPDBExists);
+
           filterResultSet(
                   ((FilterOption) cmb_filterOption.getSelectedItem())
                           .getValue());
@@ -1326,7 +1412,7 @@ public class StructureChooser extends GStructureChooser
         value = entry.getSequence();
         break;
       case 1:
-        value = entry.getPdbEntry();
+        value = entry.getQualifiedId();
         break;
       case 2:
         value = entry.getPdbEntry().getChainCode() == null ? "_"
@@ -1367,6 +1453,15 @@ public class StructureChooser extends GStructureChooser
       this.pdbEntry = pdbEntry;
     }
 
+    public String getQualifiedId()
+    {
+      if (pdbEntry.hasProvider())
+      {
+        return pdbEntry.getProvider() + ":" + pdbEntry.getId();
+      }
+      return pdbEntry.toString();
+    }
+
     public SequenceI getSequence()
     {
       return sequence;
@@ -1403,4 +1498,35 @@ public class StructureChooser extends GStructureChooser
   {
     return sViewer == null ? null : sViewer.sview;
   }
+
+  @Override
+  protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
+  {
+    data.setDocFieldPrefs(newPrefs);
+
+  }
+
+  /**
+   * 
+   * @return true when all initialisation threads have finished and dialog is
+   *         visible
+   */
+  public boolean isDialogVisible()
+  {
+    return mainFrame != null && data != null && cmb_filterOption != null
+            && mainFrame.isVisible()
+            && cmb_filterOption.getSelectedItem() != null;
+  }
+  /**
+   * 
+   * @return true if the 3D-Beacons query button will/has been displayed
+   */
+  public boolean isCanQueryTDB() {
+         return canQueryTDB;
+  }
+
+  public boolean isNotQueriedTDBYet()
+  {
+    return notQueriedTDBYet;
+  }
 }
index 617706a..ad412b0 100644 (file)
@@ -29,6 +29,7 @@ import java.util.Map.Entry;
 
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.StructureViewerModel;
@@ -80,6 +81,7 @@ public class StructureViewer
     return sv;
   }
 
+  
   @Override
   public String toString()
   {
@@ -89,7 +91,11 @@ public class StructureViewer
     }
     return "New View";
   }
-  public ViewerType getViewerType()
+  /**
+   * 
+   * @return ViewerType for currently configured structure viewer 
+   */
+  public static ViewerType getViewerType()
   {
     String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
             ViewerType.JMOL.name());
@@ -175,7 +181,7 @@ public class StructureViewer
     }
     else
     {
-      Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
+      Console.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
     }
     return sview;
   }
@@ -323,7 +329,7 @@ public class StructureViewer
     }
     else
     {
-      Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
+      Console.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
     }
     return sview;
   }
@@ -361,11 +367,12 @@ public class StructureViewer
       viewer = new PymolViewer(viewerData, alignPanel, sessionFile, vid);
       break;
     default:
-      Cache.log.error(UNKNOWN_VIEWER_TYPE + type.toString());
+      Console.error(UNKNOWN_VIEWER_TYPE + type.toString());
     }
     return viewer;
   }
 
+
   public boolean isBusy()
   {
     if (sview != null)
index b349559..349871d 100644 (file)
@@ -47,6 +47,7 @@ import javax.swing.event.MenuListener;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
@@ -65,6 +66,7 @@ import jalview.util.BrowserLauncher;
 import jalview.util.MessageManager;
 import jalview.ws.dbsources.EBIAlfaFold;
 import jalview.ws.dbsources.Pdb;
+import jalview.ws.utils.UrlDownloadClient;
 
 /**
  * Base class with common functionality for JMol, Chimera or other structure
@@ -154,6 +156,15 @@ public abstract class StructureViewerBase extends GStructureViewer
   {
     alignAddedStructures = alignAdded;
   }
+  
+  /**
+   * called by the binding model to indicate when adding structures is happening or has been completed
+   * @param addingStructures
+   */
+  public synchronized void setAddingStructures(boolean addingStructures)
+  {
+    this.addingStructures = addingStructures;
+  }
 
   /**
    * 
@@ -211,6 +222,10 @@ public abstract class StructureViewerBase extends GStructureViewer
       _alignwith.add(ap);
     }
     ;
+    // TODO: refactor to allow concrete classes to register buttons for adding
+    // here
+    // currently have to override to add buttons back in after they are cleared
+    // in this loop
     for (Component c : viewerActionMenu.getMenuComponents())
     {
       if (c != alignStructs)
@@ -800,7 +815,7 @@ public abstract class StructureViewerBase extends GStructureViewer
       {
         sp.append("'" + alignPanel.getViewName() + "' ");
       }
-      Cache.log.info("Couldn't align structures with the " + sp.toString()
+      Console.info("Couldn't align structures with the " + sp.toString()
               + "associated alignment panels.", e);
     }
     return reply;
@@ -1077,7 +1092,7 @@ public abstract class StructureViewerBase extends GStructureViewer
     progressBar = pi;
   }
 
-  protected void setProgressMessage(String message, long id)
+  public void setProgressMessage(String message, long id)
   {
     if (progressBar != null)
     {
@@ -1142,9 +1157,29 @@ public abstract class StructureViewerBase extends GStructureViewer
     {
       if (afclient.isValidReference(pdbid))
       {
-        pdbseq = afclient.getSequenceRecords(pdbid);
+        pdbseq = afclient.getSequenceRecords(pdbid,processingEntry.getRetrievalUrl());
       } else {
-        pdbseq = pdbclient.getSequenceRecords(pdbid);
+          if (processingEntry.hasRetrievalUrl())
+          {
+            String safePDBId = java.net.URLEncoder.encode(pdbid,"UTF-8").replace("%","__");
+                     
+            // retrieve from URL to new local tmpfile
+            File tmpFile = File.createTempFile(safePDBId,
+                    "." + (PDBEntry.Type.MMCIF.toString().equals(
+                            processingEntry.getType().toString()) ? "cif"
+                                    : "pdb"));
+            String fromUrl = processingEntry.getRetrievalUrl();
+            UrlDownloadClient.download(fromUrl, tmpFile);
+            
+            // may not need this check ?
+            String file = tmpFile.getAbsolutePath();
+            if (file != null)
+            {
+              pdbseq = EBIAlfaFold.importDownloadedStructureFromUrl(fromUrl,tmpFile,pdbid,null,null,null);
+            }
+          } else {
+            pdbseq = pdbclient.getSequenceRecords(pdbid);
+          }
       }
     } catch (Exception e)
     {
@@ -1178,8 +1213,23 @@ public abstract class StructureViewerBase extends GStructureViewer
    */
   public File saveSession()
   {
-    // TODO: a wait loop to ensure the file is written fully before returning?
-    return getBinding() == null ? null : getBinding().saveSession();
+    if (getBinding() == null) { return  null;}
+    File session = getBinding().saveSession();
+    long l = session.length();
+    int wait=50;
+    do {
+      try {
+        Thread.sleep(5);
+      } catch (InterruptedException e) {
+      } 
+      long nextl = session.length();
+      if (nextl!=l)
+      {
+        wait = 50;
+        l=nextl;
+      }
+    } while (--wait>0);
+    return session;
   }
 
   /**
@@ -1248,5 +1298,11 @@ public abstract class StructureViewerBase extends GStructureViewer
                       + ex.getMessage());
     }
   }
-
+  @Override
+  public boolean hasViewerActionsMenu()
+  {
+    return viewerActionMenu != null && viewerActionMenu.isEnabled()
+            && viewerActionMenu.getItemCount() > 0
+            && viewerActionMenu.isVisible();
+  }
 }
index 2d8e729..db6ba42 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AverageDistanceTree;
 import jalview.analysis.NJTree;
@@ -28,6 +30,8 @@ import jalview.analysis.TreeModel;
 import jalview.analysis.scoremodels.ScoreModels;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
+import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.commands.OrderCommand;
 import jalview.datamodel.Alignment;
@@ -406,7 +410,7 @@ public class TreePanel extends GTreePanel
   {
     // TODO: JAL-3048 save newick file for Jalview-JS
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.save_tree_as_newick"));
@@ -417,7 +421,7 @@ public class TreePanel extends GTreePanel
     if (value == JalviewFileChooser.APPROVE_OPTION)
     {
       String choice = chooser.getSelectedFile().getPath();
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY",
+      Cache.setProperty("LAST_DIRECTORY",
               chooser.getSelectedFile().getParent());
 
       try
@@ -456,7 +460,7 @@ public class TreePanel extends GTreePanel
     AlignmentView originalData = tree.getOriginalData();
     if (originalData == null)
     {
-      jalview.bin.Cache.log.info(
+      Console.info(
               "Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
       return;
     }
@@ -693,7 +697,7 @@ public class TreePanel extends GTreePanel
     String tree = MessageManager.getString("label.tree");
     ImageExporter exporter = new ImageExporter(writer, null, imageFormat,
             tree);
-    exporter.doExport(null, this, width, height, tree.toLowerCase());
+    exporter.doExport(null, this, width, height, tree.toLowerCase(Locale.ROOT));
   }
 
   /**
@@ -723,7 +727,7 @@ public class TreePanel extends GTreePanel
             // search dbrefs, features and annotation
             List<DBRefEntry> refs = jalview.util.DBRefUtils
                     .selectRefs(sq.getDBRefs(), new String[]
-                    { labelClass.toUpperCase() });
+                    { labelClass.toUpperCase(Locale.ROOT) });
             if (refs != null)
             {
               for (int i = 0, ni = refs.size(); i < ni; i++)
@@ -786,7 +790,7 @@ public class TreePanel extends GTreePanel
      * i18n description of Neighbour Joining or Average Distance method
      */
     String treecalcnm = MessageManager
-            .getString("label.tree_calc_" + treeType.toLowerCase());
+            .getString("label.tree_calc_" + treeType.toLowerCase(Locale.ROOT));
 
     /*
      * short score model name (long description can be too long)
index 4846049..c3f132b 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import jalview.bin.Cache;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
@@ -205,8 +207,8 @@ public class UserDefinedColours extends GUserDefinedColours
       {
         int row = i / cols + 1;
         int index = (row * cols) + i;
-        JButton button = makeButton(ResidueProperties.aa[i].toLowerCase(),
-                ResidueProperties.aa[i].toLowerCase(), lowerCaseButtons, i);
+        JButton button = makeButton(ResidueProperties.aa[i].toLowerCase(Locale.ROOT),
+                ResidueProperties.aa[i].toLowerCase(Locale.ROOT), lowerCaseButtons, i);
 
         buttonPanel.add(button, index);
       }
index ef86756..385eb57 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.util.MessageManager;
 
 import java.io.BufferedReader;
@@ -42,7 +44,7 @@ public class UserQuestionnaireCheck implements Runnable
   {
     if (url.indexOf("questionnaire.pl") == -1)
     {
-      jalview.bin.Cache.log.error("'" + url
+      Console.error("'" + url
               + "' is an Invalid URL for the checkForQuestionnaire() method.\n"
               + "This argument is only for questionnaires derived from jalview's questionnaire.pl cgi interface.");
     }
@@ -56,7 +58,7 @@ public class UserQuestionnaireCheck implements Runnable
 
   private boolean checkresponse(URL qurl) throws Exception
   {
-    jalview.bin.Cache.log.debug("Checking Response for : " + qurl);
+    Console.debug("Checking Response for : " + qurl);
     boolean prompt = false;
     // see if we have already responsed to this questionnaire or get a new
     // qid/rid pair
@@ -101,7 +103,7 @@ public class UserQuestionnaireCheck implements Runnable
     try
     {
       // First - check to see if wee have an old questionnaire/response id pair.
-      String lastq = jalview.bin.Cache.getProperty("QUESTIONNAIRE");
+      String lastq = Cache.getProperty("QUESTIONNAIRE");
       if (lastq == null)
       {
         prompt = checkresponse(new URL(url
@@ -133,14 +135,13 @@ public class UserQuestionnaireCheck implements Runnable
       if (qid != null && rid != null)
       {
         // Update our local property cache with latest qid and rid
-        jalview.bin.Cache.setProperty("QUESTIONNAIRE", qid + ":" + rid);
+        Cache.setProperty("QUESTIONNAIRE", qid + ":" + rid);
       }
       if (prompt)
       {
         String qurl = url + (url.indexOf('?') > -1 ? "&" : "?") + "qid="
                 + qid + "&rid=" + rid;
-        jalview.bin.Cache.log
-                .info("Prompting user for questionnaire at " + qurl);
+        Console.info("Prompting user for questionnaire at " + qurl);
         int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
                 MessageManager.getString("label.jalview_new_questionnaire"),
                 MessageManager.getString("label.jalview_user_survey"),
@@ -148,14 +149,13 @@ public class UserQuestionnaireCheck implements Runnable
 
         if (reply == JvOptionPane.YES_OPTION)
         {
-          jalview.bin.Cache.log.debug("Opening " + qurl);
+          Console.debug("Opening " + qurl);
           jalview.util.BrowserLauncher.openURL(qurl);
         }
       }
     } catch (Exception e)
     {
-      jalview.bin.Cache.log
-              .warn("When trying to access questionnaire URL " + url, e);
+      Console.warn("When trying to access questionnaire URL " + url, e);
     }
   }
 
index 19ede62..9defed4 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
@@ -201,7 +202,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
 
     } catch (Exception e)
     {
-      jalview.bin.Cache.log.error("Couldn't instantiate vamsas client !",
+      Console.error("Couldn't instantiate vamsas client !",
               e);
       return false;
     }
@@ -225,12 +226,12 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       }
     } catch (Error e)
     {
-      Cache.log.warn(
+      Console.warn(
               "Probable SERIOUS VAMSAS client incompatibility - carrying on regardless",
               e);
     } catch (Exception e)
     {
-      Cache.log.warn(
+      Console.warn(
               "Probable VAMSAS client incompatibility - carrying on regardless",
               e);
     }
@@ -244,7 +245,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
   private ClientHandle getJalviewHandle()
   {
     return new ClientHandle("jalview.bin.Jalview",
-            jalview.bin.Cache.getProperty("VERSION"));
+            Cache.getProperty("VERSION"));
   }
 
   /**
@@ -271,12 +272,12 @@ public class VamsasApplication implements SelectionSource, VamsasSource
     addStoreDocumentHandler();
     startSession();
     inInitialUpdate = true;
-    Cache.log.debug(
+    Console.debug(
             "Jalview loading the Vamsas Session for the first time.");
     dealWithDocumentUpdate(false); // we don't push an update out to the
     inInitialUpdate = false;
     // document yet.
-    Cache.log.debug("... finished update for the first time.");
+    Console.debug("... finished update for the first time.");
   }
 
   /**
@@ -306,7 +307,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       }
     } catch (Exception e)
     {
-      Cache.log.warn(
+      Console.warn(
               "Exception whilst refreshing jalview windows after a vamsas document update.",
               e);
     }
@@ -320,10 +321,10 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       @Override
       public void run()
       {
-        Cache.log.info("Jalview updating to the Vamsas Session.");
+        Console.info("Jalview updating to the Vamsas Session.");
 
         dealWithDocumentUpdate(true);
-        Cache.log.info("Jalview finished updating to the Vamsas Session.");
+        Console.info("Jalview finished updating to the Vamsas Session.");
       }
 
     });
@@ -353,7 +354,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
     {
       throw new Error("Jalview not connected to Vamsas session");
     }
-    Cache.log.info("Jalview disconnecting from the Vamsas Session.");
+    Console.info("Jalview disconnecting from the Vamsas Session.");
     try
     {
       if (joinedSession)
@@ -361,12 +362,12 @@ public class VamsasApplication implements SelectionSource, VamsasSource
         boolean ourprompt = this.promptUser;
         this.promptUser = promptUser;
         vclient.finalizeClient();
-        Cache.log.info("Jalview has left the session.");
+        Console.info("Jalview has left the session.");
         this.promptUser = ourprompt; // restore default value
       }
       else
       {
-        Cache.log.warn(
+        Console.warn(
                 "JV Client leaving a session that's its not joined yet.");
       }
       joinedSession = false;
@@ -377,13 +378,13 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       vobj2jv = null;
     } catch (Exception e)
     {
-      Cache.log.error("Vamsas Session finalization threw exceptions!", e);
+      Console.error("Vamsas Session finalization threw exceptions!", e);
     }
   }
 
   public void updateJalview(IClientDocument cdoc)
   {
-    Cache.log.debug("Jalview updating from sesion document ..");
+    Console.debug("Jalview updating from sesion document ..");
     ensureJvVamsas();
     VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj,
             baseProvEntry(), alRedoState);
@@ -392,7 +393,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       vds.updateToJalview();
     } catch (Exception e)
     {
-      Cache.log.error("Failed to update Jalview from vamsas document.", e);
+      Console.error("Failed to update Jalview from vamsas document.", e);
     }
     try
     {
@@ -404,10 +405,10 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       }
     } catch (Exception e)
     {
-      Cache.log.error(
+      Console.error(
               "Exception when updating Jalview settings from Appdata.", e);
     }
-    Cache.log.debug(".. finished updating from sesion document.");
+    Console.debug(".. finished updating from sesion document.");
 
   }
 
@@ -481,7 +482,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
             } catch (Exception e)
             {
               errorsDuringUpdate = true;
-              Cache.log.error("Exception synchronizing " + af.getTitle()
+              Console.error("Exception synchronizing " + af.getTitle()
                       + " "
                       + (af.getViewport().getViewName() == null ? ""
                               : " view " + af.getViewport().getViewName())
@@ -519,7 +520,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       }
     } catch (Exception e)
     {
-      Cache.log.error("Exception synchronizing Views to Document :", e);
+      Console.error("Exception synchronizing Views to Document :", e);
       errorsDuringUpdate = true;
     }
 
@@ -536,7 +537,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       }
     } catch (Exception e)
     {
-      Cache.log.error("Client Appdata Write exception", e);
+      Console.error("Client Appdata Write exception", e);
       errorsDuringAppUpdate = true;
     }
     vds.clearSkipList();
@@ -564,32 +565,32 @@ public class VamsasApplication implements SelectionSource, VamsasSource
   {
     int storedviews = 0;
     // called by update handler for document update.
-    Cache.log.debug("Updating jalview from changed vamsas document.");
+    Console.debug("Updating jalview from changed vamsas document.");
     disableGui(true);
     try
     {
       long time = System.currentTimeMillis();
       IClientDocument cdoc = vclient.getClientDocument();
-      if (Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        Cache.log.debug("Time taken to get ClientDocument = "
+        Console.debug("Time taken to get ClientDocument = "
                 + (System.currentTimeMillis() - time));
         time = System.currentTimeMillis();
       }
       if (fromJalview)
       {
         storedviews += updateVamsasDocument(cdoc);
-        if (Cache.log.isDebugEnabled())
+        if (Console.isDebugEnabled())
         {
-          Cache.log.debug(
+          Console.debug(
                   "Time taken to update Vamsas Document from jalview\t= "
                           + (System.currentTimeMillis() - time));
           time = System.currentTimeMillis();
         }
         cdoc.setVamsasRoots(cdoc.getVamsasRoots());
-        if (Cache.log.isDebugEnabled())
+        if (Console.isDebugEnabled())
         {
-          Cache.log.debug("Time taken to set Document Roots\t\t= "
+          Console.debug("Time taken to set Document Roots\t\t= "
                   + (System.currentTimeMillis() - time));
           time = System.currentTimeMillis();
         }
@@ -597,9 +598,9 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       else
       {
         updateJalview(cdoc);
-        if (Cache.log.isDebugEnabled())
+        if (Console.isDebugEnabled())
         {
-          Cache.log.debug(
+          Console.debug(
                   "Time taken to update Jalview from vamsas document Roots\t= "
                           + (System.currentTimeMillis() - time));
           time = System.currentTimeMillis();
@@ -607,9 +608,9 @@ public class VamsasApplication implements SelectionSource, VamsasSource
 
       }
       vclient.updateDocument(cdoc);
-      if (Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        Cache.log.debug("Time taken to update Session Document\t= "
+        Console.debug("Time taken to update Session Document\t= "
                 + (System.currentTimeMillis() - time));
         time = System.currentTimeMillis();
       }
@@ -623,7 +624,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       recover_objectMappingBackup();
       storedviews = 0;
     }
-    Cache.log.debug("Finished updating from document change.");
+    Console.debug("Finished updating from document change.");
     disableGui(false);
     return storedviews;
   }
@@ -636,12 +637,12 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       @Override
       public void propertyChange(PropertyChangeEvent evt)
       {
-        Cache.log.debug("Dealing with document update event.");
+        Console.debug("Dealing with document update event.");
         client.dealWithDocumentUpdate(false);
-        Cache.log.debug("finished dealing with event.");
+        Console.debug("finished dealing with event.");
       }
     });
-    Cache.log.debug("Added Jalview handler for vamsas document updates.");
+    Console.debug("Added Jalview handler for vamsas document updates.");
   }
 
   private void addStoreDocumentHandler()
@@ -656,7 +657,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
               {
                 if (client.promptUser)
                 {
-                  Cache.log.debug(
+                  Console.debug(
                           "Asking user if the vamsas session should be stored.");
                   int reply = JvOptionPane.showInternalConfirmDialog(
                           Desktop.desktop,
@@ -667,22 +668,21 @@ public class VamsasApplication implements SelectionSource, VamsasSource
 
                   if (reply == JvOptionPane.YES_OPTION)
                   {
-                    Cache.log.debug("Prompting for vamsas store filename.");
+                    Console.debug("Prompting for vamsas store filename.");
                     Desktop.instance.vamsasSave_actionPerformed(null);
-                    Cache.log
-                            .debug("Finished attempt at storing document.");
+                    Console.debug("Finished attempt at storing document.");
                   }
-                  Cache.log.debug(
+                  Console.debug(
                           "finished dealing with REQUESTTOCLOSE event.");
                 }
                 else
                 {
-                  Cache.log.debug(
+                  Console.debug(
                           "Ignoring store document request (promptUser==false)");
                 }
               }
             });
-    Cache.log.debug("Added Jalview handler for vamsas document updates.");
+    Console.debug("Added Jalview handler for vamsas document updates.");
   }
 
   public void disableGui(boolean b)
@@ -756,7 +756,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
       } catch (Exception e)
       {
         // Complain to GUI
-        Cache.log.error("Failed to join vamsas session.", e);
+        Console.error("Failed to join vamsas session.", e);
         vclient = null;
       }
       try
@@ -785,16 +785,16 @@ public class VamsasApplication implements SelectionSource, VamsasSource
               {
                 return;
               }
-              // if (Cache.log.isDebugEnabled())
+              // if (Cache.isDebugEnabled())
               // {
-              // Cache.log.debug("Received MouseOverMessage "+mm.getVorbaID()+"
+              // Cache.debug("Received MouseOverMessage "+mm.getVorbaID()+"
               // "+mm.getPosition());
               // }
               Object jvobj = vobj2jv.get(mm.getVorbaID());
               if (jvobj != null && jvobj instanceof SequenceI)
               {
                 last = mstring;
-                // Cache.log.debug("Handling Mouse over "+mm.getVorbaID()+"
+                // Cache.debug("Handling Mouse over "+mm.getVorbaID()+"
                 // bound to "+jvobj+" at "+mm.getPosition());
                 // position is character position in aligned sequence
                 ssm.mouseOverVamsasSequence((SequenceI) jvobj,
@@ -980,7 +980,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
               if (v != null)
               {
                 // this should really be a trace message.
-                // Cache.log.debug("Mouse over " + v.getId() + " bound to "
+                // Cache.debug("Mouse over " + v.getId() + " bound to "
                 // + seq + " at " + index);
                 last = seq;
                 i = index;
@@ -1001,7 +1001,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
           {
             if (vobj2jv == null)
             {
-              Cache.log.warn(
+              Console.warn(
                       "Selection listener still active for dead session.");
               // not in a session.
               return;
@@ -1101,7 +1101,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
               if (sm != null)
               {
                 sm.validate(); // debug
-                Cache.log.debug("Selection Message\n" + sm.getRawMessage());
+                Console.debug("Selection Message\n" + sm.getRawMessage());
                 pm.sendMessage(sm);
               }
             }
@@ -1112,7 +1112,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
         ssm.addSelectionListener(selecter);
       } catch (Exception e)
       {
-        Cache.log.error("Failed to init Vamsas Picking", e);
+        Console.error("Failed to init Vamsas Picking", e);
       }
     }
   }
index a1529fc..134164e 100644 (file)
@@ -22,6 +22,7 @@ package jalview.gui;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 import java.awt.Component;
 import java.awt.event.ActionEvent;
@@ -261,6 +262,7 @@ public class ViewSelectionMenu extends JMenu
           }
         }
       });
+      final ViewSelectionMenu us=this;
       checkBox.addMouseListener(new MouseAdapter()
       {
         @Override
@@ -268,7 +270,6 @@ public class ViewSelectionMenu extends JMenu
         {
           try
           {
-            ap.setSelected(false);
           } catch (Exception ex)
           {
           }
@@ -279,7 +280,7 @@ public class ViewSelectionMenu extends JMenu
         {
           try
           {
-            ap.setSelected(true);
+            ap.setAlignFrameView();
           } catch (Exception ex)
           {
           }
index 0773a7b..ee1b473 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import java.util.Locale;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -545,7 +547,7 @@ public class WebserviceInfo extends GWebserviceInfo
     {
       return null;
     }
-    String lowertxt = text.toLowerCase();
+    String lowertxt = text.toLowerCase(Locale.ROOT);
     int htmlpos = leaveFirst ? -1 : lowertxt.indexOf("<body");
 
     int htmlend = leaveLast ? -1 : lowertxt.indexOf("</body");
@@ -574,7 +576,7 @@ public class WebserviceInfo extends GWebserviceInfo
     {
       return "";
     }
-    String lowertxt = text.toLowerCase();
+    String lowertxt = text.toLowerCase(Locale.ROOT);
     int htmlpos = lowertxt.indexOf("<body");
     int htmlend = lowertxt.indexOf("</body");
     int doctype = lowertxt.indexOf("<!doctype");
index 976e551..d9a0dda 100644 (file)
  */
 package jalview.gui;
 
-import jalview.gui.OptsAndParamsPage.OptionBox;
-import jalview.gui.OptsAndParamsPage.ParamBox;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.JabaPreset;
-import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.ArgumentI;
-import jalview.ws.params.OptionI;
-import jalview.ws.params.ParamDatastoreI;
-import jalview.ws.params.ParameterI;
-import jalview.ws.params.WsParamSetI;
-
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -75,6 +62,19 @@ import compbio.metadata.Parameter;
 import compbio.metadata.Preset;
 import compbio.metadata.PresetManager;
 import compbio.metadata.RunnerConfig;
+import jalview.bin.Console;
+import jalview.gui.OptsAndParamsPage.OptionBox;
+import jalview.gui.OptsAndParamsPage.ParamBox;
+import jalview.util.MessageManager;
+import jalview.ws.jws2.JabaParamStore;
+import jalview.ws.jws2.JabaPreset;
+import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.ParameterI;
+import jalview.ws.params.WsParamSetI;
 import net.miginfocom.swing.MigLayout;
 
 /**
@@ -1339,8 +1339,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
     if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
     {
       final String setname = (String) setName.getSelectedItem();
-      System.out.println("Item state changed for " + setname
-              + " (handling ? " + !settingDialog + ")");
+      if (Console.isDebugEnabled())
+      {
+        Console.debug("Item state changed for " + setname
+                + " (handling ? " + !settingDialog + ")");
+      }
       if (settingDialog)
       {
         // ignore event
index bb5d996..de1be5d 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.util.MessageManager;
@@ -106,7 +107,7 @@ public class WsParamSetManager implements ParamManager
         }
       } catch (IOException e)
       {
-        Cache.log.info("Failed to parse parameter file " + pfile
+        Console.info("Failed to parse parameter file " + pfile
                 + " (Check that all JALVIEW_WSPARAMFILES entries are valid!)",
                 e);
       }
@@ -171,7 +172,7 @@ public class WsParamSetManager implements ParamManager
     {
       if (filename != null && !((outfile = new File(filename)).canWrite()))
       {
-        Cache.log.warn("Can't write to " + filename
+        Console.warn("Can't write to " + filename
                 + " - Prompting for new file to write to.");
         filename = null;
       }
@@ -218,7 +219,7 @@ public class WsParamSetManager implements ParamManager
     }
     if (outfile != null)
     {
-      String paramFiles = jalview.bin.Cache.getDefault("WS_PARAM_FILES",
+      String paramFiles = Cache.getDefault("WS_PARAM_FILES",
               filename);
       if (paramFiles.indexOf(filename) == -1)
       {
@@ -255,14 +256,14 @@ public class WsParamSetManager implements ParamManager
         parameterSet.setSourceFile(filename);
       } catch (Exception e)
       {
-        Cache.log.error("Couldn't write parameter file to " + outfile, e);
+        Console.error("Couldn't write parameter file to " + outfile, e);
       }
     }
   }
 
   /*
    * 
-   * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
+   * JalviewFileChooser chooser = new JalviewFileChooser(Cache
    * .getProperty("LAST_DIRECTORY"), new String[] { "jc" }, new String[] {
    * "Jalview User Colours" }, "Jalview User Colours"); chooser.setFileView(new
    * jalview.io.JalviewFileView());
@@ -272,8 +273,8 @@ public class WsParamSetManager implements ParamManager
    * int value = chooser.showOpenDialog(this);
    * 
    * if (value == JalviewFileChooser.APPROVE_OPTION) { File choice =
-   * chooser.getSelectedFile(); jalview.bin.Cache.setProperty("LAST_DIRECTORY",
-   * choice.getParent()); String defaultColours = jalview.bin.Cache.getDefault(
+   * chooser.getSelectedFile(); Cache.setProperty("LAST_DIRECTORY",
+   * choice.getParent()); String defaultColours = Cache.getDefault(
    * "USER_DEFINED_COLOURS", choice.getPath()); if
    * (defaultColours.indexOf(choice.getPath()) == -1) { defaultColours =
    * defaultColours.concat("|") .concat(choice.getPath()); } (non-Javadoc)
@@ -290,7 +291,7 @@ public class WsParamSetManager implements ParamManager
     {
       return;
     }
-    String paramFiles = jalview.bin.Cache.getDefault("WS_PARAM_FILES", "");
+    String paramFiles = Cache.getDefault("WS_PARAM_FILES", "");
     if (paramFiles.indexOf(filename) > -1)
     {
       String nparamFiles = new String();
@@ -303,7 +304,7 @@ public class WsParamSetManager implements ParamManager
           nparamFiles = nparamFiles.concat("|").concat(fl);
         }
       }
-      jalview.bin.Cache.setProperty("WS_PARAM_FILES", nparamFiles);
+      Cache.setProperty("WS_PARAM_FILES", nparamFiles);
     }
 
     try
@@ -320,7 +321,7 @@ public class WsParamSetManager implements ParamManager
       }
     } catch (Exception e)
     {
-      Cache.log.error(
+      Console.error(
               "Exception when trying to delete webservice user preset: ",
               e);
     }
diff --git a/src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java b/src/jalview/gui/structurechooser/PDBStructureChooserQuerySource.java
new file mode 100644 (file)
index 0000000..727d8e0
--- /dev/null
@@ -0,0 +1,373 @@
+package jalview.gui.structurechooser;
+
+import java.util.Locale;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.jbgui.FilterOption;
+import jalview.util.MessageManager;
+
+/**
+ * logic for querying the PDBe API for structures of sequences
+ * 
+ * @author jprocter
+ */
+public class PDBStructureChooserQuerySource
+        extends StructureChooserQuerySource
+{
+
+  private static int MAX_QLENGTH = 7820;
+
+  protected FTSRestRequest lastPdbRequest;
+
+  protected FTSRestClientI pdbRestClient;
+
+  public PDBStructureChooserQuerySource()
+  {
+    pdbRestClient = PDBFTSRestClient.getInstance();
+    docFieldPrefs = new FTSDataColumnPreferences(
+            PreferenceSource.STRUCTURE_CHOOSER,
+            PDBFTSRestClient.getInstance());
+
+  }
+
+
+  /**
+   * Builds a query string for a given sequences using its DBRef entries
+   * 
+   * @param seq
+   *          the sequences to build a query for
+   * @return the built query string
+   */
+
+  public String buildQuery(SequenceI seq)
+  {
+    boolean isPDBRefsFound = false;
+    boolean isUniProtRefsFound = false;
+    StringBuilder queryBuilder = new StringBuilder();
+    Set<String> seqRefs = new LinkedHashSet<>();
+
+    /*
+     * note PDBs as DBRefEntry so they are not duplicated in query
+     */
+    Set<String> pdbids = new HashSet<>();
+
+    if (seq.getAllPDBEntries() != null
+            && queryBuilder.length() < MAX_QLENGTH)
+    {
+      for (PDBEntry entry : seq.getAllPDBEntries())
+      {
+        if (isValidSeqName(entry.getId()))
+        {
+          String id = entry.getId().toLowerCase(Locale.ROOT);
+          queryBuilder.append("pdb_id:").append(id).append(" OR ");
+          isPDBRefsFound = true;
+          pdbids.add(id);
+        }
+      }
+    }
+
+    List<DBRefEntry> refs = seq.getDBRefs();
+    if (refs != null && refs.size() != 0)
+    {
+      for (int ib = 0, nb = refs.size(); ib < nb; ib++)
+      {
+        DBRefEntry dbRef = refs.get(ib);
+        if (isValidSeqName(getDBRefId(dbRef))
+                && queryBuilder.length() < MAX_QLENGTH)
+        {
+          if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
+          {
+            queryBuilder.append("uniprot_accession:")
+                    .append(getDBRefId(dbRef)).append(" OR ");
+            queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
+                    .append(" OR ");
+            isUniProtRefsFound = true;
+          }
+          else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
+          {
+
+            String id = getDBRefId(dbRef).toLowerCase(Locale.ROOT);
+            if (!pdbids.contains(id))
+            {
+              queryBuilder.append("pdb_id:").append(id).append(" OR ");
+              isPDBRefsFound = true;
+              pdbids.add(id);
+            }
+          }
+          else
+          {
+            seqRefs.add(getDBRefId(dbRef));
+          }
+        }
+      }
+    }
+
+    if (!isPDBRefsFound && !isUniProtRefsFound)
+    {
+      String seqName = seq.getName();
+      seqName = sanitizeSeqName(seqName);
+      String[] names = seqName.toLowerCase(Locale.ROOT).split("\\|");
+      for (String name : names)
+      {
+        // System.out.println("Found name : " + name);
+        name.trim();
+        if (isValidSeqName(name))
+        {
+          seqRefs.add(name);
+        }
+      }
+
+      for (String seqRef : seqRefs)
+      {
+        queryBuilder.append("text:").append(seqRef).append(" OR ");
+      }
+    }
+
+    int endIndex = queryBuilder.lastIndexOf(" OR ");
+    if (queryBuilder.toString().length() < 6)
+    {
+      return null;
+    }
+    String query = queryBuilder.toString().substring(0, endIndex);
+    return query;
+  }
+
+  /**
+   * Remove the following special characters from input string +, -, &, !, (, ),
+   * {, }, [, ], ^, ", ~, *, ?, :, \
+   * 
+   * @param seqName
+   * @return
+   */
+  public static String sanitizeSeqName(String seqName)
+  {
+    Objects.requireNonNull(seqName);
+    return seqName.replaceAll("\\[\\d*\\]", "")
+            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
+  }
+
+  /**
+   * Ensures sequence ref names are not less than 3 characters and does not
+   * contain a database name
+   * 
+   * @param seqName
+   * @return
+   */
+  static boolean isValidSeqName(String seqName)
+  {
+    // System.out.println("seqName : " + seqName);
+    String ignoreList = "pdb,uniprot,swiss-prot";
+    if (seqName.length() < 3)
+    {
+      return false;
+    }
+    if (seqName.contains(":"))
+    {
+      return false;
+    }
+    seqName = seqName.toLowerCase(Locale.ROOT);
+    for (String ignoredEntry : ignoreList.split(","))
+    {
+      if (seqName.contains(ignoredEntry))
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static String getDBRefId(DBRefEntry dbRef)
+  {
+    String ref = dbRef.getAccessionId().replaceAll("GO:", "");
+    return ref;
+  }
+
+  /**
+   * FTSRestClient specific query builder to recover associated structure data
+   * records for a sequence
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
+          Collection<FTSDataColumnI> wantedFields,
+          FilterOption selectedFilterOpt, boolean b) throws Exception
+  {
+    FTSRestResponse resultList;
+    FTSRestRequest pdbRequest = new FTSRestRequest();
+    pdbRequest.setAllowEmptySeq(false);
+    pdbRequest.setResponseSize(500);
+    pdbRequest.setFieldToSearchBy("(");
+    pdbRequest.setFieldToSortBy(selectedFilterOpt.getValue(), b);
+    pdbRequest.setWantedFields(wantedFields);
+    pdbRequest.setSearchTerm(buildQuery(seq) + ")");
+    pdbRequest.setAssociatedSequence(seq);
+    resultList = pdbRestClient.executeRequest(pdbRequest);
+
+    lastPdbRequest = pdbRequest;
+    return resultList;
+  }
+  public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
+  {
+    List<FilterOption> filters = new ArrayList<FilterOption>();
+    filters.add(new FilterOption("PDBe "+
+            MessageManager.getString("label.best_quality"),
+            "overall_quality", VIEWS_FILTER, false,this));
+    filters.add(new FilterOption("PDBe "+
+            MessageManager.getString("label.best_resolution"),
+            "resolution", VIEWS_FILTER, false,this));
+    filters.add(new FilterOption("PDBe "+
+            MessageManager.getString("label.most_protein_chain"),
+            "number_of_protein_chains", VIEWS_FILTER, false,this));
+    filters.add(new FilterOption("PDBe "+
+            MessageManager.getString("label.most_bound_molecules"),
+            "number_of_bound_molecules", VIEWS_FILTER, false,this));
+    filters.add(new FilterOption("PDBe "+
+            MessageManager.getString("label.most_polymer_residues"),
+            "number_of_polymer_residues", VIEWS_FILTER, true,this));
+  
+    return filters;
+  }
+
+  @Override
+  public boolean needsRefetch(FilterOption selectedFilterOpt)
+  {
+    // PDBe queries never need a refetch first
+    return false;
+  }
+
+  /**
+   * FTSRestClient specific query builder to pick top ranked entry from a
+   * fetchStructuresMetaData query
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public FTSRestResponse selectFirstRankedQuery(SequenceI seq, Collection<FTSData> collectedResults,
+          Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
+          boolean b) throws Exception
+  {
+
+    FTSRestResponse resultList;
+    FTSRestRequest pdbRequest = new FTSRestRequest();
+    if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
+    {
+      pdbRequest.setAllowEmptySeq(false);
+      pdbRequest.setResponseSize(1);
+      pdbRequest.setFieldToSearchBy("(");
+      pdbRequest.setSearchTerm(buildQuery(seq) + ")");
+      pdbRequest.setWantedFields(wantedFields);
+      pdbRequest.setAssociatedSequence(seq);
+      pdbRequest.setFacet(true);
+      pdbRequest.setFacetPivot(fieldToFilterBy + ",entry_entity");
+      pdbRequest.setFacetPivotMinCount(1);
+    }
+    else
+    {
+      pdbRequest.setAllowEmptySeq(false);
+      pdbRequest.setResponseSize(1);
+      pdbRequest.setFieldToSearchBy("(");
+      pdbRequest.setFieldToSortBy(fieldToFilterBy, b);
+      pdbRequest.setSearchTerm(buildQuery(seq) + ")");
+      pdbRequest.setWantedFields(wantedFields);
+      pdbRequest.setAssociatedSequence(seq);
+    }
+    resultList = pdbRestClient.executeRequest(pdbRequest);
+
+    lastPdbRequest = pdbRequest;
+    return resultList;
+  }
+
+
+  @Override
+  public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
+          List<SequenceI> selectedSeqsToView)
+  {
+    int refSeqColIndex = restable.getColumn("Ref Sequence")
+            .getModelIndex();
+
+    PDBEntry[] pdbEntriesToView=new PDBEntry[selectedRows.length];
+    int count = 0;
+    int idColumnIndex=-1;
+    boolean fromTDB=true;
+    idColumnIndex = restable.getColumn("PDB Id").getModelIndex();
+    
+    for (int row : selectedRows)
+    {
+      
+      String pdbIdStr = restable.getValueAt(row,idColumnIndex)
+              .toString();
+      SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
+              refSeqColIndex);
+      selectedSeqsToView.add(selectedSeq);
+      PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
+      if (pdbEntry == null)
+      {
+        pdbEntry = getFindEntry(pdbIdStr,
+                selectedSeq.getAllPDBEntries());
+      }
+
+      if (pdbEntry == null)
+      {
+        pdbEntry = new PDBEntry();
+        pdbEntry.setId(pdbIdStr);
+        pdbEntry.setType(PDBEntry.Type.MMCIF);
+        selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
+      }
+      pdbEntriesToView[count++] = pdbEntry;
+    }
+    return pdbEntriesToView;
+  }
+
+
+  @Override
+  protected FTSRestRequest getLastFTSRequest()
+  {
+    return lastPdbRequest;
+  }
+
+
+  public FTSRestResponse executePDBFTSRestRequest(FTSRestRequest pdbRequest) throws Exception
+  {
+    return pdbRestClient.executeRequest(pdbRequest);
+  }
+
+}
\ No newline at end of file
diff --git a/src/jalview/gui/structurechooser/StructureChooserQuerySource.java b/src/jalview/gui/structurechooser/StructureChooserQuerySource.java
new file mode 100644 (file)
index 0000000..1aad2e0
--- /dev/null
@@ -0,0 +1,276 @@
+package jalview.gui.structurechooser;
+
+import java.util.Locale;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Vector;
+
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.jbgui.FilterOption;
+
+/**
+ * logic for querying sources of structural data for structures of sequences
+ * 
+ * @author jprocter
+ *
+ * @param <T>
+ */
+public abstract class StructureChooserQuerySource
+{
+
+  protected FTSDataColumnPreferences docFieldPrefs;
+
+  /**
+   * max length of a GET URL (probably :( )
+   */
+  protected static int MAX_QLENGTH = 7820;
+
+  public StructureChooserQuerySource()
+  {
+  }
+
+  public static StructureChooserQuerySource getPDBfts()
+  {
+    return new PDBStructureChooserQuerySource();
+  }
+
+  public static StructureChooserQuerySource getTDBfts()
+  {
+    return new ThreeDBStructureChooserQuerySource();
+  }
+
+  public FTSDataColumnPreferences getDocFieldPrefs()
+  {
+    return docFieldPrefs;
+  }
+
+  public void setDocFieldPrefs(FTSDataColumnPreferences docFieldPrefs)
+  {
+    this.docFieldPrefs = docFieldPrefs;
+  }
+
+  public FTSDataColumnPreferences getInitialFieldPreferences()
+  {
+    return docFieldPrefs;
+  }
+
+  /**
+   * Builds a query string for a given sequences using its DBRef entries
+   * 
+   * @param seq
+   *          the sequences to build a query for
+   * @return the built query string
+   */
+
+  public abstract String buildQuery(SequenceI seq);
+
+  /**
+   * Remove the following special characters from input string +, -, &, !, (, ),
+   * {, }, [, ], ^, ", ~, *, ?, :, \
+   * 
+   * @param seqName
+   * @return
+   */
+  public static String sanitizeSeqName(String seqName)
+  {
+    Objects.requireNonNull(seqName);
+    return seqName.replaceAll("\\[\\d*\\]", "")
+            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
+  }
+
+  /**
+   * Ensures sequence ref names are not less than 3 characters and does not
+   * contain a database name
+   * 
+   * @param seqName
+   * @return
+   */
+  static boolean isValidSeqName(String seqName)
+  {
+    // System.out.println("seqName : " + seqName);
+    String ignoreList = "pdb,uniprot,swiss-prot";
+    if (seqName.length() < 3)
+    {
+      return false;
+    }
+    if (seqName.contains(":"))
+    {
+      return false;
+    }
+    seqName = seqName.toLowerCase(Locale.ROOT);
+    for (String ignoredEntry : ignoreList.split(","))
+    {
+      if (seqName.contains(ignoredEntry))
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static String getDBRefId(DBRefEntry dbRef)
+  {
+    String ref = dbRef.getAccessionId().replaceAll("GO:", "");
+    return ref;
+  }
+
+  static PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
+  {
+    Objects.requireNonNull(id);
+    Objects.requireNonNull(pdbEntries);
+    PDBEntry foundEntry = null;
+    for (PDBEntry entry : pdbEntries)
+    {
+      if (entry.getId().equalsIgnoreCase(id))
+      {
+        return entry;
+      }
+    }
+    return foundEntry;
+  }
+
+  /**
+   * FTSRestClient specific query builder to recover associated structure data
+   * records for a sequence
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public abstract FTSRestResponse fetchStructuresMetaData(SequenceI seq,
+          Collection<FTSDataColumnI> wantedFields,
+          FilterOption selectedFilterOpt, boolean b) throws Exception;
+
+  /**
+   * FTSRestClient specific query builder to pick top ranked entry from a
+   * fetchStructuresMetaData query
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param discoveredStructuresSet
+   *          - existing set of entries - allows client side selection
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public abstract FTSRestResponse selectFirstRankedQuery(SequenceI seq,
+          Collection<FTSData> discoveredStructuresSet,
+          Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
+          boolean b) throws Exception;
+
+  /**
+   * 
+   * @param discoveredStructuresSet
+   * @return the table model for the given result set for this engine
+   */
+  public TableModel getTableModel(
+          Collection<FTSData> discoveredStructuresSet)
+  {
+    return FTSRestResponse.getTableModel(getLastFTSRequest(),
+            discoveredStructuresSet);
+  }
+
+  protected abstract FTSRestRequest getLastFTSRequest();
+
+  public abstract PDBEntry[] collectSelectedRows(JTable restable,
+          int[] selectedRows, List<SequenceI> selectedSeqsToView);
+
+  /**
+   * @param VIEWS_FILTER
+   *          - a String key that can be used by the caller to tag the returned
+   *          filter options to distinguish them in a collection
+   * @return list of FilterOption - convention is that the last one in the list
+   *         will be constructed with 'addSeparator==true'
+   */
+  public abstract List<FilterOption> getAvailableFilterOptions(
+          String VIEWS_FILTER);
+
+  /**
+   * construct a structure chooser query source for the given set of sequences
+   * 
+   * @param selectedSeqs
+   * @return PDBe or 3DB query source
+   */
+  public static StructureChooserQuerySource getQuerySourceFor(
+          SequenceI[] selectedSeqs)
+  {
+    ThreeDBStructureChooserQuerySource tdbSource = new ThreeDBStructureChooserQuerySource();
+    boolean hasUniprot = false, hasCanonical = false;
+    boolean hasNA = false, hasProtein = false;
+    int protWithoutUni = 0;
+    int protWithoutCanon = 0;
+    for (SequenceI seq : selectedSeqs)
+    {
+      hasNA |= !seq.isProtein();
+      hasProtein |= seq.isProtein();
+      if (seq.isProtein())
+      {
+        int refsAvailable = ThreeDBStructureChooserQuerySource
+                .checkUniprotRefs(seq.getDBRefs());
+        if (refsAvailable > -2)
+        {
+          if (refsAvailable > -1)
+          {
+            hasCanonical = true;
+          } else {
+            protWithoutCanon++;
+          }
+          hasUniprot = true;
+        } else {
+          protWithoutUni++;
+          
+        }
+      }
+    }
+    //
+    // logic: all canonicals - no fetchdb
+    // some uniprot no canonicals: defer to PDB, user can optionally fetch
+    //
+    if (hasProtein && hasCanonical && !hasNA && protWithoutCanon == 0 && protWithoutUni == 0)
+
+    {
+      return tdbSource;
+    }
+    return new PDBStructureChooserQuerySource();
+  }
+
+  /**
+   * some filter options may mean the original query needs to be executed again.
+   * 
+   * @param selectedFilterOpt
+   * @return true if the fetchStructuresMetadata method needs to be called again
+   */
+  public abstract boolean needsRefetch(FilterOption selectedFilterOpt);
+
+  public void updateAvailableFilterOptions(String VIEWS_FILTER,
+          List<FilterOption> xtantOptions, Collection<FTSData> lastFTSData)
+  {
+    // TODO Auto-generated method stub
+
+  }
+}
\ No newline at end of file
diff --git a/src/jalview/gui/structurechooser/TDBResultAnalyser.java b/src/jalview/gui/structurechooser/TDBResultAnalyser.java
new file mode 100644 (file)
index 0000000..a453529
--- /dev/null
@@ -0,0 +1,286 @@
+package jalview.gui.structurechooser;
+
+import java.util.Locale;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.core.FTSRestRequest;
+
+public class TDBResultAnalyser
+{
+
+  /**
+   * model categories - update as needed. warnings output if unknown types
+   * encountered.
+   * 
+   * Order denotes 'trust'
+   */
+  private static List<String> EXP_CATEGORIES = Arrays
+          .asList(new String[]
+          { "EXPERIMENTALLY DETERMINED", "DEEP-LEARNING", "TEMPLATE-BASED",
+              "AB-INITIO", "CONFORMATIONAL ENSEMBLE" });
+
+  private SequenceI seq;
+
+  private Collection<FTSData> collectedResults;
+
+  private FTSRestRequest lastTdbRequest;
+
+  private int idx_ups;
+
+  private int idx_upe;
+
+  private int idx_mcat;
+
+  private int idx_mqual;
+
+  private int idx_resol;
+
+  /**
+   * selection model
+   */
+  private String filter = null;
+
+  /**
+   * limit to particular source
+   */
+  private String sourceFilter = null;
+
+  private int idx_mprov;
+
+  public TDBResultAnalyser(SequenceI seq,
+          Collection<FTSData> collectedResults,
+          FTSRestRequest lastTdbRequest, String fieldToFilterBy,
+          String string)
+  {
+    this.seq = seq;
+    this.collectedResults = collectedResults;
+    this.lastTdbRequest = lastTdbRequest;
+    this.filter = fieldToFilterBy;
+    this.sourceFilter = string;
+    idx_ups = lastTdbRequest.getFieldIndex("Uniprot Start");
+    idx_upe = lastTdbRequest.getFieldIndex("Uniprot End");
+    idx_mcat = lastTdbRequest.getFieldIndex("Model Category");
+    idx_mprov = lastTdbRequest.getFieldIndex("Provider");
+    idx_mqual = lastTdbRequest.getFieldIndex("Confidence");
+    idx_resol = lastTdbRequest.getFieldIndex("Resolution");
+  }
+
+  /**
+   * maintain and resolve categories to 'trust order' TODO: change the trust
+   * scheme to something comprehensible.
+   * 
+   * @param cat
+   * @return 0 for null cat, less than zero for others
+   */
+  public final int scoreCategory(String cat)
+  {
+    if (cat == null)
+    {
+      return 0;
+    }
+    String upper_cat = cat.toUpperCase(Locale.ROOT);
+    int idx = EXP_CATEGORIES.indexOf(upper_cat);
+    if (idx == -1)
+    {
+      System.out.println("Unknown category: '" + cat + "'");
+      EXP_CATEGORIES.add(upper_cat);
+      idx = EXP_CATEGORIES.size() - 1;
+    }
+    return -EXP_CATEGORIES.size() - idx;
+  }
+
+  /**
+   * sorts records discovered by 3D beacons and excludes any that don't
+   * intersect with the sequence's start/end rage
+   * 
+   * @return
+   */
+  public List<FTSData> getFilteredResponse()
+  {
+    List<FTSData> filteredResponse = new ArrayList<FTSData>();
+
+    // ignore anything outside the sequence region
+    for (FTSData row : collectedResults)
+    {
+      int up_s = (Integer) row.getSummaryData()[idx_ups];
+      int up_e = (Integer) row.getSummaryData()[idx_upe];
+      String provider = (String) row.getSummaryData()[idx_mprov];
+      String mcat = (String) row.getSummaryData()[idx_mcat];
+      // this makes sure all new categories are in the score array.
+      int scorecat = scoreCategory(mcat); 
+      if (sourceFilter == null ||  sourceFilter.equals(provider))
+      {
+        if (seq == row.getSummaryData()[0] && up_e > seq.getStart()
+                && up_s < seq.getEnd())
+        {
+          filteredResponse.add(row);
+        }
+      }
+    }
+    // sort according to decreasing length,
+    // increasing start
+    Collections.sort(filteredResponse, new Comparator<FTSData>()
+    {
+      @Override
+      public int compare(FTSData o1, FTSData o2)
+      {
+        Object[] o1data = o1.getSummaryData();
+        Object[] o2data = o2.getSummaryData();
+        int o1_s = (Integer) o1data[idx_ups];
+        int o1_e = (Integer) o1data[idx_upe];
+        int o1_cat = scoreCategory((String) o1data[idx_mcat]);
+        String o1_prov= ((String) o1data[idx_mprov]).toUpperCase(Locale.ROOT);
+        int o2_s = (Integer) o2data[idx_ups];
+        int o2_e = (Integer) o2data[idx_upe];
+        int o2_cat = scoreCategory((String) o2data[idx_mcat]);
+        String o2_prov= ((String) o2data[idx_mprov]).toUpperCase(Locale.ROOT);
+        
+
+        if (o1_cat == o2_cat)
+        {
+          if (o1_s == o2_s)
+          {
+            int o1_xtent = o1_e - o1_s;
+            int o2_xtent = o2_e - o2_s;
+            if (o1_xtent == o2_xtent)
+            {
+              if (o1_cat == scoreCategory(EXP_CATEGORIES.get(0)))
+              {
+                if (o1_prov.equals(o2_prov)) {
+                  if ("PDBE".equals(o1_prov)) {
+                    if (eitherNull(idx_resol,o1data,o2data))
+                    {
+                       return nonNullFirst(idx_resol,o1data,o2data);
+                    }
+                // experimental structures, so rank on quality
+                double o1_res = (Double) o1data[idx_resol];
+                double o2_res = (Double) o2data[idx_resol];
+                return (o2_res < o1_res) ? 1 : (o2_res == o1_res) ? 0 : -1;
+                } else {
+                  return 0; // no change in order
+                }
+              } else {
+                // PDBe always ranked above all other experimentally determined categories
+                return "PDBE".equals(o1_prov) ? -1 : "PDBE".equals(o2_prov) ? 1 : 0;
+              }
+              }
+              else
+              {
+                if (eitherNull(idx_mqual,o1data, o2data)) {
+                  return nonNullFirst(idx_mqual, o1data, o2data);
+                }
+                // models, so rank on qmean - b
+                double o1_mq = (Double) o1data[idx_mqual];
+                double o2_mq = (Double) o2data[idx_mqual];
+                return (o2_mq < o1_mq) ? 1 : (o2_mq == o1_mq) ? 0 : -1;
+              }
+            }
+            else
+            {
+              return o1_xtent - o2_xtent;
+            }
+          }
+          else
+          {
+            return o1_s - o2_s;
+          }
+        }
+        else
+        {
+          return o2_cat - o1_cat;
+        }
+      }
+
+      private int nonNullFirst(int idx_resol, Object[] o1data,
+              Object[] o2data)
+      {
+          return o1data[idx_resol] == o2data[idx_resol] ? 0: o1data[idx_resol] != null ? -1 : 1; 
+      }
+
+      private boolean eitherNull(int idx_resol, Object[] o1data,
+              Object[] o2data)
+      {
+        return (o1data[idx_resol] == null || o2data[idx_resol]==null);
+      }
+
+      @Override
+      public boolean equals(Object obj)
+      {
+        return super.equals(obj);
+      }
+    });
+    return filteredResponse;
+  }
+
+  /**
+   * return list of structures to be marked as selected for this sequence
+   * according to given criteria
+   * 
+   * @param filteredStructures
+   *          - sorted, filtered structures from getFilteredResponse
+   * 
+   */
+  public List<FTSData> selectStructures(List<FTSData> filteredStructures)
+  {
+    List<FTSData> selected = new ArrayList<FTSData>();
+    BitSet cover = new BitSet();
+    cover.set(seq.getStart(), seq.getEnd());
+    // walk down the list of structures, selecting some to add to selected
+    // TODO: could do simple DP - double loop to select largest number of
+    // structures covering largest number of sites
+    for (FTSData structure : filteredStructures)
+    {
+      Object[] odata = structure.getSummaryData();
+      int o1_s = (Integer) odata[idx_ups];
+      int o1_e = (Integer) odata[idx_upe];
+      int o1_cat = scoreCategory((String) odata[idx_mcat]);
+      BitSet scover = new BitSet();
+      // measure intersection
+      scover.set(o1_s, o1_e);
+      scover.and(cover);
+      if (scover.cardinality() > 4)
+      {
+        selected.add(structure);
+        // clear the range covered by this structure
+        cover.andNot(scover);
+      }
+    }
+    if (selected.size()==0)
+    {
+      return selected;
+    }
+    // final step is to sort on length - this might help the superposition
+    // process
+    Collections.sort(selected, new Comparator<FTSData>()
+    {
+      @Override
+      public int compare(FTSData o1, FTSData o2)
+      {
+        Object[] o1data = o1.getSummaryData();
+        Object[] o2data = o2.getSummaryData();
+        int o1_xt = ((Integer) o1data[idx_upe])
+                - ((Integer) o1data[idx_ups]);
+        int o1_cat = scoreCategory((String) o1data[idx_mcat]);
+        int o2_xt = ((Integer) o2data[idx_upe] - (Integer) o2data[idx_ups]);
+        int o2_cat = scoreCategory((String) o2data[idx_mcat]);
+        return o2_xt - o1_xt;
+      }
+    });
+    if (filter.equals(
+            ThreeDBStructureChooserQuerySource.FILTER_FIRST_BEST_COVERAGE))
+    {
+      return selected.subList(0, 1);
+    }
+    return selected;
+  }
+
+}
diff --git a/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java b/src/jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.java
new file mode 100644 (file)
index 0000000..669e58a
--- /dev/null
@@ -0,0 +1,569 @@
+package jalview.gui.structurechooser;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.swing.JTable;
+
+import jalview.bin.Console;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.threedbeacons.TDB_FTSData;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
+import jalview.jbgui.FilterOption;
+
+/**
+ * logic for querying the 3DBeacons API for structures of sequences
+ * 
+ * @author jprocter
+ */
+public class ThreeDBStructureChooserQuerySource
+        extends StructureChooserQuerySource
+{
+
+  private Set<String> tdBeaconsFilters = null, defaultFilters = null;
+
+  public static final String FILTER_TDBEACONS_COVERAGE = "3d_beacons_coverage";
+
+  public static final String FILTER_FIRST_BEST_COVERAGE = "3d_beacons_first_best_coverage";
+
+  private static final String FILTER_SOURCE_PREFIX = "only_";
+
+  protected FTSRestRequest lastTdbRequest;
+
+  protected FTSRestClientI tdbRestClient;
+
+  private FTSRestRequest lastPdbRequest;
+
+  public ThreeDBStructureChooserQuerySource()
+  {
+    defaultFilters = new LinkedHashSet<String>();
+    defaultFilters.add(FILTER_TDBEACONS_COVERAGE);
+    defaultFilters.add(FILTER_FIRST_BEST_COVERAGE);
+
+    tdbRestClient = TDBeaconsFTSRestClient.getInstance();
+    docFieldPrefs = new FTSDataColumnPreferences(
+            PreferenceSource.STRUCTURE_CHOOSER,
+            TDBeaconsFTSRestClient.getInstance());
+  }
+
+  /**
+   * Builds a query string for a given sequences using its DBRef entries 3d
+   * Beacons is only useful for uniprot IDs
+   * 
+   * @param seq
+   *          the sequences to build a query for
+   * @return the built query string
+   */
+
+  public String buildQuery(SequenceI seq)
+  {
+    List<DBRefEntry> refs = seq.getDBRefs();
+    int ib = checkUniprotRefs(refs);
+    if (ib > -1)
+    {
+      return getDBRefId(refs.get(ib));
+    }
+    return null;
+  }
+
+  /**
+   * Searches DBRefEntry for uniprot refs
+   * 
+   * @param seq
+   * @return -2 if no uniprot refs, -1 if no canonical ref., otherwise index of
+   *         Uniprot canonical DBRefEntry
+   */
+  public static int checkUniprotRefs(List<DBRefEntry> refs)
+  {
+    boolean hasUniprot = false;
+    if (refs != null && refs.size() != 0)
+    {
+      for (int ib = 0, nb = refs.size(); ib < nb; ib++)
+      {
+        DBRefEntry dbRef = refs.get(ib);
+        if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
+        {
+          hasUniprot = true;
+          if (dbRef.isCanonical())
+          {
+            return ib;
+          }
+        }
+      }
+    }
+    return hasUniprot ? -1 : -2;
+  }
+
+  /**
+   * Ensures sequence ref names are not less than 3 characters and does not
+   * contain a database name
+   * 
+   * @param seqName
+   * @return
+   */
+  static boolean isValidSeqName(String seqName)
+  {
+    String ignoreList = "pdb,uniprot,swiss-prot";
+    if (seqName.length() < 3)
+    {
+      return false;
+    }
+    if (seqName.contains(":"))
+    {
+      return false;
+    }
+    seqName = seqName.toLowerCase(Locale.ROOT);
+    for (String ignoredEntry : ignoreList.split(","))
+    {
+      if (seqName.contains(ignoredEntry))
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static String getDBRefId(DBRefEntry dbRef)
+  {
+    String ref = dbRef.getAccessionId().replaceAll("GO:", "");
+    return ref;
+  }
+
+  /**
+   * FTSRestClient specific query builder to recover associated structure data
+   * records for a sequence
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public FTSRestResponse fetchStructuresMetaData(SequenceI seq,
+          Collection<FTSDataColumnI> wantedFields,
+          FilterOption selectedFilterOpt, boolean b) throws Exception
+  {
+    FTSRestResponse resultList;
+    if (selectedFilterOpt != null
+            && tdBeaconsFilter(selectedFilterOpt.getValue()))
+    {
+      FTSRestRequest tdbRequest = getTDBeaconsRequest(seq, wantedFields);
+      resultList = tdbRestClient.executeRequest(tdbRequest);
+
+      lastTdbRequest = tdbRequest;
+      if (resultList != null)
+      { // Query the PDB and add additional metadata
+        FTSRestResponse pdbResponse = fetchStructuresMetaDataFor(
+                getPDBQuerySource(), resultList);
+
+        resultList = joinResponses(resultList, pdbResponse);
+      }
+      return resultList;
+    }
+    // use the PDBFTS directly
+    resultList = getPDBQuerySource().fetchStructuresMetaData(seq,
+            wantedFields, selectedFilterOpt, b);
+    lastTdbRequest = getPDBQuerySource().lastPdbRequest;
+    lastPdbRequest = lastTdbRequest; // both queries the same - indicates we
+    // rank using PDBe
+    return resultList;
+
+  }
+
+  PDBStructureChooserQuerySource pdbQuerySource = null;
+
+  private PDBStructureChooserQuerySource getPDBQuerySource()
+  {
+    if (pdbQuerySource == null)
+    {
+      pdbQuerySource = new PDBStructureChooserQuerySource();
+    }
+    return pdbQuerySource;
+  }
+
+  private FTSRestRequest getTDBeaconsRequest(SequenceI seq,
+          Collection<FTSDataColumnI> wantedFields)
+  {
+    FTSRestRequest pdbRequest = new FTSRestRequest();
+    pdbRequest.setAllowEmptySeq(false);
+    pdbRequest.setResponseSize(500);
+    pdbRequest.setWantedFields(wantedFields);
+    String query = buildQuery(seq);
+    if (query == null)
+    {
+      return null;
+    }
+    pdbRequest.setSearchTerm(query + ".json");
+    pdbRequest.setAssociatedSequence(seq);
+    return pdbRequest;
+  }
+
+  @Override
+  public List<FilterOption> getAvailableFilterOptions(String VIEWS_FILTER)
+  {
+    List<FilterOption> filters = getPDBQuerySource()
+            .getAvailableFilterOptions(VIEWS_FILTER);
+    tdBeaconsFilters = new LinkedHashSet<String>();
+    tdBeaconsFilters.addAll(defaultFilters);
+    filters.add(0, new FilterOption("Best 3D-Beacons Coverage",
+            FILTER_FIRST_BEST_COVERAGE, VIEWS_FILTER, false, this));
+    filters.add(1, new FilterOption("Multiple 3D-Beacons Coverage",
+            FILTER_TDBEACONS_COVERAGE, VIEWS_FILTER, true, this));
+
+    return filters;
+  }
+
+  @Override
+  public void updateAvailableFilterOptions(String VIEWS_FILTER,
+          List<FilterOption> xtantOptions, Collection<FTSData> tdbEntries)
+  {
+    if (tdbEntries != null && lastTdbRequest != null)
+    {
+      boolean hasPDBe = false;
+      for (FTSData _row : tdbEntries)
+      {
+        // tdb returns custom object
+        TDB_FTSData row = (TDB_FTSData) _row;
+        String provider = (String) row.getProvider();
+        FilterOption providerOpt = new FilterOption(
+                "3DB Provider - " + provider,
+                FILTER_SOURCE_PREFIX + provider, VIEWS_FILTER, false, this);
+        if (!xtantOptions.contains(providerOpt))
+        {
+          xtantOptions.add(1, providerOpt);
+          tdBeaconsFilters.add(FILTER_SOURCE_PREFIX + provider);
+          if ("PDBe".equalsIgnoreCase(provider))
+          {
+            hasPDBe = true;
+          }
+        }
+      }
+      if (!hasPDBe)
+      {
+        // remove the PDBe options from the available filters
+        int op = 0;
+        while (op < xtantOptions.size())
+        {
+          FilterOption filter = xtantOptions.get(op);
+          if (filter
+                  .getQuerySource() instanceof PDBStructureChooserQuerySource)
+          {
+            xtantOptions.remove(op);
+          }
+          else
+          {
+            op++;
+          }
+        }
+      }
+    }
+
+  }
+
+  private boolean tdBeaconsFilter(String fieldToFilterBy)
+  {
+    return tdBeaconsFilters != null
+            && tdBeaconsFilters.contains(fieldToFilterBy);
+  }
+
+  private String remove_prefix(String fieldToFilterBy)
+  {
+    if (tdBeaconsFilters != null
+            && tdBeaconsFilters.contains(fieldToFilterBy)
+            && !defaultFilters.contains(fieldToFilterBy))
+    {
+      return fieldToFilterBy.substring(FILTER_SOURCE_PREFIX.length());
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  @Override
+  public boolean needsRefetch(FilterOption selectedFilterOpt)
+  {
+    return selectedFilterOpt == null
+            || !tdBeaconsFilter(selectedFilterOpt.getValue())
+                    && lastPdbRequest != lastTdbRequest;
+  }
+
+  /**
+   * FTSRestClient specific query builder to pick top ranked entry from a
+   * fetchStructuresMetaData query
+   * 
+   * @param seq
+   *          - seq to generate a query for
+   * @param wantedFields
+   *          - fields to retrieve
+   * @param selectedFilterOpt
+   *          - criterion for ranking results (e.g. resolution)
+   * @param b
+   *          - sort ascending or descending
+   * @return
+   * @throws Exception
+   */
+  public FTSRestResponse selectFirstRankedQuery(SequenceI seq,
+          Collection<FTSData> collectedResults,
+          Collection<FTSDataColumnI> wantedFields, String fieldToFilterBy,
+          boolean b) throws Exception
+  {
+    if (fieldToFilterBy != null && tdBeaconsFilter(fieldToFilterBy))
+    {
+      TDBResultAnalyser analyser = new TDBResultAnalyser(seq,
+              collectedResults, lastTdbRequest, fieldToFilterBy,
+              remove_prefix(fieldToFilterBy));
+
+      FTSRestResponse resultList = new FTSRestResponse();
+
+      List<FTSData> filteredResponse = analyser.getFilteredResponse();
+
+      List<FTSData> selectedStructures = analyser
+              .selectStructures(filteredResponse);
+      resultList.setNumberOfItemsFound(selectedStructures.size());
+      resultList.setSearchSummary(selectedStructures);
+      return resultList;
+    }
+    // Fall back to PDBe rankings
+    return getPDBQuerySource().selectFirstRankedQuery(seq, collectedResults,
+            wantedFields, fieldToFilterBy, b);
+  }
+
+  @Override
+  public PDBEntry[] collectSelectedRows(JTable restable, int[] selectedRows,
+          List<SequenceI> selectedSeqsToView)
+  {
+    int refSeqColIndex = restable.getColumn("Ref Sequence").getModelIndex();
+
+    PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
+    int count = 0;
+    int idColumnIndex = restable.getColumn("Model id").getModelIndex();
+    int urlColumnIndex = restable.getColumn("Url").getModelIndex();
+    int typeColumnIndex = restable.getColumn("Provider").getModelIndex();
+    int humanUrl = restable.getColumn("Page URL").getModelIndex();
+    int modelformat = restable.getColumn("Model Format").getModelIndex();
+    final int up_start_idx = restable.getColumn("Uniprot Start")
+            .getModelIndex();
+    final int up_end_idx = restable.getColumn("Uniprot End")
+            .getModelIndex();
+    int i = 0;
+
+    // bleugh!
+    Integer[] sellist = new Integer[selectedRows.length];
+    for (Integer row : selectedRows)
+    {
+      sellist[i++] = row;
+    }
+    // Sort rows by coverage
+    Arrays.sort(sellist, new Comparator<Integer>()
+    {
+      @Override
+      public int compare(Integer o1, Integer o2)
+      {
+        int o1_xt = ((Integer) restable.getValueAt(o1, up_end_idx))
+                - (Integer) restable.getValueAt(o1, up_start_idx);
+        int o2_xt = ((Integer) restable.getValueAt(o2, up_end_idx))
+                - (Integer) restable.getValueAt(o2, up_start_idx);
+        return o2_xt - o1_xt;
+      }
+    });
+
+    for (int row : sellist)
+    {
+      // unique id - could be a horrible hash
+
+      String pdbIdStr = restable.getValueAt(row, idColumnIndex).toString();
+      String urlStr = restable.getValueAt(row, urlColumnIndex).toString();
+      String typeColumn = restable.getValueAt(row, typeColumnIndex)
+              .toString();
+      String modelPage = humanUrl < 1 ? null
+              : (String) restable.getValueAt(row, humanUrl);
+      String strucFormat = restable.getValueAt(row, modelformat).toString();
+
+      SequenceI selectedSeq = (SequenceI) restable.getValueAt(row,
+              refSeqColIndex);
+      selectedSeqsToView.add(selectedSeq);
+      PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
+      if (pdbEntry == null)
+      {
+        pdbEntry = getFindEntry(pdbIdStr, selectedSeq.getAllPDBEntries());
+      }
+
+      if (pdbEntry == null)
+      {
+        pdbEntry = new PDBEntry();
+        pdbEntry.setId(pdbIdStr);
+        pdbEntry.setAuthoritative(true);
+        try
+        {
+          pdbEntry.setType(PDBEntry.Type.valueOf(strucFormat));
+        } catch (Exception q)
+        {
+          Console.warn("Unknown filetype for 3D Beacons Model from: "
+                  + strucFormat + " - " + pdbIdStr + " - " + modelPage);
+        }
+
+        if (!"PDBe".equalsIgnoreCase(typeColumn))
+        {
+          pdbEntry.setRetrievalUrl(urlStr);
+        }
+        pdbEntry.setProvider(typeColumn);
+        pdbEntry.setProviderPage(modelPage);
+        selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
+      }
+      pdbEntriesToView[count++] = pdbEntry;
+    }
+    return pdbEntriesToView;
+  }
+
+  @Override
+  protected FTSRestRequest getLastFTSRequest()
+  {
+    return lastTdbRequest;
+  }
+
+  /**
+   * generate a query for PDBFTS to retrieve structure metadata
+   * 
+   * @param ftsRestRequest
+   * @param upResponse
+   * @return
+   */
+
+  public String buildPDBFTSQueryFor(FTSRestResponse upResponse)
+  {
+    Set<String> pdbIds = new HashSet<String>();
+    int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
+    int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
+    for (FTSData row : upResponse.getSearchSummary())
+    {
+      String id = (String) row.getSummaryData()[idx_modelId];
+      String provider = (String) row.getSummaryData()[idx_provider];
+      if ("PDBe".equalsIgnoreCase(provider))
+      {
+        pdbIds.add(id);
+      }
+    }
+    return String.join(" OR ", pdbIds).toString();
+  }
+
+  /**
+   * query PDBe for structure metadata
+   * 
+   * @param pdbquery
+   * @param upResponse
+   * @return FTSRestResponse via PDBStructureChooserQuerySource
+   */
+  public FTSRestResponse fetchStructuresMetaDataFor(
+          PDBStructureChooserQuerySource pdbquery,
+          FTSRestResponse upResponse) throws Exception
+  {
+
+    String pdb_Query = buildPDBFTSQueryFor(upResponse);
+    if (pdb_Query.length() == 0)
+    {
+      return null;
+    }
+    FTSRestResponse resultList;
+    FTSRestRequest pdbRequest = new FTSRestRequest();
+    pdbRequest.setAllowEmptySeq(false);
+    pdbRequest.setResponseSize(500);
+    pdbRequest.setFieldToSearchBy("(");
+    // pdbRequest.setFieldToSortBy("pdb_id");
+    pdbRequest.setWantedFields(
+            pdbquery.getDocFieldPrefs().getStructureSummaryFields());
+    pdbRequest.setSearchTerm(pdb_Query + ")");
+
+    resultList = pdbquery.executePDBFTSRestRequest(pdbRequest);
+
+    lastPdbRequest = pdbRequest;
+    return resultList;
+  }
+
+  public FTSRestResponse joinResponses(FTSRestResponse upResponse,
+          FTSRestResponse pdbResponse)
+  {
+    boolean hasPdbResp = lastPdbRequest != null;
+
+    int idx_provider = getLastFTSRequest().getFieldIndex("Provider");
+    // join on
+    int idx_modelId = getLastFTSRequest().getFieldIndex("Model id");
+    int pdbIdx = hasPdbResp ? lastPdbRequest.getFieldIndex("PDB Id") : -1;
+    int pdbTitle_idx = hasPdbResp ? lastPdbRequest.getFieldIndex("Title")
+            : -1;
+    int tdbTitle_idx = getLastFTSRequest().getFieldIndex("Title");
+
+    for (final FTSData row : upResponse.getSearchSummary())
+    {
+      String id = (String) row.getSummaryData()[idx_modelId];
+      String provider = (String) row.getSummaryData()[idx_provider];
+      if ("PDBe".equalsIgnoreCase(provider))
+      {
+        if (!hasPdbResp)
+        {
+          System.out.println(
+                  "Warning: seems like we couldn't get to the PDBe search interface.");
+        }
+        else
+        {
+          for (final FTSData pdbrow : pdbResponse.getSearchSummary())
+          {
+            String pdbid = (String) pdbrow.getSummaryData()[pdbIdx];
+            if (id.equalsIgnoreCase(pdbid))
+            {
+              row.getSummaryData()[tdbTitle_idx] = pdbrow
+                      .getSummaryData()[pdbTitle_idx];
+            }
+          }
+        }
+
+      }
+      else
+      {
+        row.getSummaryData()[tdbTitle_idx] = "Model from TDB";
+      }
+    }
+    return upResponse;
+  }
+
+  public TDB_FTSData getFTSDataFor(JTable restable, int selectedRow,
+          Collection<FTSData> discoveredStructuresSet)
+  {
+    int idColumnIndex = restable.getColumn("Model id").getModelIndex();
+
+    String modelId = (String) restable.getValueAt(selectedRow,
+            idColumnIndex);
+    for (FTSData row : discoveredStructuresSet)
+    {
+      if (row instanceof TDB_FTSData
+              && ((TDB_FTSData) row).getModelId().equals(modelId))
+      {
+        return ((TDB_FTSData) row);
+      }
+    }
+    return null;
+  }
+
+}
\ No newline at end of file
index cea2870..3202ac9 100755 (executable)
  */
 package jalview.io;
 
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceGroup;
-import jalview.datamodel.SequenceI;
-import jalview.util.MessageManager;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -34,6 +27,13 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Vector;
 
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.MessageManager;
+
 /**
  * DOCUMENT ME!
  * 
@@ -79,6 +79,8 @@ public abstract class AlignFile extends FileParse
 
   private boolean parseImmediately = true;
 
+  private boolean dataClosed = false;
+
   /**
    * @return if doParse() was called at construction time
    */
@@ -165,6 +167,12 @@ public abstract class AlignFile extends FileParse
   public AlignFile(boolean parseImmediately, FileParse source)
           throws IOException
   {
+    this(parseImmediately, source, true);
+  }
+
+  public AlignFile(boolean parseImmediately, FileParse source,
+          boolean closeData) throws IOException
+  {
     super(source);
     initData();
 
@@ -174,7 +182,7 @@ public abstract class AlignFile extends FileParse
 
     if (parseImmediately)
     {
-      doParse();
+      doParse(closeData);
     }
   }
 
@@ -185,6 +193,11 @@ public abstract class AlignFile extends FileParse
    */
   public void doParse() throws IOException
   {
+    doParse(true);
+  }
+
+  public void doParse(boolean closeData) throws IOException
+  {
     if (parseCalled)
     {
       throw new IOException(
@@ -193,6 +206,11 @@ public abstract class AlignFile extends FileParse
     }
     parseCalled = true;
     parse();
+    if (closeData && !dataClosed)
+    {
+      dataIn.close();
+      dataClosed = true;
+    }
   }
 
   /**
index 2182b24..934be41 100755 (executable)
@@ -25,6 +25,7 @@ import java.io.BufferedReader;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
@@ -1086,8 +1087,8 @@ public class AnnotationFile
               if (rowset != null && rowset.size() > 0)
               {
                 AlignmentAnnotation alan = null;
-                for (int elm = 0, elmSize = rowset
-                        .size(); elm < elmSize; elm++)
+                for (int elm = 0,
+                        elmSize = rowset.size(); elm < elmSize; elm++)
                 {
                   alan = (AlignmentAnnotation) rowset.elementAt(elm);
                   alan.groupRef = theGroup;
@@ -1549,110 +1550,120 @@ public class AnnotationFile
     }
 
     String name = st.nextToken();
-    SequenceGroup sg = null;
-    for (SequenceGroup _sg : al.getGroups())
+
+    Map<String, String> properties = new HashMap<>();
+    while (st.hasMoreTokens())
     {
-      if ((sg = _sg).getName().equals(name))
-      {
-        break;
-      }
-      else
+      String keyValue = st.nextToken();
+      String key = keyValue.substring(0, keyValue.indexOf("="));
+      String value = keyValue.substring(keyValue.indexOf("=") + 1);
+      properties.put(key, value);
+    }
+
+    for (SequenceGroup sg : al.getGroups())
+    {
+      if (sg.getName().equals(name))
       {
-        sg = null;
+        addProperties(sg, properties, al);
       }
     }
+  }
 
-    if (sg != null)
+  /**
+   * Helper method that applies any specified properties to a SequenceGroup
+   * 
+   * @param sg
+   * @param properties
+   * @param al
+   */
+  private void addProperties(SequenceGroup sg,
+          Map<String, String> properties, AlignmentI al)
+  {
+    ColourSchemeI def = sg.getColourScheme();
+    for (String key : properties.keySet())
     {
-      String keyValue, key, value;
-      ColourSchemeI def = sg.getColourScheme();
-      while (st.hasMoreTokens())
+      String value = properties.get(key);
+      if (key.equalsIgnoreCase("description"))
       {
-        keyValue = st.nextToken();
-        key = keyValue.substring(0, keyValue.indexOf("="));
-        value = keyValue.substring(keyValue.indexOf("=") + 1);
-
-        if (key.equalsIgnoreCase("description"))
-        {
-          sg.setDescription(value);
-        }
-        else if (key.equalsIgnoreCase("colour"))
-        {
-          // TODO need to notify colourscheme of view reference once it is
-          // available
-          sg.cs.setColourScheme(
-                  ColourSchemeProperty.getColourScheme(null, al, value));
-        }
-        else if (key.equalsIgnoreCase("pidThreshold"))
-        {
-          sg.cs.setThreshold(Integer.parseInt(value), true);
+        sg.setDescription(value);
+      }
+      else if (key.equalsIgnoreCase("colour"))
+      {
+        // TODO need to notify colourscheme of view reference once it is
+        // available
+        sg.cs.setColourScheme(
+                ColourSchemeProperty.getColourScheme(null, al, value));
+      }
+      else if (key.equalsIgnoreCase("pidThreshold"))
+      {
+        sg.cs.setThreshold(Integer.parseInt(value), true);
 
-        }
-        else if (key.equalsIgnoreCase("consThreshold"))
-        {
-          sg.cs.setConservationInc(Integer.parseInt(value));
-          Conservation c = new Conservation("Group", sg.getSequences(null),
-                  sg.getStartRes(), sg.getEndRes() + 1);
+      }
+      else if (key.equalsIgnoreCase("consThreshold"))
+      {
+        sg.cs.setConservationInc(Integer.parseInt(value));
+        Conservation c = new Conservation("Group", sg.getSequences(null),
+                sg.getStartRes(), sg.getEndRes() + 1);
 
-          c.calculate();
-          c.verdict(false, 25); // TODO: refer to conservation percent threshold
+        c.calculate();
+        c.verdict(false, 25); // TODO: refer to conservation percent threshold
 
-          sg.cs.setConservation(c);
+        sg.cs.setConservation(c);
 
-        }
-        else if (key.equalsIgnoreCase("outlineColour"))
-        {
-          sg.setOutlineColour(ColorUtils.parseColourString(value));
-        }
-        else if (key.equalsIgnoreCase("displayBoxes"))
-        {
-          sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());
-        }
-        else if (key.equalsIgnoreCase("showUnconserved"))
-        {
-          sg.setShowNonconserved(Boolean.valueOf(value).booleanValue());
-        }
-        else if (key.equalsIgnoreCase("displayText"))
-        {
-          sg.setDisplayText(Boolean.valueOf(value).booleanValue());
-        }
-        else if (key.equalsIgnoreCase("colourText"))
-        {
-          sg.setColourText(Boolean.valueOf(value).booleanValue());
-        }
-        else if (key.equalsIgnoreCase("textCol1"))
-        {
-          sg.textColour = ColorUtils.parseColourString(value);
-        }
-        else if (key.equalsIgnoreCase("textCol2"))
-        {
-          sg.textColour2 = ColorUtils.parseColourString(value);
-        }
-        else if (key.equalsIgnoreCase("textColThreshold"))
-        {
-          sg.thresholdTextColour = Integer.parseInt(value);
-        }
-        else if (key.equalsIgnoreCase("idColour"))
-        {
-          Color idColour = ColorUtils.parseColourString(value);
-          sg.setIdColour(idColour == null ? Color.black : idColour);
-        }
-        else if (key.equalsIgnoreCase("hide"))
-        {
-          // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
-          sg.setHidereps(true);
-        }
-        else if (key.equalsIgnoreCase("hidecols"))
-        {
-          // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
-          sg.setHideCols(true);
-        }
-        sg.recalcConservation();
       }
-      if (sg.getColourScheme() == null)
+      else if (key.equalsIgnoreCase("outlineColour"))
       {
-        sg.setColourScheme(def);
+        sg.setOutlineColour(ColorUtils.parseColourString(value));
       }
+      else if (key.equalsIgnoreCase("displayBoxes"))
+      {
+        sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());
+      }
+      else if (key.equalsIgnoreCase("showUnconserved"))
+      {
+        sg.setShowNonconserved(Boolean.valueOf(value).booleanValue());
+      }
+      else if (key.equalsIgnoreCase("displayText"))
+      {
+        sg.setDisplayText(Boolean.valueOf(value).booleanValue());
+      }
+      else if (key.equalsIgnoreCase("colourText"))
+      {
+        sg.setColourText(Boolean.valueOf(value).booleanValue());
+      }
+      else if (key.equalsIgnoreCase("textCol1"))
+      {
+        sg.textColour = ColorUtils.parseColourString(value);
+      }
+      else if (key.equalsIgnoreCase("textCol2"))
+      {
+        sg.textColour2 = ColorUtils.parseColourString(value);
+      }
+      else if (key.equalsIgnoreCase("textColThreshold"))
+      {
+        sg.thresholdTextColour = Integer.parseInt(value);
+      }
+      else if (key.equalsIgnoreCase("idColour"))
+      {
+        Color idColour = ColorUtils.parseColourString(value);
+        sg.setIdColour(idColour == null ? Color.black : idColour);
+      }
+      else if (key.equalsIgnoreCase("hide"))
+      {
+        // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
+        sg.setHidereps(true);
+      }
+      else if (key.equalsIgnoreCase("hidecols"))
+      {
+        // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
+        sg.setHideCols(true);
+      }
+      sg.recalcConservation();
+    }
+
+    if (sg.getColourScheme() == null)
+    {
+      sg.setColourScheme(def);
     }
   }
 
index 1facf22..c25d3d9 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.Alignment;
@@ -444,7 +446,7 @@ public class AppletFormatAdapter
     
     String data = dataObject.toString();
     DataSourceType protocol = DataSourceType.PASTE;
-    String ft = data.toLowerCase().trim();
+    String ft = data.toLowerCase(Locale.ROOT).trim();
     if (ft.indexOf("http:") == 0 || ft.indexOf("https:") == 0
             || ft.indexOf("file:") == 0)
     {
index 2b6147f..defc47b 100644 (file)
@@ -33,6 +33,7 @@ import java.util.Map;
 import java.util.TreeMap;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
 import jalview.util.MessageManager;
@@ -131,17 +132,17 @@ public class BackupFiles
       {
         String tempfilename = file.getName();
         File tempdir = file.getParentFile();
-        Cache.trace(
+        Console.trace(
                 "BACKUPFILES [file!=null] attempting to create temp file for "
                         + tempfilename + " in dir " + tempdir);
         temp = File.createTempFile(tempfilename,
                 TEMP_FILE_EXT + newTempFileSuffix, tempdir);
-        Cache.debug(
+        Console.debug(
                 "BACKUPFILES using temp file " + temp.getAbsolutePath());
       }
       else
       {
-        Cache.trace(
+        Console.trace(
                 "BACKUPFILES [file==null] attempting to create default temp file "
                         + DEFAULT_TEMP_FILE + " with extension "
                         + TEMP_FILE_EXT);
@@ -149,29 +150,29 @@ public class BackupFiles
       }
     } catch (IOException e)
     {
-      Cache.error("Could not create temp file to save to (IOException)");
-      Cache.error(e.getMessage());
-      Cache.debug(Cache.getStackTraceString(e));
+      Console.error("Could not create temp file to save to (IOException)");
+      Console.error(e.getMessage());
+      Console.debug(Cache.getStackTraceString(e));
     } catch (Exception e)
     {
-      Cache.error("Exception creating temp file for saving");
-      Cache.debug(Cache.getStackTraceString(e));
+      Console.error("Exception creating temp file for saving");
+      Console.debug(Cache.getStackTraceString(e));
     }
     this.setTempFile(temp);
   }
 
   public static void classInit()
   {
-    Cache.initLogger();
-    Cache.trace("BACKUPFILES classInit");
+    Console.initLogger();
+    Console.trace("BACKUPFILES classInit");
     boolean e = Cache.getDefault(ENABLED, !Platform.isJS());
     setEnabled(e);
-    Cache.trace("BACKUPFILES " + (e ? "enabled" : "disabled"));
+    Console.trace("BACKUPFILES " + (e ? "enabled" : "disabled"));
     BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
             .getSavedBackupEntry();
-    Cache.trace("BACKUPFILES preset scheme " + bfpe.toString());
+    Console.trace("BACKUPFILES preset scheme " + bfpe.toString());
     setConfirmDelete(bfpe.confirmDelete);
-    Cache.trace("BACKUPFILES confirm delete " + bfpe.confirmDelete);
+    Console.trace("BACKUPFILES confirm delete " + bfpe.confirmDelete);
   }
 
   public static void setEnabled(boolean flag)
@@ -215,9 +216,9 @@ public class BackupFiles
       path = this.getTempFile().getCanonicalPath();
     } catch (IOException e)
     {
-      Cache.error("IOException when getting Canonical Path of temp file '"
+      Console.error("IOException when getting Canonical Path of temp file '"
               + this.getTempFile().getName() + "'");
-      Cache.debug(Cache.getStackTraceString(e));
+      Console.debug(Cache.getStackTraceString(e));
     }
     return path;
   }
@@ -253,7 +254,7 @@ public class BackupFiles
             || suffix.length() == 0)
     {
       // nothing to do
-      Cache.debug("BACKUPFILES rollBackupFiles nothing to do." + ", "
+      Console.debug("BACKUPFILES rollBackupFiles nothing to do." + ", "
               + "filename: " + (file != null ? file.getName() : "null")
               + ", " + "file exists: " + file.exists() + ", " + "enabled: "
               + enabled + ", " + "max: " + max + ", " + "suffix: '" + suffix
@@ -261,7 +262,7 @@ public class BackupFiles
       return true;
     }
 
-    Cache.trace("BACKUPFILES rollBackupFiles starting");
+    Console.trace("BACKUPFILES rollBackupFiles starting");
 
     String dir = "";
     File dirFile;
@@ -269,18 +270,18 @@ public class BackupFiles
     {
       dirFile = file.getParentFile();
       dir = dirFile.getCanonicalPath();
-      Cache.trace("BACKUPFILES dir: " + dir);
+      Console.trace("BACKUPFILES dir: " + dir);
     } catch (Exception e)
     {
-      Cache.error("Could not get canonical path for file '" + file + "'");
-      Cache.error(e.getMessage());
-      Cache.debug(Cache.getStackTraceString(e));
+      Console.error("Could not get canonical path for file '" + file + "'");
+      Console.error(e.getMessage());
+      Console.debug(Cache.getStackTraceString(e));
       return false;
     }
     String filename = file.getName();
     String basename = filename;
 
-    Cache.trace("BACKUPFILES filename is " + filename);
+    Console.trace("BACKUPFILES filename is " + filename);
     boolean ret = true;
     // Create/move backups up one
 
@@ -292,11 +293,11 @@ public class BackupFiles
     File[] backupFiles = dirFile.listFiles(bff);
     int nextIndexNum = 0;
 
-    Cache.trace("BACKUPFILES backupFiles.length: " + backupFiles.length);
+    Console.trace("BACKUPFILES backupFiles.length: " + backupFiles.length);
     if (backupFiles.length == 0)
     {
       // No other backup files. Just need to move existing file to backupfile_1
-      Cache.trace(
+      Console.trace(
               "BACKUPFILES no existing backup files, setting index to 1");
       nextIndexNum = 1;
     }
@@ -310,7 +311,7 @@ public class BackupFiles
       if (reverseOrder)
       {
         // backup style numbering
-        Cache.trace("BACKUPFILES rolling files in reverse order");
+        Console.trace("BACKUPFILES rolling files in reverse order");
 
         int tempMax = noMax ? -1 : max;
         // noMax == true means no limits
@@ -342,7 +343,7 @@ public class BackupFiles
             // no "oldest" file to delete
             previousFile = backupfile_n;
             fileToBeDeleted = null;
-            Cache.trace("BACKUPFILES No oldest file to delete");
+            Console.trace("BACKUPFILES No oldest file to delete");
             continue;
           }
 
@@ -353,9 +354,9 @@ public class BackupFiles
             File replacementFile = backupfile_n;
             long fileToBeDeletedLMT = fileToBeDeleted.lastModified();
             long replacementFileLMT = replacementFile.lastModified();
-            Cache.trace("BACKUPFILES fileToBeDeleted is "
+            Console.trace("BACKUPFILES fileToBeDeleted is "
                     + fileToBeDeleted.getAbsolutePath());
-            Cache.trace("BACKUPFILES replacementFile is "
+            Console.trace("BACKUPFILES replacementFile is "
                     + backupfile_n.getAbsolutePath());
 
             try
@@ -369,7 +370,7 @@ public class BackupFiles
                         .format(fileToBeDeletedLMT);
                 String replacementFileLMTString = sdf
                         .format(replacementFileLMT);
-                Cache.warn("WARNING! I am set to delete backupfile "
+                Console.warn("WARNING! I am set to delete backupfile "
                         + fileToBeDeleted.getName()
                         + " has modification time "
                         + fileToBeDeletedLMTString
@@ -380,7 +381,7 @@ public class BackupFiles
 
                 boolean delete = confirmNewerDeleteFile(fileToBeDeleted,
                         replacementFile, true);
-                Cache.trace("BACKUPFILES " + (delete ? "confirmed" : "not")
+                Console.trace("BACKUPFILES " + (delete ? "confirmed" : "not")
                         + " deleting file "
                         + fileToBeDeleted.getAbsolutePath()
                         + " which is newer than "
@@ -393,7 +394,7 @@ public class BackupFiles
                 }
                 else
                 {
-                  Cache.debug("BACKUPFILES moving "
+                  Console.debug("BACKUPFILES moving "
                           + fileToBeDeleted.getAbsolutePath() + " to "
                           + oldestTempFile.getAbsolutePath());
                   moveFileToFile(fileToBeDeleted, oldestTempFile);
@@ -401,7 +402,7 @@ public class BackupFiles
               }
               else
               {
-                Cache.debug("BACKUPFILES going to move "
+                Console.debug("BACKUPFILES going to move "
                         + fileToBeDeleted.getAbsolutePath() + " to "
                         + oldestTempFile.getAbsolutePath());
                 moveFileToFile(fileToBeDeleted, oldestTempFile);
@@ -410,10 +411,10 @@ public class BackupFiles
 
             } catch (Exception e)
             {
-              Cache.error(
+              Console.error(
                       "Error occurred, probably making new temp file for '"
                               + fileToBeDeleted.getName() + "'");
-              Cache.error(Cache.getStackTraceString(e));
+              Console.error(Cache.getStackTraceString(e));
             }
 
             // reset
@@ -455,12 +456,12 @@ public class BackupFiles
           }
           bfsb.append(backupFiles[i].getName());
         }
-        Cache.trace("BACKUPFILES backupFiles: " + bfsb.toString());
+        Console.trace("BACKUPFILES backupFiles: " + bfsb.toString());
 
         // noMax == true means keep all backup files
         if ((!noMax) && bfTreeMap.size() >= max)
         {
-          Cache.trace("BACKUPFILES noMax: " + noMax + ", " + "max: " + max
+          Console.trace("BACKUPFILES noMax: " + noMax + ", " + "max: " + max
                   + ", " + "bfTreeMap.size(): " + bfTreeMap.size());
           // need to delete some files to keep number of backups to designated
           // max.
@@ -470,7 +471,7 @@ public class BackupFiles
           int numToDelete = suffix.indexOf(NUM_PLACEHOLDER) > -1
                   ? bfTreeMap.size() - max + 1
                   : 0;
-          Cache.trace("BACKUPFILES numToDelete: " + numToDelete);
+          Console.trace("BACKUPFILES numToDelete: " + numToDelete);
           // the "replacement" file is the latest backup file being kept (it's
           // not replacing though)
           File replacementFile = numToDelete < backupFiles.length
@@ -483,7 +484,7 @@ public class BackupFiles
             File fileToBeDeleted = backupFiles[i];
             boolean delete = true;
 
-            Cache.trace("BACKUPFILES fileToBeDeleted: " + fileToBeDeleted);
+            Console.trace("BACKUPFILES fileToBeDeleted: " + fileToBeDeleted);
 
             boolean newer = false;
             if (replacementFile != null)
@@ -499,7 +500,7 @@ public class BackupFiles
                 String replacementFileLMTString = sdf
                         .format(replacementFileLMT);
 
-                Cache.warn("WARNING! I am set to delete backupfile '"
+                Console.warn("WARNING! I am set to delete backupfile '"
                         + fileToBeDeleted.getName()
                         + "' has modification time "
                         + fileToBeDeletedLMTString
@@ -514,14 +515,14 @@ public class BackupFiles
                 {
                   // User has confirmed delete -- no need to add it to the list
                   fileToBeDeleted.delete();
-                  Cache.debug("BACKUPFILES deleting fileToBeDeleted: "
+                  Console.debug("BACKUPFILES deleting fileToBeDeleted: "
                           + fileToBeDeleted);
                   delete = false;
                 }
                 else
                 {
                   // keeping file, nothing to do!
-                  Cache.debug("BACKUPFILES keeping fileToBeDeleted: "
+                  Console.debug("BACKUPFILES keeping fileToBeDeleted: "
                           + fileToBeDeleted);
                 }
               }
@@ -529,7 +530,7 @@ public class BackupFiles
             if (delete)
             {
               addDeleteFile(fileToBeDeleted);
-              Cache.debug("BACKUPFILES addDeleteFile(fileToBeDeleted): "
+              Console.debug("BACKUPFILES addDeleteFile(fileToBeDeleted): "
                       + fileToBeDeleted);
             }
 
@@ -545,16 +546,16 @@ public class BackupFiles
     String latestBackupFilename = dir + File.separatorChar
             + BackupFilenameParts.getBackupFilename(nextIndexNum, basename,
                     suffix, digits);
-    Cache.trace("BACKUPFILES Moving old file [" + file
+    Console.trace("BACKUPFILES Moving old file [" + file
             + "] to latestBackupFilename [" + latestBackupFilename + "]");
     // using boolean '&' instead of '&&' as don't want moveFileToFile attempt to
     // be conditional (short-circuit)
     ret = ret & moveFileToFile(file, new File(latestBackupFilename));
-    Cache.debug("BACKUPFILES moving " + file + " to " + latestBackupFilename
+    Console.debug("BACKUPFILES moving " + file + " to " + latestBackupFilename
             + " was " + (ret ? "" : "NOT ") + "successful");
     if (tidyUp)
     {
-      Cache.debug("BACKUPFILES tidying up files");
+      Console.debug("BACKUPFILES tidying up files");
       tidyUpFiles();
     }
 
@@ -610,7 +611,7 @@ public class BackupFiles
         saveFile = nextTempFile(ftbd.getName(), ftbd.getParentFile());
       } catch (Exception e)
       {
-        Cache.error(
+        Console.error(
                 "Error when confirming to keep backup file newer than other backup files.");
         e.printStackTrace();
       }
@@ -720,10 +721,10 @@ public class BackupFiles
         for (int i = 0; i < deleteFiles.size(); i++)
         {
           File fileToDelete = deleteFiles.get(i);
-          Cache.trace("BACKUPFILES about to delete fileToDelete:"
+          Console.trace("BACKUPFILES about to delete fileToDelete:"
                   + fileToDelete);
           fileToDelete.delete();
-          Cache.warn("deleted '" + fileToDelete.getName() + "'");
+          Console.warn("deleted '" + fileToDelete.getName() + "'");
         }
       }
 
@@ -832,7 +833,7 @@ public class BackupFiles
       dirFile = file.getParentFile();
     } catch (Exception e)
     {
-      Cache.error("Could not get canonical path for file '" + file + "'");
+      Console.error("Could not get canonical path for file '" + file + "'");
       return new TreeMap<>();
     }
 
@@ -873,14 +874,14 @@ public class BackupFiles
     int pos = deleteFiles.indexOf(fileToBeDeleted);
     if (pos > -1)
     {
-      Cache.debug("BACKUPFILES not adding file "
+      Console.debug("BACKUPFILES not adding file "
               + fileToBeDeleted.getAbsolutePath()
               + " to the delete list (already at index" + pos + ")");
       return true;
     }
     else
     {
-      Cache.debug("BACKUPFILES adding file "
+      Console.debug("BACKUPFILES adding file "
               + fileToBeDeleted.getAbsolutePath() + " to the delete list");
       deleteFiles.add(fileToBeDeleted);
     }
@@ -889,31 +890,31 @@ public class BackupFiles
 
   public static boolean moveFileToFile(File oldFile, File newFile)
   {
-    Cache.initLogger();
+    Console.initLogger();
     boolean ret = false;
     Path oldPath = Paths.get(oldFile.getAbsolutePath());
     Path newPath = Paths.get(newFile.getAbsolutePath());
     try
     {
       // delete destination file - not usually necessary but Just In Case...
-      Cache.trace("BACKUPFILES deleting " + newFile.getAbsolutePath());
+      Console.trace("BACKUPFILES deleting " + newFile.getAbsolutePath());
       newFile.delete();
-      Cache.trace("BACKUPFILES moving " + oldFile.getAbsolutePath() + " to "
+      Console.trace("BACKUPFILES moving " + oldFile.getAbsolutePath() + " to "
               + newFile.getAbsolutePath());
       Files.move(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING);
       ret = true;
-      Cache.trace("BACKUPFILES move seems to have succeeded");
+      Console.trace("BACKUPFILES move seems to have succeeded");
     } catch (IOException e)
     {
-      Cache.warn("Could not move file '" + oldPath.toString() + "' to '"
+      Console.warn("Could not move file '" + oldPath.toString() + "' to '"
               + newPath.toString() + "'");
-      Cache.error(e.getMessage());
-      Cache.debug(Cache.getStackTraceString(e));
+      Console.error(e.getMessage());
+      Console.debug(Cache.getStackTraceString(e));
       ret = false;
     } catch (Exception e)
     {
-      Cache.error(e.getMessage());
-      Cache.debug(Cache.getStackTraceString(e));
+      Console.error(e.getMessage());
+      Console.debug(Cache.getStackTraceString(e));
       ret = false;
     }
     return ret;
index ff8a5e6..3c70b82 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.StringTokenizer;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.util.MessageManager;
 
 public class BackupFilesPresetEntry
@@ -124,7 +125,7 @@ public class BackupFilesPresetEntry
       confirmDelete = Boolean.valueOf(st.nextToken());
     } catch (Exception e)
     {
-      Cache.log.error("Error parsing backupfiles scheme '" + line + "'");
+      Console.error("Error parsing backupfiles scheme '" + line + "'");
     }
 
     return new BackupFilesPresetEntry(suffix, digits, reverse, keepAll,
index 9db3df2..48988cf 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io;
 
+import jalview.bin.Cache;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.OOMWarning;
 import jalview.json.binding.biojs.BioJSReleasePojo;
@@ -47,10 +48,10 @@ public class BioJsHTMLOutput extends HTMLOutput
   public static final String DEFAULT_DIR = System.getProperty("user.home")
           + File.separatorChar + ".biojs_templates" + File.separatorChar;
 
-  public static final String BJS_TEMPLATES_LOCAL_DIRECTORY = jalview.bin.Cache
+  public static final String BJS_TEMPLATES_LOCAL_DIRECTORY = Cache
           .getDefault("biojs_template_directory", DEFAULT_DIR);
 
-  public static final String BJS_TEMPLATE_GIT_REPO = jalview.bin.Cache
+  public static final String BJS_TEMPLATE_GIT_REPO = Cache
           .getDefault("biojs_template_git_repo",
                   "https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json");
 
diff --git a/src/jalview/io/EMBLLikeFlatFile.java b/src/jalview/io/EMBLLikeFlatFile.java
new file mode 100644 (file)
index 0000000..e8ce34b
--- /dev/null
@@ -0,0 +1,830 @@
+package jalview.io;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import jalview.bin.Console;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.FeatureProperties;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.util.DBRefUtils;
+import jalview.util.DnaUtils;
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
+
+/**
+ * A base class to support parsing of GenBank, EMBL or DDBJ flat file format
+ * data. Example files (rather than formal specifications) are provided at
+ * 
+ * <pre>
+ * https://ena-docs.readthedocs.io/en/latest/submit/fileprep/flat-file-example.html
+ * https://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html
+ * </pre>
+ * 
+ * or to compare the same entry, see
+ * 
+ * <pre>
+ * https://www.ebi.ac.uk/ena/browser/api/embl/X81322.1
+ * https://www.ncbi.nlm.nih.gov/nuccore/X81322.1
+ * </pre>
+ * 
+ * The feature table part of the file has a common definition, only the start of
+ * each line is formatted differently in GenBank and EMBL. See
+ * http://www.insdc.org/files/feature_table.html#7.1.
+ */
+public abstract class EMBLLikeFlatFile extends AlignFile
+{
+  protected static final String LOCATION = "location";
+
+  protected static final String QUOTE = "\"";
+
+  protected static final String DOUBLED_QUOTE = QUOTE + QUOTE;
+
+  protected static final String WHITESPACE = "\\s+";
+
+  /**
+   * Removes leading or trailing double quotes (") unless doubled, and changes
+   * any 'escaped' (doubled) double quotes to single characters. As per the
+   * Feature Table specification for Qualifiers, Free Text.
+   * 
+   * @param value
+   * @return
+   */
+  protected static String removeQuotes(String value)
+  {
+    if (value == null)
+    {
+      return null;
+    }
+    if (value.startsWith(QUOTE) && !value.startsWith(DOUBLED_QUOTE))
+    {
+      value = value.substring(1);
+    }
+    if (value.endsWith(QUOTE) && !value.endsWith(DOUBLED_QUOTE))
+    {
+      value = value.substring(0, value.length() - 1);
+    }
+    value = value.replace(DOUBLED_QUOTE, QUOTE);
+    return value;
+  }
+
+  /**
+   * Truncates (if necessary) the exon intervals to match 3 times the length of
+   * the protein(including truncation for stop codon included in exon)
+   * 
+   * @param proteinLength
+   * @param exon
+   *          an array of [start, end, start, end...] intervals
+   * @return the same array (if unchanged) or a truncated copy
+   */
+  protected static int[] adjustForProteinLength(int proteinLength,
+          int[] exon)
+  {
+    if (proteinLength <= 0 || exon == null)
+    {
+      return exon;
+    }
+    int expectedCdsLength = proteinLength * 3;
+    int exonLength = MappingUtils.getLength(Arrays.asList(exon));
+
+    /*
+     * if exon length matches protein, or is shorter, then leave it unchanged
+     */
+    if (expectedCdsLength >= exonLength)
+    {
+      return exon;
+    }
+
+    int origxon[];
+    int sxpos = -1;
+    int endxon = 0;
+    origxon = new int[exon.length];
+    System.arraycopy(exon, 0, origxon, 0, exon.length);
+    int cdspos = 0;
+    for (int x = 0; x < exon.length; x += 2)
+    {
+      cdspos += Math.abs(exon[x + 1] - exon[x]) + 1;
+      if (expectedCdsLength <= cdspos)
+      {
+        // advanced beyond last codon.
+        sxpos = x;
+        if (expectedCdsLength != cdspos)
+        {
+          // System.err
+          // .println("Truncating final exon interval on region by "
+          // + (cdspos - cdslength));
+        }
+
+        /*
+         * shrink the final exon - reduce end position if forward
+         * strand, increase it if reverse
+         */
+        if (exon[x + 1] >= exon[x])
+        {
+          endxon = exon[x + 1] - cdspos + expectedCdsLength;
+        }
+        else
+        {
+          endxon = exon[x + 1] + cdspos - expectedCdsLength;
+        }
+        break;
+      }
+    }
+
+    if (sxpos != -1)
+    {
+      // and trim the exon interval set if necessary
+      int[] nxon = new int[sxpos + 2];
+      System.arraycopy(exon, 0, nxon, 0, sxpos + 2);
+      nxon[sxpos + 1] = endxon; // update the end boundary for the new exon
+                                // set
+      exon = nxon;
+    }
+    return exon;
+  }
+
+  /*
+   * when true, interpret the mol_type 'source' feature attribute
+   * and generate an RNA sequence from the DNA record
+   */
+  protected boolean produceRna=true;
+    
+
+  /*
+   * values parsed from the data file
+   */
+  protected String sourceDb;
+
+  protected String accession;
+
+  protected String version;
+
+  protected String description;
+
+  protected int length = 128;
+
+  protected List<DBRefEntry> dbrefs;
+
+  protected boolean sequenceStringIsRNA=false;
+
+  protected String sequenceString;
+
+  protected Map<String, CdsData> cds;
+
+  /**
+   * Constructor
+   * 
+   * @param fp
+   * @param sourceId
+   * @throws IOException
+   */
+  public EMBLLikeFlatFile(FileParse fp, String sourceId) throws IOException
+  {
+    super(false, fp); // don't parse immediately
+    this.sourceDb = sourceId;
+    dbrefs = new ArrayList<>();
+
+    /*
+     * using TreeMap gives CDS sequences in alphabetical, so readable, order
+     */
+    cds = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+    
+    parse();
+  }
+
+  /**
+   * process attributes for 'source' until the next FT feature entry
+   * only interested in 'mol_type'
+   * @param tokens
+   * @return
+   * @throws IOException
+   */
+  private String parseSourceQualifiers(String[] tokens) throws IOException
+  {
+    if (!"source".equals(tokens[0]))
+    {
+      throw (new RuntimeException("Not given a 'source' qualifier line"));
+    }
+    // search for mol_type attribute
+
+    StringBuilder sb = new StringBuilder().append(tokens[1]); // extent of
+                                                              // sequence
+
+    String line = parseFeatureQualifier(sb, false);
+    while (line != null)
+    {
+      if (!line.startsWith("FT    ")) // four spaces, end of this feature table
+                                      // entry
+      {
+        return line;
+      }
+
+      // case sensitive ?
+      int p = line.indexOf("\\mol_type");
+      int qs = line.indexOf("\"", p);
+      int qe = line.indexOf("\"", qs + 1);
+      String qualifier=line.substring(qs,qe).toLowerCase(Locale.ROOT);
+      if (qualifier.indexOf("rna") > -1)
+      {
+        sequenceStringIsRNA = true;
+      }
+      if (qualifier.indexOf("dna") > -1)
+      {
+        sequenceStringIsRNA = false;
+      }
+      line=parseFeatureQualifier(sb, false);
+    }
+    return line;
+  }
+
+   
+  /**
+   * Parses one (GenBank or EMBL format) CDS feature, saves the parsed data, and
+   * returns the next line
+   * 
+   * @param location
+   * @return
+   * @throws IOException
+   */
+  protected String parseCDSFeature(String location) throws IOException
+  {
+    String line;
+
+    /*
+     * parse location, which can be over >1 line e.g. EAW51554
+     */
+    CdsData data = new CdsData();
+    StringBuilder sb = new StringBuilder().append(location);
+    line = parseFeatureQualifier(sb, false);
+    data.cdsLocation = sb.toString();
+
+    while (line != null)
+    {
+      if (!isFeatureContinuationLine(line))
+      {
+        // e.g. start of next feature "FT source..."
+        break;
+      }
+
+      /*
+       * extract qualifier, e.g. FT    /protein_id="CAA37824.1"
+       * - the value may extend over more than one line
+       * - if the value has enclosing quotes, these are removed
+       * - escaped double quotes ("") are reduced to a single character
+       */
+      int slashPos = line.indexOf('/');
+      if (slashPos == -1)
+      {
+        Console.error("Unexpected EMBL line ignored: " + line);
+        line = nextLine();
+        continue;
+      }
+      int eqPos = line.indexOf('=', slashPos + 1);
+      if (eqPos == -1)
+      {
+        // can happen, e.g. /ribosomal_slippage
+        line = nextLine();
+        continue;
+      }
+      String qualifier = line.substring(slashPos + 1, eqPos);
+      String value = line.substring(eqPos + 1);
+      value = removeQuotes(value);
+      sb = new StringBuilder().append(value);
+      boolean asText = !"translation".equals(qualifier);
+      line = parseFeatureQualifier(sb, asText);
+      String featureValue = sb.toString();
+
+      if ("protein_id".equals(qualifier))
+      {
+        data.proteinId = featureValue;
+      }
+      else if ("codon_start".equals(qualifier))
+      {
+        try
+        {
+          data.codonStart = Integer.parseInt(featureValue.trim());
+        } catch (NumberFormatException e)
+        {
+          Console.error("Invalid codon_start in XML for " + this.accession
+                  + ": " + e.getMessage());
+        }
+      }
+      else if ("db_xref".equals(qualifier))
+      {
+        String[] parts = featureValue.split(":");
+        if (parts.length == 2)
+        {
+          String db = parts[0].trim();
+          db = DBRefUtils.getCanonicalName(db);
+          DBRefEntry dbref = new DBRefEntry(db, "0", parts[1].trim());
+          data.xrefs.add(dbref);
+        }
+      }
+      else if ("product".equals(qualifier))
+      {
+        data.proteinName = featureValue;
+      }
+      else if ("translation".equals(qualifier))
+      {
+        data.translation = featureValue;
+      }
+      else if (!"".equals(featureValue))
+      {
+        // throw anything else into the additional properties hash
+        data.cdsProps.put(qualifier, featureValue);
+      }
+    }
+
+    if (data.proteinId != null)
+    {
+      this.cds.put(data.proteinId, data);
+    }
+    else
+    {
+      Console.error("Ignoring CDS feature with no protein_id for "
+              + sourceDb + ":" + accession);
+    }
+
+    return line;
+  }
+
+  protected abstract boolean isFeatureContinuationLine(String line);
+
+  /**
+   * Output (print) is not (yet) implemented for flat file format
+   */
+  @Override
+  public String print(SequenceI[] seqs, boolean jvsuffix)
+  {
+    return null;
+  }
+
+  /**
+   * Constructs and saves the sequence from parsed components
+   */
+  protected void buildSequence()
+  {
+    if (this.accession == null || this.sequenceString == null)
+    {
+      Console.error("Failed to parse data from EMBL");
+      return;
+    }
+
+    String name = this.accession;
+    if (this.sourceDb != null)
+    {
+      name = this.sourceDb + "|" + name;
+    }
+
+    if (produceRna && sequenceStringIsRNA)
+    {
+      sequenceString = sequenceString.replace('T', 'U').replace('t', 'u');
+    }
+
+    SequenceI seq = new Sequence(name, this.sequenceString);
+    seq.setDescription(this.description);
+
+    /*
+     * add a DBRef to itself
+     */
+    DBRefEntry selfRef = new DBRefEntry(sourceDb, version, accession);
+    int[] startEnd = new int[] { 1, seq.getLength() };
+    selfRef.setMap(new Mapping(null, startEnd, startEnd, 1, 1));
+    seq.addDBRef(selfRef);
+
+    for (DBRefEntry dbref : this.dbrefs)
+    {
+      seq.addDBRef(dbref);
+    }
+
+    processCDSFeatures(seq);
+
+    seq.deriveSequence();
+
+    addSequence(seq);
+  }
+
+  /**
+   * Process the CDS features, including generation of cross-references and
+   * mappings to the protein products (translation)
+   * 
+   * @param seq
+   */
+  protected void processCDSFeatures(SequenceI seq)
+  {
+    /*
+     * record protein products found to avoid duplication i.e. >1 CDS with 
+     * the same /protein_id [though not sure I can find an example of this]
+     */
+    Map<String, SequenceI> proteins = new HashMap<>();
+    for (CdsData data : cds.values())
+    {
+      processCDSFeature(seq, data, proteins);
+    }
+  }
+
+  /**
+   * Processes data for one parsed CDS feature to
+   * <ul>
+   * <li>create a protein product sequence for the translation</li>
+   * <li>create a cross-reference to protein with mapping from dna</li>
+   * <li>add a CDS feature to the sequence for each CDS start-end range</li>
+   * <li>add any CDS dbrefs to the sequence and to the protein product</li>
+   * </ul>
+   * 
+   * @param SequenceI
+   *          dna
+   * @param proteins
+   *          map of protein products so far derived from CDS data
+   */
+  void processCDSFeature(SequenceI dna, CdsData data,
+          Map<String, SequenceI> proteins)
+  {
+    /*
+     * parse location into a list of [start, end, start, end] positions
+     */
+    int[] exons = getCdsRanges(this.accession, data.cdsLocation);
+
+    MapList maplist = buildMappingToProtein(dna, exons, data);
+
+    int exonNumber = 0;
+
+    for (int xint = 0; exons != null && xint < exons.length - 1; xint += 2)
+    {
+      int exonStart = exons[xint];
+      int exonEnd = exons[xint + 1];
+      int begin = Math.min(exonStart, exonEnd);
+      int end = Math.max(exonStart, exonEnd);
+      exonNumber++;
+      String desc = String.format("Exon %d for protein EMBLCDS:%s",
+              exonNumber, data.proteinId);
+
+      SequenceFeature sf = new SequenceFeature("CDS", desc, begin, end,
+              this.sourceDb);
+      for (Entry<String, String> val : data.cdsProps.entrySet())
+      {
+        sf.setValue(val.getKey(), val.getValue());
+      }
+
+      sf.setEnaLocation(data.cdsLocation);
+      boolean forwardStrand = exonStart <= exonEnd;
+      sf.setStrand(forwardStrand ? "+" : "-");
+      sf.setPhase(String.valueOf(data.codonStart - 1));
+      sf.setValue(FeatureProperties.EXONPOS, exonNumber);
+      sf.setValue(FeatureProperties.EXONPRODUCT, data.proteinName);
+
+      dna.addSequenceFeature(sf);
+    }
+
+    boolean hasUniprotDbref = false;
+    for (DBRefEntry xref : data.xrefs)
+    {
+      dna.addDBRef(xref);
+      if (xref.getSource().equals(DBRefSource.UNIPROT))
+      {
+        /*
+         * construct (or find) the sequence for (data.protein_id, data.translation)
+         */
+        SequenceI protein = buildProteinProduct(dna, xref, data, proteins);
+        Mapping map = new Mapping(protein, maplist);
+        map.setMappedFromId(data.proteinId);
+        xref.setMap(map);
+
+        /*
+         * add DBRefs with mappings from dna to protein and the inverse
+         */
+        DBRefEntry db1 = new DBRefEntry(sourceDb, version, accession);
+        db1.setMap(new Mapping(dna, maplist.getInverse()));
+        protein.addDBRef(db1);
+
+        hasUniprotDbref = true;
+      }
+    }
+
+    /*
+     * if we have a product (translation) but no explicit Uniprot dbref
+     * (example: EMBL M19487 protein_id AAB02592.1)
+     * then construct mappings to an assumed EMBLCDSPROTEIN accession
+     */
+    if (!hasUniprotDbref)
+    {
+      SequenceI protein = proteins.get(data.proteinId);
+      if (protein == null)
+      {
+        protein = new Sequence(data.proteinId, data.translation);
+        protein.setDescription(data.proteinName);
+        proteins.put(data.proteinId, protein);
+      }
+      // assuming CDSPROTEIN sequence version = dna version (?!)
+      DBRefEntry db1 = new DBRefEntry(DBRefSource.EMBLCDSProduct,
+              this.version, data.proteinId);
+      protein.addDBRef(db1);
+
+      DBRefEntry dnaToEmblProteinRef = new DBRefEntry(
+              DBRefSource.EMBLCDSProduct, this.version, data.proteinId);
+      Mapping map = new Mapping(protein, maplist);
+      map.setMappedFromId(data.proteinId);
+      dnaToEmblProteinRef.setMap(map);
+      dna.addDBRef(dnaToEmblProteinRef);
+    }
+
+    /*
+     * comment brought forward from EmblXmlSource, lines 447-451:
+     * TODO: if retrieved from EMBLCDS, add a DBRef back to the parent EMBL
+     * sequence with the exon  map; if given a dataset reference, search
+     * dataset for parent EMBL sequence if it exists and set its map;
+     * make a new feature annotating the coding contig
+     */
+  }
+
+  /**
+   * Computes a mapping from CDS positions in DNA sequence to protein product
+   * positions, with allowance for stop codon or incomplete start codon
+   * 
+   * @param dna
+   * @param exons
+   * @param data
+   * @return
+   */
+  MapList buildMappingToProtein(final SequenceI dna, final int[] exons,
+          final CdsData data)
+  {
+    MapList dnaToProteinMapping = null;
+    int peptideLength = data.translation.length();
+
+    int[] proteinRange = new int[] { 1, peptideLength };
+    if (exons != null && exons.length > 0)
+    {
+      /*
+       * We were able to parse 'location'; do a final 
+       * product length truncation check
+       */
+      int[] cdsRanges = adjustForProteinLength(peptideLength, exons);
+      dnaToProteinMapping = new MapList(cdsRanges, proteinRange, 3, 1);
+    }
+    else
+    {
+      /*
+       * workaround until we handle all 'location' formats fully
+       * e.g. X53828.1:60..1058 or <123..>289
+       */
+      Console.error(String.format(
+              "Implementation Notice: EMBLCDS location '%s'not properly supported yet"
+                      + " - Making up the CDNA region of (%s:%s)... may be incorrect",
+              data.cdsLocation, sourceDb, this.accession));
+
+      int completeCodonsLength = 1 - data.codonStart + dna.getLength();
+      int mappedDnaEnd = dna.getEnd();
+      if (peptideLength * 3 == completeCodonsLength)
+      {
+        // this might occur for CDS sequences where no features are marked
+        Console.warn("Assuming no stop codon at end of cDNA fragment");
+        mappedDnaEnd = dna.getEnd();
+      }
+      else if ((peptideLength + 1) * 3 == completeCodonsLength)
+      {
+        Console.warn("Assuming stop codon at end of cDNA fragment");
+        mappedDnaEnd = dna.getEnd() - 3;
+      }
+
+      if (mappedDnaEnd != -1)
+      {
+        int[] cdsRanges = new int[] {
+            dna.getStart() + (data.codonStart - 1), mappedDnaEnd };
+        dnaToProteinMapping = new MapList(cdsRanges, proteinRange, 3, 1);
+      }
+    }
+
+    return dnaToProteinMapping;
+  }
+
+  /**
+   * Constructs a sequence for the protein product for the CDS data (if there is
+   * one), and dbrefs with mappings from CDS to protein and the reverse
+   * 
+   * @param dna
+   * @param xref
+   * @param data
+   * @param proteins
+   * @return
+   */
+  SequenceI buildProteinProduct(SequenceI dna, DBRefEntry xref,
+          CdsData data, Map<String, SequenceI> proteins)
+  {
+    /*
+     * check we have some data to work with
+     */
+    if (data.proteinId == null || data.translation == null)
+    {
+      return null;
+    }
+
+    /*
+     * Construct the protein sequence (if not already seen)
+     */
+    String proteinSeqName = xref.getSource() + "|" + xref.getAccessionId();
+    SequenceI protein = proteins.get(proteinSeqName);
+    if (protein == null)
+    {
+      protein = new Sequence(proteinSeqName, data.translation, 1,
+              data.translation.length());
+      protein.setDescription(data.proteinName != null ? data.proteinName
+              : "Protein Product from " + sourceDb);
+      proteins.put(proteinSeqName, protein);
+    }
+
+    return protein;
+  }
+
+  /**
+   * Returns the CDS location as a single array of [start, end, start, end...]
+   * positions. If on the reverse strand, these will be in descending order.
+   * 
+   * @param accession
+   * @param location
+   * @return
+   */
+  protected int[] getCdsRanges(String accession, String location)
+  {
+    if (location == null)
+    {
+      return new int[] {};
+    }
+
+    try
+    {
+      List<int[]> ranges = DnaUtils.parseLocation(location);
+      return MappingUtils.rangeListToArray(ranges);
+    } catch (ParseException e)
+    {
+      Console.warn(
+              String.format("Not parsing inexact CDS location %s in ENA %s",
+                      location, accession));
+      return new int[] {};
+    }
+  }
+
+  /**
+   * Reads the value of a feature (FT) qualifier from one or more lines of the
+   * file, and returns the next line after that. Values are appended to the
+   * string buffer, which should be already primed with the value read from the
+   * first line for the qualifier (with any leading double quote removed).
+   * Enclosing double quotes are removed, and escaped (repeated) double quotes
+   * reduced to one only. For example for
+   * 
+   * <pre>
+   * FT      /note="gene_id=hCG28070.3 
+   * FT      ""foobar"" isoform=CRA_b"
+   * the returned value is
+   * gene_id=hCG28070.3 "foobar" isoform=CRA_b
+   * </pre>
+   * 
+   * Note the side-effect of this method, to advance data reading to the next
+   * line after the feature qualifier (which could be another qualifier, a
+   * different feature, a non-feature line, or null at end of file).
+   * 
+   * @param sb
+   *          a string buffer primed with the first line of the value
+   * @param asText
+   * @return
+   * @throws IOException
+   */
+  String parseFeatureQualifier(StringBuilder sb, boolean asText)
+          throws IOException
+  {
+    String line;
+    while ((line = nextLine()) != null)
+    {
+      if (!isFeatureContinuationLine(line))
+      {
+        break; // reached next feature or other input line
+      }
+      String[] tokens = line.split(WHITESPACE);
+      if (tokens.length < 2)
+      {
+        Console.error("Ignoring bad EMBL line for " + this.accession
+                + ": " + line);
+        break;
+      }
+      if (tokens[1].startsWith("/"))
+      {
+        break; // next feature qualifier
+      }
+
+      /*
+       * if text (e.g. /product), add a word separator for a new line,
+       * else (e.g. /translation) don't
+       */
+      if (asText)
+      {
+        sb.append(" ");
+      }
+
+      /*
+       * remove trailing " and unescape doubled ""
+       */
+      String data = removeQuotes(tokens[1]);
+      sb.append(data);
+    }
+
+    return line;
+  }
+
+  /**
+   * Reads and saves the sequence, read from the lines following the ORIGIN
+   * (GenBank) or SQ (EMBL) line. Whitespace and position counters are
+   * discarded. Returns the next line following the sequence data (the next line
+   * that doesn't start with whitespace).
+   * 
+   * @throws IOException
+   */
+  protected String parseSequence() throws IOException
+  {
+    StringBuilder sb = new StringBuilder(this.length);
+    String line = nextLine();
+    while (line != null && line.startsWith(" "))
+    {
+      line = line.trim();
+      String[] blocks = line.split(WHITESPACE);
+
+      /*
+       * the first or last block on each line might be a position count - omit
+       */
+      for (int i = 0; i < blocks.length; i++)
+      {
+        try
+        {
+          Long.parseLong(blocks[i]);
+          // position counter - ignore it
+        } catch (NumberFormatException e)
+        {
+          // sequence data - append it
+          sb.append(blocks[i]);
+        }
+      }
+      line = nextLine();
+    }
+    this.sequenceString = sb.toString();
+
+    return line;
+  }
+
+  /**
+   * Processes a feature line. If it declares a feature type of interest
+   * (currently, only CDS is processed), processes all of the associated lines
+   * (feature qualifiers), and returns the next line after that, otherwise
+   * simply returns the next line.
+   * 
+   * @param line
+   *          the first line for the feature (with initial FT omitted for EMBL
+   *          format)
+   * @return
+   * @throws IOException
+   */
+  protected String parseFeature(String line) throws IOException
+  {
+    String[] tokens = line.trim().split(WHITESPACE);
+    if (tokens.length < 2 || (!"CDS".equals(tokens[0]) && (!"source".equals(tokens[0]))))
+    {
+      return nextLine();
+    }
+    if (tokens[0].equals("source"))
+    {
+      return parseSourceQualifiers(tokens);
+    }
+    return parseCDSFeature(tokens[1]);
+  }
+}
+
+/**
+ * A data bean class to hold values parsed from one CDS Feature
+ */
+class CdsData
+{
+  String translation; // from /translation qualifier
+
+  String cdsLocation; // the raw value e.g. join(1..1234,2012..2837)
+
+  int codonStart = 1; // from /codon_start qualifier
+
+  String proteinName; // from /product qualifier; used for protein description
+
+  String proteinId; // from /protein_id qualifier
+
+  List<DBRefEntry> xrefs = new ArrayList<>(); // from /db_xref qualifiers
+
+  Map<String, String> cdsProps = new Hashtable<>(); // other qualifiers
+}
diff --git a/src/jalview/io/EmblFlatFile.java b/src/jalview/io/EmblFlatFile.java
new file mode 100644 (file)
index 0000000..75b8981
--- /dev/null
@@ -0,0 +1,209 @@
+package jalview.io;
+
+import java.io.IOException;
+
+import jalview.bin.Console;
+import jalview.datamodel.DBRefEntry;
+import jalview.util.DBRefUtils;
+
+/**
+ * A class that provides selective parsing of the EMBL flatfile format.
+ * <p>
+ * The initial implementation is limited to extracting fields used by Jalview
+ * after fetching an EMBL or EMBLCDS entry:
+ * 
+ * <pre>
+ * accession, version, sequence, xref
+ * and (for CDS feature) location, protein_id, product, codon_start, translation
+ * </pre>
+ * 
+ * For a complete parser, it may be best to adopt that provided in
+ * https://github.com/enasequence/sequencetools/tree/master/src/main/java/uk/ac/ebi/embl/flatfile
+ * (but note this has a dependency on the Apache Commons library)
+ * 
+ * @author gmcarstairs
+ * @see ftp://ftp.ebi.ac.uk/pub/databases/ena/sequence/release/doc/usrman.txt
+ * @see ftp://ftp.ebi.ac.uk/pub/databases/embl/doc/FT_current.html
+ */
+public class EmblFlatFile extends EMBLLikeFlatFile
+{
+  /**
+   * Constructor given a data source and the id of the source database
+   * 
+   * @param fp
+   * @param sourceId
+   * @throws IOException
+   */
+  public EmblFlatFile(FileParse fp, String sourceId) throws IOException
+  {
+    super(fp, sourceId);
+  }
+
+  /**
+   * Parses the flatfile, and if successful, saves as an annotated sequence
+   * which may be retrieved by calling {@code getSequence()}
+   * 
+   * @throws IOException
+   */
+  @Override
+  public void parse() throws IOException
+  {
+    String line = nextLine();
+    while (line != null)
+    {
+      if (line.startsWith("ID"))
+      {
+        line = parseID(line);
+      }
+      else if (line.startsWith("DE"))
+      {
+        line = parseDE(line);
+      }
+      else if (line.startsWith("DR"))
+      {
+        line = parseDR(line);
+      }
+      else if (line.startsWith("SQ"))
+      {
+        line = parseSequence();
+      }
+      else if (line.startsWith("FT"))
+      {
+        line = parseFeature(line.substring(2));
+      }
+      else
+      {
+        line = nextLine();
+      }
+    }
+    buildSequence();
+  }
+
+  /**
+   * Extracts and saves the primary accession and version (SV value) from an ID
+   * line, or null if not found. Returns the next line after the one processed.
+   * 
+   * @param line
+   * @throws IOException
+   */
+  String parseID(String line) throws IOException
+  {
+    String[] tokens = line.substring(2).split(";");
+
+    /*
+     * first is primary accession
+     */
+    String token = tokens[0].trim();
+    if (!token.isEmpty())
+    {
+      this.accession = token;
+    }
+
+    /*
+     * second token is 'SV versionNo'
+     */
+    if (tokens.length > 1)
+    {
+      token = tokens[1].trim();
+      if (token.startsWith("SV"))
+      {
+        String[] bits = token.trim().split(WHITESPACE);
+        this.version = bits[bits.length - 1];
+      }
+    }
+
+    /*
+     * seventh token is 'length BP'
+     */
+    if (tokens.length > 6)
+    {
+      token = tokens[6].trim();
+      String[] bits = token.trim().split(WHITESPACE);
+      try
+      {
+        this.length = Integer.valueOf(bits[0]);
+      } catch (NumberFormatException e)
+      {
+        Console.error("bad length read in flatfile, line: " + line);
+      }
+    }
+
+    return nextLine();
+  }
+
+  /**
+   * Reads sequence description from the first DE line found. Any trailing
+   * period is discarded. If there are multiple DE lines, only the first (short
+   * description) is read, the rest are ignored.
+   * 
+   * @param line
+   * @return
+   * @throws IOException
+   */
+  String parseDE(String line) throws IOException
+  {
+    String desc = line.substring(2).trim();
+    if (desc.endsWith("."))
+    {
+      desc = desc.substring(0, desc.length() - 1);
+    }
+    this.description = desc;
+
+    /*
+     * pass over any additional DE lines
+     */
+    while ((line = nextLine()) != null)
+    {
+      if (!line.startsWith("DE"))
+      {
+        break;
+      }
+    }
+
+    return line;
+  }
+
+  /**
+   * Processes one DR line and saves as a DBRefEntry cross-reference. Returns
+   * the line following the line processed.
+   * 
+   * @param line
+   * @throws IOException
+   */
+  String parseDR(String line) throws IOException
+  {
+    String[] tokens = line.substring(2).split(";");
+    if (tokens.length > 1)
+    {
+      /*
+       * ensure UniProtKB/Swiss-Prot converted to UNIPROT
+       */
+      String db = tokens[0].trim();
+      db = DBRefUtils.getCanonicalName(db);
+      String acc = tokens[1].trim();
+      if (acc.endsWith("."))
+      {
+        acc = acc.substring(0, acc.length() - 1);
+      }
+      String version = "0";
+      if (tokens.length > 2)
+      {
+        String secondaryId = tokens[2].trim();
+        if (!secondaryId.isEmpty())
+        {
+          // todo: is this right? secondary id is not a version number
+          // version = secondaryId;
+        }
+      }
+      this.dbrefs.add(new DBRefEntry(db, version, acc));
+    }
+
+    return nextLine();
+  }
+
+  @Override
+  protected boolean isFeatureContinuationLine(String line)
+  {
+    return line.startsWith("FT    "); // 4 spaces
+  }
+}
index 9acd7da..c698a31 100755 (executable)
  */
 package jalview.io;
 
+import java.io.IOException;
+
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 
-import java.io.IOException;
-
 /**
  * DOCUMENT ME!
  * 
@@ -69,7 +69,12 @@ public class FastaFile extends AlignFile
 
   public FastaFile(FileParse source) throws IOException
   {
-    super(source);
+    this(source, true);
+  }
+
+  public FastaFile(FileParse source, boolean closeData) throws IOException
+  {
+    super(true, source, closeData);
   }
 
   public FastaFile(SequenceI[] seqs)
index c08c84e..71fc659 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import java.awt.Color;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -234,7 +236,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
         // skip comments/process pragmas
         if (line.length() == 0 || line.startsWith("#"))
         {
-          if (line.toLowerCase().startsWith("##"))
+          if (line.toLowerCase(Locale.ROOT).startsWith("##"))
           {
             processGffPragma(line, gffProps, align, newseqs);
           }
@@ -346,7 +348,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
     String line;
     while ((line = nextLine()) != null)
     {
-      if (line.toUpperCase().startsWith(ENDFILTERS))
+      if (line.toUpperCase(Locale.ROOT).startsWith(ENDFILTERS))
       {
         return;
       }
@@ -1391,7 +1393,9 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
     } catch (IOException q)
     {
     }
-    FastaFile parser = new FastaFile(this);
+    // Opening a FastaFile object with the remainder of this object's dataIn.
+    // Tell the constructor to NOT close the dataIn when finished.
+    FastaFile parser = new FastaFile(this, false);
     List<SequenceI> includedseqs = parser.getSeqs();
 
     SequenceIdMatcher smatcher = new SequenceIdMatcher(newseqs);
index cb61740..a743694 100644 (file)
  */
 package jalview.io;
 
+import java.io.IOException;
+
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.ext.jmol.JmolParser;
 import jalview.structure.StructureImportSettings;
 
-import java.io.IOException;
-
 public enum FileFormat implements FileFormatI
 {
   Fasta("Fasta", "fa, fasta, mfa, fastq", true, true)
@@ -243,6 +244,37 @@ public enum FileFormat implements FileFormatI
       return new PhylipFile();
     }
   },
+  GenBank("GenBank Flatfile", "gb, gbk", true, false)
+  {
+    @Override
+    public AlignmentFileReaderI getReader(FileParse source)
+            throws IOException
+    {
+      return new GenBankFile(source, "GenBank");
+    }
+
+    @Override
+    public AlignmentFileWriterI getWriter(AlignmentI al)
+    {
+      return null;
+    }
+  },
+  Embl("ENA Flatfile", "txt", true, false)
+  {
+    @Override
+    public AlignmentFileReaderI getReader(FileParse source)
+            throws IOException
+    {
+      // Always assume we import from EMBL for now
+      return new EmblFlatFile(source, DBRefSource.EMBL);
+    }
+
+    @Override
+    public AlignmentFileWriterI getWriter(AlignmentI al)
+    {
+      return null;
+    }
+  },
   Jnet("JnetFile", "", false, false)
   {
     @Override
@@ -407,8 +439,8 @@ public enum FileFormat implements FileFormatI
    * @param shortName
    * @param extensions
    *          comma-separated list of file extensions associated with the format
-   * @param isReadable
-   * @param isWritable
+   * @param isReadable - can be recognised by IdentifyFile and imported with the given reader
+   * @param isWritable - can be exported with the returned writer
    */
   private FileFormat(String shortName, String extensions,
           boolean isReadable, boolean isWritable)
index aadcdb9..9e0a7f7 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -102,7 +104,7 @@ public class FileFormats
   protected void registerFileFormat(FileFormatI format,
           boolean isIdentifiable)
   {
-    String name = format.getName().toUpperCase();
+    String name = format.getName().toUpperCase(Locale.ROOT);
     if (formats.containsKey(name))
     {
       System.err.println("Overwriting file format: " + format.getName());
@@ -121,7 +123,7 @@ public class FileFormats
    */
   public void deregisterFileFormat(String name)
   {
-    FileFormatI ff = formats.remove(name.toUpperCase());
+    FileFormatI ff = formats.remove(name.toUpperCase(Locale.ROOT));
     identifiable.remove(ff);
   }
 
@@ -174,7 +176,7 @@ public class FileFormats
    */
   public FileFormatI forName(String format)
   {
-    return format == null ? null : formats.get(format.toUpperCase());
+    return format == null ? null : formats.get(format.toUpperCase(Locale.ROOT));
   }
 
   /**
index 3aa433e..3d2dded 100755 (executable)
@@ -416,12 +416,9 @@ public class FileLoader implements Runnable
                   .getFeatureColourScheme();
           if (viewport != null)
           {
-            if (proxyColourScheme != null)
-            {
-              viewport.applyFeaturesStyle(proxyColourScheme);
-            }
             // append to existing alignment
             viewport.addAlignment(al, title);
+            viewport.applyFeaturesStyle(proxyColourScheme);
           }
           else
           {
@@ -486,7 +483,7 @@ public class FileLoader implements Runnable
 
             try
             {
-              alignFrame.setMaximum(jalview.bin.Cache
+              alignFrame.setMaximum(Cache
                       .getDefault("SHOW_FULLSCREEN", false));
             } catch (java.beans.PropertyVetoException ex)
             {
index 2ff0d27..2dec559 100755 (executable)
@@ -41,7 +41,7 @@ import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsModelI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
@@ -225,12 +225,12 @@ public class FileParse
   {
     if (!input.markSupported())
     {
-      Cache.log.error(
+      Console.error(
               "FileParse.izGzipStream: input stream must support mark/reset");
       return false;
     }
     input.mark(4);
-    
+
     // get first 2 bytes or return false
     byte[] bytes = new byte[2];
     int read = input.read(bytes);
@@ -239,7 +239,7 @@ public class FileParse
     {
       return false;
     }
-    
+
     int header = (bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
     return (GZIPInputStream.GZIP_MAGIC == header);
   }
index 85cf48a..00920db 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
@@ -63,13 +65,13 @@ public class FormatAdapter extends AppletFormatAdapter
 
   private void init()
   {
-    if (jalview.bin.Cache.getDefault("STRUCT_FROM_PDB", true))
+    if (Cache.getDefault("STRUCT_FROM_PDB", true))
     {
-      annotFromStructure = jalview.bin.Cache.getDefault("ADD_TEMPFACT_ANN",
+      annotFromStructure = Cache.getDefault("ADD_TEMPFACT_ANN",
               true);
-      localSecondaryStruct = jalview.bin.Cache.getDefault("ADD_SS_ANN",
+      localSecondaryStruct = Cache.getDefault("ADD_SS_ANN",
               true);
-      serviceSecondaryStruct = jalview.bin.Cache.getDefault("USE_RNAVIEW",
+      serviceSecondaryStruct = Cache.getDefault("USE_RNAVIEW",
               true);
     }
     else
@@ -162,7 +164,7 @@ public class FormatAdapter extends AppletFormatAdapter
 
   public boolean getCacheSuffixDefault(FileFormatI format)
   {
-    return Cache.getDefault(format.getName().toUpperCase() + "_JVSUFFIX",
+    return Cache.getDefault(format.getName().toUpperCase(Locale.ROOT) + "_JVSUFFIX",
             true);
   }
 
diff --git a/src/jalview/io/GenBankFile.java b/src/jalview/io/GenBankFile.java
new file mode 100644 (file)
index 0000000..f1ca0e3
--- /dev/null
@@ -0,0 +1,189 @@
+package jalview.io;
+
+import java.io.IOException;
+
+/**
+ * A class that provides selective parsing of the GenBank flatfile format.
+ * <p>
+ * The initial implementation is limited to extracting fields used by Jalview
+ * after fetching an EMBL or EMBLCDS entry:
+ * 
+ * <pre>
+ * accession, version, sequence, xref
+ * and (for CDS feature) location, protein_id, product, codon_start, translation
+ * </pre>
+ * 
+ * @author gmcarstairs
+ * @see https://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html
+ */
+public class GenBankFile extends EMBLLikeFlatFile
+{
+  private static final String DEFINITION = "DEFINITION";
+
+  /**
+   * Constructor given a data source and the id of the source database
+   * 
+   * @param fp
+   * @param sourceId
+   * @throws IOException
+   */
+  public GenBankFile(FileParse fp, String sourceId) throws IOException
+  {
+    super(fp, sourceId);
+  }
+
+  /**
+   * Parses the flatfile, and if successful, saves as an annotated sequence
+   * which may be retrieved by calling {@code getSequence()}
+   * 
+   * @throws IOException
+   * @see https://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html
+   */
+  @Override
+  public void parse() throws IOException
+  {
+    String line = nextLine();
+    while (line != null)
+    {
+      if (line.startsWith("LOCUS"))
+      {
+        line = parseLocus(line);
+      }
+      else if (line.startsWith(DEFINITION))
+      {
+        line = parseDefinition(line);
+      }
+      else if (line.startsWith("ACCESSION"))
+      {
+        this.accession = line.split(WHITESPACE)[1];
+        line = nextLine();
+      }
+      else if (line.startsWith("VERSION"))
+      {
+        line = parseVersion(line);
+      }
+      else if (line.startsWith("ORIGIN"))
+      {
+        line = parseSequence();
+      }
+      else if (line.startsWith("FEATURES"))
+      {
+        line = nextLine();
+        while (line.startsWith(" "))
+        {
+          line = parseFeature(line);
+        }
+      }
+      else
+      {
+        line = nextLine();
+      }
+    }
+    buildSequence();
+  }
+
+  /**
+   * Extracts and saves the primary accession and version (SV value) from an ID
+   * line, or null if not found. Returns the next line after the one processed.
+   * 
+   * @param line
+   * @throws IOException
+   */
+  String parseLocus(String line) throws IOException
+  {
+    String[] tokens = line.split(WHITESPACE);
+
+    /*
+     * first should be "LOCUS"
+     */
+    if (tokens.length < 2 || !"LOCUS".equals(tokens[0]))
+    {
+      return nextLine();
+    }
+    /*
+     * second is primary accession
+     */
+    String token = tokens[1].trim();
+    if (!token.isEmpty())
+    {
+      this.accession = token;
+    }
+
+    // not going to guess the rest just yet, but third is length with unit (bp)
+
+    return nextLine();
+  }
+
+  /**
+   * Reads sequence description from DEFINITION lines. Any trailing period is
+   * discarded. Returns the next line after the definition line(s).
+   * 
+   * @param line
+   * @return
+   * @throws IOException
+   */
+  String parseDefinition(String line) throws IOException
+  {
+    String desc = line.substring(DEFINITION.length()).trim();
+    if (desc.endsWith("."))
+    {
+      desc = desc.substring(0, desc.length() - 1);
+    }
+
+    /*
+     * pass over any additional DE lines
+     */
+    while ((line = nextLine()) != null)
+    {
+      if (line.startsWith(" "))
+      {
+        // definition continuation line
+        desc += line.trim();
+      }
+      else
+      {
+        break;
+      }
+    }
+    this.description = desc;
+
+    return line;
+  }
+
+  /**
+   * Parses the VERSION line e.g.
+   * 
+   * <pre>
+   * VERSION     X81322.1
+   * </pre>
+   * 
+   * and returns the next line
+   * 
+   * @param line
+   * @throws IOException
+   */
+  String parseVersion(String line) throws IOException
+  {
+    /*
+     * extract version part of <accession>.<version>
+     * https://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html#VersionB
+     */
+    String[] tokens = line.split(WHITESPACE);
+    if (tokens.length > 1)
+    {
+      tokens = tokens[1].split("\\.");
+      if (tokens.length > 1)
+      {
+        this.version = tokens[1];
+      }
+    }
+
+    return nextLine();
+  }
+
+  @Override
+  protected boolean isFeatureContinuationLine(String line)
+  {
+    return line.startsWith("      "); // 6 spaces
+  }
+}
index b8241c8..81773bc 100644 (file)
@@ -189,7 +189,7 @@ public class HtmlSvgOutput extends HTMLOutput
   public boolean isEmbedData()
   {
     return Boolean.valueOf(
-            jalview.bin.Cache.getDefault("EXPORT_EMBBED_BIOJSON", "true"));
+            Cache.getDefault("EXPORT_EMBBED_BIOJSON", "true"));
   }
 
   @Override
index b312474..5a3d700 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import java.io.File;
 import java.io.IOException;
 
@@ -178,13 +180,26 @@ public class IdentifyFile
             break;
           }
         }
-        data = data.toUpperCase();
+        data = data.toUpperCase(Locale.ROOT);
 
         if (data.startsWith(ScoreMatrixFile.SCOREMATRIX))
         {
           reply = FileFormat.ScoreMatrix;
           break;
         }
+        if (data.startsWith("LOCUS"))
+        {
+          reply = FileFormat.GenBank;
+          break;
+        }
+        if (data.startsWith("ID "))
+        {
+          if (data.substring(2).trim().split(";").length == 7)
+          {
+            reply = FileFormat.Embl;
+            break;
+          }
+        }
         if (data.startsWith("H ") && !aaIndexHeaderRead)
         {
           aaIndexHeaderRead = true;
@@ -319,7 +334,7 @@ public class IdentifyFile
         if ((lessThan > -1)) // possible Markup Language data i.e HTML,
                              // RNAML, XML
         {
-          String upper = data.toUpperCase();
+          String upper = data.toUpperCase(Locale.ROOT);
           if (upper.substring(lessThan).startsWith("<HTML"))
           {
             reply = FileFormat.Html;
index 6af92b7..ab2c00a 100755 (executable)
@@ -25,6 +25,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Sequence;
@@ -409,7 +411,7 @@ public class JPredFile extends AlignFile
     // check that no stray annotations have been added at the end.
     {
       SequenceI sq = seqs.elementAt(j - 1);
-      if (sq.getName().toUpperCase().startsWith("JPRED"))
+      if (sq.getName().toUpperCase(Locale.ROOT).startsWith("JPRED"))
       {
         annotSeqs.addElement(sq);
         seqs.removeElementAt(--j);
index e0f28bb..022148a 100644 (file)
@@ -70,7 +70,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
 {
   private static String version = new BuildDetails().getVersion();
 
-  private String webstartUrl = "http://www.jalview.org/services/launchApp";
+  private String webstartUrl = "https://www.jalview.org/services/launchApp";
 
   private String application = "Jalview";
 
index bc20342..28dd2eb 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import java.io.File;
 import java.util.Hashtable;
 import java.util.Iterator;
@@ -134,7 +136,7 @@ public class JalviewFileFilter extends FileFilter
 
       if ((i > 0) && (i < (filename.length() - 1)))
       {
-        return filename.substring(i + 1).toLowerCase();
+        return filename.substring(i + 1).toLowerCase(Locale.ROOT);
       }
 
       ;
@@ -150,7 +152,7 @@ public class JalviewFileFilter extends FileFilter
       filters = new LinkedHashMap<>(5);
     }
 
-    filters.put(extension.toLowerCase(), this);
+    filters.put(extension.toLowerCase(Locale.ROOT), this);
     fullDescription = null;
   }
 
index 52d130c..b90bd7a 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.util.MessageManager;
 
 import java.io.File;
@@ -47,7 +49,7 @@ public class JalviewFileView extends FileView
       String exts = ff.getExtensions();
       for (String ext : exts.split(","))
       {
-        ext = ext.trim().toLowerCase();
+        ext = ext.trim().toLowerCase(Locale.ROOT);
         extensions.put(ext,
                 desc + ("jar".equals(ext) ? " (old)" : ""));
       }
@@ -136,7 +138,7 @@ public class JalviewFileView extends FileView
 
     if ((i > 0) && (i < (s.length() - 1)))
     {
-      ext = s.substring(i + 1).toLowerCase();
+      ext = s.substring(i + 1).toLowerCase(Locale.ROOT);
     }
 
     return ext;
index 6828202..27fc869 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -88,7 +90,7 @@ public class JnetAnnotationMaker
 
     while (i < preds.length)
     {
-      String id = preds[i].getName().toUpperCase();
+      String id = preds[i].getName().toUpperCase(Locale.ROOT);
 
       if (id.startsWith("LUPAS") || id.startsWith("JNET")
               || id.startsWith("JPRED"))
index df2bed2..e954703 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.util.Comparison;
@@ -184,7 +186,7 @@ public class MSFfile extends AlignFile
   public int checkSum(String seq)
   {
     int check = 0;
-    String sequence = seq.toUpperCase();
+    String sequence = seq.toUpperCase(Locale.ROOT);
 
     for (int i = 0; i < sequence.length(); i++)
     {
index a56f2af..d66fe6c 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.io;
 
+import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
 
@@ -110,7 +111,7 @@ public class ModellerDescription
     {
       value = r.stringMatched(1);
     }
-    // jalview.bin.Cache.log.debug("from '" + field + "' matched '" + value +
+    // Cache.debug("from '" + field + "' matched '" + value +
     // "'");
     try
     {
@@ -165,7 +166,7 @@ public class ModellerDescription
                 }
                 else
                 {
-                  // jalview.bin.Cache.log.debug(
+                  // Cache.debug(
                   // "Ignoring non-Modeller description: invalid integer-like
                   // field '" + field + "'");
                   type = -1; /* invalid field! - throw the FieldSet away */
index f3eaa45..ec5d267 100755 (executable)
@@ -26,6 +26,8 @@
 // TODO: Extended SequenceNodeI to hold parsed NHX strings
 package jalview.io;
 
+import java.util.Locale;
+
 import jalview.datamodel.SequenceNode;
 import jalview.util.MessageManager;
 
@@ -656,7 +658,7 @@ public class NewickFile extends FileParse
           try
           {
             // parse out code/value pairs
-            if (code.toLowerCase().equals("b"))
+            if (code.toLowerCase(Locale.ROOT).equals("b"))
             {
               int v = -1;
               Float iv = Float.valueOf(value);
index 01610a1..6b09cd1 100644 (file)
@@ -36,10 +36,9 @@ public class PDBFeatureSettings extends FeatureSettingsAdapter
   private static final String FEATURE_RES_NUM = PDBChain.RESNUM_FEATURE;
 
   @Override
-  public boolean isFeatureDisplayed(String type)
+  public boolean isFeatureHidden(String type)
   {
-    return type.equalsIgnoreCase(FEATURE_INSERTION)
-            || type.equalsIgnoreCase(FEATURE_RES_NUM);
+    return type.equalsIgnoreCase(FEATURE_RES_NUM);
   }
 
   @Override
index 8e4e783..9ffdf21 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.io;
 
+import java.util.Locale;
+
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
@@ -207,12 +209,27 @@ public class SequenceAnnotationReport
      * if this is a virtual features, convert begin/end to the
      * coordinates of the sequence it is mapped to
      */
-    int[] beginRange = null;
-    int[] endRange = null;
+    int[] beginRange = null; // feature start in local coordinates
+    int[] endRange = null; // feature end in local coordinates
     if (mf != null)
     {
-      beginRange = mf.getMappedPositions(begin, begin);
-      endRange = mf.getMappedPositions(end, end);
+      if (feature.isContactFeature())
+      {
+        /*
+         * map start and end points individually
+         */
+        beginRange = mf.getMappedPositions(begin, begin);
+        endRange = begin == end ? beginRange
+                : mf.getMappedPositions(end, end);
+      }
+      else
+      {
+        /*
+         * map the feature extent
+         */
+        beginRange = mf.getMappedPositions(begin, end);
+        endRange = beginRange;
+      }
       if (beginRange == null || endRange == null)
       {
         // something went wrong
@@ -273,7 +290,7 @@ public class SequenceAnnotationReport
          * truncate overlong descriptions unless they contain an href
          * before the truncation point (as truncation could leave corrupted html)
          */
-        int linkindex = description.toLowerCase().indexOf("<a ");
+        int linkindex = description.toLowerCase(Locale.ROOT).indexOf("<a ");
         boolean hasLink = linkindex > -1
                 && linkindex < MAX_DESCRIPTION_LENGTH;
         if (description.length() > MAX_DESCRIPTION_LENGTH && !hasLink)
@@ -400,8 +417,8 @@ public class SequenceAnnotationReport
                       + "\" target=\""
                       + urllink.get(0)
                       + "\">"
-                      + (urllink.get(0).toLowerCase()
-                              .equals(urllink.get(1).toLowerCase()) ? urllink
+                      + (urllink.get(0).toLowerCase(Locale.ROOT)
+                              .equals(urllink.get(1).toLowerCase(Locale.ROOT)) ? urllink
                               .get(0) : (urllink.get(0) + ":" + urllink
                                               .get(1)))
                       + "</a><br/>");
index 8b26757..cff328b 100644 (file)
@@ -31,6 +31,7 @@ import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Vector;
 
@@ -55,8 +56,6 @@ import jalview.util.DBRefUtils;
 import jalview.util.Format;
 import jalview.util.MessageManager;
 
-// import org.apache.log4j.*;
-
 /**
  * This class is supposed to parse a Stockholm format file into Jalview There
  * are TODOs in this class: we do not know what the database source and version
@@ -77,14 +76,15 @@ public class StockholmFile extends AlignFile
 {
   private static final String ANNOTATION = "annotation";
 
-//  private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "(");
-//
-//  private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")");
+  // private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "(");
+  //
+  // private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")");
 
   public static final Regex DETECT_BRACKETS = new Regex(
           "(<|>|\\[|\\]|\\(|\\)|\\{|\\})");
 
-  // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using NOT_RNASS first.
+  // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using
+  // NOT_RNASS first.
   public static final String RNASS_BRACKETS = "<>[](){}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
 
   // use the following regex to decide an annotations (whole) line is NOT an RNA
@@ -240,8 +240,8 @@ public class StockholmFile extends AlignFile
     Regex openparen = new Regex("(<|\\[)", "(");
     Regex closeparen = new Regex("(>|\\])", ")");
 
-//    // Detect if file is RNA by looking for bracket types
-//    Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");
+    // // Detect if file is RNA by looking for bracket types
+    // Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");
 
     rend.optimize();
     p.optimize();
@@ -337,7 +337,8 @@ public class StockholmFile extends AlignFile
             if (dbr != null)
             {
               // we could get very clever here - but for now - just try to
-              // guess accession type from type of sequence, source of alignment plus
+              // guess accession type from type of sequence, source of alignment
+              // plus
               // structure
               // of accession
               guessDatabaseFor(seqO, dbr, dbsource);
@@ -525,8 +526,10 @@ public class StockholmFile extends AlignFile
               treeName = an.stringMatched(2);
               treeString = new StringBuffer();
             }
-            // TODO: JAL-3532 - this is where GF comments and database references are lost
-            // suggest overriding this method for Stockholm files to catch and properly
+            // TODO: JAL-3532 - this is where GF comments and database
+            // references are lost
+            // suggest overriding this method for Stockholm files to catch and
+            // properly
             // process CC, DR etc into multivalued properties
             setAlignmentProperty(an.stringMatched(1), an.stringMatched(2));
           }
@@ -758,7 +761,8 @@ public class StockholmFile extends AlignFile
     }
     if (dbsource == null)
     {
-      // make up an origin based on whether the sequence looks like it is nucleotide
+      // make up an origin based on whether the sequence looks like it is
+      // nucleotide
       // or protein
       dbsource = (seqO.isProtein()) ? "PFAM" : "RFAM";
     }
@@ -942,6 +946,7 @@ public class StockholmFile extends AlignFile
     return ref.getSource().toString() + " ; "
             + ref.getAccessionId().toString();
   }
+
   @Override
   public String print(SequenceI[] s, boolean jvSuffix)
   {
@@ -1110,7 +1115,7 @@ public class StockholmFile extends AlignFile
         }
         else
         {
-          key = type2id(aa.label.toLowerCase());
+          key = type2id(aa.label.toLowerCase(Locale.ROOT));
           if (key == null)
           {
             label = aa.label;
index 084f886..94a832b 100644 (file)
@@ -119,6 +119,7 @@ public abstract class StructureFile extends AlignFile
     pdbSequence.setName(getId() + "|" + pdbSequence.getName());
     PDBEntry entry = new PDBEntry();
     entry.setId(getId());
+    entry.setFakedPDBId(!isPPDBIdAvailable());
     entry.setType(getStructureFileType());
     if (chain.id != null)
     {
index 2fc526b..5365dfa 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.io;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.GraphLine;
@@ -183,7 +183,7 @@ public class VamsasAppDatastore
           Vobject obj = getjv2vObj(seqsetidobj);
           if (obj != null && !(obj instanceof Alignment))
           {
-            Cache.log.warn(
+            Console.warn(
                     "IMPLEMENTATION ERROR?: Unexpected mapping for unmapped jalview string object content:"
                             + seqsetidobj + " to object " + obj);
           }
@@ -191,16 +191,16 @@ public class VamsasAppDatastore
         }
         else
         {
-          Cache.log.warn("Unexpected mapping for Jalview String Object ID "
+          Console.warn("Unexpected mapping for Jalview String Object ID "
                   + seqsetidobj + " to another jalview dataset object "
                   + seqsetidobj);
         }
       }
     }
 
-    if (Cache.log.isDebugEnabled())
+    if (Console.isDebugEnabled())
     {
-      Cache.log.debug(
+      Console.debug(
               "Returning null VorbaID binding for jalview object " + jvobj);
     }
     return null;
@@ -217,7 +217,7 @@ public class VamsasAppDatastore
     if (id == null)
     {
       id = cdoc.registerObject(vobj);
-      Cache.log.debug(
+      Console.debug(
               "Registering new object and returning null for getvObj2jv");
       return null;
     }
@@ -237,7 +237,7 @@ public class VamsasAppDatastore
       if (id == null || vobj.getVorbaId() == null
               || cdoc.getObject(id) != vobj)
       {
-        Cache.log.error("Failed to get id for "
+        Console.error("Failed to get id for "
                 + (vobj.isRegisterable() ? "registerable"
                         : "unregisterable")
                 + " object " + vobj);
@@ -247,7 +247,7 @@ public class VamsasAppDatastore
     if (vobj2jv.containsKey(vobj.getVorbaId())
             && !((VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
     {
-      Cache.log.debug(
+      Console.debug(
               "Warning? Overwriting existing vamsas id binding for "
                       + vobj.getVorbaId(),
               new Exception(MessageManager.getString(
@@ -256,19 +256,19 @@ public class VamsasAppDatastore
     else if (jv2vobj.containsKey(jvobj)
             && !((VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
     {
-      Cache.log.debug(
+      Console.debug(
               "Warning? Overwriting existing jalview object binding for "
                       + jvobj,
               new Exception("Overwriting jalview object binding."));
     }
     /*
-     * Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id "
+     * Cache.error("Attempt to make conflicting object binding! "+vobj+" id "
      * +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+"
      * already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to
      * bindjvvobj")); }
      */
     // we just update the hash's regardless!
-    Cache.log.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
+    Console.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
     vobj2jv.put(vobj.getVorbaId(), jvobj);
     // JBPNote - better implementing a hybrid invertible hash.
     jv2vobj.put(jvobj, vobj.getVorbaId());
@@ -297,7 +297,7 @@ public class VamsasAppDatastore
       DataSet dataset = null;
       if (jds == null)
       {
-        Cache.log.warn("Creating new dataset for an alignment.");
+        Console.warn("Creating new dataset for an alignment.");
         jal.setDataset(null);
         jds = jal.getDataset();
       }
@@ -349,7 +349,7 @@ public class VamsasAppDatastore
 
       if (dataset == null)
       {
-        Cache.log.warn("Creating new vamsas dataset for alignment view "
+        Console.warn("Creating new vamsas dataset for alignment view "
                 + av.getSequenceSetId());
         // we create a new dataset on the default vamsas root.
         root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying.
@@ -556,7 +556,7 @@ public class VamsasAppDatastore
           if (aa[i].groupRef != null)
           {
             // TODO: store any group associated annotation references
-            Cache.log.warn(
+            Console.warn(
                     "Group associated sequence annotation is not stored in VAMSAS document.");
             continue;
           }
@@ -699,13 +699,13 @@ public class VamsasAppDatastore
               // LOCK METHODS)
               {
                 // verify annotation - update (perhaps)
-                Cache.log.info(
+                Console.info(
                         "update alignment sequence annotation. not yet implemented.");
               }
               else
               {
                 // verify annotation - update (perhaps)
-                Cache.log.info(
+                Console.info(
                         "updated alignment sequence annotation added.");
               }
             }
@@ -889,7 +889,7 @@ public class VamsasAppDatastore
     }
     if (getjv2vObj(jvalsq.getDatasetSequence()) == null)
     {
-      Cache.log.warn(
+      Console.warn(
               "Serious Implementation error - Unbound dataset sequence in alignment: "
                       + jvalsq.getDatasetSequence());
     }
@@ -947,9 +947,9 @@ public class VamsasAppDatastore
         alseq.setDescription(valseq.getDescription());
         modal = true;
       }
-      if (modal && Cache.log.isDebugEnabled())
+      if (modal && Console.isDebugEnabled())
       {
-        Cache.log.debug(
+        Console.debug(
                 "Updating apparently edited sequence " + alseq.getName());
       }
     }
@@ -986,7 +986,7 @@ public class VamsasAppDatastore
       }
       else
       {
-        Cache.log.error(
+        Console.error(
                 "Invalid dataset sequence id (null) for alignment sequence "
                         + valseq.getVorbaId());
       }
@@ -1332,7 +1332,7 @@ public class VamsasAppDatastore
               @Override
               public JarInputStream getJarInputStream() throws IOException
               {
-                jalview.bin.Cache.log.debug(
+                Console.debug(
                         "Returning client input stream for Jalview from Vamsas Document.");
                 return new JarInputStream(cappdata.getClientInputStream());
               }
@@ -1380,7 +1380,7 @@ public class VamsasAppDatastore
             @Override
             public JarInputStream getJarInputStream() throws IOException
             {
-              jalview.bin.Cache.log.debug(
+              Console.debug(
                       "Returning user input stream for Jalview from Vamsas Document.");
               return new JarInputStream(cappdata.getUserInputStream());
             }
@@ -1426,8 +1426,7 @@ public class VamsasAppDatastore
       // TODO implement this : af.getNumberOfViews
       String seqsetidobj = av.getSequenceSetId();
       views = Desktop.getViewports(seqsetidobj);
-      Cache.log
-              .debug("Found " + (views == null ? " no " : "" + views.length)
+      Console.debug("Found " + (views == null ? " no " : "" + views.length)
                       + " views for '" + av.getSequenceSetId() + "'");
       if (views.length > 1)
       {
@@ -1544,14 +1543,14 @@ public class VamsasAppDatastore
       } catch (Exception e)
       {
         // TODO raise GUI warning if user requests it.
-        jalview.bin.Cache.log.error(
+        Console.error(
                 "Couldn't update jalview client application data. Giving up - local settings probably lost.",
                 e);
       }
     }
     else
     {
-      jalview.bin.Cache.log.error(
+      Console.error(
               "Couldn't access client application data for vamsas session. This is probably a vamsas client bug.");
     }
   }
@@ -1617,13 +1616,13 @@ public class VamsasAppDatastore
         int jremain = 0;
         if (jdataset == null)
         {
-          Cache.log.debug("Initialising new jalview dataset fields");
+          Console.debug("Initialising new jalview dataset fields");
           newds = true;
           dsseqs = new Vector();
         }
         else
         {
-          Cache.log.debug("Update jalview dataset from vamsas.");
+          Console.debug("Update jalview dataset from vamsas.");
           jremain = jdataset.getHeight();
           dsseqs = jdataset.getSequences();
         }
@@ -1663,7 +1662,7 @@ public class VamsasAppDatastore
             dsseqs.set(i, null);
           }
           jdataset = new jalview.datamodel.Alignment(seqs);
-          Cache.log.debug("New vamsas dataset imported into jalview.");
+          Console.debug("New vamsas dataset imported into jalview.");
           bindjvvobj(jdataset, dataset);
         }
         // ////////
@@ -1683,7 +1682,7 @@ public class VamsasAppDatastore
               // annotations
               if (dsSeq == null)
               {
-                jalview.bin.Cache.log.warn(
+                Console.warn(
                         "Couldn't resolve jalview sequenceI for dataset object reference "
                                 + ((Vobject) dataset
                                         .getDataSetAnnotations(dsa)
@@ -1704,14 +1703,14 @@ public class VamsasAppDatastore
                   // JBPNote: we could just add them to all alignments but
                   // that may complicate cross references in the jalview
                   // datamodel
-                  Cache.log.warn(
+                  Console.warn(
                           "Ignoring dataset annotation with annotationElements. Not yet supported in jalview.");
                 }
               }
             }
             else
             {
-              Cache.log.warn(
+              Console.warn(
                       "Ignoring multiply referenced dataset sequence annotation for binding to datsaet sequence features.");
             }
           }
@@ -1807,7 +1806,7 @@ public class VamsasAppDatastore
                     // OBJECT LOCK
                     // METHODS)
                     {
-                      Cache.log.info(
+                      Console.info(
                               "UNIMPLEMENTED: not recovering user modifiable sequence alignment annotation");
                       // TODO: should at least replace with new one - otherwise
                       // things will break
@@ -1831,7 +1830,7 @@ public class VamsasAppDatastore
                 dsseqs.set(i, null);
               }
               jal = new jalview.datamodel.Alignment(seqs);
-              Cache.log.debug("New vamsas alignment imported into jalview "
+              Console.debug("New vamsas alignment imported into jalview "
                       + alignment.getVorbaId().getId());
               jal.setDataset(jdataset);
             }
@@ -1870,7 +1869,7 @@ public class VamsasAppDatastore
                   // jan.update(getjAlignmentAnnotation(jal, an[a])); // update
                   // from another annotation object in place.
 
-                  Cache.log.debug(
+                  Console.debug(
                           "update from vamsas alignment annotation to existing jalview alignment annotation.");
                   if (an[j].getModifiable() == null) // TODO: USE VAMSAS
                   // LIBRARY OBJECT LOCK
@@ -1878,7 +1877,7 @@ public class VamsasAppDatastore
                   {
                     // TODO: user defined annotation is totally mutable... - so
                     // load it up or throw away if locally edited.
-                    Cache.log.info(
+                    Console.info(
                             "NOT IMPLEMENTED - Recovering user-modifiable annotation - yet...");
                   }
                   // TODO: compare annotation element rows
@@ -1898,7 +1897,7 @@ public class VamsasAppDatastore
             AlignFrame alignFrame;
             if (av == null)
             {
-              Cache.log.debug("New alignframe for alignment "
+              Console.debug("New alignframe for alignment "
                       + alignment.getVorbaId());
               // ///////////////////////////////
               // construct alignment view
@@ -1924,7 +1923,7 @@ public class VamsasAppDatastore
               }
               // TODO: automatically create meaningful title for a vamsas
               // alignment using its provenance.
-              if (Cache.log.isDebugEnabled())
+              if (Console.isDebugEnabled())
               {
                 title = title + "(" + alignment.getVorbaId() + ")";
 
@@ -1971,12 +1970,12 @@ public class VamsasAppDatastore
                     vstree.UpdateSequenceTreeMap(tp);
                   } catch (RuntimeException e)
                   {
-                    Cache.log.warn("update of labels failed.", e);
+                    Console.warn("update of labels failed.", e);
                   }
                 }
                 else
                 {
-                  Cache.log.warn("Cannot create tree for tree " + t
+                  Console.warn("Cannot create tree for tree " + t
                           + " in document ("
                           + alignment.getTree(t).getVorbaId());
                 }
@@ -2073,7 +2072,7 @@ public class VamsasAppDatastore
           if (anot[row][pos] != null)
           {
             // only time this should happen is if the After flag is set.
-            Cache.log.debug("Ignoring duplicate annotation site at " + pos);
+            Console.debug("Ignoring duplicate annotation site at " + pos);
             continue;
           }
           if (anot[1 - row][pos] != null)
@@ -2109,7 +2108,7 @@ public class VamsasAppDatastore
               else if (glyphs[g].getDict().equals(
                       uk.ac.vamsas.objects.utils.GlyphDictionary.PROTEIN_HD_HYDRO))
               {
-                Cache.log.debug("ignoring hydrophobicity glyph marker.");
+                Console.debug("ignoring hydrophobicity glyph marker.");
                 AeContent[HASHPHOB] = true;
                 char c = (dc = glyphs[g].getContent()).charAt(0);
                 // dc may get overwritten - but we still set the colour.
@@ -2125,7 +2124,7 @@ public class VamsasAppDatastore
               }
               else
               {
-                Cache.log.debug(
+                Console.debug(
                         "IMPLEMENTATION TODO: Ignoring unknown glyph type "
                                 + glyphs[g].getDict());
               }
@@ -2137,7 +2136,7 @@ public class VamsasAppDatastore
             AeContent[HASVALS] = true;
             if (ae[aa].getValueCount() > 1)
             {
-              Cache.log.warn(
+              Console.warn(
                       "ignoring additional " + (ae[aa].getValueCount() - 1)
                               + " values in annotation element.");
             }
@@ -2158,7 +2157,7 @@ public class VamsasAppDatastore
         }
         else
         {
-          Cache.log.warn("Ignoring out of bound annotation element " + aa
+          Console.warn("Ignoring out of bound annotation element " + aa
                   + " in " + annotation.getVorbaId().getId());
         }
       }
@@ -2249,7 +2248,7 @@ public class VamsasAppDatastore
             val = Float.valueOf(props[p].getContent());
           } catch (Exception e)
           {
-            Cache.log.warn("Failed to parse threshold property");
+            Console.warn("Failed to parse threshold property");
           }
           if (val != null)
           {
@@ -2289,14 +2288,14 @@ public class VamsasAppDatastore
     }
     if (parsedRangeAnnotation == null)
     {
-      Cache.log.debug(
+      Console.debug(
               "Inserting empty annotation row elements for a whole-alignment annotation.");
     }
     else
     {
       if (parsedRangeAnnotation[3] != null)
       {
-        Cache.log.warn("Ignoring 'After' annotation row in "
+        Console.warn("Ignoring 'After' annotation row in "
                 + annotation.getVorbaId());
       }
       jalview.datamodel.Annotation[] arow = (jalview.datamodel.Annotation[]) parsedRangeAnnotation[2];
@@ -2416,7 +2415,7 @@ public class VamsasAppDatastore
       }
       if (annotation.getLinkCount() > 0)
       {
-        Cache.log.warn("Ignoring " + annotation.getLinkCount()
+        Console.warn("Ignoring " + annotation.getLinkCount()
                 + "links added to AlignmentAnnotation.");
       }
       if (annotation.getModifiable() == null
@@ -2441,7 +2440,7 @@ public class VamsasAppDatastore
         }
       } catch (Exception e)
       {
-        Cache.log.info(
+        Console.info(
                 "UNIMPLEMENTED : Couldn't parse non-integer group value for setting graphGroup correctly.");
       }
       return jan;
@@ -2737,7 +2736,7 @@ public class VamsasAppDatastore
       DataSet dataset = null;
       if (jal.getDataset() == null)
       {
-        Cache.log.warn("Creating new dataset for an alignment.");
+        Console.warn("Creating new dataset for an alignment.");
         jal.setDataset(null);
       }
       dataset = (DataSet) ((Alignment) getjv2vObj(
@@ -2745,7 +2744,7 @@ public class VamsasAppDatastore
       if (dataset == null)
       {
         dataset = (DataSet) getjv2vObj(jal.getDataset());
-        Cache.log.error(
+        Console.error(
                 "Can't find the correct dataset for the alignment in this view. Creating new one.");
 
       }
@@ -2770,7 +2769,7 @@ public class VamsasAppDatastore
               }
               else
               {
-                Cache.log.warn(
+                Console.warn(
                         "NO Vamsas Binding for local sequence! NOT CREATING MAPPING FOR "
                                 + dmps[smp].getDisplayId(true) + " to "
                                 + mps[smp].getTo().getName());
index da0c245..9ce4cc6 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.io.gff;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.MappingType;
@@ -341,7 +343,7 @@ public class ExonerateHelper extends Gff2Helper
     // e.g. exonerate:protein2genome:local
     if (model != null)
     {
-      String mdl = model.toLowerCase();
+      String mdl = model.toLowerCase(Locale.ROOT);
       if (mdl.contains(PROTEIN2DNA) || mdl.contains(PROTEIN2GENOME)
               || mdl.contains(CODING2CODING) || mdl.contains(CODING2GENOME)
               || mdl.contains(CDNA2GENOME) || mdl.contains(GENOME2GENOME))
index d40446d..37dd66b 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.io.packed;
 
+import java.util.Locale;
+
 import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentI;
 import jalview.io.AppletFormatAdapter;
@@ -235,7 +237,7 @@ public class ParsePackedSet
       String type = args[i++];
       final String file = args[i++];
       final JvDataType jtype = DataProvider.JvDataType
-              .valueOf(type.toUpperCase());
+              .valueOf(type.toUpperCase(Locale.ROOT));
       if (jtype != null)
       {
         final FileParse fp;
@@ -254,7 +256,7 @@ public class ParsePackedSet
       else
       {
         System.out.println("Couldn't parse source type token '"
-                + type.toUpperCase() + "'");
+                + type.toUpperCase(Locale.ROOT) + "'");
       }
     }
     if (i < args.length)
index 56d9fa4..ed262c5 100644 (file)
  */
 package jalview.io.vamsas;
 
-import jalview.bin.Cache;
-import jalview.io.VamsasAppDatastore;
-import jalview.util.MessageManager;
-
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
 import java.util.Vector;
 
+import jalview.bin.Console;
+import jalview.io.VamsasAppDatastore;
+import jalview.log.JLoggerLog4j;
+import jalview.util.MessageManager;
 import uk.ac.vamsas.client.IClientDocument;
 import uk.ac.vamsas.client.Vobject;
 import uk.ac.vamsas.client.VorbaId;
@@ -60,7 +60,7 @@ public abstract class DatastoreItem
   /**
    * shared log instance
    */
-  protected static org.apache.log4j.Logger log = org.apache.log4j.Logger
+  protected static JLoggerLog4j log = JLoggerLog4j
           .getLogger(DatastoreItem.class);
 
   /**
@@ -74,9 +74,9 @@ public abstract class DatastoreItem
     {
       return cdoc.getObject((VorbaId) jv2vobj.get(jvobj));
     }
-    if (Cache.log.isDebugEnabled())
+    if (Console.isDebugEnabled())
     {
-      Cache.log.debug(
+      Console.debug(
               "Returning null VorbaID binding for jalview object " + jvobj);
     }
     return null;
@@ -95,7 +95,7 @@ public abstract class DatastoreItem
     if (id == null)
     {
       id = cdoc.registerObject(vobj);
-      Cache.log.debug(
+      Console.debug(
               "Registering new object and returning null for getvObj2jv");
       return null;
     }
@@ -122,7 +122,7 @@ public abstract class DatastoreItem
       if (id == null || vobj.getVorbaId() == null
               || cdoc.getObject(id) != vobj)
       {
-        Cache.log.error("Failed to get id for "
+        Console.error("Failed to get id for "
                 + (vobj.isRegisterable() ? "registerable"
                         : "unregisterable")
                 + " object " + vobj);
@@ -131,7 +131,7 @@ public abstract class DatastoreItem
     if (vobj2jv.containsKey(vobj.getVorbaId())
             && !(vobj2jv.get(vobj.getVorbaId())).equals(jvobj))
     {
-      Cache.log.debug(
+      Console.debug(
               "Warning? Overwriting existing vamsas id binding for "
                       + vobj.getVorbaId(),
               new Exception(MessageManager.getString(
@@ -140,20 +140,20 @@ public abstract class DatastoreItem
     else if (jv2vobj.containsKey(jvobj)
             && !((VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))
     {
-      Cache.log.debug(
+      Console.debug(
               "Warning? Overwriting existing jalview object binding for "
                       + jvobj,
               new Exception(MessageManager.getString(
                       "exception.overwriting_jalview_id_binding")));
     }
     /*
-     * Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id "
+     * Cache.error("Attempt to make conflicting object binding! "+vobj+" id "
      * +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+"
      * already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to
      * bindjvvobj")); }
      */
     // we just update the hash's regardless!
-    Cache.log.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
+    Console.debug("Binding " + vobj.getVorbaId() + " to " + jvobj);
     vobj2jv.put(vobj.getVorbaId(), jvobj);
     // JBPNote - better implementing a hybrid invertible hash.
     jv2vobj.put(jvobj, vobj.getVorbaId());
@@ -171,8 +171,8 @@ public abstract class DatastoreItem
   {
     if (this.jvobj != null && this.vobj != null)
     {
-      Cache.log.debug("updating dsobj registry. ("
-              + this.getClass().getName() + ")");
+      Console.debug("updating dsobj registry. (" + this.getClass().getName()
+              + ")");
     }
     this.jvobj = jvobj;
     this.vobj = vobj;
index b53de08..233685b 100644 (file)
@@ -24,9 +24,11 @@ import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.Map;
 
+import jalview.log.JLoggerLog4j;
+
 public class DatastoreRegistry implements AutoCloseable
 {
-  protected static org.apache.log4j.Logger log = org.apache.log4j.Logger
+  protected static JLoggerLog4j log = JLoggerLog4j
           .getLogger(DatastoreRegistry.class);
 
   /**
index bdef00f..91bf666 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.vamsas;
 
+import jalview.bin.Console;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
 import jalview.io.VamsasAppDatastore;
@@ -92,7 +93,7 @@ public class Dbref extends Rangetype
     }
     else
     {
-      jalview.bin.Cache.log.debug(
+      Console.debug(
               "Ignoring mapless DbRef.Map " + jvobj.getSrcAccString());
     }
 
@@ -158,8 +159,7 @@ public class Dbref extends Rangetype
       // TODO: Jalview ignores all the other maps
       if (vobj.getMapCount() > 1)
       {
-        jalview.bin.Cache.log
-                .debug("Ignoring additional mappings on DbRef: "
+        Console.debug("Ignoring additional mappings on DbRef: "
                         + jvobj.getSource() + ":" + jvobj.getAccessionId());
       }
       jalview.datamodel.Mapping mp = new jalview.datamodel.Mapping(
@@ -175,8 +175,7 @@ public class Dbref extends Rangetype
   {
     DbRef vobj = (DbRef) this.vobj;
     DBRefEntry jvobj = (DBRefEntry) this.jvobj;
-    jalview.bin.Cache.log
-            .debug("Conflict in dbentry update for " + vobj.getAccessionId()
+    Console.debug("Conflict in dbentry update for " + vobj.getAccessionId()
                     + vobj.getSource() + " " + vobj.getVorbaId());
     // TODO Auto-generated method stub
 
@@ -195,8 +194,7 @@ public class Dbref extends Rangetype
       // TODO: Jalview ignores all the other maps
       if (vobj.getMapCount() > 1)
       {
-        jalview.bin.Cache.log
-                .debug("Ignoring additional mappings on DbRef: "
+        Console.debug("Ignoring additional mappings on DbRef: "
                         + jvobj.getSource() + ":" + jvobj.getAccessionId());
       }
       jalview.datamodel.Mapping mp = new jalview.datamodel.Mapping(
@@ -230,7 +228,7 @@ public class Dbref extends Rangetype
       }
       else
       {
-        jalview.bin.Cache.log.debug(
+        Console.debug(
                 "Ignoring mapless DbRef.Map " + jvobj.getSrcAccString());
       }
     }
index 0fed7d7..bd25c62 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.vamsas;
 
+import jalview.bin.Console;
 import jalview.io.VamsasAppDatastore;
 import jalview.util.MessageManager;
 
@@ -271,8 +272,7 @@ public abstract class Rangetype extends DatastoreItem
   {
     if (!map.getLocal().hasUnit() || map.getMapped().hasUnit())
     {
-      jalview.bin.Cache.log
-              .warn("using default mapping length of 1:1 for map "
+      Console.warn("using default mapping length of 1:1 for map "
                       + (map.isRegistered() ? map.getVorbaId().toString()
                               : ("<no Id registered> " + map.toString())));
     }
index f8d86d5..e6302fc 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.io.vamsas;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.VamsasAppDatastore;
@@ -97,7 +97,7 @@ public class Sequencefeature extends Rangetype
     DataSetAnnotations dsa = (DataSetAnnotations) vobj;
     if (dsa.getSeqRefCount() != 1)
     {
-      Cache.log.warn("Not binding " + dsa.getVorbaId()
+      Console.warn("Not binding " + dsa.getVorbaId()
               + " to Sequence Feature - has multiple dataset sequence references.");
       return;
     }
@@ -128,7 +128,7 @@ public class Sequencefeature extends Rangetype
     if (dsa.getSeqRefCount() != 1)
     {
       replaceJvObjMapping(feature, null);
-      Cache.log.warn(
+      Console.warn(
               "Binding of annotation to jalview feature has changed. Removing binding and recreating.");
       doSync(); // re-verify bindings.
     }
@@ -139,8 +139,7 @@ public class Sequencefeature extends Rangetype
       getDSAnnotationFromJalview(dsa, feature);
       if (oldref != dsa.hashCode())
       {
-        Cache.log
-                .debug("Updated dataset sequence annotation from feature.");
+        Console.debug("Updated dataset sequence annotation from feature.");
         addProvenance(dsa.getProvenance(), "modified");
       }
     }
@@ -156,7 +155,7 @@ public class Sequencefeature extends Rangetype
     {
       // conflicting update from document - we cannot map this feature anymore.
       replaceJvObjMapping(feature, null);
-      Cache.log.warn("annotation (" + dsa.getVorbaId()
+      Console.warn("annotation (" + dsa.getVorbaId()
               + " bound to jalview feature cannot be mapped. Removing binding, deleting feature, and deleting feature.");
       // - consider deleting the feature ?
       dsSeq.deleteFeature(feature);
@@ -198,7 +197,7 @@ public class Sequencefeature extends Rangetype
     vSeg.setInclusive(true);
     if (dsa.getSegCount() > 1)
     {
-      Cache.log.debug(
+      Console.debug(
               "About to destroy complex annotation in vamsas document mapped to sequence feature ("
                       + dsa.getVorbaId() + ")");
     }
index 0a582e5..5a172fe 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.vamsas;
 
+import jalview.bin.Console;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
@@ -99,13 +100,13 @@ public class Sequencemapping extends Rangetype
     }
     if (from != null && sequenceMapping.getLoc() != from)
     {
-      jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + from
+      Console.warn("Probable IMPLEMENTATION ERROR: " + from
               + " doesn't match the local mapping sequence.");
     }
     if (ds != null && sequenceMapping.is__stored_in_document()
             && sequenceMapping.getV_parent() != ds)
     {
-      jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + ds
+      Console.warn("Probable IMPLEMENTATION ERROR: " + ds
               + " doesn't match the parent of the bound sequence mapping object.");
     }
   }
@@ -153,7 +154,7 @@ public class Sequencemapping extends Rangetype
     SequenceType to = (SequenceType) getjv2vObj(jvto);
     if (to == null)
     {
-      jalview.bin.Cache.log.warn(
+      Console.warn(
               "FIXME NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object");
       return;
     }
@@ -184,7 +185,7 @@ public class Sequencemapping extends Rangetype
 
     if (!dnaToProt)
     {
-      jalview.bin.Cache.log.warn(
+      Console.warn(
               "Ignoring Mapping - don't support protein to protein mapping in vamsas document yet.");
       return;
     }
@@ -224,28 +225,26 @@ public class Sequencemapping extends Rangetype
     // mapping
     bindjvvobj(mjvmapping.getMap(), sequenceMapping);
 
-    jalview.bin.Cache.log.debug(
+    Console.debug(
             "Successfully created mapping " + sequenceMapping.getVorbaId());
   }
 
   // private void update(jalview.util.MapList mjvmapping,
   // SequenceMapping sequenceMapping)
   {
-    jalview.bin.Cache.log
-            .error("Not implemented: Jalview Update Alcodon Mapping:TODO!");
+    Console.error("Not implemented: Jalview Update Alcodon Mapping:TODO!");
   }
 
   private void update(SequenceMapping sequenceMapping,
           jalview.datamodel.Mapping mjvmapping)
   {
-    jalview.bin.Cache.log
-            .error("Not implemented: Update DBRef Mapping from Jalview");
+    Console.error("Not implemented: Update DBRef Mapping from Jalview");
   }
 
   private void update(jalview.datamodel.Mapping mjvmapping,
           SequenceMapping sequenceMapping)
   {
-    jalview.bin.Cache.log.error(
+    Console.error(
             "Not implemented: Jalview Update Sequence DBRef Mapping");
   }
 
@@ -282,7 +281,7 @@ public class Sequencemapping extends Rangetype
     }
     if (sdloc == null || sdmap == null)
     {
-      jalview.bin.Cache.log.info("Ignoring non sequence-sequence mapping");
+      Console.info("Ignoring non sequence-sequence mapping");
       return;
     }
     mobj = this.getvObj2jv(sdloc);
@@ -298,7 +297,7 @@ public class Sequencemapping extends Rangetype
     if (from == null || to == null)
     {
 
-      jalview.bin.Cache.log.error(
+      Console.error(
               "Probable Vamsas implementation error : unbound dataset sequences involved in a mapping are being parsed!");
       return;
     }
@@ -389,16 +388,16 @@ public class Sequencemapping extends Rangetype
   {
     if (from.getDBRefs() == null && to.getDBRefs() == null)
     {
-      if (jalview.bin.Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        jalview.bin.Cache.log.debug("Not matching conjugate refs for "
+        Console.debug("Not matching conjugate refs for "
                 + from.getName() + " and " + to.getName());
       }
       return;
     }
-    if (jalview.bin.Cache.log.isDebugEnabled())
+    if (Console.isDebugEnabled())
     {
-      jalview.bin.Cache.log.debug("Matching conjugate refs for "
+      Console.debug("Matching conjugate refs for "
               + from.getName() + " and " + to.getName());
     }
     List<DBRefEntry> fdb = from.getDBRefs();
@@ -422,7 +421,7 @@ public class Sequencemapping extends Rangetype
       boolean fmpnnl = (fmp != null);
       // if (fmpnnl && fmp.getTo()!=null)
       // {
-      // jalview.bin.Cache.log.debug("Not overwriting existing To reference in
+      // Cache.debug("Not overwriting existing To reference in
       // "+fe);
       // continue;
       // }
index 00e4fbc..1b7a8bf 100644 (file)
@@ -22,7 +22,7 @@ package jalview.io.vamsas;
 
 import jalview.analysis.TreeBuilder;
 import jalview.analysis.TreeModel;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.BinaryNode;
@@ -128,7 +128,7 @@ public class Tree extends DatastoreItem
       }
     } catch (Exception e)
     {
-      Cache.log.warn("Problems parsing treefile '"
+      Console.warn("Problems parsing treefile '"
               + tree.getNewick(0).getContent() + "'", e);
     }
   }
@@ -141,7 +141,7 @@ public class Tree extends DatastoreItem
   @Override
   public void conflict()
   {
-    Cache.log.info(
+    Console.info(
             "Update (with conflict) from vamsas document to alignment associated tree not implemented yet.");
   }
 
@@ -186,7 +186,7 @@ public class Tree extends DatastoreItem
      * idata[0] != null) { inputData = (AlignmentView) idata[0]; } ntree =
      * getNtree(); title = tree.getNewick(0).getTitle(); if (title == null ||
      * title.length() == 0) { title = tree.getTitle(); // hack!!!! } } catch
-     * (Exception e) { Cache.log.warn("Problems parsing treefile '" +
+     * (Exception e) { Cache.warn("Problems parsing treefile '" +
      * tree.getNewick(0).getContent() + "'", e); }
      */
     log.debug("Update the local tree in jalview from the document.");
@@ -214,7 +214,7 @@ public class Tree extends DatastoreItem
    */
   private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
   {
-    Cache.log.debug("Making Tree provenance for " + tp.getTitle());
+    Console.debug("Making Tree provenance for " + tp.getTitle());
     Provenance prov = new Provenance();
     prov.addEntry(new Entry());
     prov.getEntry(0).setAction("imported " + tp.getTitle());
@@ -259,7 +259,7 @@ public class Tree extends DatastoreItem
         vInput.addSeg(visSeg);
       }
     }
-    Cache.log.debug("Finished Tree provenance for " + tp.getTitle());
+    Console.debug("Finished Tree provenance for " + tp.getTitle());
     return prov;
   }
 
@@ -297,7 +297,7 @@ public class Tree extends DatastoreItem
     }
     if (alsq.size() < sequences.length)
     {
-      Cache.log.warn(
+      Console.warn(
               "Not recovered all alignment sequences for given set of input sequence CIGARS");
     }
     return alsq;
@@ -319,7 +319,7 @@ public class Tree extends DatastoreItem
 
     if (tp.getTree() == null)
     {
-      Cache.log.warn(
+      Console.warn(
               "Not updating SequenceTreeMap for " + tree.getVorbaId());
       return;
     }
@@ -532,7 +532,7 @@ public class Tree extends DatastoreItem
       {
         if (tp.getEntry(pe).getInputCount() > 1)
         {
-          Cache.log.warn(
+          Console.warn(
                   "Ignoring additional input spec in provenance entry "
                           + tp.getEntry(pe).toString());
         }
@@ -589,7 +589,7 @@ public class Tree extends DatastoreItem
           // bidirection alignments yet.
           if (to < se[1])
           {
-            Cache.log.warn("Ignoring invalid segment in InputData spec.");
+            Console.warn("Ignoring invalid segment in InputData spec.");
           }
           else
           {
@@ -612,7 +612,7 @@ public class Tree extends DatastoreItem
         return new Object[] { new AlignmentView(view), jal };
       }
     }
-    Cache.log.debug(
+    Console.debug(
             "Returning null for input data recovery from provenance.");
     return null;
   }
@@ -658,7 +658,7 @@ public class Tree extends DatastoreItem
       return true;
     } catch (Exception e)
     {
-      Cache.log.debug("Failed to parse newick tree string", e);
+      Console.debug("Failed to parse newick tree string", e);
     }
     return false;
   }
index f4ffc0c..29b3004 100644 (file)
  */
 package jalview.io.vcf;
 
-import jalview.analysis.Dna;
-import jalview.api.AlignViewControllerGuiI;
-import jalview.bin.Cache;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.GeneLociI;
-import jalview.datamodel.Mapping;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceI;
-import jalview.datamodel.features.FeatureAttributeType;
-import jalview.datamodel.features.FeatureSource;
-import jalview.datamodel.features.FeatureSources;
-import jalview.ext.ensembl.EnsemblMap;
-import jalview.ext.htsjdk.HtsContigDb;
-import jalview.ext.htsjdk.VCFReader;
-import jalview.io.gff.Gff3Helper;
-import jalview.io.gff.SequenceOntologyI;
-import jalview.util.MapList;
-import jalview.util.MappingUtils;
-import jalview.util.MessageManager;
-import jalview.util.StringUtils;
+import java.util.Locale;
 
 import java.io.File;
 import java.io.IOException;
@@ -67,6 +48,27 @@ import htsjdk.variant.vcf.VCFHeaderLine;
 import htsjdk.variant.vcf.VCFHeaderLineCount;
 import htsjdk.variant.vcf.VCFHeaderLineType;
 import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import jalview.analysis.Dna;
+import jalview.api.AlignViewControllerGuiI;
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GeneLociI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureAttributeType;
+import jalview.datamodel.features.FeatureSource;
+import jalview.datamodel.features.FeatureSources;
+import jalview.ext.ensembl.EnsemblMap;
+import jalview.ext.htsjdk.HtsContigDb;
+import jalview.ext.htsjdk.VCFReader;
+import jalview.io.gff.Gff3Helper;
+import jalview.io.gff.SequenceOntologyI;
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+import jalview.util.StringUtils;
 
 /**
  * A class to read VCF data (using the htsjdk) and add variants as sequence
@@ -313,7 +315,7 @@ public class VCFLoader
     VCFHeaderLine headerLine = header.getOtherHeaderLine(VCFHeader.REFERENCE_KEY);
     if (headerLine == null)
     {
-      Cache.log.error("VCF reference header not found");
+      Console.error("VCF reference header not found");
       return null;
     }
     String ref = headerLine.getValue();
@@ -335,7 +337,7 @@ public class VCFLoader
     }
     else
     {
-      Cache.log.error("VCF reference not found: " + ref);
+      Console.error("VCF reference not found: " + ref);
     }
 
     return seq;
@@ -428,11 +430,11 @@ public class VCFLoader
   {
     if (reference == null)
     {
-      Cache.log.error("No VCF ##reference found, defaulting to "
+      Console.error("No VCF ##reference found, defaulting to "
               + DEFAULT_REFERENCE + ":" + DEFAULT_SPECIES);
       reference = DEFAULT_REFERENCE; // default to GRCh37 if not specified
     }
-    reference = reference.toLowerCase();
+    reference = reference.toLowerCase(Locale.ROOT);
 
     /*
      * for a non-human species, or other assembly identifier,
@@ -447,7 +449,7 @@ public class VCFLoader
       String[] tokens = token.split("=");
       if (tokens.length == 2)
       {
-        if (reference.contains(tokens[0].trim().toLowerCase()))
+        if (reference.contains(tokens[0].trim().toLowerCase(Locale.ROOT)))
         {
           vcfAssembly = tokens[1].trim();
           break;
@@ -464,7 +466,7 @@ public class VCFLoader
         String[] tokens = token.split("=");
         if (tokens.length == 2)
         {
-          if (reference.contains(tokens[0].trim().toLowerCase()))
+          if (reference.contains(tokens[0].trim().toLowerCase(Locale.ROOT)))
           {
             vcfSpecies = tokens[1].trim();
             break;
@@ -569,7 +571,7 @@ public class VCFLoader
   {
     for (Pattern p : filters)
     {
-      if (p.matcher(id.toUpperCase()).matches())
+      if (p.matcher(id.toUpperCase(Locale.ROOT)).matches())
       {
         return true;
       }
@@ -663,7 +665,7 @@ public class VCFLoader
     {
       try
       {
-      patterns.add(Pattern.compile(token.toUpperCase()));
+      patterns.add(Pattern.compile(token.toUpperCase(Locale.ROOT)));
       } catch (PatternSyntaxException e)
       {
         System.err.println("Invalid pattern ignored: " + token);
@@ -674,7 +676,6 @@ public class VCFLoader
 
   /**
    * Transfers VCF features to sequences to which this sequence has a mapping.
-   * If the mapping is 3:1, computes peptide variants from nucleotide variants.
    * 
    * @param seq
    */
@@ -775,7 +776,7 @@ public class VCFLoader
     GeneLociI seqCoords = seq.getGeneLoci();
     if (seqCoords == null)
     {
-      Cache.log.warn(String.format(
+      Console.warn(String.format(
               "Can't query VCF for %s as chromosome coordinates not known",
               seq.getName()));
       return null;
@@ -790,7 +791,7 @@ public class VCFLoader
     // returned with the Ensembl sequence; todo: support aliases?
     if (!vcfSpecies.equalsIgnoreCase(species))
     {
-      Cache.log.warn("No VCF loaded to " + seq.getName()
+      Console.warn("No VCF loaded to " + seq.getName()
               + " as species not matched");
       return null;
     }
@@ -820,7 +821,7 @@ public class VCFLoader
               vcfAssembly);
       if (newRange == null)
       {
-        Cache.log.error(
+        Console.error(
                 String.format("Failed to map %s:%s:%s:%d:%d to %s", species,
                         chromosome, seqRef, range[0], range[1],
                         vcfAssembly));
@@ -897,12 +898,19 @@ public class VCFLoader
           int[] featureRange = map.map.locateInFrom(variant.getStart(),
                   variant.getEnd());
 
+          /*
+           * only take features whose range is fully mappable to sequence positions
+           */
           if (featureRange != null)
           {
             int featureStart = Math.min(featureRange[0], featureRange[1]);
             int featureEnd = Math.max(featureRange[0], featureRange[1]);
-            count += addAlleleFeatures(seq, variant, featureStart,
-                    featureEnd, forwardStrand);
+            if (featureEnd - featureStart == variant.getEnd()
+                    - variant.getStart())
+            {
+              count += addAlleleFeatures(seq, variant, featureStart,
+                      featureEnd, forwardStrand);
+            }
           }
         }
         variants.close();
@@ -913,7 +921,7 @@ public class VCFLoader
          */
         String msg = String.format("Error reading VCF for %s:%d-%d: %s ",
                 map.chromosome, vcfStart, vcfEnd,e.getLocalizedMessage());
-        Cache.log.error(msg);
+        Console.error(msg);
       }
     }
 
@@ -1028,7 +1036,7 @@ public class VCFLoader
      */
     String consequence = getConsequenceForAlleleAndFeature(variant, CSQ_FIELD,
             altAlleleIndex, csqAlleleFieldIndex,
-            csqAlleleNumberFieldIndex, seq.getName().toLowerCase(),
+            csqAlleleNumberFieldIndex, seq.getName().toLowerCase(Locale.ROOT),
             csqFeatureFieldIndex);
 
     /*
@@ -1221,7 +1229,7 @@ public class VCFLoader
       {
         String featureIdentifier = csqFields[featureFieldIndex];
         if (featureIdentifier.length() > 4
-                && seqName.indexOf(featureIdentifier.toLowerCase()) > -1)
+                && seqName.indexOf(featureIdentifier.toLowerCase(Locale.ROOT)) > -1)
         {
           /*
            * feature (transcript) matched - now check for allele match
@@ -1375,7 +1383,7 @@ public class VCFLoader
     VCFInfoHeaderLine infoHeader = header.getInfoHeaderLine(infoId);
     if (infoHeader == null)
     {
-      Cache.log.error("Field " + infoId + " has no INFO header");
+      Console.error("Field " + infoId + " has no INFO header");
       return false;
     }
     VCFHeaderLineType infoType = infoHeader.getType();
@@ -1416,7 +1424,7 @@ public class VCFLoader
     if (!badData.contains(token))
     {
       badData.add(token);
-      Cache.log.error(String.format("Invalid VCF data at %s:%d %s=%s",
+      Console.error(String.format("Invalid VCF data at %s:%d %s=%s",
               variant.getContig(), variant.getStart(), infoId, value));
     }
   }
index 6a4d0f8..16b57a4 100644 (file)
@@ -44,7 +44,7 @@ public class MouseOverListener extends JSFunctionExec
     if (seq != last || i != index)
     {
       // this should really be a trace message.
-      // Cache.log.debug("Mouse over " + v.getId() + " bound to "
+      // Cache.debug("Mouse over " + v.getId() + " bound to "
       // + seq + " at " + index);
       last = seq;
       i = index;
diff --git a/src/jalview/javascript/log4j/Appender.java b/src/jalview/javascript/log4j/Appender.java
deleted file mode 100644 (file)
index 1b2b676..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-package jalview.javascript.log4j;
-
-import jalview.javascript.log4j.spi.LoggingEvent;
-
-public abstract class Appender
-{
-  public abstract void append(LoggingEvent loggingEvent);
-
-}
diff --git a/src/jalview/javascript/log4j/ConsoleAppender.java b/src/jalview/javascript/log4j/ConsoleAppender.java
deleted file mode 100644 (file)
index f1aca45..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-package jalview.javascript.log4j;
-
-import jalview.javascript.log4j.spi.LoggingEvent;
-
-public class ConsoleAppender
-{
-
-  private String name;
-
-  private Layout layout;
-
-
-  public ConsoleAppender()
-  {
-  }
-
-  public ConsoleAppender(Layout layout, String name)
-  {
-    this.layout = layout;
-    this.name = name;
-  }
-
-  public void setLayout(Layout layout)
-  {
-    this.layout = layout;
-  }
-
-  public void setName(String name)
-  {
-    this.name = name;
-  }
-
-  public void append(LoggingEvent event)
-  {
-
-    System.out
-            .println(event.getLevel() + ": " + event.getRenderedMessage());
-
-  }
-
-}
diff --git a/src/jalview/javascript/log4j/Layout.java b/src/jalview/javascript/log4j/Layout.java
deleted file mode 100644 (file)
index ea79e1b..0000000
+++ /dev/null
@@ -1,86 +0,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.
- */
-package jalview.javascript.log4j;
-
-import jalview.javascript.log4j.spi.LoggingEvent;
-import jalview.javascript.log4j.spi.OptionHandler;
-
-import org.apache.log4j.PatternLayout;
-import org.apache.log4j.TTCCLayout;
-
-public abstract class Layout implements OptionHandler
-{
-
-  // Note that the line.separator property can be looked up even by
-  // applets.
-  public final static String LINE_SEP = System
-          .getProperty("line.separator");
-
-  public final static int LINE_SEP_LEN = LINE_SEP.length();
-
-  /**
-   * Implement this method to create your own layout format.
-   */
-  abstract public String format(LoggingEvent event);
-
-  /**
-   * Returns the content type output by this layout. The base class returns
-   * "text/plain".
-   */
-  public String getContentType()
-  {
-    return "text/plain";
-  }
-
-  /**
-   * Returns the header for the layout format. The base class returns
-   * <code>null</code>.
-   */
-  public String getHeader()
-  {
-    return null;
-  }
-
-  /**
-   * Returns the footer for the layout format. The base class returns
-   * <code>null</code>.
-   */
-  public String getFooter()
-  {
-    return null;
-  }
-
-  /**
-   * If the layout handles the throwable object contained within
-   * {@link LoggingEvent}, then the layout should return <code>false</code>.
-   * Otherwise, if the layout ignores throwable object, then the layout should
-   * return <code>true</code>. If ignoresThrowable is true, the appender is
-   * responsible for rendering the throwable.
-   * <p>
-   * The {@link SimpleLayout}, {@link TTCCLayout}, {@link PatternLayout} all
-   * return <code>true</code>. The {@link org.apache.log4j.xml.XMLLayout}
-   * returns <code>false</code>.
-   * 
-   * @since 0.8.4
-   */
-  abstract public boolean ignoresThrowable();
-
-}
diff --git a/src/jalview/javascript/log4j/Level.java b/src/jalview/javascript/log4j/Level.java
deleted file mode 100644 (file)
index 5691a47..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-package jalview.javascript.log4j;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.ObjectStreamException;
-import java.io.Serializable;
-
-/**
- * Defines the minimum set of levels recognized by the system, that is
- * <code>OFF</code>, <code>FATAL</code>, <code>ERROR</code>, <code>WARN</code>,
- * <code>INFO</code>, <code>DEBUG</code> and <code>ALL</code>.
- * 
- * <p>
- * The <code>Level</code> class may be subclassed to define a larger level set.
- * </p>
- * 
- * @author Ceki G&uuml;lc&uuml;
- */
-public class Level extends Priority implements Serializable
-{
-
-  private static final String ALL_NAME = "ALL";
-
-  private static final String TRACE_NAME = "TRACE";
-
-  private static final String DEBUG_NAME = "DEBUG";
-
-  private static final String INFO_NAME = "INFO";
-
-  private static final String WARN_NAME = "WARN";
-
-  private static final String ERROR_NAME = "ERROR";
-
-  private static final String FATAL_NAME = "FATAL";
-
-  private static final String OFF_NAME = "OFF";
-
-  /**
-   * TRACE level integer value.
-   * 
-   * @since 1.2.12
-   */
-  public static final int TRACE_INT = 5000;
-
-  /**
-   * The <code>OFF</code> has the highest possible rank and is intended to turn
-   * off logging.
-   */
-  final static public Level OFF = new Level(OFF_INT, OFF_NAME, 0);
-
-  /**
-   * The <code>FATAL</code> level designates very severe error events that will
-   * presumably lead the application to abort.
-   */
-  final static public Level FATAL = new Level(FATAL_INT, FATAL_NAME, 0);
-
-  /**
-   * The <code>ERROR</code> level designates error events that might still allow
-   * the application to continue running.
-   */
-  final static public Level ERROR = new Level(ERROR_INT, ERROR_NAME, 3);
-
-  /**
-   * The <code>WARN</code> level designates potentially harmful situations.
-   */
-  final static public Level WARN = new Level(WARN_INT, WARN_NAME, 4);
-
-  /**
-   * The <code>INFO</code> level designates informational messages that
-   * highlight the progress of the application at coarse-grained level.
-   */
-  final static public Level INFO = new Level(INFO_INT, INFO_NAME, 6);
-
-  /**
-   * The <code>DEBUG</code> Level designates fine-grained informational events
-   * that are most useful to debug an application.
-   */
-  final static public Level DEBUG = new Level(DEBUG_INT, DEBUG_NAME, 7);
-
-  /**
-   * The <code>TRACE</code> Level designates finer-grained informational events
-   * than the <code>DEBUG</code level.
-   * 
-   * @since 1.2.12
-   */
-  public static final Level TRACE = new Level(TRACE_INT, TRACE_NAME, 7);
-
-  /**
-   * The <code>ALL</code> has the lowest possible rank and is intended to turn
-   * on all logging.
-   */
-  final static public Level ALL = new Level(ALL_INT, ALL_NAME, 7);
-
-  /**
-   * Serialization version id.
-   */
-  static final long serialVersionUID = 3491141966387921974L;
-
-  /**
-   * Instantiate a Level object.
-   */
-  protected Level(int level, String levelStr, int syslogEquivalent)
-  {
-    super(level, levelStr, syslogEquivalent);
-  }
-
-  /**
-   * Convert the string passed as argument to a level. If the conversion fails,
-   * then this method returns {@link #DEBUG}.
-   */
-  public static Level toLevel(String sArg)
-  {
-    return toLevel(sArg, Level.DEBUG);
-  }
-
-  /**
-   * Convert an integer passed as argument to a level. If the conversion fails,
-   * then this method returns {@link #DEBUG}.
-   */
-  public static Level toLevel(int val)
-  {
-    return toLevel(val, Level.DEBUG);
-  }
-
-  /**
-   * Convert an integer passed as argument to a level. If the conversion fails,
-   * then this method returns the specified default.
-   */
-  public static Level toLevel(int val, Level defaultLevel)
-  {
-    switch (val)
-    {
-    case ALL_INT:
-      return ALL;
-    case DEBUG_INT:
-      return Level.DEBUG;
-    case INFO_INT:
-      return Level.INFO;
-    case WARN_INT:
-      return Level.WARN;
-    case ERROR_INT:
-      return Level.ERROR;
-    case FATAL_INT:
-      return Level.FATAL;
-    case OFF_INT:
-      return OFF;
-    case TRACE_INT:
-      return Level.TRACE;
-    default:
-      return defaultLevel;
-    }
-  }
-
-  /**
-   * Convert the string passed as argument to a level. If the conversion fails,
-   * then this method returns the value of <code>defaultLevel</code>.
-   */
-  public static Level toLevel(String sArg, Level defaultLevel)
-  {
-    if (sArg == null)
-    {
-      return defaultLevel;
-    }
-    String s = sArg.toUpperCase();
-
-    if (s.equals(ALL_NAME))
-    {
-      return Level.ALL;
-    }
-    if (s.equals(DEBUG_NAME))
-    {
-      return Level.DEBUG;
-    }
-    if (s.equals(INFO_NAME))
-    {
-      return Level.INFO;
-    }
-    if (s.equals(WARN_NAME))
-    {
-      return Level.WARN;
-    }
-    if (s.equals(ERROR_NAME))
-    {
-      return Level.ERROR;
-    }
-    if (s.equals(FATAL_NAME))
-    {
-      return Level.FATAL;
-    }
-    if (s.equals(OFF_NAME))
-    {
-      return Level.OFF;
-    }
-    if (s.equals(TRACE_NAME))
-    {
-      return Level.TRACE;
-    }
-    //
-    // For Turkish i problem, see bug 40937
-    //
-    if (s.equals("\u0130NFO"))
-    {
-      return Level.INFO;
-    }
-    return defaultLevel;
-  }
-
-  /**
-   * Custom deserialization of Level.
-   * 
-   * @param s
-   *          serialization stream.
-   * @throws IOException
-   *           if IO exception.
-   * @throws ClassNotFoundException
-   *           if class not found.
-   */
-  private void readObject(final ObjectInputStream s)
-          throws IOException, ClassNotFoundException
-  {
-    s.defaultReadObject();
-    level = s.readInt();
-    syslogEquivalent = s.readInt();
-    levelStr = s.readUTF();
-    if (levelStr == null)
-    {
-      levelStr = "";
-    }
-  }
-
-  /**
-   * Serialize level.
-   * 
-   * @param s
-   *          serialization stream.
-   * @throws IOException
-   *           if exception during serialization.
-   */
-  private void writeObject(final ObjectOutputStream s) throws IOException
-  {
-    s.defaultWriteObject();
-    s.writeInt(level);
-    s.writeInt(syslogEquivalent);
-    s.writeUTF(levelStr);
-  }
-
-  /**
-   * Resolved deserialized level to one of the stock instances. May be overriden
-   * in classes derived from Level.
-   * 
-   * @return resolved object.
-   * @throws ObjectStreamException
-   *           if exception during resolution.
-   */
-  private Object readResolve() throws ObjectStreamException
-  {
-    //
-    // if the deserizalized object is exactly an instance of Level
-    //
-    if (getClass() == Level.class)
-    {
-      return toLevel(level);
-    }
-    //
-    // extension of Level can't substitute stock item
-    //
-    return this;
-  }
-
-}
diff --git a/src/jalview/javascript/log4j/Logger.java b/src/jalview/javascript/log4j/Logger.java
deleted file mode 100644 (file)
index bb7eb34..0000000
+++ /dev/null
@@ -1,194 +0,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.
- */
-package jalview.javascript.log4j;
-
-import jalview.javascript.log4j.spi.LoggingEvent;
-
-import java.util.Hashtable;
-import java.util.Map;
-
-public class Logger
-{
-
-  private static Map<String, Logger> registry;
-
-  private String name;
-
-  private Level level;
-
-  private boolean enabled = true;
-
-  private boolean isEnabled;
-
-  private Appender appender;
-
-  private Logger(String name)
-  {
-    this.name = name;
-  }
-
-  public static Logger getLogger(String name)
-  {
-    if (registry == null)
-    {
-      registry = new Hashtable<>();
-      getLogger("root");
-    }
-    Logger logger = registry.get(name);
-    if (logger == null)
-    {
-      registry.put(name, logger = new Logger(name));
-      logger.setLevel(Level.INFO);
-    }
-    return logger;
-  }
-
-  public static Logger getRootLogger()
-  {
-    return getLogger("root");
-  }
-
-  public void setLevel(Level l)
-  {
-    this.level = l;
-  }
-
-  public void addAppender(Appender appender)
-  {
-    this.appender = appender;
-  }
-
-  public boolean isDebugEnabled()
-  {
-    return isEnabled;
-  }
-
-  public void debug(Object o)
-  {
-    debug(o, null);
-  }
-
-  public void debug(Object o, Throwable e)
-  {
-    switch (level.level)
-    {
-    case Priority.FATAL_INT:
-    case Priority.ERROR_INT:
-    case Priority.WARN_INT:
-    case Priority.INFO_INT:
-    case Priority.DEBUG_INT:
-      log(o, e);
-      break;
-    }
-  }
-
-  public void info(Object o)
-  {
-    info(o, null);
-  }
-
-  public void info(Object o, Throwable e)
-  {
-    switch (level.level)
-    {
-    case Priority.FATAL_INT:
-    case Priority.ERROR_INT:
-    case Priority.WARN_INT:
-    case Priority.INFO_INT:
-      log(o, e);
-      break;
-    }
-
-  }
-
-  public void warn(Object o)
-  {
-    warn(o, null);
-  }
-
-  public void warn(Object o, Throwable e)
-  {
-    switch (level.level)
-    {
-    case Priority.FATAL_INT:
-    case Priority.ERROR_INT:
-    case Priority.WARN_INT:
-      log(o, e);
-      break;
-    }
-
-  }
-
-  public void error(Object o)
-  {
-    error(o, null);
-  }
-
-  public void error(Object o, Throwable e)
-  {
-    switch (level.level)
-    {
-    case Priority.FATAL_INT:
-    case Priority.ERROR_INT:
-      log(o, e);
-      break;
-    }
-
-  }
-
-  private void log(Object s, Throwable e)
-  {
-    switch (level.level)
-    {
-    case Priority.ERROR_INT:
-      if (appender == null)
-      {
-        System.err.println(s);
-        return;
-      }
-      break;
-    case Priority.WARN_INT:
-      if (appender == null)
-      {
-        System.err.println(s);
-        return;
-      }
-      break;
-    case Priority.INFO_INT:
-      if (appender == null)
-      {
-        System.out.println(s);
-        return;
-      }
-      break;
-    case Priority.DEBUG_INT:
-      if (appender == null)
-      {
-        System.out.println(s);
-        return;
-      }
-      break;
-    }
-    e.printStackTrace();
-    appender.append(new LoggingEvent(this, s.toString(), level));
-  }
-
-}
diff --git a/src/jalview/javascript/log4j/Priority.java b/src/jalview/javascript/log4j/Priority.java
deleted file mode 100644 (file)
index 2ace1eb..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-// Contributors:  Kitching Simon <Simon.Kitching@orange.ch>
-
-package jalview.javascript.log4j;
-
-/**
-   <font color="#AA4444">Refrain from using this class directly, use
-   the {@link Level} class instead</font>.
-
-   @author Ceki G&uuml;lc&uuml; */
-public class Priority {
-
-  transient int level;
-  transient String levelStr;
-  transient int syslogEquivalent;
-
-  public final static int OFF_INT = Integer.MAX_VALUE;
-  public final static int FATAL_INT = 50000;
-  public final static int ERROR_INT = 40000;
-  public final static int WARN_INT  = 30000;
-  public final static int INFO_INT  = 20000;
-  public final static int DEBUG_INT = 10000;
-    //public final static int FINE_INT = DEBUG_INT;
-  public final static int ALL_INT = Integer.MIN_VALUE;
-
-  // too twisted for J2S -- Level class initializer initializes Priority, which
-  // creates a
-  // new Level before Priority is indicated to be a superclass of Level.
-  /**
-   * @deprecated Use {@link Level#FATAL} instead.
-   */
-  @Deprecated
-  final static public Priority FATAL = null;// new Level(FATAL_INT, "FATAL", 0);
-
-  /**
-   * @deprecated Use {@link Level#ERROR} instead.
-   */
-  @Deprecated
-  final static public Priority ERROR = null;// new Level(ERROR_INT, "ERROR", 3);
-
-  /**
-   * @deprecated Use {@link Level#WARN} instead.
-   */
-  @Deprecated
-  final static public Priority WARN = null;// new Level(WARN_INT, "WARN", 4);
-
-  /**
-   * @deprecated Use {@link Level#INFO} instead.
-   */
-  @Deprecated
-  final static public Priority INFO = null;// new Level(INFO_INT, "INFO", 6);
-
-  /**
-   * @deprecated Use {@link Level#DEBUG} instead.
-   */
-  @Deprecated
-  final static public Priority DEBUG = null;// new Level(DEBUG_INT, "DEBUG", 7);
-
-  /**
-    * Default constructor for deserialization.
-    */
-  protected Priority() {
-      level = DEBUG_INT;
-      levelStr = "DEBUG";
-      syslogEquivalent = 7;
-  }
-
-  /**
-     Instantiate a level object.
-   */
-  protected
-  Priority(int level, String levelStr, int syslogEquivalent) {
-    this.level = level;
-    this.levelStr = levelStr;
-    this.syslogEquivalent = syslogEquivalent;
-  }
-
-  /**
-     Two priorities are equal if their level fields are equal.
-     @since 1.2
-   */
-  @Override
-  public
-  boolean equals(Object o) {
-    if(o instanceof Priority) {
-      Priority r = (Priority) o;
-      return (this.level == r.level);
-    } else {
-      return false;
-    }
-  }
-
-  /**
-     Return the syslog equivalent of this priority as an integer.
-   */
-  public
-  final
-  int getSyslogEquivalent() {
-    return syslogEquivalent;
-  }
-
-
-   
-  /**
-     Returns <code>true</code> if this level has a higher or equal
-     level than the level passed as argument, <code>false</code>
-     otherwise.  
-     
-     <p>You should think twice before overriding the default
-     implementation of <code>isGreaterOrEqual</code> method.
-
-  */
-  public
-  boolean isGreaterOrEqual(Priority r) {
-    return level >= r.level;
-  }
-
-  // /**
-  // Return all possible priorities as an array of Level objects in
-  // descending order.
-  //
-  // @deprecated This method will be removed with no replacement.
-  // */
-  // public
-  // static
-  // Priority[] getAllPossiblePriorities() {
-  // return new Priority[] {Priority.FATAL, Priority.ERROR, Level.WARN,
-  // Priority.INFO, Priority.DEBUG};
-  // }
-
-
-  /**
-     Returns the string representation of this priority.
-   */
-  @Override
-  final
-  public
-  String toString() {
-    return levelStr;
-  }
-
-  /**
-     Returns the integer representation of this level.
-   */
-  public
-  final
-  int toInt() {
-    return level;
-  }
-
-  // /**
-  // * @deprecated Please use the {@link Level#toLevel(String)} method instead.
-  // */
-  // public
-  // static
-  // Priority toPriority(String sArg) {
-  // return Level.toLevel(sArg);
-  // }
-
-  // /**
-  // * @deprecated Please use the {@link Level#toLevel(int)} method instead.
-  // */
-  // public
-  // static
-  // Priority toPriority(int val) {
-  // return toPriority(val, Priority.DEBUG);
-  // }
-
-  // /**
-  // * @deprecated Please use the {@link Level#toLevel(int, Level)} method
-  // instead.
-  // */
-  // public
-  // static
-  // Priority toPriority(int val, Priority defaultPriority) {
-  // return Level.toLevel(val, (Level) defaultPriority);
-  // }
-  //
-  // /**
-  // * @deprecated Please use the {@link Level#toLevel(String, Level)} method
-  // instead.
-  // */
-  // public
-  // static
-  // Priority toPriority(String sArg, Priority defaultPriority) {
-  // return Level.toLevel(sArg, (Level) defaultPriority);
-  // }
-}
diff --git a/src/jalview/javascript/log4j/SimpleLayout.java b/src/jalview/javascript/log4j/SimpleLayout.java
deleted file mode 100644 (file)
index 9e5cbba..0000000
+++ /dev/null
@@ -1,55 +0,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.
- */
-package jalview.javascript.log4j;
-
-import jalview.javascript.log4j.spi.LoggingEvent;
-
-public class SimpleLayout extends Layout
-{
-
-  StringBuffer sbuf = new StringBuffer(128);
-
-  @Override
-  public void activateOptions()
-  {
-    // TODO Auto-generated method stub
-
-  }
-
-  @Override
-  public String format(LoggingEvent event)
-  {
-
-    sbuf.setLength(0);
-    sbuf.append(event.getLevel().toString());
-    sbuf.append(" - ");
-    sbuf.append(event.getRenderedMessage());
-    sbuf.append(LINE_SEP);
-    return sbuf.toString();
-  }
-  @Override
-  public boolean ignoresThrowable()
-  {
-    // TODO Auto-generated method stub
-    return false;
-  }
-
-}
diff --git a/src/jalview/javascript/log4j/WriterAppender.java b/src/jalview/javascript/log4j/WriterAppender.java
deleted file mode 100644 (file)
index 1a015f2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 jalview.javascript.log4j;
-
-public abstract class WriterAppender extends Appender
-{
-
-}
diff --git a/src/jalview/javascript/log4j/spi/LoggingEvent.java b/src/jalview/javascript/log4j/spi/LoggingEvent.java
deleted file mode 100644 (file)
index 669ae52..0000000
+++ /dev/null
@@ -1,51 +0,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.
- */
-package jalview.javascript.log4j.spi;
-
-import jalview.javascript.log4j.Logger;
-
-public class LoggingEvent
-{
-
-  private Object level;
-
-  private String msg;
-
-  private Logger logger;
-
-  public LoggingEvent(Logger logger, String level, Object message)
-  {
-    this.logger = logger;
-    this.level = level;
-    this.msg = message.toString();
-
-  }
-
-  public Object getLevel()
-  {
-    return level;
-  }
-
-  public String getRenderedMessage()
-  {
-    return msg;
-  }
-}
diff --git a/src/jalview/javascript/log4j/spi/OptionHandler.java b/src/jalview/javascript/log4j/spi/OptionHandler.java
deleted file mode 100644 (file)
index 9cd0f01..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package jalview.javascript.log4j.spi;
-
-public interface OptionHandler
-{
-
-  void activateOptions();
-
-}
diff --git a/src/jalview/jbgui/FilterOption.java b/src/jalview/jbgui/FilterOption.java
new file mode 100644 (file)
index 0000000..57a1a42
--- /dev/null
@@ -0,0 +1,119 @@
+package jalview.jbgui;
+
+import jalview.gui.structurechooser.StructureChooserQuerySource;
+import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
+
+/**
+ * This inner class provides the data model for the structure filter combo-box
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public class FilterOption
+{
+  private String name;
+
+  private String value;
+
+  private String view;
+
+  private boolean addSeparatorAfter;
+
+  private StructureChooserQuerySource querySource;
+
+  /**
+   * Model for structure filter option
+   * 
+   * @param name
+   *          - the name of the Option
+   * @param value
+   *          - the value of the option
+   * @param view
+   *          - the category of the filter option
+   * @param addSeparatorAfter
+   *          - if true, a horizontal separator is rendered immediately after
+   *          this filter option, otherwise
+   * @param structureChooserQuerySource
+   *          - the query source that actions this filter
+   */
+  public FilterOption(String name, String value, String view,
+          boolean addSeparatorAfter,
+          StructureChooserQuerySource structureChooserQuerySource)
+  {
+    this.name = name;
+    this.value = value;
+    this.view = view;
+    this.querySource = structureChooserQuerySource;
+    this.addSeparatorAfter = addSeparatorAfter;
+  }
+
+  public String getName()
+  {
+    return name;
+  }
+
+  public void setName(String name)
+  {
+    this.name = name;
+  }
+
+  public String getValue()
+  {
+    return value;
+  }
+
+  public void setValue(String value)
+  {
+    this.value = value;
+  }
+
+  public String getView()
+  {
+    return view;
+  }
+
+  public void setView(String view)
+  {
+    this.view = view;
+  }
+
+  @Override
+  public String toString()
+  {
+    return this.name;
+  }
+
+  public boolean isAddSeparatorAfter()
+  {
+    return addSeparatorAfter;
+  }
+
+  public void setAddSeparatorAfter(boolean addSeparatorAfter)
+  {
+    this.addSeparatorAfter = addSeparatorAfter;
+  }
+
+  public StructureChooserQuerySource getQuerySource()
+  {
+    return querySource;
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (obj instanceof FilterOption) {
+      FilterOption o=(FilterOption) obj;
+      return o.name.equals(name) && o.querySource==querySource && o.value.equals(value) && o.view==view;
+    } else {
+      return super.equals(obj);
+    }
+  }
+
+  @Override
+  public int hashCode()
+  {
+    return ("" + name + ":" + value).hashCode()
+            + (view != null ? view.hashCode() : 0)
+            + (querySource != null ? querySource.hashCode() : 0);
+  }
+}
\ No newline at end of file
index 6685c67..6aaba84 100755 (executable)
@@ -1063,7 +1063,7 @@ public class GAlignFrame extends JInternalFrame
     });
     seqLimits.setText(
             MessageManager.getString("label.show_sequence_limits"));
-    seqLimits.setState(jalview.bin.Cache.getDefault("SHOW_JVSUFFIX", true));
+    seqLimits.setState(Cache.getDefault("SHOW_JVSUFFIX", true));
     seqLimits.addActionListener(new ActionListener()
     {
       @Override
@@ -1214,7 +1214,7 @@ public class GAlignFrame extends JInternalFrame
 
     padGapsMenuitem.setText(MessageManager.getString("label.pad_gaps"));
     padGapsMenuitem
-            .setState(jalview.bin.Cache.getDefault("PAD_GAPS", false));
+            .setState(Cache.getDefault("PAD_GAPS", false));
     padGapsMenuitem.addActionListener(new ActionListener()
     {
       @Override
@@ -1358,7 +1358,7 @@ public class GAlignFrame extends JInternalFrame
     autoCalculate.setText(
             MessageManager.getString("label.autocalculate_consensus"));
     autoCalculate.setState(
-            jalview.bin.Cache.getDefault("AUTO_CALC_CONSENSUS", true));
+            Cache.getDefault("AUTO_CALC_CONSENSUS", true));
     autoCalculate.addActionListener(new ActionListener()
     {
       @Override
@@ -1372,7 +1372,7 @@ public class GAlignFrame extends JInternalFrame
     sortByTree.setToolTipText("<html>" + MessageManager.getString(
             "label.enable_automatically_sort_alignment_when_open_new_tree"));
     sortByTree
-            .setState(jalview.bin.Cache.getDefault("SORT_BY_TREE", false));
+            .setState(Cache.getDefault("SORT_BY_TREE", false));
     sortByTree.addActionListener(new ActionListener()
     {
       @Override
index 1a4a44b..d281c8d 100755 (executable)
@@ -43,6 +43,7 @@ import java.util.List;
 
 import javax.swing.AbstractCellEditor;
 import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.DefaultListCellRenderer;
 import javax.swing.JButton;
@@ -54,6 +55,7 @@ import javax.swing.JPanel;
 import javax.swing.JPasswordField;
 import javax.swing.JRadioButton;
 import javax.swing.JScrollPane;
+import javax.swing.JSlider;
 import javax.swing.JSpinner;
 import javax.swing.JTabbedPane;
 import javax.swing.JTable;
@@ -75,6 +77,8 @@ import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.bin.MemorySetting;
 import jalview.fts.core.FTSDataColumnPreferences;
 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
 import jalview.fts.service.pdb.PDBFTSRestClient;
@@ -89,6 +93,7 @@ import jalview.io.BackupFilesPresetEntry;
 import jalview.io.IntKeyStringValueEntry;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.StringUtils;
 
 /**
  * Base class for the Preferences panel.
@@ -175,8 +180,6 @@ public class GPreferences extends JPanel
 
   protected JCheckBox structFromPdb = new JCheckBox();
 
-  protected JCheckBox useRnaView = new JCheckBox();
-
   protected JCheckBox addSecondaryStructure = new JCheckBox();
 
   protected JCheckBox addTempFactor = new JCheckBox();
@@ -381,6 +384,30 @@ public class GPreferences extends JPanel
 
   private JLabel messageLabel = new JLabel("", JLabel.CENTER);
 
+  /*
+   * Startup tab components
+   */
+
+  protected JCheckBox customiseMemorySetting = new JCheckBox();
+
+  protected JLabel exampleMemoryLabel = new JLabel();
+
+  protected JTextArea exampleMemoryMessageTextArea = new JTextArea();
+
+  protected JLabel maxMemoryLabel = new JLabel();
+
+  protected JLabel jvmMemoryPercentLabel = new JLabel();
+
+  protected JSlider jvmMemoryPercentSlider = new JSlider();
+
+  protected JLabel jvmMemoryPercentDisplay = new JLabel();
+
+  protected JLabel jvmMemoryMaxLabel = new JLabel();
+
+  protected JTextField jvmMemoryMaxTextField = new JTextField(null, 8);
+
+  protected JComboBox<Object> lafCombo = new JComboBox<>();
+
   /**
    * Creates a new GPreferences object.
    */
@@ -442,6 +469,9 @@ public class GPreferences extends JPanel
     tabbedPane.add(initEditingTab(),
             MessageManager.getString("label.editing"));
 
+    tabbedPane.add(initStartupTab(),
+            MessageManager.getString("label.startup"));
+
     /*
      * See WsPreferences for the real work of configuring this tab.
      */
@@ -510,9 +540,12 @@ public class GPreferences extends JPanel
     }
   }
 
-  public final static int CONNECTIONS_TAB = 5;
+  public static enum TabRef
+  {
+    CONNECTIONS_TAB, STRUCTURE_TAB
+  };
 
-  public void selectTab(int selectTab)
+  public void selectTab(TabRef selectTab)
   {
     // select a given tab - currently only for Connections
     switch (selectTab)
@@ -520,6 +553,9 @@ public class GPreferences extends JPanel
     case CONNECTIONS_TAB:
       tabbedPane.setSelectedComponent(connectTab);
       break;
+    case STRUCTURE_TAB:
+      tabbedPane.setSelectedComponent(structureTab);
+      break;
     default:
     }
   }
@@ -1646,7 +1682,6 @@ public class GPreferences extends JPanel
       {
         boolean selected = structFromPdb.isSelected();
         // enable other options only when the first is checked
-        useRnaView.setEnabled(selected);
         addSecondaryStructure.setEnabled(selected);
         addTempFactor.setEnabled(selected);
       }
@@ -1655,12 +1690,6 @@ public class GPreferences extends JPanel
 
     // indent checkboxes that are conditional on the first one
     ypos += lineSpacing;
-    useRnaView.setFont(LABEL_FONT);
-    useRnaView.setText(MessageManager.getString("label.use_rnaview"));
-    useRnaView.setBounds(new Rectangle(25, ypos, width, height));
-    structureTab.add(useRnaView);
-
-    ypos += lineSpacing;
     addSecondaryStructure.setFont(LABEL_FONT);
     addSecondaryStructure
             .setText(MessageManager.getString("label.autoadd_secstr"));
@@ -1789,8 +1818,8 @@ public class GPreferences extends JPanel
   }
 
   /**
-   * Show a dialog for the user to choose a file. Returns the chosen path, or
-   * null on Cancel.
+   * Show a dialog for the user to choose a file. Returns the chosen path, or null
+   * on Cancel.
    * 
    * @return
    */
@@ -2203,6 +2232,19 @@ public class GPreferences extends JPanel
     updateBackupFilesExampleLabel();
   }
 
+  /*
+   * Load the saved Memory settings
+   */
+  protected void loadLastSavedMemorySettings()
+  {
+    customiseMemorySetting.setSelected(
+            Cache.getDefault(MemorySetting.CUSTOMISED_SETTINGS, false));
+    jvmMemoryPercentSlider
+            .setValue(Cache.getDefault(MemorySetting.MEMORY_JVMMEMPC, 90));
+    jvmMemoryMaxTextField.setText(
+            Cache.getDefault(MemorySetting.MEMORY_JVMMEMMAX, "32g"));
+  }
+
   private boolean warnAboutSuffixReverseChange()
   {
     BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
@@ -2220,6 +2262,285 @@ public class GPreferences extends JPanel
             && nowSuffixTemplate.equals(savedSuffixTemplate);
   }
 
+  /* Initialises the Startup tabbed panel.
+   * 
+   * @return
+   * */
+
+  private JPanel initStartupTab()
+  {
+    JPanel startupTab = new JPanel();
+    startupTab.setBorder(
+            new TitledBorder(MessageManager.getString("label.memory")));
+    startupTab.setLayout(new GridBagLayout());
+
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.weightx = 0.0;
+    gbc.weighty = 0.0;
+    gbc.anchor = GridBagConstraints.FIRST_LINE_START;
+    gbc.fill = GridBagConstraints.NONE;
+
+    initMemoryPanel();
+
+    gbc.gridheight = 1;
+    gbc.gridwidth = 3;
+
+    gbc.gridy = 0; // row 1
+    gbc.gridx = 0;
+    JLabel memoryText = new JLabel();
+    memoryText.setFont(LABEL_FONT_ITALIC);
+    memoryText
+            .setText(MessageManager.getString("label.memory_setting_text"));
+    startupTab.add(memoryText, gbc);
+
+    gbc.gridy++; // row 2
+    gbc.gridx = 0;
+    JPanel exampleMemoryPanel = new JPanel();
+    exampleMemoryPanel
+            .setLayout(new BoxLayout(exampleMemoryPanel, BoxLayout.Y_AXIS));
+    exampleMemoryPanel.setToolTipText(JvSwingUtils.wrapTooltip(true,
+            MessageManager.getString("label.memory_example_tooltip")));
+    JLabel exampleTextLabel = new JLabel();
+    exampleTextLabel
+            .setText(MessageManager.getString("label.memory_example_text"));
+    exampleTextLabel.setForeground(Color.GRAY);
+    exampleTextLabel.setFont(LABEL_FONT);
+    exampleMemoryPanel.add(exampleTextLabel);
+    exampleMemoryPanel.add(exampleMemoryLabel);
+    exampleMemoryPanel.setBackground(Color.WHITE);
+    exampleMemoryPanel.setBorder(BorderFactory.createEtchedBorder());
+    startupTab.add(exampleMemoryPanel, gbc);
+
+    gbc.gridy++; // row 3
+    gbc.gridx = 0;
+    startupTab.add(customiseMemorySetting, gbc);
+
+    gbc.gridy += 2; // row 4 with a gap
+    gbc.gridx = 0;
+    startupTab.add(maxMemoryLabel, gbc);
+
+    gbc.gridy += 2; // row 5
+    gbc.gridx = 0;
+    gbc.gridwidth = 1;
+    startupTab.add(jvmMemoryPercentLabel, gbc);
+    gbc.gridx++;
+    startupTab.add(jvmMemoryPercentSlider, gbc);
+    gbc.gridx++;
+    // gbc.weightx = 0.1;
+    startupTab.add(jvmMemoryPercentDisplay, gbc);
+    // gbc.weightx = 1.0;
+    gbc.gridwidth = 3;
+
+    gbc.gridy++; // row 6
+    gbc.gridx = 0;
+    startupTab.add(jvmMemoryMaxLabel, gbc);
+    gbc.gridx++;
+    startupTab.add(jvmMemoryMaxTextField, gbc);
+
+    gbc.gridy++; // row 7
+    gbc.gridx = 0;
+    gbc.gridwidth = 4;
+    exampleMemoryMessageTextArea.setBackground(startupTab.getBackground());
+    JScrollPane sp = new JScrollPane(exampleMemoryMessageTextArea);
+    sp.setBorder(BorderFactory.createEmptyBorder());
+    sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
+    startupTab.add(sp, gbc);
+
+    // fill empty space to push widget to top left
+    gbc.gridy++;
+    gbc.weighty = 1.0;
+    gbc.gridx = 100;
+    gbc.gridwidth = 1;
+    gbc.weightx = 1.0;
+    startupTab.add(new JPanel(), gbc);
+
+    setMemoryPercentDisplay();
+    memoryOptionsSetEnabled();
+    return startupTab;
+  }
+
+  private void initMemoryPanel()
+  {
+    // Enable memory settings checkbox
+    customiseMemorySetting.setFont(LABEL_FONT_BOLD);
+    customiseMemorySetting.setText(
+            MessageManager.getString("label.customise_memory_settings"));
+    customiseMemorySetting.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        memoryOptionsSetEnabled();
+      }
+    });
+
+    loadLastSavedMemorySettings();
+
+    exampleMemoryLabel.setFont(LABEL_FONT_BOLD);
+    exampleMemoryLabel.setBackground(Color.WHITE);
+
+    maxMemoryLabel = new JLabel(
+            MessageManager.getString("label.maximum_memory_used"));
+    maxMemoryLabel.setFont(LABEL_FONT_BOLD);
+
+    // Maximum memory percentage slider
+    jvmMemoryPercentLabel.setFont(LABEL_FONT);
+    jvmMemoryPercentLabel.setText(
+            MessageManager.getString("label.percent_of_physical_memory"));
+    jvmMemoryPercentSlider.setPaintLabels(true);
+    jvmMemoryPercentSlider.setPaintTicks(true);
+    jvmMemoryPercentSlider.setPaintTrack(true);
+    jvmMemoryPercentSlider.setMajorTickSpacing(50);
+    jvmMemoryPercentSlider.setMinorTickSpacing(10);
+    jvmMemoryPercentSlider.addChangeListener(new ChangeListener()
+    {
+      @Override
+      public void stateChanged(ChangeEvent e)
+      {
+        setMemoryPercentDisplay();
+      }
+    });
+    jvmMemoryPercentDisplay.setFont(LABEL_FONT);
+    setMemoryPercentDisplay();
+
+    // Maximum memory cap textbox
+    jvmMemoryMaxLabel.setFont(LABEL_FONT);
+    jvmMemoryMaxLabel
+            .setText(MessageManager.getString("label.maximum_memory"));
+    initMemoryMaxTextField();
+
+    exampleMemoryMessageTextArea.setFont(LABEL_FONT_ITALIC);
+    exampleMemoryMessageTextArea.setForeground(Color.GRAY);
+    exampleMemoryMessageTextArea.setEditable(false);
+    exampleMemoryMessageTextArea.setLineWrap(true);
+    exampleMemoryMessageTextArea.setWrapStyleWord(true);
+    exampleMemoryMessageTextArea.setText(" ");
+    exampleMemoryMessageTextArea.setRows(2);
+    exampleMemoryMessageTextArea.setColumns(40);
+
+    setExampleMemoryLabel();
+  }
+
+  private void initMemoryMaxTextField()
+  {
+    jvmMemoryMaxTextField.setToolTipText(
+            MessageManager.getString("label.maximum_memory_tooltip"));
+    jvmMemoryMaxTextField.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        validateMemoryMaxTextField();
+        setExampleMemoryLabel();
+      }
+    });
+
+    jvmMemoryMaxTextField.addKeyListener(new KeyListener()
+    {
+      @Override
+      public void keyReleased(KeyEvent e)
+      {
+        validateMemoryMaxTextField();
+        setExampleMemoryLabel();
+      }
+
+      @Override
+      public void keyPressed(KeyEvent e)
+      {
+      }
+
+      // try and stop invalid typing
+      @Override
+      public void keyTyped(KeyEvent e)
+      {
+        char c = Character.toLowerCase(e.getKeyChar());
+        String text = jvmMemoryMaxTextField.getText();
+        String suffixes = "tgmkb";
+        int pos = jvmMemoryMaxTextField.getCaretPosition();
+        int suffixPos = StringUtils.firstCharPosIgnoreCase(text, suffixes);
+        if (!((('0' <= c && c <= '9')
+                && (suffixPos == -1 || pos <= suffixPos)) // digits only allowed
+                // before suffix
+                || (suffixes.indexOf(Character.toLowerCase(c)) >= 0 // valid
+                                                                    // suffix
+                        && pos == text.length() // at end of text and
+                        && suffixPos == -1) // there isn't already one
+        ))
+        {
+          // don't process
+          e.consume();
+        }
+      }
+    });
+  }
+
+  private boolean isMemoryMaxTextFieldValid()
+  {
+    return MemorySetting
+            .isValidMemoryString(jvmMemoryMaxTextField.getText());
+  }
+
+  private void validateMemoryMaxTextField()
+  {
+    if (isMemoryMaxTextFieldValid())
+    {
+      jvmMemoryMaxTextField.setBackground(Color.WHITE);
+    }
+    else
+    {
+      jvmMemoryMaxTextField.setBackground(Color.PINK);
+    }
+  }
+
+  private void setMemoryPercentDisplay()
+  {
+    jvmMemoryPercentDisplay
+            .setText(jvmMemoryPercentSlider.getValue() + "%");
+    setExampleMemoryLabel();
+  }
+
+  private void setExampleMemoryLabel()
+  {
+    boolean selected = customiseMemorySetting.isSelected();
+    int jvmmempc = jvmMemoryPercentSlider.getValue();
+    String jvmmemmax = jvmMemoryMaxTextField.getText();
+
+    long mem;
+    if (selected && (0 <= jvmmempc && jvmmempc <= 100)
+            && MemorySetting.isValidMemoryString(jvmmemmax))
+    {
+      mem = MemorySetting.getMemorySetting(jvmmemmax,
+              String.valueOf(jvmmempc), false, true);
+    }
+    else
+    {
+      mem = MemorySetting.getMemorySetting(null, null, false, true);
+    }
+    exampleMemoryLabel.setText(MemorySetting.memoryLongToString(mem));
+    String message = MemorySetting.getAdjustmentMessage();
+    exampleMemoryMessageTextArea.setText(
+            MessageManager.getString("label.adjustments_for_this_computer")
+                    + ": "
+                    + (message == null
+                            ? MessageManager.getString("label.none")
+                            : message));
+  }
+
+  private void memoryOptionsSetEnabled()
+  {
+    boolean enabled = customiseMemorySetting.isSelected();
+    // leave exampleMemoryLabel enabled always
+    maxMemoryLabel.setEnabled(enabled);
+    jvmMemoryPercentLabel.setEnabled(enabled);
+    jvmMemoryPercentSlider.setEnabled(enabled);
+    jvmMemoryPercentDisplay.setEnabled(enabled);
+    jvmMemoryMaxLabel.setEnabled(enabled);
+    jvmMemoryMaxTextField.setEnabled(enabled);
+    exampleMemoryMessageTextArea.setEnabled(enabled);
+    setExampleMemoryLabel();
+  }
+
   /**
    * Initialises the Backups tabbed panel.
    * 
@@ -2473,7 +2794,7 @@ public class GPreferences extends JPanel
     }
     else
     {
-      Cache.log.error(
+      Console.error(
               "Preset '" + value + "' [key:" + key + "] not implemented");
     }
 
@@ -2493,7 +2814,7 @@ public class GPreferences extends JPanel
               .getSelectedItem();
     } catch (Exception ex)
     {
-      Cache.log.error(
+      Console.error(
               "Problem casting Combo entry to IntKeyStringValueEntry.");
       e = null;
     }
@@ -2511,7 +2832,7 @@ public class GPreferences extends JPanel
         e = (IntKeyStringValueEntry) backupfilesPresetsCombo2.getItemAt(i);
       } catch (Exception ex)
       {
-        Cache.log.error(
+        Console.error(
                 "Problem casting Combo entry to IntKeyStringValueEntry. Skipping item. ");
         continue;
       }
@@ -2959,7 +3280,7 @@ public class GPreferences extends JPanel
         i = ((Integer) s.getValue()).intValue();
       } catch (Exception e)
       {
-        Cache.log.error(
+        Console.error(
                 "Exception casting the initial value of s.getValue()");
       }
     }
@@ -2995,7 +3316,7 @@ public class GPreferences extends JPanel
       i = (Integer) s.getValue();
     } catch (Exception e)
     {
-      Cache.log.error("Failed casting (Integer) JSpinner s.getValue()");
+      Console.error("Failed casting (Integer) JSpinner s.getValue()");
     }
     return i;
   }
@@ -3166,7 +3487,7 @@ public class GPreferences extends JPanel
    * DOCUMENT ME!
    * 
    * @param e
-   *          DOCUMENT ME!
+   *            DOCUMENT ME!
    */
   public void ok_actionPerformed(ActionEvent e)
   {
@@ -3176,7 +3497,7 @@ public class GPreferences extends JPanel
    * DOCUMENT ME!
    * 
    * @param e
-   *          DOCUMENT ME!
+   *            DOCUMENT ME!
    */
   public void cancel_actionPerformed(ActionEvent e)
   {
@@ -3186,7 +3507,7 @@ public class GPreferences extends JPanel
    * DOCUMENT ME!
    * 
    * @param e
-   *          DOCUMENT ME!
+   *            DOCUMENT ME!
    */
   public void annotations_actionPerformed(ActionEvent e)
   {
index b9c9267..70d99c1 100644 (file)
@@ -39,6 +39,7 @@ import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.GridLayout;
+import java.awt.Point;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -67,6 +68,7 @@ import javax.swing.JTable;
 import javax.swing.JTextField;
 import javax.swing.ListCellRenderer;
 import javax.swing.Timer;
+import javax.swing.UIManager;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.DocumentEvent;
@@ -88,7 +90,7 @@ public abstract class GStructureChooser extends JPanel
 {
   private static final Font VERDANA_12 = new Font("Verdana", 0, 12);
 
-  protected static final String VIEWS_FILTER = "VIEWS_FILTER";
+  public static final String VIEWS_FILTER = "VIEWS_FILTER";
 
   protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
 
@@ -119,6 +121,8 @@ public abstract class GStructureChooser extends JPanel
   protected JButton btn_newView;
 
   protected JButton btn_pdbFromFile = new JButton();
+  
+  protected JButton btn_queryTDB = new JButton();
 
   protected JCheckBox chk_superpose = new JCheckBox(
           MessageManager.getString("label.superpose_structures"));
@@ -145,6 +149,9 @@ public abstract class GStructureChooser extends JPanel
   protected ImageIcon warningImage = new ImageIcon(
           getClass().getResource("/images/warning.gif"));
 
+  protected ImageIcon tdbImage = new ImageIcon(
+          getClass().getResource("/images/3d-beacons-logo-transparent.png"));
+
   protected JLabel lbl_loading = new JLabel(loadingImage);
 
   protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
@@ -161,9 +168,9 @@ public abstract class GStructureChooser extends JPanel
 
   protected JTabbedPane pnl_filter = new JTabbedPane();
 
-  protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
-          PreferenceSource.STRUCTURE_CHOOSER,
-          PDBFTSRestClient.getInstance());
+  protected abstract FTSDataColumnPreferences getFTSDocFieldPrefs();
+  protected abstract void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs);
+
 
   protected FTSDataColumnI[] previousWantedFields;
 
@@ -244,11 +251,15 @@ public abstract class GStructureChooser extends JPanel
                                       + "...\"")
                       : JvSwingUtils.wrapTooltip(true, toolTipText)));
       return toolTipText;
-    }
+    }    
   };
 
   public GStructureChooser()
   {
+  }
+  protected void initDialog()
+  {
+
     try
     {
       jbInit();
@@ -261,7 +272,7 @@ public abstract class GStructureChooser extends JPanel
       e.printStackTrace();
     }
   }
-
+  
   // BH SwingJS optimization
   // (a) 100-ms interruptable timer for text entry -- BH 1/10/2019
   // (b) two-character minimum, at least for JavaScript.
@@ -302,15 +313,42 @@ public abstract class GStructureChooser extends JPanel
     tbl_summary.addMouseListener(new MouseAdapter()
     {
       @Override
+      public void mousePressed(MouseEvent e)
+      {
+        if (!popupAction(e))
+        {
+          super.mousePressed(e);
+        }
+      }
+      @Override
       public void mouseClicked(MouseEvent e)
       {
-        validateSelections();
+        if (!popupAction(e))
+        {
+          validateSelections();
+        }
       }
 
       @Override
       public void mouseReleased(MouseEvent e)
       {
+        if (!popupAction(e))
+        {
         validateSelections();
+        }
+      }
+      boolean popupAction(MouseEvent e)
+      {
+       if (e.isPopupTrigger())
+       {
+         Point pt = e.getPoint();
+         int selectedRow = tbl_summary.rowAtPoint(pt);
+         if (showPopupFor(selectedRow,pt.x,pt.y))
+         {
+           return true;
+         }
+       }
+       return false;
       }
     });
     tbl_summary.addKeyListener(new KeyAdapter()
@@ -427,7 +465,9 @@ public abstract class GStructureChooser extends JPanel
       }
     });
 
-    btn_newView = new JButton(MessageManager.getString("action.new_view"));
+    btn_newView = new JButton(
+            MessageManager.formatMessage("action.new_structure_view_with",
+                    StructureViewer.getViewerType().toString()));
     btn_newView.setFont(VERDANA_12);
     btn_newView.addActionListener(new java.awt.event.ActionListener()
     {
@@ -448,6 +488,8 @@ public abstract class GStructureChooser extends JPanel
         }
       }
     });
+    
+    // TODO: JAL-3898 - get list of available external programs to view structures with
 
     btn_add = new JButton(MessageManager.getString("action.add"));
     btn_add.setFont(VERDANA_12);
@@ -543,6 +585,12 @@ public abstract class GStructureChooser extends JPanel
     });
 
     chk_invertFilter.addItemListener(this);
+    btn_queryTDB.setFont(VERDANA_12);
+    //btn_queryTDB.setPreferredSize(new Dimension(200,22));
+    btn_queryTDB.setText(MessageManager.getString("label.search_3dbeacons"));
+    btn_queryTDB.setToolTipText(MessageManager.getString("label.find_models_from_3dbeacons"));
+    btn_queryTDB.setIcon(tdbImage);
+    btn_queryTDB.setVisible(false);
 
     targetView.setVisible(false);
 
@@ -553,10 +601,13 @@ public abstract class GStructureChooser extends JPanel
     actionsPanel.add(btn_newView);
     actionsPanel.add(btn_cancel, "right");
 
-    JPanel pnl_main = new JPanel();
-    pnl_main.add(cmb_filterOption);
-    pnl_main.add(lbl_loading);
-    pnl_main.add(chk_invertFilter);
+    JPanel pnl_main = new JPanel(new BorderLayout());
+    JPanel pnl_controls = new JPanel();
+    pnl_main.add(btn_queryTDB,BorderLayout.NORTH);
+    pnl_controls.add(cmb_filterOption);
+    pnl_controls.add(lbl_loading);
+    pnl_controls.add(chk_invertFilter);
+    pnl_main.add(pnl_controls,BorderLayout.CENTER);
     lbl_loading.setVisible(false);
 
     JPanel pnl_fileChooser = new JPanel(new FlowLayout());
@@ -596,7 +647,7 @@ public abstract class GStructureChooser extends JPanel
           btn_add.setVisible(false);
           btn_newView.setEnabled(false);
           btn_cancel.setVisible(false);
-          previousWantedFields = pdbDocFieldPrefs
+          previousWantedFields = getFTSDocFieldPrefs()
                   .getStructureSummaryFields()
                   .toArray(new FTSDataColumnI[0]);
         }
@@ -618,7 +669,7 @@ public abstract class GStructureChooser extends JPanel
     pnl_filter.addChangeListener(changeListener);
     pnl_filter.setPreferredSize(new Dimension(width, height));
     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
-    pnl_filter.add(configureCols, pdbDocFieldPrefs);
+    pnl_filter.add(configureCols, getFTSDocFieldPrefs());
 
     JPanel pnl_locPDB = new JPanel(new BorderLayout());
     pnl_locPDB.add(scrl_localPDB);
@@ -662,6 +713,7 @@ public abstract class GStructureChooser extends JPanel
   }
 
 
+protected abstract boolean showPopupFor(int selectedRow, int x, int y);
 protected void closeAction(int preferredHeight)
   {
     // System.out.println(">>>>>>>>>> closing internal frame!!!");
@@ -683,7 +735,7 @@ protected void closeAction(int preferredHeight)
       return true;
     }
 
-    FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
+    FTSDataColumnI[] currentWantedFields = getFTSDocFieldPrefs()
             .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
     return Arrays.equals(currentWantedFields, previousWantedFields) ? false
             : true;
@@ -700,91 +752,6 @@ protected void closeAction(int preferredHeight)
   }
 
   /**
-   * This inner class provides the data model for the structure filter combo-box
-   * 
-   * @author tcnofoegbu
-   *
-   */
-  public class FilterOption
-  {
-    private String name;
-
-    private String value;
-
-    private String view;
-
-    private boolean addSeparatorAfter;
-
-    /**
-     * Model for structure filter option
-     * 
-     * @param name
-     *          - the name of the Option
-     * @param value
-     *          - the value of the option
-     * @param view
-     *          - the category of the filter option
-     * @param addSeparatorAfter
-     *          - if true, a horizontal separator is rendered immediately after
-     *          this filter option, otherwise
-     */
-    public FilterOption(String name, String value, String view,
-            boolean addSeparatorAfter)
-    {
-      this.name = name;
-      this.value = value;
-      this.view = view;
-      this.addSeparatorAfter = addSeparatorAfter;
-    }
-
-    public String getName()
-    {
-      return name;
-    }
-
-    public void setName(String name)
-    {
-      this.name = name;
-    }
-
-    public String getValue()
-    {
-      return value;
-    }
-
-    public void setValue(String value)
-    {
-      this.value = value;
-    }
-
-    public String getView()
-    {
-      return view;
-    }
-
-    public void setView(String view)
-    {
-      this.view = view;
-    }
-
-    @Override
-    public String toString()
-    {
-      return this.name;
-    }
-
-    public boolean isAddSeparatorAfter()
-    {
-      return addSeparatorAfter;
-    }
-
-    public void setAddSeparatorAfter(boolean addSeparatorAfter)
-    {
-      this.addSeparatorAfter = addSeparatorAfter;
-    }
-  }
-
-  /**
    * This inner class provides the provides the data model for associate
    * sequence combo-box - cmb_assSeq
    * 
index 84de493..928b370 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.jbgui;
 
+import jalview.bin.Cache;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -432,7 +433,7 @@ public class GWsPreferences extends JPanel
     wsMenuRefreshButs.add(resetWs, null);
     wsMenuRefreshButs.add(progressBar, null);
     myBorderlayout.setHgap(3);
-    if (jalview.bin.Cache.getDefault("ENABLE_RSBS_EDITOR", false))
+    if (Cache.getDefault("ENABLE_RSBS_EDITOR", false))
     {
       JTabbedPane listPanels = new JTabbedPane();
       listPanels.addTab("JABAWS Servers", wsListPanel);
index b3422ab..6b877bf 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.json.binding.biojson.v1;
 
+import java.util.Locale;
+
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.BuriedColourScheme;
@@ -62,7 +64,7 @@ public class ColourSchemeMapper
   public static ColourSchemeI getJalviewColourScheme(
           String colourSchemeName, AnnotatedCollectionI annotCol)
   {
-    switch (colourSchemeName.toUpperCase())
+    switch (colourSchemeName.toUpperCase(Locale.ROOT))
     {
     case "ZAPPO":
       return csZappo;
diff --git a/src/jalview/log/JLogger.java b/src/jalview/log/JLogger.java
new file mode 100644 (file)
index 0000000..2f4fafb
--- /dev/null
@@ -0,0 +1,196 @@
+package jalview.log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jalview.bin.Console;
+import jalview.util.Platform;
+
+public abstract class JLogger implements JLoggerI
+{
+  protected String name;
+
+  protected LogLevel level;
+
+  private Object logger = null;
+
+  private static Map<String, JLogger> registry = new HashMap<>();
+
+  // implement these abstract methods
+  protected abstract void loggerSetup();
+
+  public abstract boolean loggerExists();
+
+  protected abstract void loggerSetLevel(LogLevel level);
+
+  protected abstract void loggerLogMessage(LogLevel level, String message,
+          Throwable t);
+
+  public static LogLevel toLevel(String levelString)
+  {
+    try
+    {
+      return LogLevel.valueOf(levelString);
+    } catch (IllegalArgumentException e)
+    {
+      Console.error("Could not parse LogLevel '" + levelString + "'", e);
+      return LogLevel.INFO;
+    }
+  }
+
+  public static JLogger getLogger(Class c)
+  {
+    return getLogger(c);
+  }
+
+  public static JLogger getLogger(Class c, LogLevel loglevel)
+  {
+    return getLogger(c.getCanonicalName(), loglevel);
+  }
+
+  public static JLogger getLogger(String name)
+  {
+    return getLogger(name, LogLevel.INFO);
+  }
+
+  public static JLogger getLogger(String name, LogLevel loglevel)
+  {
+    return registry.containsKey(name) ? (JLogger) registry.get(name) : null;
+  }
+
+  protected JLogger()
+  {
+  }
+
+  protected JLogger(String name, LogLevel level)
+  {
+    this.name = name;
+    this.level = level;
+    this.loggerSetup();
+    this.registryStore();
+  }
+
+  protected void registryStore()
+  {
+    registry.put(this.name, this);
+  }
+
+  protected static boolean registryContainsKey(String name)
+  {
+    return registry.containsKey(name);
+  }
+
+  protected static JLogger registryGet(String name)
+  {
+    return registry.get(name);
+  }
+
+  public LogLevel getLevel()
+  {
+    return this.level;
+  }
+
+  public void setLevel(LogLevel level)
+  {
+    this.level = level;
+    if (loggerExists())
+      loggerSetLevel(level);
+  }
+
+  private boolean println(LogLevel loglevel, String message, Throwable t)
+  {
+    if (loglevel.compareTo(this.level) < 0)
+    {
+      return false;
+    }
+    if (!loggerExists() || Platform.isJS())
+    {
+      String logLine = String.format("%s: %s", loglevel.toString(),
+              message);
+      System.out.println(logLine);
+      if (t != null)
+      {
+        if (loglevel.compareTo(LogLevel.DEBUG) <= 0)
+          t.printStackTrace(System.err);
+        else
+          System.err.println(t.getMessage());
+      }
+      return false;
+    }
+    else
+    {
+      loggerLogMessage(loglevel, message, t);
+      return true;
+    }
+  }
+
+  public void trace(String message)
+  {
+    trace(message, null);
+  }
+
+  public void trace(String message, Throwable t)
+  {
+    println(LogLevel.TRACE, message, t);
+  }
+
+  public void debug(String message)
+  {
+    debug(message, null);
+  }
+
+  public void debug(String message, Throwable t)
+  {
+    println(LogLevel.DEBUG, message, t);
+  }
+
+  public void info(String message)
+  {
+    info(message, null);
+  }
+
+  public void info(String message, Throwable t)
+  {
+    println(LogLevel.INFO, message, t);
+  }
+
+  public void warn(String message)
+  {
+    warn(message, null);
+  }
+
+  public void warn(String message, Throwable t)
+  {
+    println(LogLevel.WARN, message, t);
+  }
+
+  public void error(String message)
+  {
+    error(message, null);
+  }
+
+  public void error(String message, Throwable t)
+  {
+    println(LogLevel.ERROR, message, t);
+  }
+
+  public void fatal(String message)
+  {
+    fatal(message, null);
+  }
+
+  public void fatal(String message, Throwable t)
+  {
+    println(LogLevel.FATAL, message, t);
+  }
+
+  public boolean isDebugEnabled()
+  {
+    return level.compareTo(LogLevel.DEBUG) <= 0;
+  }
+
+  public boolean isTraceEnabled()
+  {
+    return level.compareTo(LogLevel.TRACE) <= 0;
+  }
+}
diff --git a/src/jalview/log/JLoggerI.java b/src/jalview/log/JLoggerI.java
new file mode 100644 (file)
index 0000000..94f149b
--- /dev/null
@@ -0,0 +1,41 @@
+package jalview.log;
+
+public interface JLoggerI
+{
+  public enum LogLevel
+  {
+    ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL
+  }
+
+  public LogLevel getLevel();
+
+  public void setLevel(LogLevel level);
+
+  public void trace(String message);
+
+  public void trace(String message, Throwable t);
+
+  public void debug(String message);
+
+  public void debug(String message, Throwable t);
+
+  public void info(String message);
+
+  public void info(String message, Throwable t);
+
+  public void warn(String message);
+
+  public void warn(String message, Throwable t);
+
+  public void error(String message);
+
+  public void error(String message, Throwable t);
+
+  public void fatal(String message);
+
+  public void fatal(String message, Throwable t);
+
+  public boolean isDebugEnabled();
+
+  public boolean isTraceEnabled();
+}
diff --git a/src/jalview/log/JLoggerLog4j.java b/src/jalview/log/JLoggerLog4j.java
new file mode 100644 (file)
index 0000000..bacab74
--- /dev/null
@@ -0,0 +1,146 @@
+package jalview.log;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+
+import jalview.util.Log4j;
+import jalview.util.Platform;
+
+public class JLoggerLog4j extends JLogger implements JLoggerI
+{
+  private Logger logger = null;
+
+  public static JLoggerLog4j getLogger(Class c)
+  {
+    return getLogger(c);
+  }
+
+  public static JLoggerLog4j getLogger(Class c, LogLevel loglevel)
+  {
+    return getLogger(c.getCanonicalName(), loglevel);
+  }
+
+  public static JLoggerLog4j getLogger(String name)
+  {
+    return getLogger(name, LogLevel.INFO);
+  }
+
+  public static JLoggerLog4j getLogger(String name, LogLevel loglevel)
+  {
+    return registryContainsKey(name) ? (JLoggerLog4j) registryGet(name)
+            : new JLoggerLog4j(name, loglevel);
+  }
+
+  private JLoggerLog4j(String name, LogLevel level)
+  {
+    this.name = name;
+    this.level = level;
+    this.loggerSetup();
+    this.registryStore();
+  }
+
+  @Override
+  protected void loggerSetup()
+  {
+    if (!Platform.isJS())
+      this.logger = Log4j.isInit() ? Log4j.getLogger(this.name, this.level)
+              : null;
+  }
+
+  @Override
+  public boolean loggerExists()
+  {
+    return logger != null;
+  }
+
+  @Override
+  protected void loggerSetLevel(JLoggerI.LogLevel level)
+  {
+    if (loggerExists())
+    {
+      Log4j.setLevel(logger, level);
+    }
+  }
+
+  @Override
+  protected void loggerLogMessage(LogLevel level, String message,
+          Throwable t)
+  {
+    if (!loggerExists())
+      return;
+    if (t != null)
+    {
+      switch (level)
+      {
+      case FATAL:
+        logger.fatal(message, t);
+        break;
+      case ERROR:
+        logger.error(message, t);
+        break;
+      case WARN:
+        logger.warn(message, t);
+        break;
+      case INFO:
+        logger.info(message, t);
+        break;
+      case DEBUG:
+        logger.debug(message, t);
+        break;
+      case TRACE:
+        logger.trace(message, t);
+        break;
+      case ALL:
+        logger.trace(message, t);
+        break;
+      }
+    }
+    else
+    {
+      switch (level)
+      {
+      case FATAL:
+        logger.fatal(message);
+        break;
+      case ERROR:
+        logger.error(message);
+        break;
+      case WARN:
+        logger.warn(message);
+        break;
+      case INFO:
+        logger.info(message);
+        break;
+      case DEBUG:
+        logger.debug(message);
+        break;
+      case TRACE:
+        logger.trace(message);
+        break;
+      case ALL:
+        logger.trace(message);
+        break;
+      }
+    }
+  }
+
+  private Logger getLoggerObject()
+  {
+    return this.logger;
+  }
+
+  public synchronized static void addAppender(JLoggerLog4j level,
+          Appender appender)
+  {
+    if (!Platform.isJS())
+      Log4j.addAppender(level.getLoggerObject(), appender);
+  }
+
+  public synchronized static void addAppender(JLoggerLog4j l1,
+          JLoggerLog4j l2, String name)
+  {
+    if (!Platform.isJS())
+      Log4j.addAppender(l1.getLoggerObject(), l2.getLoggerObject(), name);
+  }
+
+}
similarity index 56%
rename from src/jalview/gui/JalviewAppender.java
rename to src/jalview/log/JalviewAppender.java
index 1d7064b..07239f8 100644 (file)
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-package jalview.gui;
+package jalview.log;
+
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
 
 import javax.swing.JTextArea;
 import javax.swing.SwingUtilities;
 
-import org.apache.log4j.WriterAppender;
-import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+
+import jalview.log.JLoggerI.LogLevel;
+import jalview.util.Log4j;
 
 /**
  * From http://textareaappender.zcage.com/ the means to capture the logs, too.
  * Simple example of creating a Log4j appender that will write to a JTextArea.
  */
-public class JalviewAppender extends WriterAppender
+public class JalviewAppender extends AbstractAppender
 {
+  public final static String NAME = "JalviewAppender";
+
+  public JalviewAppender()
+  {
+    this(LogLevel.INFO);
+  }
+
+  public JalviewAppender(LogLevel loglevel)
+  {
+    super(NAME,
+            Log4j.getThresholdFilter(loglevel == null ? Level.INFO
+                    : Log4j.log4jLevel(loglevel)),
+            Log4j.getSimpleLayout(), false, new Property[0]);
+  }
+
+  protected JalviewAppender(String name, Filter filter,
+          Layout<? extends Serializable> layout, boolean ignoreExceptions,
+          Property[] properties)
+  {
+    super(name, filter, layout, ignoreExceptions, properties);
+    // TODO Auto-generated constructor stub
+  }
 
   static private JTextArea jTextArea = null;
 
@@ -44,9 +76,10 @@ public class JalviewAppender extends WriterAppender
   /**
    * Format and then append the loggingEvent to the stored JTextArea.
    */
-  public void append(LoggingEvent loggingEvent)
+  public void append(LogEvent logEvent)
   {
-    final String message = this.layout.format(loggingEvent);
+    final String message = new String(
+            this.getLayout().toByteArray(logEvent), StandardCharsets.UTF_8);
 
     // Append formatted message to textarea using the Swing Thread.
     SwingUtilities.invokeLater(new Runnable()
index 64b3a9c..8877af2 100644 (file)
@@ -54,6 +54,7 @@ import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -83,6 +84,7 @@ import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
@@ -575,7 +577,7 @@ public class Jalview2XML
 
     } catch (Exception e)
     {
-      Cache.log.error("Couln't write Jalview state to " + statefile, e);
+      Console.error("Couln't write Jalview state to " + statefile, e);
       // TODO: inform user of the problem - they need to know if their data was
       // not saved !
       if (errorMessage == null)
@@ -881,7 +883,7 @@ public class Jalview2XML
       System.err.println("error writing date: " + e.toString());
     }
     object.setVersion(
-            jalview.bin.Cache.getDefault("VERSION", "Development Build"));
+            Cache.getDefault("VERSION", "Development Build"));
 
     /**
      * rjal is full height alignment, jal is actual alignment with full metadata
@@ -1108,7 +1110,7 @@ public class Jalview2XML
                 }
                 else
                 {
-                  Cache.log.error(
+                  Console.error(
                           "Failed to save viewer state for " + viewerType);
                 }
               }
@@ -1631,7 +1633,7 @@ public class Jalview2XML
                 .getHiddenColumns();
         if (hidden == null)
         {
-          warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
+          Console.warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
         }
         else
         {
@@ -1800,7 +1802,7 @@ public class Jalview2XML
       object.getPcaViewer().add(viewer);
     } catch (Throwable t)
     {
-      Cache.log.error("Error saving PCA: " + t.getMessage());
+      Console.error("Error saving PCA: " + t.getMessage());
     }
   }
 
@@ -2075,9 +2077,9 @@ public class Jalview2XML
     {
       final PDBEntry pdbentry = bindingModel.getPdbEntry(peid);
       final String pdbId = pdbentry.getId();
-      if (!pdbId.equals(entry.getId())
-              && !(entry.getId().length() > 4 && entry.getId().toLowerCase()
-                      .startsWith(pdbId.toLowerCase())))
+      if (!pdbId.equals(entry.getId()) && !(entry.getId().length() > 4
+              && entry.getId().toLowerCase(Locale.ROOT)
+                      .startsWith(pdbId.toLowerCase(Locale.ROOT))))
       {
         /*
          * not interested in a binding to a different PDB entry here
@@ -2090,7 +2092,7 @@ public class Jalview2XML
       }
       else if (!matchedFile.equals(pdbentry.getFile()))
       {
-        Cache.log.warn(
+        Console.warn(
                 "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
                         + pdbentry.getFile());
       }
@@ -2388,7 +2390,7 @@ public class Jalview2XML
                   calcIdParam.getParameters().replace("|\\n|", "\n"));
         } catch (IOException x)
         {
-          warn("Couldn't parse parameter data for "
+          Console.warn("Couldn't parse parameter data for "
                   + calcIdParam.getCalcId(), x);
           return false;
         }
@@ -2416,7 +2418,7 @@ public class Jalview2XML
       }
       else
       {
-        warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
+        Console.warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
         return false;
       }
     }
@@ -2460,7 +2462,7 @@ public class Jalview2XML
         return id.toString();
       }
       // give up and warn that something has gone wrong
-      warn("Cannot find ID for object in external mapping : " + jvobj);
+      Console.warn("Cannot find ID for object in external mapping : " + jvobj);
     }
     return altCode;
   }
@@ -2529,6 +2531,7 @@ public class Jalview2XML
         dbref.setSource(ref.getSource());
         dbref.setVersion(ref.getVersion());
         dbref.setAccessionId(ref.getAccessionId());
+        dbref.setCanonical(ref.isCanonical());
         if (ref instanceof GeneLocus)
         {
           dbref.setLocus(true);
@@ -2596,12 +2599,12 @@ public class Jalview2XML
         mp.setDseqFor(jmpid);
         if (!seqRefIds.containsKey(jmpid))
         {
-          jalview.bin.Cache.log.debug("creatign new DseqFor ID");
+          Console.debug("creatign new DseqFor ID");
           seqRefIds.put(jmpid, ps);
         }
         else
         {
-          jalview.bin.Cache.log.debug("reusing DseqFor ID");
+          Console.debug("reusing DseqFor ID");
         }
 
         // mp.setMappingChoice(mpc);
@@ -2644,7 +2647,7 @@ public class Jalview2XML
         for (int i = 0; i < colours.length; i++)
         {
           Colour col = new Colour();
-          col.setName(ResidueProperties.aa[i].toLowerCase());
+          col.setName(ResidueProperties.aa[i].toLowerCase(Locale.ROOT));
           col.setRGB(jalview.util.Format.getHexString(colours[i]));
           // jbucs.addColour(col);
           jbucs.getColour().add(col);
@@ -2919,6 +2922,7 @@ public class Jalview2XML
           entryCount++;
         }
       } while (jarentry != null);
+      jin.close();
       resolveFrefedSequences();
     } catch (IOException ex)
     {
@@ -3226,7 +3230,7 @@ public class Jalview2XML
       }
       else
       {
-        warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
+        Console.warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
       }
     } catch (Exception ex)
     {
@@ -4201,7 +4205,7 @@ public class Jalview2XML
         tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews());
         if (tp == null)
         {
-          warn("There was a problem recovering stored Newick tree: \n"
+          Console.warn("There was a problem recovering stored Newick tree: \n"
                   + tree.getNewick());
           continue;
         }
@@ -4363,7 +4367,7 @@ public class Jalview2XML
             else
             {
               errorMessage = ("The Jmol views in this project were imported\nfrom an older version of Jalview.\nPlease review the sequence colour associations\nin the Colour by section of the Jmol View menu.\n\nIn the case of problems, see note at\nhttp://issues.jalview.org/browse/JAL-747");
-              warn(errorMessage);
+              Console.warn(errorMessage);
             }
           }
         }
@@ -4418,7 +4422,7 @@ public class Jalview2XML
     } catch (IllegalArgumentException | NullPointerException e)
     {
       // TODO JAL-3619 show error dialog / offer an alternative viewer
-      Cache.log.error("Invalid structure viewer type: " + type);
+      Console.error("Invalid structure viewer type: " + type);
     }
   }
 
@@ -4950,7 +4954,7 @@ public class Jalview2XML
           }
           else
           {
-            warn("Couldn't recover parameters for "
+            Console.warn("Couldn't recover parameters for "
                     + calcIdParam.getCalcId());
           }
         }
@@ -5226,10 +5230,7 @@ public class Jalview2XML
     String id = object.getViewport().get(0).getSequenceSetId();
     if (skipList.containsKey(id))
     {
-      if (Cache.log != null && Cache.log.isDebugEnabled())
-      {
-        Cache.log.debug("Skipping seuqence set id " + id);
-      }
+      Console.debug("Skipping seuqence set id " + id);
       return true;
     }
     return false;
@@ -5281,14 +5282,14 @@ public class Jalview2XML
       {
         if (ds != null && ds != seqSetDS)
         {
-          warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
+          Console.warn("JAL-3171 regression: Overwriting a dataset reference for an alignment"
                   + " - CDS/Protein crossreference data may be lost");
           if (xtant_ds != null)
           {
             // This can only happen if the unique sequence set ID was bound to a
             // dataset that did not contain any of the sequences in the view
             // currently being restored.
-            warn("JAL-3171 SERIOUS!  TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed.");
+            Console.warn("JAL-3171 SERIOUS!  TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed.");
           }
         }
         ds = seqSetDS;
@@ -5313,7 +5314,7 @@ public class Jalview2XML
       SequenceI[] dsseqs = new SequenceI[dseqs.size()];
       dseqs.copyInto(dsseqs);
       ds = new jalview.datamodel.Alignment(dsseqs);
-      debug("Created new dataset " + vamsasSet.getDatasetId()
+      Console.debug("Created new dataset " + vamsasSet.getDatasetId()
               + " for alignment " + System.identityHashCode(al));
       addDatasetRef(vamsasSet.getDatasetId(), ds);
     }
@@ -5366,7 +5367,7 @@ public class Jalview2XML
       AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds);
       if (prevDS != null && prevDS != ds)
       {
-        warn("Dataset sequence appears in many datasets: "
+        Console.warn("Dataset sequence appears in many datasets: "
                 + restoredSeq.getDsseqid());
         // TODO: try to merge!
       }
@@ -5572,7 +5573,7 @@ public class Jalview2XML
   {
     if (dataset.getDataset() != null)
     {
-      warn("Serious issue!  Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
+      Console.warn("Serious issue!  Dataset Object passed to getDatasetIdRef is not a Jalview DATASET alignment...");
     }
     String datasetId = makeHashCode(dataset, null);
     if (datasetId == null)
@@ -5622,6 +5623,7 @@ public class Jalview2XML
       {
         entry.setMap(addMapping(dr.getMapping()));
       }
+      entry.setCanonical(dr.isCanonical());
       datasetSequence.addDBRef(entry);
     }
   }
@@ -5707,7 +5709,7 @@ public class Jalview2XML
         seqRefIds.put(sqid, djs);
 
       }
-      jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
+      Console.debug("about to recurse on addDBRefs.");
       addDBRefs(djs, ms);
 
     }
@@ -5760,62 +5762,6 @@ public class Jalview2XML
 
   private Hashtable jvids2vobj;
 
-  private void warn(String msg)
-  {
-    warn(msg, null);
-  }
-
-  private void warn(String msg, Exception e)
-  {
-    if (Cache.log != null)
-    {
-      if (e != null)
-      {
-        Cache.log.warn(msg, e);
-      }
-      else
-      {
-        Cache.log.warn(msg);
-      }
-    }
-    else
-    {
-      System.err.println("Warning: " + msg);
-      if (e != null)
-      {
-        e.printStackTrace();
-      }
-    }
-  }
-
-  private void debug(String string)
-  {
-    debug(string, null);
-  }
-
-  private void debug(String msg, Exception e)
-  {
-    if (Cache.log != null)
-    {
-      if (e != null)
-      {
-        Cache.log.debug(msg, e);
-      }
-      else
-      {
-        Cache.log.debug(msg);
-      }
-    }
-    else
-    {
-      System.err.println("Warning: " + msg);
-      if (e != null)
-      {
-        e.printStackTrace();
-      }
-    }
-  }
-
   /**
    * set the object to ID mapping tables used to write/recover objects and XML
    * ID strings for the jalview project. If external tables are provided then
@@ -5874,7 +5820,7 @@ public class Jalview2XML
         if (!jvann.annotationId.equals(anid))
         {
           // TODO verify that this is the correct behaviour
-          this.warn("Overriding Annotation ID for " + anid
+          Console.warn("Overriding Annotation ID for " + anid
                   + " from different id : " + jvann.annotationId);
           jvann.annotationId = anid;
         }
@@ -5889,7 +5835,7 @@ public class Jalview2XML
       }
       else
       {
-        Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
+        Console.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
       }
     }
   }
@@ -5959,7 +5905,7 @@ public class Jalview2XML
       }
       else
       {
-        warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
+        Console.warn("Couldn't find entry in Jalview Jar for " + jarEntryName);
       }
     } catch (Exception ex)
     {
@@ -6109,7 +6055,7 @@ public class Jalview2XML
       }
     } catch (Exception ex)
     {
-      Cache.log.error("Error loading PCA: " + ex.toString());
+      Console.error("Error loading PCA: " + ex.toString());
     }
   }
 
@@ -6169,7 +6115,7 @@ public class Jalview2XML
       });
     } catch (InvocationTargetException | InterruptedException ex)
     {
-      warn("Unexpected error when opening " + viewerType
+      Console.warn("Unexpected error when opening " + viewerType
               + " structure viewer", ex);
     }
   }
@@ -6276,7 +6222,7 @@ public class Jalview2XML
       }
     } catch (IOException e)
     {
-      Cache.log.error("Error restoring Jmol session: " + e.toString());
+      Console.error("Error restoring Jmol session: " + e.toString());
     }
     return null;
   }
@@ -6529,7 +6475,7 @@ public class Jalview2XML
         maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
       } catch (Exception e)
       {
-        Cache.log.warn("Couldn't parse out graduated feature color.", e);
+        Console.warn("Couldn't parse out graduated feature color.", e);
       }
 
       NoValueColour noCol = colourModel.getNoValueColour();
index 95e320f..7ab4960 100644 (file)
@@ -1550,6 +1550,8 @@ public class AnnotationRenderer
                       .deriveFont(AffineTransform.getScaleInstance(sx, sy));
               g.setFont(font);
               g.drawChars(dc, 0, dc.length, x * charWidth, hght);
+              g.setFont(ofont);
+
               ht += newHeight;
             }
           }
index 19723ca..5a2d5dc 100755 (executable)
  */
 package jalview.schemes;
 
+import java.awt.Color;
+import java.util.List;
+import java.util.Map;
+
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
 import jalview.util.Comparison;
 
-import java.awt.Color;
-import java.util.List;
-import java.util.Map;
-
 public class ClustalxColourScheme extends ResidueColourScheme
 {
   private static final int EIGHTY_FIVE = 85;
@@ -95,7 +95,7 @@ public class ClustalxColourScheme extends ResidueColourScheme
   }
 
   @Override
-  public void alignmentChanged(AnnotatedCollectionI alignment,
+  public synchronized void alignmentChanged(AnnotatedCollectionI alignment,
           Map<SequenceI, SequenceCollectionI> hiddenReps)
   {
     int maxWidth = alignment.getWidth();
@@ -278,7 +278,7 @@ public class ClustalxColourScheme extends ResidueColourScheme
   }
 
   @Override
-  protected Color findColour(char c, int j, SequenceI seq)
+  protected synchronized Color findColour(char c, int j, SequenceI seq)
   {
     // TODO why the test for includeGaps here?
     if (cons2.length <= j || Comparison.isGap(c)
index 141ef10..061ccd4 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.schemes;
 
+import java.util.Locale;
+
 import jalview.xml.binding.jalview.JalviewUserColours;
 
 import java.awt.Color;
@@ -92,7 +94,7 @@ public class ColourSchemeLoader
 
         Color color = new Color(
                 Integer.parseInt(jucs.getColour().get(i).getRGB(), 16));
-        if (name.toLowerCase().equals(name))
+        if (name.toLowerCase(Locale.ROOT).equals(name))
         {
           caseSensitive = true;
           lowerCase[index] = color;
index d31fbba..faada0e 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.schemes;
 
+import java.util.Locale;
+
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceCollectionI;
@@ -104,7 +106,7 @@ public class ColourSchemes
      * name is lower-case for non-case-sensitive lookup
      * (name in the colour keeps its true case)
      */
-    String lower = name.toLowerCase();
+    String lower = name.toLowerCase(Locale.ROOT);
     if (schemes.containsKey(lower))
     {
       System.err
@@ -122,7 +124,7 @@ public class ColourSchemes
   {
     if (name != null)
     {
-      schemes.remove(name.toLowerCase());
+      schemes.remove(name.toLowerCase(Locale.ROOT));
     }
   }
 
@@ -148,7 +150,7 @@ public class ColourSchemes
     {
       return null;
     }
-    ColourSchemeI cs = schemes.get(name.toLowerCase());
+    ColourSchemeI cs = schemes.get(name.toLowerCase(Locale.ROOT));
     return cs == null ? null
             : cs.getInstance(viewport, forData);
   }
@@ -193,6 +195,6 @@ public class ColourSchemes
     {
       return false;
     }
-    return schemes.containsKey(name.toLowerCase());
+    return schemes.containsKey(name.toLowerCase(Locale.ROOT));
   }
 }
index 0d36f4f..e5bda58 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.schemes;
 
+import java.util.Locale;
+
 import jalview.api.FeatureColourI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.features.FeatureMatcher;
@@ -194,19 +196,19 @@ public class FeatureColour implements FeatureColourI
               "Expected either 'label' or a colour specification in the line: "
                       + descriptor);
     }
-    if (nextToken.toLowerCase().startsWith(LABEL))
+    if (nextToken.toLowerCase(Locale.ROOT).startsWith(LABEL))
     {
       byLabel = true;
       // get the token after the next delimiter:
       mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
       mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
     }
-    else if (nextToken.toLowerCase().startsWith(SCORE))
+    else if (nextToken.toLowerCase(Locale.ROOT).startsWith(SCORE))
     {
       mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
       mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
     }
-    else if (nextToken.toLowerCase().startsWith(ATTRIBUTE))
+    else if (nextToken.toLowerCase(Locale.ROOT).startsWith(ATTRIBUTE))
     {
       byAttribute = true;
       attName = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
@@ -304,7 +306,7 @@ public class FeatureColour implements FeatureColourI
       }
 
       gcol.nextToken(); // skip next '|'
-      if (tok.toLowerCase().startsWith(ABSOLUTE))
+      if (tok.toLowerCase(Locale.ROOT).startsWith(ABSOLUTE))
       {
         minval = gcol.nextToken();
         gcol.nextToken(); // skip next '|'
@@ -380,17 +382,17 @@ public class FeatureColour implements FeatureColourI
       {
         // threshold type and possibly a threshold value
         ttype = gcol.nextToken();
-        if (ttype.toLowerCase().startsWith(BELOW))
+        if (ttype.toLowerCase(Locale.ROOT).startsWith(BELOW))
         {
           featureColour.setBelowThreshold(true);
         }
-        else if (ttype.toLowerCase().startsWith(ABOVE))
+        else if (ttype.toLowerCase(Locale.ROOT).startsWith(ABOVE))
         {
           featureColour.setAboveThreshold(true);
         }
         else
         {
-          if (!ttype.toLowerCase().startsWith("no"))
+          if (!ttype.toLowerCase(Locale.ROOT).startsWith("no"))
           {
             System.err.println(
                     "Ignoring unrecognised threshold type : " + ttype);
index b15e4cf..6e8554f 100644 (file)
@@ -36,6 +36,12 @@ public class FeatureSettingsAdapter implements FeatureSettingsModelI
   }
 
   @Override
+  public boolean isFeatureHidden(String type)
+  {
+    return false;
+  }
+
+  @Override
   public boolean isGroupDisplayed(String group)
   {
     return true;
index 5f84ca0..2eb303d 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.schemes;
 
+import java.util.Locale;
+
 import jalview.analysis.GeneticCodes;
 
 import java.awt.Color;
@@ -2347,7 +2349,7 @@ public class ResidueProperties
         {
           continue;
         }
-        nuc = nuc.toUpperCase();
+        nuc = nuc.toUpperCase(Locale.ROOT);
         if (!result.contains(nuc))
         {
           result.add(nuc);
@@ -2366,7 +2368,7 @@ public class ResidueProperties
         {
           continue;
         }
-        res = res.toUpperCase();
+        res = res.toUpperCase(Locale.ROOT);
         if (!result.contains(res))
         {
           result.add(res);
@@ -2391,7 +2393,7 @@ public class ResidueProperties
       return '0';
     }
     Integer index = ResidueProperties.aa3Hash
-            .get(threeLetterCode.toUpperCase());
+            .get(threeLetterCode.toUpperCase(Locale.ROOT));
     return index == null ? '0' : aa[index].charAt(0);
   }
 }
index d77f2f5..d55ffbf 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.schemes;
 
+import java.util.Locale;
+
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.util.ColorUtils;
@@ -215,7 +217,7 @@ public class UserColourScheme extends ResidueColourScheme
             continue;
           }
 
-          if (residue.equals(residue.toLowerCase()))
+          if (residue.equals(residue.toLowerCase(Locale.ROOT)))
           {
             if (lowerCaseColours == null)
             {
@@ -306,7 +308,7 @@ public class UserColourScheme extends ResidueColourScheme
         c = lowerCaseColours[index];
         if (c != null && !c.equals(Color.white))
         {
-          residue = residue.toLowerCase();
+          residue = residue.toLowerCase(Locale.ROOT);
           if (colours.get(c) == null)
           {
             colours.put(c, new ArrayList<String>());
index 8716691..fdc8d16 100644 (file)
@@ -141,7 +141,7 @@ public abstract class StructureCommandsBase implements StructureCommandsI
   protected StructureCommandI getColourCommand(AtomSpecModel atomSpecModel,
           Color colour)
   {
-    String atomSpec = getAtomSpec(atomSpecModel, false);
+    String atomSpec = getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY);
     return colourResidues(atomSpec, colour);
   }
 
index 91e0494..0489bda 100644 (file)
@@ -86,10 +86,11 @@ public interface StructureCommandsI
    * 
    * @param refAtoms
    * @param atomSpec
+   * @param backbone - superpose based on which kind of atomType
    * @return
    */
   List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
-          AtomSpecModel atomSpec);
+          AtomSpecModel atomSpec, AtomSpecType backbone);
 
   /**
    * Returns a command to open a file of commands at the given path
@@ -108,16 +109,17 @@ public interface StructureCommandsI
    */
   StructureCommandI saveSession(String filepath);
 
+  enum AtomSpecType { RESIDUE_ONLY, ALPHA, PHOSPHATE }; 
   /**
    * Returns a representation of the atom set represented by the model, in
    * viewer syntax format. If {@code alphaOnly} is true, this is restricted to
    * Alpha Carbon (peptide) or Phosphorous (rna) only
    * 
    * @param model
-   * @param alphaOnly
+   * @param specType
    * @return
    */
-  String getAtomSpec(AtomSpecModel model, boolean alphaOnly);
+  String getAtomSpec(AtomSpecModel model, AtomSpecType specType);
 
   /**
    * Returns the lowest model number used by the structure viewer (likely 0 or
index 9662fee..cbd59b1 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.structure;
 
+import java.util.Locale;
+
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
 
@@ -130,7 +132,7 @@ public class StructureImportSettings
           String defaultStructureFileFormat)
   {
     StructureImportSettings.defaultStructureFileFormat = PDBEntry.Type
-            .valueOf(defaultStructureFileFormat.toUpperCase());
+            .valueOf(defaultStructureFileFormat.toUpperCase(Locale.ROOT));
   }
 
   public static String getDefaultPDBFileParser()
@@ -147,7 +149,7 @@ public class StructureImportSettings
   public static void setDefaultPDBFileParser(String defaultPDBFileParser)
   {
     StructureImportSettings.defaultPDBFileParser = StructureParser
-            .valueOf(defaultPDBFileParser.toUpperCase());
+            .valueOf(defaultPDBFileParser.toUpperCase(Locale.ROOT));
   }
 
 }
index 9fcb336..0209e20 100644 (file)
@@ -28,12 +28,13 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Vector;
 
 import jalview.analysis.AlignSeq;
 import jalview.api.StructureSelectionManagerProvider;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
 import jalview.commands.OrderCommand;
@@ -410,7 +411,17 @@ public class StructureSelectionManager
         registerPDBFile(pdb.getId().trim(), pdbFile);
       }
       // if PDBId is unavailable then skip SIFTS mapping execution path
-      isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable() && !pdb.getId().startsWith("AF-");
+      // TODO: JAL-3868 need to know if structure is actually from 
+      // PDB (has valid PDB ID and has provenance suggesting it 
+      // actually came from PDB)
+      boolean isProtein = false;
+      for (SequenceI s:sequenceArray) {
+        if (s.isProtein()) {
+          isProtein = true;
+          break;
+        }
+      }
+      isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable() && !pdb.getId().startsWith("AF-") && isProtein;
 
     } catch (Exception ex)
     {
@@ -430,8 +441,8 @@ public class StructureSelectionManager
     } catch (SiftsException e)
     {
       isMapUsingSIFTs = false;
-      Cache.log.error("SIFTS mapping failed", e);
-      Cache.log.error("Falling back on Needleman & Wunsch alignment");
+      Console.error("SIFTS mapping failed", e);
+      Console.error("Falling back on Needleman & Wunsch alignment");
       siftsClient = null;
     }
 
@@ -538,19 +549,19 @@ public class StructureSelectionManager
                     pdb, maxChain, sqmpping, maxAlignseq, siftsClient);
             seqToStrucMapping.add(siftsMapping);
             maxChain.makeExactMapping(siftsMapping, seq);
-            maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");
+            maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS",pdb.getId().toLowerCase(Locale.ROOT));
             maxChain.transferResidueAnnotation(siftsMapping, null);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
 
           } catch (SiftsException e)
           {
             // fall back to NW alignment
-            Cache.log.error(e.getMessage());
+            Console.error(e.getMessage());
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     targetChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
             maxChain.makeExactMapping(maxAlignseq, seq);
-            maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is
+            maxChain.transferRESNUMFeatures(seq, "IEA:Jalview",pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is
                                                                  // this
                                                         // "IEA:Jalview" ?
             maxChain.transferResidueAnnotation(nwMapping, sqmpping);
@@ -570,7 +581,7 @@ public class StructureSelectionManager
                       siftsClient);
               foundSiftsMappings.add(siftsMapping);
               chain.makeExactMapping(siftsMapping, seq);
-              chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this
+              chain.transferRESNUMFeatures(seq, "IEA: SIFTS",pdb.getId().toLowerCase(Locale.ROOT));// FIXME: is this
               // "IEA:SIFTS" ?
               chain.transferResidueAnnotation(siftsMapping, null);
             } catch (SiftsException e)
@@ -595,7 +606,7 @@ public class StructureSelectionManager
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     maxChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
-            maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
+            maxChain.transferRESNUMFeatures(seq, null,pdb.getId().toLowerCase(Locale.ROOT)); // FIXME: is this
                                                         // "IEA:Jalview" ?
             maxChain.transferResidueAnnotation(nwMapping, sqmpping);
             ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
@@ -763,7 +774,7 @@ public class StructureSelectionManager
     maxChain.makeExactMapping(maxAlignseq, seq);
     jalview.datamodel.Mapping sqmpping = maxAlignseq
             .getMappingFromS1(false);
-    maxChain.transferRESNUMFeatures(seq, null);
+    maxChain.transferRESNUMFeatures(seq, null, pdb.getId().toLowerCase(Locale.ROOT));
 
     HashMap<Integer, int[]> mapping = new HashMap<>();
     int resNum = -10000;
index 289d340..9ecf630 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.structures.models;
 
+import java.util.Locale;
+
 import java.awt.Color;
 import java.io.File;
 import java.io.IOException;
@@ -39,7 +41,7 @@ import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
 import jalview.api.StructureSelectionManagerProvider;
 import jalview.api.structures.JalviewStructureDisplayI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.MappedFeatures;
@@ -59,6 +61,7 @@ import jalview.structure.AtomSpec;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommandI;
 import jalview.structure.StructureCommandsI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 import jalview.structure.StructureListener;
 import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
@@ -67,7 +70,7 @@ import jalview.util.MessageManager;
 
 /**
  * 
- * A base class to hold common function for protein structure model binding.
+ * A base class to hold common function for 3D structure model binding.
  * Initial version created by refactoring JMol and Chimera binding models, but
  * other structure viewers could in principle be accommodated in future.
  * 
@@ -89,6 +92,9 @@ public abstract class AAStructureBindingModel
 
     public String chain = "";
 
+    /**
+     * is the mapped sequence not protein ?
+     */
     public boolean isRna;
 
     /*
@@ -165,6 +171,9 @@ public abstract class AAStructureBindingModel
 
   protected boolean colourBySequence = true;
 
+  /**
+   * true if all sequences appear to be nucleotide
+   */
   private boolean nucleotide;
 
   private boolean finishedInit = false;
@@ -582,6 +591,7 @@ public abstract class AAStructureBindingModel
       }
     }
   }
+  
 
   @Override
   public abstract void highlightAtoms(List<AtomSpec> atoms);
@@ -713,7 +723,7 @@ public abstract class AAStructureBindingModel
               structures[pdbfnum].chain = chain;
             }
             structures[pdbfnum].pdbId = mapping.getPdbId();
-            structures[pdbfnum].isRna = theSequence.getRNA() != null;
+            structures[pdbfnum].isRna = !theSequence.isProtein();
 
             /*
              * move on to next pdb file (ignore sequences for other chains
@@ -915,7 +925,8 @@ public abstract class AAStructureBindingModel
        */
       // todo better way to ensure synchronous than setting getReply true!!
       executeCommands(commandGenerator.showBackbone(), true, null);
-
+      
+      AtomSpecType backbone = structures[refStructure].isRna ? AtomSpecType.PHOSPHATE : AtomSpecType.ALPHA;
       /*
        * superpose each (other) structure to the reference in turn
        */
@@ -925,12 +936,12 @@ public abstract class AAStructureBindingModel
         {
           AtomSpecModel atomSpec = getAtomSpec(structures[i], matched);
           List<StructureCommandI> commands = commandGenerator
-                  .superposeStructures(refAtoms, atomSpec);
+                  .superposeStructures(refAtoms, atomSpec, backbone);
           List<String> replies = executeCommands(commands, true, null);
           for (String reply : replies)
           {
             // return this error (Chimera only) to the user
-            if (reply.toLowerCase().contains("unequal numbers of atoms"))
+            if (reply.toLowerCase(Locale.ROOT).contains("unequal numbers of atoms"))
             {
               error += "; " + reply;
             }
@@ -1072,7 +1083,10 @@ public abstract class AAStructureBindingModel
    * executed.
    * <p>
    * If a reply is wanted, the execution is done synchronously (waits),
-   * otherwise it is done in a separate thread (doesn't wait).
+   * otherwise it is done in a separate thread (doesn't wait). WARNING: if you
+   * are sending commands that need to execute before later calls to
+   * executeCommand (e.g. mouseovers, which clean up after previous ones) then
+   * set getReply true to ensure that commands are not executed out of order.
    * 
    * @param getReply
    * @param msg
@@ -1216,8 +1230,7 @@ public abstract class AAStructureBindingModel
   }
 
   /**
-   * Returns the FeatureRenderer for the given alignment view, or null if
-   * feature display is turned off in the view.
+   * Returns the FeatureRenderer for the given alignment view
    * 
    * @param avp
    * @return
@@ -1230,9 +1243,7 @@ public abstract class AAStructureBindingModel
     {
       return null;
     }
-    return ap.getAlignViewport().isShowSequenceFeatures()
-            ? ap.getFeatureRenderer()
-            : null;
+    return ap.getFeatureRenderer();
   }
 
   protected void setStructureCommands(StructureCommandsI cmd)
@@ -1494,7 +1505,7 @@ public abstract class AAStructureBindingModel
       saveSession(f);
     } catch (IOException e)
     {
-      Cache.log.error(String.format("Error saving %s session: %s", prefix,
+      Console.error(String.format("Error saving %s session: %s", prefix,
               e.toString()));
     }
 
index a0f42f0..02e565e 100644 (file)
@@ -21,7 +21,7 @@
 
 package jalview.urls;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.urls.api.UrlProviderI;
 import jalview.util.UrlLink;
 
@@ -101,7 +101,7 @@ public class UrlLinkTableModel extends AbstractTableModel
           dataProvider.setUrlData(data);
         } catch (IllegalArgumentException ex)
         {
-          Cache.log.error(ex.getMessage());
+          Console.error(ex.getMessage());
         }
       }
     });
index 8119daa..dbd9177 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.util;
 
+import jalview.bin.Cache;
+
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
@@ -712,7 +714,7 @@ public class BrowserLauncher
 
     case OTHER:
     default:
-      browser = jalview.bin.Cache.getDefault("DEFAULT_BROWSER", "firefox");
+      browser = Cache.getDefault("DEFAULT_BROWSER", "firefox");
 
       break;
     }
index a01c035..536671d 100644 (file)
@@ -25,6 +25,8 @@ package jalview.util;
  * want to preserve case, but do not want to duplicate upper and lower case
  * variants
  */
+import java.util.Locale;
+
 public final class CaseInsensitiveString
 {
   String value;
@@ -72,6 +74,6 @@ public final class CaseInsensitiveString
   public int hashCode()
   {
     return value == null ? super.hashCode()
-            : value.toUpperCase().hashCode();
+            : value.toUpperCase(Locale.ROOT).hashCode();
   }
 }
index 109eaa5..40f6110 100644 (file)
@@ -1,6 +1,9 @@
 package jalview.util;
 
 import java.awt.Image;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -13,14 +16,12 @@ import java.util.Properties;
 
 import javax.swing.ImageIcon;
 
-import jalview.bin.Cache;
-
 public class ChannelProperties
 {
 
-  private static final String CHANNEL_PROPERTIES_FILENAME = "/channel.props";
+  public static final String CHANNEL_PROPERTIES_FILENAME = "channel.props";
 
-  private static final Properties channelProps;
+  private static Properties channelProps;
 
   private static final Properties defaultProps;
 
@@ -60,11 +61,11 @@ public class ChannelProperties
     // load channel_properties
     Properties tryChannelProps = new Properties();
     URL channelPropsURL = ChannelProperties.class
-            .getResource(CHANNEL_PROPERTIES_FILENAME);
+            .getResource("/" + CHANNEL_PROPERTIES_FILENAME);
     if (channelPropsURL == null)
     {
       // complete failure of channel_properties, set all properties to defaults
-      System.err.println("Failed to find '" + CHANNEL_PROPERTIES_FILENAME
+      System.err.println("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
               + "' file at '"
               + (channelPropsURL == null ? "null"
                       : channelPropsURL.toString())
@@ -80,7 +81,7 @@ public class ChannelProperties
         channelPropsIS.close();
       } catch (IOException e)
       {
-        Cache.log.warn(e.getMessage());
+        System.err.println(e.getMessage());
         // return false;
       }
     }
@@ -113,7 +114,9 @@ public class ChannelProperties
         Image logo = null;
         String path = defaultProps.getProperty("logo." + size);
         URL imageURL = ChannelProperties.class.getResource(path);
-        logo = new ImageIcon(imageURL).getImage();
+        ImageIcon imgIcon = imageURL == null ? null
+                : new ImageIcon(imageURL);
+        logo = imgIcon == null ? null : imgIcon.getImage();
         if (logo != null)
         {
           iconList.add(logo);
@@ -122,6 +125,25 @@ public class ChannelProperties
     }
   }
 
+  protected static void loadProps(File dir)
+  {
+    File channelPropsFile = new File(dir, CHANNEL_PROPERTIES_FILENAME);
+    if (channelPropsFile.exists())
+    {
+      try
+      {
+        InputStream is = new FileInputStream(channelPropsFile);
+        channelProps.load(is);
+      } catch (FileNotFoundException e)
+      {
+        System.err.println(e.getMessage());
+      } catch (IOException e)
+      {
+        System.err.println(e.getMessage());
+      }
+    }
+  }
+
   private static Properties channelProps()
   {
     return channelProps;
@@ -219,7 +241,8 @@ public class ChannelProperties
       }
 
       URL imageURL = ChannelProperties.class.getResource(path);
-      img = new ImageIcon(imageURL).getImage();
+      ImageIcon imgIcon = imageURL == null ? null : new ImageIcon(imageURL);
+      img = imgIcon == null ? null : imgIcon.getImage();
       if (img == null)
       {
         System.err.println(
index 60129fb..5db333f 100644 (file)
@@ -24,6 +24,8 @@
 
 package jalview.util;
 
+import java.util.Locale;
+
 import java.awt.Color;
 import java.util.HashMap;
 import java.util.Map;
@@ -324,7 +326,7 @@ public class ColorUtils
       return null;
     }
     Color col = null;
-    name = name.toLowerCase();
+    name = name.toLowerCase(Locale.ROOT);
 
     // or make a static map; or use reflection on the field name
     switch (name)
index 286bfb2..0d945ac 100644 (file)
@@ -261,7 +261,7 @@ public class Comparison
 
   /**
    * Overloaded method signature to test whether a single sequence is nucleotide
-   * (that is, more than 85% CGTA)
+   * (that is, more than 85% CGTAUNX)
    * 
    * @param seq
    * @return
@@ -274,27 +274,32 @@ public class Comparison
     }
     long ntCount = 0;
     long aaCount = 0;
+    long nCount = 0;
 
     int len = seq.getLength();
     for (int i = 0; i < len; i++)
     {
       char c = seq.getCharAt(i);
-      if (isNucleotide(c))
+      if (isNucleotide(c) || isX(c))
       {
         ntCount++;
       }
       else if (!isGap(c))
       {
         aaCount++;
+        if (isN(c))
+        {
+          nCount++;
+        }
       }
     }
     /*
      * Check for nucleotide count > 85% of total count (in a form that evades
      * int / float conversion or divide by zero).
      */
-    if (ntCount * 100 > EIGHTY_FIVE * (ntCount + aaCount))
+    if ((ntCount+nCount) * 100 > EIGHTY_FIVE * (ntCount + aaCount))
     {
-      return true;
+      return ntCount>0; // all N is considered protein. Could use a threshold here too
     }
     else
     {
@@ -317,17 +322,18 @@ public class Comparison
       return false;
     }
     // true if we have seen a nucleotide sequence
-    boolean na=false;
+    boolean na = false;
     for (SequenceI seq : seqs)
     {
       if (seq == null)
       {
         continue;
       }
-      na=true;
+      na = true;
       // TODO could possibly make an informed guess just from the first sequence
       // to save a lengthy calculation
-      if (seq.isProtein()) {
+      if (seq.isProtein())
+      {
         // if even one looks like protein, the alignment is protein
         return false;
       }
@@ -347,7 +353,6 @@ public class Comparison
     {
       c -= TO_UPPER_CASE;
     }
-
     switch (c)
     {
     case 'A':
@@ -360,6 +365,28 @@ public class Comparison
     return false;
   }
 
+  public static boolean isN(char c)
+  {
+    switch (c)
+    {
+    case 'N':
+    case 'n':
+      return true;
+    }
+    return false;
+  }
+
+  public static boolean isX(char c)
+  {
+    switch (c)
+    {
+    case 'X':
+    case 'x':
+      return true;
+    }
+    return false;
+  }
+
   /**
    * Answers true if every character in the string is one of aAcCgGtTuU, or
    * (optionally) a gap character (dot, dash, space), else false
index ae0243e..bcb0bd3 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.util;
 
+import java.util.Locale;
+
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.HashMap;
@@ -73,7 +75,7 @@ public class DBRefUtils
            // guarantee we always have lowercase entries for canonical string lookups
            for (String k : canonicalSourceNameLookup.keySet())
            {
-             canonicalSourceNameLookup.put(k.toLowerCase(),
+             canonicalSourceNameLookup.put(k.toLowerCase(Locale.ROOT),
                      canonicalSourceNameLookup.get(k));
            }
    }
@@ -98,7 +100,7 @@ public class DBRefUtils
        HashSet<String> srcs = new HashSet<String>();
        for (String src : sources) 
        {
-         srcs.add(src.toUpperCase());
+         srcs.add(src.toUpperCase(Locale.ROOT));
        }
 
        int nrefs = dbrefs.size();
@@ -107,7 +109,7 @@ public class DBRefUtils
        {
          DBRefEntry dbr = dbrefs.get(ib);
          String source = getCanonicalName(dbr.getSource());
-         if (srcs.contains(source.toUpperCase())) 
+         if (srcs.contains(source.toUpperCase(Locale.ROOT))) 
          {
            res.add(dbr);
          }
@@ -181,7 +183,7 @@ public class DBRefUtils
          {
                return null;
          }
-         String canonical = canonicalSourceNameLookup.get(source.toLowerCase());
+         String canonical = canonicalSourceNameLookup.get(source.toLowerCase(Locale.ROOT));
          return canonical == null ? source : canonical;
        }
 
index 284ec10..654b03a 100644 (file)
@@ -47,6 +47,7 @@ public class DnaUtils
   public static List<int[]> parseLocation(String location)
           throws ParseException
   {
+    location = location.trim(); // failsafe for untidy input data
     if (location.startsWith("join("))
     {
       return parseJoin(location);
diff --git a/src/jalview/util/LaunchUtils.java b/src/jalview/util/LaunchUtils.java
new file mode 100644 (file)
index 0000000..3302dba
--- /dev/null
@@ -0,0 +1,56 @@
+package jalview.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Properties;
+
+public class LaunchUtils
+{
+
+  public static void loadChannelProps(File dir)
+  {
+    ChannelProperties.loadProps(dir);
+  }
+
+  private static Properties userPreferences = null;
+
+  public static String getUserPreference(String key)
+  {
+    if (userPreferences == null)
+    {
+      String channelPrefsFilename = ChannelProperties
+              .getProperty("preferences.filename");
+      if (channelPrefsFilename == null)
+      {
+        return null;
+      }
+      File propertiesFile = new File(System.getProperty("user.home"),
+              channelPrefsFilename);
+      if (!propertiesFile.exists())
+      {
+        return null;
+      }
+      try
+      {
+        userPreferences = new Properties();
+        userPreferences.load(new FileInputStream(propertiesFile));
+      } catch (FileNotFoundException e)
+      {
+        // didn't find user preferences file
+        return null;
+      } catch (IOException e)
+      {
+        System.err.println(e.getMessage());
+        return null;
+      }
+    }
+    return userPreferences.getProperty(key);
+  }
+
+  public static boolean getBooleanUserPreference(String key)
+  {
+    return Boolean.parseBoolean(getUserPreference(key));
+  }
+}
diff --git a/src/jalview/util/Log4j.java b/src/jalview/util/Log4j.java
new file mode 100644 (file)
index 0000000..05c641b
--- /dev/null
@@ -0,0 +1,204 @@
+package jalview.util;
+
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+import org.apache.logging.log4j.core.filter.ThresholdFilter;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+
+import jalview.log.JLogger;
+import jalview.log.JalviewAppender;
+
+public class Log4j
+{
+
+  public final static String SIMPLE_PATTERN = "%level - %m%n";
+
+  private static boolean init = false;
+
+  public static boolean isInit()
+  {
+    return init;
+  }
+
+  public static Level log4jLevel(JLogger.LogLevel loglevel)
+  {
+    return Level.toLevel(loglevel.toString());
+  }
+
+  public static void init(JLogger.LogLevel myLevel)
+  {
+    init(log4jLevel(myLevel));
+  }
+
+  public static void init(Level myLevel)
+  {
+    if (init)
+      return;
+    try
+    {
+      // configure the root logger to stderr
+      ConfigurationBuilder<BuiltConfiguration> configBuilder = Log4j
+              .getConfigurationBuilder();
+
+      configBuilder.setStatusLevel(Level.WARN);
+
+      String consoleLoggerName = "STDERR";
+      AppenderComponentBuilder appenderBuilder = configBuilder
+              .newAppender(consoleLoggerName, "Console");
+      appenderBuilder.addAttribute("target",
+              ConsoleAppender.Target.SYSTEM_ERR);
+      appenderBuilder.add(Log4j.getSimpleLayoutBuilder());
+      appenderBuilder.add(Log4j.getThresholdFilterBuilder());
+      configBuilder.add(appenderBuilder);
+
+      configBuilder.add(configBuilder.newRootLogger(myLevel)
+              .add(configBuilder.newAppenderRef(consoleLoggerName)));
+
+      Configurator.initialize(configBuilder.build());
+
+      init = true;
+    } catch (Exception e)
+    {
+      System.err.println("Problems initializing the log4j system\n");
+      e.printStackTrace(System.err);
+    }
+  }
+
+  public static Logger getLogger(String name)
+  {
+    return getLogger(name, Level.INFO);
+  }
+
+  public static Logger getLogger(String name, JLogger.LogLevel loglevel)
+  {
+    return getLogger(name, log4jLevel(loglevel));
+  }
+
+  public static Logger getLogger(String name, Level level)
+  {
+    Logger logger = LogManager.getLogger(name);
+    Log4j.setLevel(logger, level);
+    return logger;
+  }
+
+  public static ConfigurationBuilder<BuiltConfiguration> getConfigurationBuilder()
+  {
+    return ConfigurationFactory.newConfigurationBuilder();
+  }
+
+  public static Layout getSimpleLayout()
+  {
+    return PatternLayout.newBuilder().withPattern(SIMPLE_PATTERN).build();
+  }
+
+  public static LayoutComponentBuilder getSimpleLayoutBuilder()
+  {
+    return getConfigurationBuilder().newLayout("PatternLayout")
+            .addAttribute("pattern", Log4j.SIMPLE_PATTERN);
+  }
+
+  public static Filter getThresholdFilter(Level level)
+  {
+    return ThresholdFilter.createFilter(level, Filter.Result.ACCEPT,
+            Filter.Result.NEUTRAL);
+  }
+
+  public static FilterComponentBuilder getThresholdFilterBuilder()
+  {
+    return getConfigurationBuilder().newFilter("ThresholdFilter",
+            Filter.Result.ACCEPT, Filter.Result.NEUTRAL);
+  }
+
+  public static void setLevel(Logger logger, JLogger.LogLevel loglevel)
+  {
+    setLevel(logger, log4jLevel(loglevel));
+  }
+
+  public static void setLevel(Logger logger, Level level)
+  {
+    if (!Platform.isJS())
+    {
+      LoggerContext context = (LoggerContext) LogManager.getContext(false);
+      Configuration config = context.getConfiguration();
+      LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
+      loggerConfig.setLevel(level);
+
+      Map<String, Appender> appenders = config.getAppenders();
+
+      Appender jappender = config.getAppender(JalviewAppender.NAME);
+
+      context.updateLoggers();
+    }
+  }
+
+  public static void setRootLevel(JLogger.LogLevel loglevel)
+  {
+    setRootLevel(log4jLevel(loglevel));
+  }
+
+  public static void setRootLevel(Level level)
+  {
+    setLevel(LogManager.getRootLogger(), level);
+  }
+
+  public static Appender getAppender(String name)
+  {
+    LoggerContext context = (LoggerContext) LogManager.getContext(false);
+    Configuration config = context.getConfiguration();
+    Map<String, Appender> appenders = config.getAppenders();
+    return appenders.get(name);
+  }
+
+  public static void addAppender(Logger logger, Logger logger2,
+          String name2)
+  {
+    LoggerContext context = (LoggerContext) LogManager.getContext(false);
+    Configuration config = context.getConfiguration();
+    LoggerConfig logger2Config = config.getLoggerConfig(logger2.getName());
+    Map<String, Appender> logger2AppendersMap = logger2Config
+            .getAppenders();
+    Appender appender = logger2AppendersMap.get(name2);
+    addAppender(logger, appender);
+    context.updateLoggers();
+  }
+
+  public static void addAppender(Logger logger, Appender appender)
+  {
+    if (appender == null)
+      return;
+    LoggerContext context = (LoggerContext) LogManager.getContext(false);
+    Configuration config = context.getConfiguration();
+    LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
+    if (loggerConfig == null)
+      return;
+
+    Level level = loggerConfig.getLevel();
+
+    config.addAppender(appender);
+    loggerConfig.addAppender(appender, null, null);
+
+    context.updateLoggers();
+  }
+
+  public static void addAppenderToRootLogger(Appender appender)
+  {
+    Log4j.addAppender(LogManager.getRootLogger(), appender);
+  }
+}
index 731e976..d6a125b 100644 (file)
@@ -22,16 +22,17 @@ package jalview.util;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.List;
 
+import jalview.bin.Console;
+
 /**
  * A simple way of bijectively mapping a non-contiguous linear range to another
  * non-contiguous linear range.
  * 
  * Use at your own risk!
  * 
- * TODO: efficient implementation of private posMap method
- * 
  * TODO: test/ensure that sense of from and to ratio start position is conserved
  * (codon start position recovery)
  */
@@ -209,8 +210,7 @@ public class MapList
 
   /**
    * Constructor given from and to ranges as [start1, end1, start2, end2,...].
-   * If any end is equal to the next start, the ranges will be merged. There is
-   * no validation check that the ranges do not overlap each other.
+   * There is no validation check that the ranges do not overlap each other.
    * 
    * @param from
    *          contiguous regions as [start1, end1, start2, end2, ...]
@@ -228,7 +228,6 @@ public class MapList
     this.toRatio = toRatio;
     fromLowest = Integer.MAX_VALUE;
     fromHighest = Integer.MIN_VALUE;
-    int added = 0;
 
     for (int i = 0; i < from.length; i += 2)
     {
@@ -238,36 +237,16 @@ public class MapList
        */
       fromLowest = Math.min(fromLowest, Math.min(from[i], from[i + 1]));
       fromHighest = Math.max(fromHighest, Math.max(from[i], from[i + 1]));
-      if (added > 0 && from[i] == fromShifts.get(added - 1)[1])
-      {
-        /*
-         * this range starts where the last ended - just extend it
-         */
-        fromShifts.get(added - 1)[1] = from[i + 1];
-      }
-      else
-      {
-        fromShifts.add(new int[] { from[i], from[i + 1] });
-        added++;
-      }
+      fromShifts.add(new int[] { from[i], from[i + 1] });
     }
 
     toLowest = Integer.MAX_VALUE;
     toHighest = Integer.MIN_VALUE;
-    added = 0;
     for (int i = 0; i < to.length; i += 2)
     {
       toLowest = Math.min(toLowest, Math.min(to[i], to[i + 1]));
       toHighest = Math.max(toHighest, Math.max(to[i], to[i + 1]));
-      if (added > 0 && to[i] == toShifts.get(added - 1)[1])
-      {
-        toShifts.get(added - 1)[1] = to[i + 1];
-      }
-      else
-      {
-        toShifts.add(new int[] { to[i], to[i + 1] });
-        added++;
-      }
+      toShifts.add(new int[] { to[i], to[i + 1] });
     }
   }
 
@@ -330,9 +309,8 @@ public class MapList
       if (range.length != 2)
       {
         // throw new IllegalArgumentException(range);
-        System.err.println(
-                "Invalid format for fromRange " + Arrays.toString(range)
-                + " may cause errors");
+        Console.error("Invalid format for fromRange "
+                + Arrays.toString(range) + " may cause errors");
       }
       fromLowest = Math.min(fromLowest, Math.min(range[0], range[1]));
       fromHighest = Math.max(fromHighest, Math.max(range[0], range[1]));
@@ -345,9 +323,8 @@ public class MapList
       if (range.length != 2)
       {
         // throw new IllegalArgumentException(range);
-        System.err.println("Invalid format for toRange "
-                + Arrays.toString(range)
-                + " may cause errors");
+        Console.error("Invalid format for toRange "
+                + Arrays.toString(range) + " may cause errors");
       }
       toLowest = Math.min(toLowest, Math.min(range[0], range[1]));
       toHighest = Math.max(toHighest, Math.max(range[0], range[1]));
@@ -357,6 +334,17 @@ public class MapList
   /**
    * Consolidates a list of ranges so that any contiguous ranges are merged.
    * This assumes the ranges are already in start order (does not sort them).
+   * <p>
+   * The main use case for this method is when mapping cDNA sequence to its
+   * protein product, based on CDS feature ranges which derive from spliced
+   * exons, but are contiguous on the cDNA sequence. For example
+   * 
+   * <pre>
+   *   CDS 1-20  // from exon1
+   *   CDS 21-35 // from exon2
+   *   CDS 36-71 // from exon3
+   * 'coalesce' to range 1-71
+   * </pre>
    * 
    * @param ranges
    * @return the same list (if unchanged), else a new merged list, leaving the
@@ -384,27 +372,6 @@ public class MapList
         first = false;
         continue;
       }
-      if (range[0] == lastRange[0] && range[1] == lastRange[1])
-      {
-        // drop duplicate range
-        changed = true;
-        continue;
-      }
-
-      /*
-       * drop this range if it lies within the last range
-       */
-      if ((lastDirection == 1 && range[0] >= lastRange[0]
-              && range[0] <= lastRange[1] && range[1] >= lastRange[0]
-              && range[1] <= lastRange[1])
-              || (lastDirection == -1 && range[0] <= lastRange[0]
-                      && range[0] >= lastRange[1]
-                      && range[1] <= lastRange[0]
-                      && range[1] >= lastRange[1]))
-      {
-        changed = true;
-        continue;
-      }
 
       int direction = range[1] >= range[0] ? 1 : -1;
 
@@ -415,11 +382,7 @@ public class MapList
       boolean sameDirection = range[1] == range[0]
               || direction == lastDirection;
       boolean extending = range[0] == lastRange[1] + lastDirection;
-      boolean overlapping = (lastDirection == 1 && range[0] >= lastRange[0]
-              && range[0] <= lastRange[1])
-              || (lastDirection == -1 && range[0] <= lastRange[0]
-                      && range[0] >= lastRange[1]);
-      if (sameDirection && (overlapping || extending))
+      if (sameDirection && extending)
       {
         lastRange[1] = range[1];
         changed = true;
@@ -444,7 +407,7 @@ public class MapList
    */
   protected int[][] makeFromMap()
   {
-    // TODO not used - remove??
+    // TODO only used for test - remove??
     return posMap(fromShifts, fromRatio, toShifts, toRatio);
   }
 
@@ -455,7 +418,7 @@ public class MapList
    */
   protected int[][] makeToMap()
   {
-    // TODO not used - remove??
+    // TODO only used for test - remove??
     return posMap(toShifts, toRatio, fromShifts, fromRatio);
   }
 
@@ -466,10 +429,10 @@ public class MapList
    * @return int[] { from, to pos in range }, int[range.to-range.from+1]
    *         returning mapped position
    */
-  private int[][] posMap(List<int[]> shiftTo, int ratio,
-          List<int[]> shiftFrom, int toRatio)
+  private int[][] posMap(List<int[]> shiftTo, int sourceRatio,
+          List<int[]> shiftFrom, int targetRatio)
   {
-    // TODO not used - remove??
+    // TODO only used for test - remove??
     int iv = 0, ivSize = shiftTo.size();
     if (iv >= ivSize)
     {
@@ -506,7 +469,8 @@ public class MapList
     int mp[][] = new int[to - from + 2][];
     for (int i = 0; i < mp.length; i++)
     {
-      int[] m = shift(i + from, shiftTo, ratio, shiftFrom, toRatio);
+      int[] m = shift(i + from, shiftTo, sourceRatio, shiftFrom,
+              targetRatio);
       if (m != null)
       {
         if (i == 0)
@@ -600,37 +564,51 @@ public class MapList
           List<int[]> shiftFrom, int toRatio)
   {
     // TODO: javadoc; tests
-    int[] fromCount = countPos(shiftTo, pos);
+    int[] fromCount = countPositions(shiftTo, pos);
     if (fromCount == null)
     {
       return null;
     }
     int fromRemainder = (fromCount[0] - 1) % fromRatio;
     int toCount = 1 + (((fromCount[0] - 1) / fromRatio) * toRatio);
-    int[] toPos = countToPos(shiftFrom, toCount);
+    int[] toPos = traverseToPosition(shiftFrom, toCount);
     if (toPos == null)
     {
-      return null; // throw new Error("Bad Mapping!");
+      return null;
     }
-    // System.out.println(fromCount[0]+" "+fromCount[1]+" "+toCount);
     return new int[] { toPos[0], fromRemainder, toPos[1] };
   }
 
   /**
-   * count how many positions pos is along the series of intervals.
+   * Counts how many positions pos is along the series of intervals. Returns an
+   * array of two values:
+   * <ul>
+   * <li>the number of positions traversed (inclusive) to reach {@code pos}</li>
+   * <li>+1 if the last interval traversed is forward, -1 if in a negative
+   * direction</li>
+   * </ul>
+   * Returns null if {@code pos} does not lie in any of the given intervals.
    * 
-   * @param shiftTo
+   * @param intervals
+   *          a list of start-end intervals
    * @param pos
-   * @return number of positions or null if pos is not within intervals
+   *          a position that may lie in one (or more) of the intervals
+   * @return
    */
-  protected static int[] countPos(List<int[]> shiftTo, int pos)
+  protected static int[] countPositions(List<int[]> intervals, int pos)
   {
-    int count = 0, intv[], iv = 0, ivSize = shiftTo.size();
+    int count = 0;
+    int iv = 0;
+    int ivSize = intervals.size();
+
     while (iv < ivSize)
     {
-      intv = shiftTo.get(iv++);
+      int[] intv = intervals.get(iv++);
       if (intv[0] <= intv[1])
       {
+        /*
+         * forwards interval
+         */
         if (pos >= intv[0] && pos <= intv[1])
         {
           return new int[] { count + pos - intv[0] + 1, +1 };
@@ -642,6 +620,9 @@ public class MapList
       }
       else
       {
+        /*
+         * reverse interval
+         */
         if (pos >= intv[1] && pos <= intv[0])
         {
           return new int[] { count + intv[0] - pos + 1, -1 };
@@ -656,79 +637,61 @@ public class MapList
   }
 
   /**
-   * count out pos positions into a series of intervals and return the position
+   * Reads through the given intervals until {@code count} positions have been
+   * traversed, and returns an array consisting of two values:
+   * <ul>
+   * <li>the value at the {@code count'th} position</li>
+   * <li>+1 if the last interval read is forwards, -1 if reverse direction</li>
+   * </ul>
+   * Returns null if the ranges include less than {@code count} positions, or if
+   * {@code count < 1}.
    * 
-   * @param shiftFrom
-   * @param pos
-   * @return position pos in interval set
+   * @param intervals
+   *          a list of [start, end] ranges
+   * @param count
+   *          the number of positions to traverse
+   * @return
    */
-  protected static int[] countToPos(List<int[]> shiftFrom, int pos)
+  protected static int[] traverseToPosition(List<int[]> intervals,
+          final int count)
   {
-    int count = 0, diff = 0, iv = 0, ivSize = shiftFrom.size();
-    int[] intv = { 0, 0 };
+    int traversed = 0;
+    int ivSize = intervals.size();
+    int iv = 0;
+
+    if (count < 1)
+    {
+      return null;
+    }
+
     while (iv < ivSize)
     {
-      intv = shiftFrom.get(iv++);
-      diff = intv[1] - intv[0];
+      int[] intv = intervals.get(iv++);
+      int diff = intv[1] - intv[0];
       if (diff >= 0)
       {
-        if (pos <= count + 1 + diff)
+        if (count <= traversed + 1 + diff)
         {
-          return new int[] { pos - count - 1 + intv[0], +1 };
+          return new int[] { intv[0] + (count - traversed - 1), +1 };
         }
         else
         {
-          count += 1 + diff;
+          traversed += 1 + diff;
         }
       }
       else
       {
-        if (pos <= count + 1 - diff)
+        if (count <= traversed + 1 - diff)
         {
-          return new int[] { intv[0] - (pos - count - 1), -1 };
+          return new int[] { intv[0] - (count - traversed - 1), -1 };
         }
         else
         {
-          count += 1 - diff;
+          traversed += 1 - diff;
         }
       }
     }
-    return null;// (diff<0) ? (intv[1]-1) : (intv[0]+1);
-  }
-
-  /**
-   * find series of intervals mapping from start-end in the From map.
-   * 
-   * @param start
-   *          position mapped 'to'
-   * @param end
-   *          position mapped 'to'
-   * @return series of [start, end] ranges in sequence mapped 'from'
-   */
-  public int[] locateInFrom(int start, int end)
-  {
-    // inefficient implementation
-    int fromStart[] = shiftTo(start);
-    // needs to be inclusive of end of symbol position
-    int fromEnd[] = shiftTo(end);
-
-    return getIntervals(fromShifts, fromStart, fromEnd, fromRatio);
-  }
-
-  /**
-   * find series of intervals mapping from start-end in the to map.
-   * 
-   * @param start
-   *          position mapped 'from'
-   * @param end
-   *          position mapped 'from'
-   * @return series of [start, end] ranges in sequence mapped 'to'
-   */
-  public int[] locateInTo(int start, int end)
-  {
-    int toStart[] = shiftFrom(start);
-    int toEnd[] = shiftFrom(end);
-    return getIntervals(toShifts, toStart, toEnd, toRatio);
+    return null;
   }
 
   /**
@@ -907,7 +870,6 @@ public class MapList
    */
   public int getToPosition(int mpos)
   {
-    // TODO not used - remove??
     int[] mp = shiftTo(mpos);
     if (mp != null)
     {
@@ -917,53 +879,6 @@ public class MapList
   }
 
   /**
-   * get range of positions in To frame for the mpos word in From
-   * 
-   * @param mpos
-   *          position in From
-   * @return null or int[] first position in To for mpos, last position in to
-   *         for Mpos
-   */
-  public int[] getToWord(int mpos)
-  {
-    int[] mp = shiftTo(mpos);
-    if (mp != null)
-    {
-      return new int[] { mp[0], mp[0] + mp[2] * (getFromRatio() - 1) };
-    }
-    return null;
-  }
-
-  /**
-   * get From position in the associated reference frame for position pos in the
-   * associated sequence.
-   * 
-   * @param pos
-   * @return
-   */
-  public int getMappedPosition(int pos)
-  {
-    // TODO not used - remove??
-    int[] mp = shiftFrom(pos);
-    if (mp != null)
-    {
-      return mp[0];
-    }
-    return pos;
-  }
-
-  public int[] getMappedWord(int pos)
-  {
-    // TODO not used - remove??
-    int[] mp = shiftFrom(pos);
-    if (mp != null)
-    {
-      return new int[] { mp[0], mp[0] + mp[2] * (getToRatio() - 1) };
-    }
-    return null;
-  }
-
-  /**
    * 
    * @return a MapList whose From range is this maplist's To Range, and vice
    *         versa
@@ -975,33 +890,6 @@ public class MapList
   }
 
   /**
-   * test for containment rather than equivalence to another mapping
-   * 
-   * @param map
-   *          to be tested for containment
-   * @return true if local or mapped range map contains or is contained by this
-   *         mapping
-   */
-  public boolean containsEither(boolean local, MapList map)
-  {
-    // TODO not used - remove?
-    if (local)
-    {
-      return ((getFromLowest() >= map.getFromLowest()
-              && getFromHighest() <= map.getFromHighest())
-              || (getFromLowest() <= map.getFromLowest()
-                      && getFromHighest() >= map.getFromHighest()));
-    }
-    else
-    {
-      return ((getToLowest() >= map.getToLowest()
-              && getToHighest() <= map.getToHighest())
-              || (getToLowest() <= map.getToLowest()
-                      && getToHighest() >= map.getToHighest()));
-    }
-  }
-
-  /**
    * String representation - for debugging, not guaranteed not to change
    */
   @Override
@@ -1134,8 +1022,8 @@ public class MapList
   }
 
   /**
-   * A helper method that returns true unless at least one range has start > end.
-   * Behaviour is undefined for a mixture of forward and reverse ranges.
+   * A helper method that returns true unless at least one range has start >
+   * end. Behaviour is undefined for a mixture of forward and reverse ranges.
    * 
    * @param ranges
    * @return
@@ -1216,6 +1104,7 @@ public class MapList
     List<int[]> toRanges = new ArrayList<>();
     for (int[] range : getToRanges())
     {
+      int fromLength = Math.abs(range[1] - range[0]) + 1;
       int[] transferred = map.locateInTo(range[0], range[1]);
       if (transferred == null || transferred.length % 2 != 0)
       {
@@ -1226,11 +1115,21 @@ public class MapList
        *  convert [start1, end1, start2, end2, ...] 
        *  to [[start1, end1], [start2, end2], ...]
        */
+      int toLength = 0;
       for (int i = 0; i < transferred.length;)
       {
         toRanges.add(new int[] { transferred[i], transferred[i + 1] });
+        toLength += Math.abs(transferred[i + 1] - transferred[i]) + 1;
         i += 2;
       }
+
+      /*
+       * check we mapped the full range - if not, abort
+       */
+      if (fromLength * map.getToRatio() != toLength * map.getFromRatio())
+      {
+        return null;
+      }
     }
 
     return new MapList(getFromRanges(), toRanges, outFromRatio, outToRatio);
@@ -1246,4 +1145,315 @@ public class MapList
   {
     return fromShifts.size() == 1 && toShifts.size() == 1;
   }
+
+  /**
+   * <<<<<<< HEAD Returns the [start1, end1, start2, end2, ...] positions in the
+   * 'from' range that map to positions between {@code start} and {@code end} in
+   * the 'to' range. Note that for a reverse strand mapping this will return
+   * ranges with end < start. Returns null if no mapped positions are found in
+   * start-end.
+   * 
+   * @param start
+   * @param end
+   * @return
+   */
+  public int[] locateInFrom(int start, int end)
+  {
+    return mapPositions(start, end, toShifts, fromShifts, toRatio,
+            fromRatio);
+  }
+
+  /**
+   * Returns the [start1, end1, start2, end2, ...] positions in the 'to' range
+   * that map to positions between {@code start} and {@code end} in the 'from'
+   * range. Note that for a reverse strand mapping this will return ranges with
+   * end < start. Returns null if no mapped positions are found in start-end.
+   * 
+   * @param start
+   * @param end
+   * @return
+   */
+  public int[] locateInTo(int start, int end)
+  {
+    return mapPositions(start, end, fromShifts, toShifts, fromRatio,
+            toRatio);
+  }
+
+  /**
+   * Helper method that returns the [start1, end1, start2, end2, ...] positions
+   * in {@code targetRange} that map to positions between {@code start} and
+   * {@code end} in {@code sourceRange}. Note that for a reverse strand mapping
+   * this will return ranges with end < start. Returns null if no mapped
+   * positions are found in start-end.
+   * 
+   * @param start
+   * @param end
+   * @param sourceRange
+   * @param targetRange
+   * @param sourceWordLength
+   * @param targetWordLength
+   * @return
+   */
+  final static int[] mapPositions(int start, int end,
+          List<int[]> sourceRange, List<int[]> targetRange,
+          int sourceWordLength, int targetWordLength)
+  {
+    if (end < start)
+    {
+      int tmp = end;
+      end = start;
+      start = tmp;
+    }
+
+    /*
+     * traverse sourceRange and mark offsets in targetRange 
+     * of any positions that lie in [start, end]
+     */
+    BitSet offsets = getMappedOffsetsForPositions(start, end, sourceRange,
+            sourceWordLength, targetWordLength);
+
+    /*
+     * traverse targetRange and collect positions at the marked offsets
+     */
+    List<int[]> mapped = getPositionsForOffsets(targetRange, offsets);
+
+    // TODO: or just return the List and adjust calling code to match
+    return mapped.isEmpty() ? null : MappingUtils.rangeListToArray(mapped);
+  }
+
+  /**
+   * Scans the list of {@code ranges} for any values (positions) that lie
+   * between start and end (inclusive), and records the <em>offsets</em> from
+   * the start of the list as a BitSet. The offset positions are converted to
+   * corresponding words in blocks of {@code wordLength2}.
+   * 
+   * <pre>
+   * For example:
+   * 1:1 (e.g. gene to CDS):
+   * ranges { [10-20], [31-40] }, wordLengthFrom = wordLength 2 = 1
+   *   for start = 1, end = 9, returns a BitSet with no bits set
+   *   for start = 1, end = 11, returns a BitSet with bits 0-1 set
+   *   for start = 15, end = 35, returns a BitSet with bits 5-15 set
+   * 1:3 (peptide to codon):
+   * ranges { [1-200] }, wordLengthFrom = 1, wordLength 2 = 3
+   *   for start = 9, end = 9, returns a BitSet with bits 24-26 set
+   * 3:1 (codon to peptide):
+   * ranges { [101-150], [171-180] }, wordLengthFrom = 3, wordLength 2 = 1
+   *   for start = 101, end = 102 (partial first codon), returns a BitSet with bit 0 set
+   *   for start = 150, end = 171 (partial 17th codon), returns a BitSet with bit 16 set
+   * 3:1 (circular DNA to peptide):
+   * ranges { [101-150], [21-30] }, wordLengthFrom = 3, wordLength 2 = 1
+   *   for start = 24, end = 40 (spans codons 18-20), returns a BitSet with bits 17-19 set
+   * </pre>
+   * 
+   * @param start
+   * @param end
+   * @param sourceRange
+   * @param sourceWordLength
+   * @param targetWordLength
+   * @return
+   */
+  protected final static BitSet getMappedOffsetsForPositions(int start,
+          int end, List<int[]> sourceRange, int sourceWordLength,
+          int targetWordLength)
+  {
+    BitSet overlaps = new BitSet();
+    int offset = 0;
+    final int s1 = sourceRange.size();
+    for (int i = 0; i < s1; i++)
+    {
+      int[] range = sourceRange.get(i);
+      final int offset1 = offset;
+      int overlapStartOffset = -1;
+      int overlapEndOffset = -1;
+
+      if (range[1] >= range[0])
+      {
+        /*
+         * forward direction range
+         */
+        if (start <= range[1] && end >= range[0])
+        {
+          /*
+           * overlap
+           */
+          int overlapStart = Math.max(start, range[0]);
+          overlapStartOffset = offset1 + overlapStart - range[0];
+          int overlapEnd = Math.min(end, range[1]);
+          overlapEndOffset = offset1 + overlapEnd - range[0];
+        }
+      }
+      else
+      {
+        /*
+         * reverse direction range
+         */
+        if (start <= range[0] && end >= range[1])
+        {
+          /*
+           * overlap
+           */
+          int overlapStart = Math.max(start, range[1]);
+          int overlapEnd = Math.min(end, range[0]);
+          overlapStartOffset = offset1 + range[0] - overlapEnd;
+          overlapEndOffset = offset1 + range[0] - overlapStart;
+        }
+      }
+
+      if (overlapStartOffset > -1)
+      {
+        /*
+         * found an overlap
+         */
+        if (sourceWordLength != targetWordLength)
+        {
+          /*
+           * convert any overlap found to whole words in the target range
+           * (e.g. treat any partial codon overlap as if the whole codon)
+           */
+          overlapStartOffset -= overlapStartOffset % sourceWordLength;
+          overlapStartOffset = overlapStartOffset / sourceWordLength
+                  * targetWordLength;
+
+          /*
+           * similar calculation for range end, adding 
+           * (wordLength2 - 1) for end of mapped word
+           */
+          overlapEndOffset -= overlapEndOffset % sourceWordLength;
+          overlapEndOffset = overlapEndOffset / sourceWordLength
+                  * targetWordLength;
+          overlapEndOffset += targetWordLength - 1;
+        }
+        overlaps.set(overlapStartOffset, overlapEndOffset + 1);
+      }
+      offset += 1 + Math.abs(range[1] - range[0]);
+    }
+    return overlaps;
+  }
+
+  /**
+   * Returns a (possibly empty) list of the [start-end] values (positions) at
+   * offsets in the {@code targetRange} list that are marked by 'on' bits in the
+   * {@code offsets} bitset.
+   * 
+   * @param targetRange
+   * @param offsets
+   * @return
+   */
+  protected final static List<int[]> getPositionsForOffsets(
+          List<int[]> targetRange, BitSet offsets)
+  {
+    List<int[]> mapped = new ArrayList<>();
+    if (offsets.isEmpty())
+    {
+      return mapped;
+    }
+
+    /*
+     * count of positions preceding ranges[i]
+     */
+    int traversed = 0;
+
+    /*
+     * for each [from-to] range in ranges:
+     * - find subranges (if any) at marked offsets
+     * - add the start-end values at the marked positions
+     */
+    final int toAdd = offsets.cardinality();
+    int added = 0;
+    final int s2 = targetRange.size();
+    for (int i = 0; added < toAdd && i < s2; i++)
+    {
+      int[] range = targetRange.get(i);
+      added += addOffsetPositions(mapped, traversed, range, offsets);
+      traversed += Math.abs(range[1] - range[0]) + 1;
+    }
+    return mapped;
+  }
+
+  /**
+   * Helper method that adds any start-end subranges of {@code range} that are
+   * at offsets in {@code range} marked by set bits in overlaps.
+   * {@code mapOffset} is added to {@code range} offset positions. Returns the
+   * count of positions added.
+   * 
+   * @param mapped
+   * @param mapOffset
+   * @param range
+   * @param overlaps
+   * @return
+   */
+  final static int addOffsetPositions(List<int[]> mapped,
+          final int mapOffset, final int[] range, final BitSet overlaps)
+  {
+    final int rangeLength = 1 + Math.abs(range[1] - range[0]);
+    final int step = range[1] < range[0] ? -1 : 1;
+    int offsetStart = 0; // offset into range
+    int added = 0;
+
+    while (offsetStart < rangeLength)
+    {
+      /*
+       * find the start of the next marked overlap offset;
+       * if there is none, or it is beyond range, then finished
+       */
+      int overlapStart = overlaps.nextSetBit(mapOffset + offsetStart);
+      if (overlapStart == -1 || overlapStart - mapOffset >= rangeLength)
+      {
+        /*
+         * no more overlaps, or no more within range[]
+         */
+        return added;
+      }
+      overlapStart -= mapOffset;
+
+      /*
+       * end of the overlap range is just before the next clear bit;
+       * restrict it to end of range if necessary;
+       * note we may add a reverse strand range here (end < start)
+       */
+      int overlapEnd = overlaps.nextClearBit(mapOffset + overlapStart + 1);
+      overlapEnd = (overlapEnd == -1) ? rangeLength - 1
+              : Math.min(rangeLength - 1, overlapEnd - mapOffset - 1);
+      int startPosition = range[0] + step * overlapStart;
+      int endPosition = range[0] + step * overlapEnd;
+      mapped.add(new int[] { startPosition, endPosition });
+      offsetStart = overlapEnd + 1;
+      added += Math.abs(endPosition - startPosition) + 1;
+    }
+
+    return added;
+  }
+
+  /*
+   * Returns the [start, end...] positions in the range mapped from, that are
+   * mapped to by part or all of the given begin-end of the range mapped to.
+   * Returns null if begin-end does not overlap any position mapped to.
+   * 
+   * @param begin
+   * @param end
+   * @return
+   */
+  public int[] getOverlapsInFrom(final int begin, final int end)
+  {
+    int[] overlaps = MappingUtils.findOverlap(toShifts, begin, end);
+
+    return overlaps == null ? null : locateInFrom(overlaps[0], overlaps[1]);
+  }
+
+  /**
+   * Returns the [start, end...] positions in the range mapped to, that are
+   * mapped to by part or all of the given begin-end of the range mapped from.
+   * Returns null if begin-end does not overlap any position mapped from.
+   * 
+   * @param begin
+   * @param end
+   * @return
+   */
+  public int[] getOverlapsInTo(final int begin, final int end)
+  {
+    int[] overlaps = MappingUtils.findOverlap(fromShifts, begin, end);
+
+    return overlaps == null ? null : locateInTo(overlaps[0], overlaps[1]);
+  }
 }
index b552c21..8d34ea8 100644 (file)
  */
 package jalview.util;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import jalview.analysis.AlignmentSorter;
 import jalview.api.AlignViewportI;
+import jalview.bin.Console;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
 import jalview.commands.OrderCommand;
 import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Mapping;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -39,13 +49,6 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 /**
  * Helper methods for manipulations involving sequence mappings.
  * 
@@ -78,7 +81,7 @@ public final class MappingUtils
       action = action.getUndoAction();
     }
     // TODO write this
-    System.err.println("MappingUtils.mapCutOrPaste not yet implemented");
+    Console.error("MappingUtils.mapCutOrPaste not yet implemented");
   }
 
   /**
@@ -361,56 +364,55 @@ public final class MappingUtils
        */
       int startResiduePos = selected.findPosition(firstUngappedPos);
       int endResiduePos = selected.findPosition(lastUngappedPos);
-
-      for (AlignedCodonFrame acf : codonFrames)
+      for (SequenceI seq : mapTo.getAlignment().getSequences())
       {
-        SequenceI mappedSequence = targetIsNucleotide
-                ? acf.getDnaForAaSeq(selected)
-                : acf.getAaForDnaSeq(selected);
-        if (mappedSequence != null)
+        int mappedStartResidue = 0;
+        int mappedEndResidue = 0;
+        for (AlignedCodonFrame acf : codonFrames)
         {
-          for (SequenceI seq : mapTo.getAlignment().getSequences())
+          // rather than use acf.getCoveringMapping() we iterate through all
+          // mappings to make sure all CDS are selected for a protein
+          for (SequenceToSequenceMapping map: acf.getMappings())
           {
-            int mappedStartResidue = 0;
-            int mappedEndResidue = 0;
-            if (seq.getDatasetSequence() == mappedSequence)
+          if (map.covers(selected) && map.covers(seq))
+          {
+            /*
+             * Found a sequence mapping. Locate the start/end mapped residues.
+             */
+            List<AlignedCodonFrame> mapping = Arrays
+                    .asList(new AlignedCodonFrame[]
+                    { acf });
+            // locate start 
+            SearchResultsI sr = buildSearchResults(selected,
+                    startResiduePos, mapping);
+            for (SearchResultMatchI m : sr.getResults())
             {
-              /*
-               * Found a sequence mapping. Locate the start/end mapped residues.
-               */
-              List<AlignedCodonFrame> mapping = Arrays
-                      .asList(new AlignedCodonFrame[]
-                      { acf });
-              SearchResultsI sr = buildSearchResults(selected,
-                      startResiduePos, mapping);
-              for (SearchResultMatchI m : sr.getResults())
-              {
-                mappedStartResidue = m.getStart();
-                mappedEndResidue = m.getEnd();
-              }
-              sr = buildSearchResults(selected, endResiduePos, mapping);
-              for (SearchResultMatchI m : sr.getResults())
-              {
-                mappedStartResidue = Math.min(mappedStartResidue,
-                        m.getStart());
-                mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
-              }
-
-              /*
-               * Find the mapped aligned columns, save the range. Note findIndex
-               * returns a base 1 position, SequenceGroup uses base 0
-               */
-              int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
-              minStartCol = minStartCol == -1 ? mappedStartCol
-                      : Math.min(minStartCol, mappedStartCol);
-              int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
-              maxEndCol = maxEndCol == -1 ? mappedEndCol
-                      : Math.max(maxEndCol, mappedEndCol);
-              mappedGroup.addSequence(seq, false);
-              break;
+              mappedStartResidue = m.getStart();
+              mappedEndResidue = m.getEnd();
             }
+            // locate end - allowing for adjustment of start range
+            sr = buildSearchResults(selected, endResiduePos, mapping);
+            for (SearchResultMatchI m : sr.getResults())
+            {
+              mappedStartResidue = Math.min(mappedStartResidue,
+                      m.getStart());
+              mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
+            }
+
+            /*
+             * Find the mapped aligned columns, save the range. Note findIndex
+             * returns a base 1 position, SequenceGroup uses base 0
+             */
+            int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
+            minStartCol = minStartCol == -1 ? mappedStartCol
+                    : Math.min(minStartCol, mappedStartCol);
+            int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
+            maxEndCol = maxEndCol == -1 ? mappedEndCol
+                    : Math.max(maxEndCol, mappedEndCol);
+            mappedGroup.addSequence(seq, false);
+            break;
           }
-        }
+        }}
       }
     }
     mappedGroup.setStartRes(minStartCol < 0 ? 0 : minStartCol);
@@ -449,20 +451,23 @@ public final class MappingUtils
     {
       for (AlignedCodonFrame acf : mappings)
       {
-        SequenceI mappedSeq = mappingToNucleotide ? acf.getDnaForAaSeq(seq)
-                : acf.getAaForDnaSeq(seq);
-        if (mappedSeq != null)
-        {
           for (SequenceI seq2 : mapTo.getSequences())
           {
-            if (seq2.getDatasetSequence() == mappedSeq)
+            /*
+             * the corresponding peptide / CDS is the one for which there is
+             * a complete ('covering') mapping to 'seq'
+             */
+            SequenceI peptide = mappingToNucleotide ? seq2 : seq;
+            SequenceI cds = mappingToNucleotide ? seq : seq2;
+            SequenceToSequenceMapping s2s = acf.getCoveringMapping(cds,
+                    peptide);
+            if (s2s != null)
             {
               mappedOrder.add(seq2);
               j++;
               break;
             }
           }
-        }
       }
     }
 
@@ -524,7 +529,7 @@ public final class MappingUtils
 
     if (colsel == null)
     {
-      return; // mappedColumns;
+      return; 
     }
 
     char fromGapChar = mapFrom.getAlignment().getGapCharacter();
@@ -546,10 +551,9 @@ public final class MappingUtils
     while (regions.hasNext())
     {
       mapHiddenColumns(regions.next(), codonFrames, newHidden,
-              fromSequences,
-              toSequences, fromGapChar);
+              fromSequences, toSequences, fromGapChar);
     }
-    return; // mappedColumns;
+    return; 
   }
 
   /**
@@ -667,7 +671,9 @@ public final class MappingUtils
          */
         for (SequenceI toSeq : toSequences)
         {
-          if (toSeq.getDatasetSequence() == mappedSeq)
+          if (toSeq.getDatasetSequence() == mappedSeq
+                  && mappedStartResidue >= toSeq.getStart()
+                  && mappedEndResidue <= toSeq.getEnd())
           {
             int mappedStartCol = toSeq.findIndex(mappedStartResidue);
             int mappedEndCol = toSeq.findIndex(mappedEndResidue);
@@ -836,7 +842,7 @@ public final class MappingUtils
     {
       if (range.length % 2 != 0)
       {
-        System.err.println(
+        Console.error(
                 "Error unbalance start/end ranges: " + ranges.toString());
         return 0;
       }
@@ -965,7 +971,7 @@ public final class MappingUtils
 
     int min = Math.min(range[0], range[1]);
     int max = Math.max(range[0], range[1]);
-  
+
     return (min <= queryRange[0] && max >= queryRange[0]
             && min <= queryRange[1] && max >= queryRange[1]);
   }
@@ -980,8 +986,7 @@ public final class MappingUtils
    *          a list of (single) [start, end] ranges
    * @return
    */
-  public static void removeEndPositions(int positions,
-          List<int[]> ranges)
+  public static void removeEndPositions(int positions, List<int[]> ranges)
   {
     int toRemove = positions;
     Iterator<int[]> it = new ReverseListIterator<>(ranges);
@@ -993,8 +998,8 @@ public final class MappingUtils
         /*
          * not coded for [start1, end1, start2, end2, ...]
          */
-        System.err
-                .println("MappingUtils.removeEndPositions doesn't handle multiple  ranges");
+        Console.error(
+                "MappingUtils.removeEndPositions doesn't handle multiple  ranges");
         return;
       }
 
@@ -1004,8 +1009,8 @@ public final class MappingUtils
         /*
          * not coded for a reverse strand range (end < start)
          */
-        System.err
-                .println("MappingUtils.removeEndPositions doesn't handle reverse strand");
+        Console.error(
+                "MappingUtils.removeEndPositions doesn't handle reverse strand");
         return;
       }
       if (length > toRemove)
@@ -1020,4 +1025,87 @@ public final class MappingUtils
       }
     }
   }
+
+  /**
+   * Converts a list of {@code start-end} ranges to a single array of
+   * {@code start1, end1, start2, ... } ranges
+   * 
+   * @param ranges
+   * @return
+   */
+  public static int[] rangeListToArray(List<int[]> ranges)
+  {
+    int rangeCount = ranges.size();
+    int[] result = new int[rangeCount * 2];
+    int j = 0;
+    for (int i = 0; i < rangeCount; i++)
+    {
+      int[] range = ranges.get(i);
+      result[j++] = range[0];
+      result[j++] = range[1];
+    }
+    return result;
+  }
+
+  /*
+   * Returns the maximal start-end positions in the given (ordered) list of
+   * ranges which is overlapped by the given begin-end range, or null if there
+   * is no overlap.
+   * 
+   * <pre>
+   * Examples:
+   *   if ranges is {[4, 8], [10, 12], [16, 19]}
+   * then
+   *   findOverlap(ranges, 1, 20) == [4, 19]
+   *   findOverlap(ranges, 6, 11) == [6, 11]
+   *   findOverlap(ranges, 9, 15) == [10, 12]
+   *   findOverlap(ranges, 13, 15) == null
+   * </pre>
+   * 
+   * @param ranges
+   * @param begin
+   * @param end
+   * @return
+   */
+  protected static int[] findOverlap(List<int[]> ranges, final int begin,
+          final int end)
+  {
+    boolean foundStart = false;
+    int from = 0;
+    int to = 0;
+
+    /*
+     * traverse the ranges to find the first position (if any) >= begin,
+     * and the last position (if any) <= end
+     */
+    for (int[] range : ranges)
+    {
+      if (!foundStart)
+      {
+        if (range[0] >= begin)
+        {
+          /*
+           * first range that starts with, or follows, begin
+           */
+          foundStart = true;
+          from = Math.max(range[0], begin);
+        }
+        else if (range[1] >= begin)
+        {
+          /*
+           * first range that contains begin
+           */
+          foundStart = true;
+          from = begin;
+        }
+      }
+
+      if (range[0] <= end)
+      {
+        to = Math.min(end, range[1]);
+      }
+    }
+
+    return foundStart && to >= from ? new int[] { from, to } : null;
+  }
 }
index bb94566..acd4591 100644 (file)
@@ -27,7 +27,7 @@ import java.util.ResourceBundle;
 import java.util.ResourceBundle.Control;
 import java.util.Set;
 
-import org.apache.log4j.Logger;
+import jalview.log.JLoggerLog4j;
 
 /**
  * 
@@ -40,8 +40,7 @@ public class MessageManager
 {
   private static ResourceBundle rb;
 
-  // BH 2018 switched to org.apache.llog4j.Logger
-  private static Logger log = Logger
+  private static JLoggerLog4j log = JLoggerLog4j
           .getLogger(MessageManager.class.getCanonicalName());
 
   private static Locale loc;
@@ -94,7 +93,7 @@ public class MessageManager
     } catch (Exception e)
     {
       String msg = "I18N missing: " + loc + "\t" + key;
-         logWarning(key, msg);
+      logWarning(key, msg);
     }
     return value;
   }
@@ -162,15 +161,16 @@ public class MessageManager
    */
   public static String getStringOrReturn(String keyroot, String name)
   {
-    String smkey = keyroot + name.toLowerCase().replaceAll(" ", "");
+    String smkey = keyroot
+            + name.toLowerCase(Locale.ROOT).replaceAll(" ", "");
     try
     {
       name = rb.getString(smkey);
     } catch (Exception x)
     {
-      String msg = "I18N missing key with root " + keyroot + ": " + loc + "\t"
-                         + smkey;
-         logWarning(smkey, msg);
+      String msg = "I18N missing key with root " + keyroot + ": " + loc
+              + "\t" + smkey;
+      logWarning(smkey, msg);
     }
     return name;
   }
@@ -181,12 +181,12 @@ public class MessageManager
    * @param key
    * @param msg
    */
-  private static void logWarning(String key, String msg) 
+  private static void logWarning(String key, String msg)
   {
-       if (!reportedMissing.contains(key))
-       {
+    if (!reportedMissing.contains(key))
+    {
       reportedMissing.add(key);
-         log.info(msg);
-       }
+      log.info(msg);
+    }
   }
 }
index 6713bbc..0f2d01d 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.util;
 
+import java.util.Locale;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.StringTokenizer;
@@ -103,7 +105,7 @@ public class ParseHtmlBodyAndLinks
       return;
     }
     StringBuilder sb = new StringBuilder(description.length());
-    if (description.toUpperCase().indexOf("<HTML>") == -1)
+    if (description.toUpperCase(Locale.ROOT).indexOf("<HTML>") == -1)
     {
       htmlContent = false;
     }
@@ -129,7 +131,7 @@ public class ParseHtmlBodyAndLinks
         token = token.substring(0, startTag);
       }
 
-      if (tag != null && tag.toUpperCase().startsWith("A HREF="))
+      if (tag != null && tag.toUpperCase(Locale.ROOT).startsWith("A HREF="))
       {
         if (token.length() > 0)
         {
index 71d798d..2d05a1b 100644 (file)
@@ -349,7 +349,7 @@ public class Platform
 
   public static byte[] getFileBytes(File f)
   {
-    return /** @j2sNative f && swingjs.JSUtil.getFileBytes$java_io_File(f) || */
+    return /** @j2sNative f && swingjs.JSUtil.getFileAsBytes$O(f) || */
     null;
   }
 
@@ -613,18 +613,21 @@ public class Platform
 
   public static void getURLCommandArguments()
   {
-
-    /**
-     * Retrieve the first query field as command arguments to Jalview. Include
-     * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's __Info.args
-     * element to this value.
-     * 
-     * @j2sNative var a =
-     *            decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
-     *            + "?").split("?")[1].split("#")[0]); a &&
-     *            (J2S.thisApplet.__Info.args = a.split(" "));
-     */
-
+      try {
+      /**
+       * Retrieve the first query field as command arguments to Jalview. Include
+       * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's
+       * __Info.args element to this value.
+       * 
+       * @j2sNative var a =
+       *            decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
+       *            + "?").split("?")[1].split("#")[0]); a && (System.out.println("URL arguments detected were "+a)) &&
+       *            (J2S.thisApplet.__Info.urlargs = a.split(" ")); 
+       *            (!J2S.thisApplet.__Info.args || J2S.thisApplet.__Info.args == "" || J2S.thisApplet.__Info.args == "??") && (J2S.thisApplet.__Info.args = a) && (System.out.println("URL arguments were passed to J2S main."));
+       */
+    } catch (Throwable t)
+    {
+    }
   }
 
   /**
index 1f114a8..273f6ec 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.util;
 
+import java.util.Locale;
+
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.ArrayList;
@@ -409,9 +411,9 @@ public class StringUtils
     }
     if (s.length() <= 1)
     {
-      return s.toUpperCase();
+      return s.toUpperCase(Locale.ROOT);
     }
-    return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+    return s.substring(0, 1).toUpperCase(Locale.ROOT) + s.substring(1).toLowerCase(Locale.ROOT);
   }
 
   /**
@@ -427,7 +429,7 @@ public class StringUtils
     {
       return null;
     }
-    String tmp2up = text.toUpperCase();
+    String tmp2up = text.toUpperCase(Locale.ROOT);
     int startTag = tmp2up.indexOf("<HTML>");
     if (startTag > -1)
     {
@@ -446,7 +448,7 @@ public class StringUtils
     {
       text = text.substring(0, endTag);
     }
-  
+
     if (startTag == -1 && (text.contains("<") || text.contains(">")))
     {
       text = text.replaceAll("<", "&lt;");
@@ -456,8 +458,8 @@ public class StringUtils
   }
 
   /**
-   * Answers the input string with any occurrences of the 'encodeable' characters
-   * replaced by their URL encoding
+   * Answers the input string with any occurrences of the 'encodeable'
+   * characters replaced by their URL encoding
    * 
    * @param s
    * @param encodable
@@ -568,4 +570,18 @@ public class StringUtils
     }
     return enc;
   }
+
+  public static int firstCharPosIgnoreCase(String text, String chars)
+  {
+    int min = text.length() + 1;
+    for (char c : chars.toLowerCase().toCharArray())
+    {
+      int i = text.toLowerCase().indexOf(c);
+      if (0 <= i && i < min)
+      {
+        min = i;
+      }
+    }
+    return min < text.length() + 1 ? min : -1;
+  }
 }
index 51e1828..e43ead2 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.util.matcher;
 
+import java.util.Locale;
+
 import java.util.Objects;
 
 /**
@@ -102,7 +104,7 @@ public class Matcher implements MatcherI
       patternType = PatternType.String;
     }
 
-    uppercasePattern = pattern == null ? null : pattern.toUpperCase();
+    uppercasePattern = pattern == null ? null : pattern.toUpperCase(Locale.ROOT);
 
     // if we add regex conditions (e.g. matchesPattern), then
     // pattern should hold the raw regex, and
@@ -172,7 +174,7 @@ public class Matcher implements MatcherI
   boolean matchesString(String compareTo)
   {
     boolean matched = false;
-    String upper = compareTo.toUpperCase().trim();
+    String upper = compareTo.toUpperCase(Locale.ROOT).trim();
     switch(condition) {
     case Matches:
       matched = upper.equals(uppercasePattern);
index 3608626..eb1030c 100644 (file)
@@ -39,9 +39,9 @@ import jalview.api.AlignViewportI;
 import jalview.api.FeatureColourI;
 import jalview.api.FeaturesDisplayedI;
 import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.MappedFeatures;
-import jalview.datamodel.Mapping;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -104,11 +104,11 @@ public abstract class FeatureRendererModel
 
   Map<String, Float> featureOrder = null;
 
-  protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
-          this);
-
   protected AlignViewportI av;
 
+  private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+          this);
+
   @Override
   public AlignViewportI getViewport()
   {
@@ -301,13 +301,19 @@ public abstract class FeatureRendererModel
       {
         firing = Boolean.TRUE;
         findAllFeatures(true); // add all new features as visible
-        changeSupport.firePropertyChange("changeSupport", null, null);
+        notifyFeaturesChanged();
         firing = Boolean.FALSE;
       }
     }
   }
 
   @Override
+  public void notifyFeaturesChanged()
+  {
+    changeSupport.firePropertyChange("changeSupport", null, null);
+  }
+
+  @Override
   public List<SequenceFeature> findFeaturesAtColumn(SequenceI sequence, int column)
   {
     /*
@@ -1227,18 +1233,18 @@ public abstract class FeatureRendererModel
      * todo: direct lookup of CDS for peptide and vice-versa; for now,
      * have to search through an unordered list of mappings for a candidate
      */
-    Mapping mapping = null;
+    SequenceToSequenceMapping mapping = null;
     SequenceI mapFrom = null;
 
     for (AlignedCodonFrame acf : mappings)
     {
-      mapping = acf.getMappingForSequence(sequence);
-      if (mapping == null || !mapping.getMap().isTripletMap())
+      mapping = acf.getCoveringCodonMapping(ds);
+      if (mapping == null)
       {
-        continue; // we are only looking for 3:1 or 1:3 mappings
+        continue;
       }
       SearchResultsI sr = new SearchResults();
-      acf.markMappedRegion(ds, pos, sr);
+      mapping.markMappedRegion(ds, pos, sr);
       for (SearchResultMatchI match : sr.getResults())
       {
         int fromRes = match.getStart();
@@ -1291,7 +1297,7 @@ public abstract class FeatureRendererModel
       }
     }
     
-    return new MappedFeatures(mapping, mapFrom, pos, residue, result);
+    return new MappedFeatures(mapping.getMapping(), mapFrom, pos, residue, result);
   }
 
   @Override
index f44a2d1..d7da519 100644 (file)
@@ -29,9 +29,9 @@ import java.util.Set;
 
 public class FeaturesDisplayed implements FeaturesDisplayedI
 {
-  private Set<String> featuresDisplayed = new HashSet<String>();
+  private Set<String> featuresDisplayed = new HashSet<>();
 
-  private Set<String> featuresRegistered = new HashSet<String>();
+  private Set<String> featuresRegistered = new HashSet<>();
 
   public FeaturesDisplayed(FeaturesDisplayedI featuresDisplayed2)
   {
@@ -93,6 +93,13 @@ public class FeaturesDisplayed implements FeaturesDisplayedI
   }
 
   @Override
+  public void setHidden(String featureType)
+  {
+    featuresDisplayed.remove(featureType);
+    featuresRegistered.add(featureType);
+  }
+
+  @Override
   public boolean isRegistered(String type)
   {
     return featuresRegistered.contains(type);
index 80918f9..b64a526 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ws;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -127,7 +127,7 @@ public abstract class AWSThread extends Thread
               throw (new Exception(
                       "Timed out when communicating with server\nTry again later.\n"));
             }
-            jalview.bin.Cache.log.debug("Job " + j + " Result state "
+            Console.debug("Job " + j + " Result state "
                     + jobs[j].getState() + "(ServerError="
                     + jobs[j].isServerError() + ")");
           } catch (Exception ex)
@@ -137,7 +137,7 @@ public abstract class AWSThread extends Thread
                     .formatMessage("info.server_exception", new Object[]
                     { WebServiceName, ex.getMessage() }));
             // always output the exception's stack trace to the log
-            Cache.log.warn(WebServiceName + " job(" + jobs[j].jobnum
+            Console.warn(WebServiceName + " job(" + jobs[j].jobnum
                     + ") Server exception.");
             // todo: could limit trace to cause if this is a SOAPFaultException.
             ex.printStackTrace();
@@ -145,7 +145,7 @@ public abstract class AWSThread extends Thread
             if (jobs[j].allowedServerExceptions > 0)
             {
               jobs[j].allowedServerExceptions--;
-              Cache.log.debug("Sleeping after a server exception.");
+              Console.debug("Sleeping after a server exception.");
               try
               {
                 Thread.sleep(5000);
@@ -155,7 +155,7 @@ public abstract class AWSThread extends Thread
             }
             else
             {
-              Cache.log.warn("Dropping job " + j + " " + jobs[j].jobId);
+              Console.warn("Dropping job " + j + " " + jobs[j].jobId);
               jobs[j].subjobComplete = true;
               wsInfo.setStatus(jobs[j].jobnum,
                       WebserviceInfo.STATE_STOPPED_SERVERERROR);
@@ -167,7 +167,7 @@ public abstract class AWSThread extends Thread
             jobs[j].clearResponse(); // may contain out of date result data
             wsInfo.setStatus(jobs[j].jobnum,
                     WebserviceInfo.STATE_STOPPED_ERROR);
-            Cache.log.error("Out of memory when retrieving Job " + j
+            Console.error("Out of memory when retrieving Job " + j
                     + " id:" + WsUrl + "/" + jobs[j].jobId, er);
             new jalview.gui.OOMWarning(
                     "retrieving result for " + WebServiceName, er);
@@ -185,7 +185,7 @@ public abstract class AWSThread extends Thread
           Thread.sleep(5000);
         } catch (InterruptedException e)
         {
-          Cache.log.debug("Interrupted sleep waiting for next job poll.",
+          Console.debug("Interrupted sleep waiting for next job poll.",
                   e);
         }
         // System.out.println("I'm alive "+alTitle);
@@ -197,7 +197,7 @@ public abstract class AWSThread extends Thread
     }
     else
     {
-      Cache.log.debug(
+      Console.debug(
               "WebServiceJob poll loop finished with no jobs created.");
       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
       wsInfo.appendProgressText(
index 7daa7b4..4705fe5 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws;
 
+import java.util.Locale;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Enumeration;
@@ -29,10 +31,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import jalview.analysis.AlignSeq;
 import jalview.api.FeatureSettingsModelI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
@@ -243,7 +248,7 @@ public class DBRefFetcher implements Runnable
    */
   void addSeqId(SequenceI seq, String key)
   {
-    key = key.toUpperCase();
+    key = key.toUpperCase(Locale.ROOT);
 
     Vector<SequenceI> seqs;
     if (seqRefs.containsKey(key))
@@ -358,9 +363,9 @@ public class DBRefFetcher implements Runnable
           AlignmentI retrieved = null;
           try
           {
-            if (Cache.log.isDebugEnabled())
+            if (Console.isDebugEnabled())
             {
-              Cache.log.debug("Querying " + dbsource.getDbName()
+              Console.debug("Querying " + dbsource.getDbName()
                       + " with : '" + queryString.toString() + "'");
             }
             retrieved = dbsource.getSequenceRecords(queryString.toString());
@@ -397,17 +402,19 @@ public class DBRefFetcher implements Runnable
                DBRefEntry upref = uprefs.get(j);
                 addSeqId(sequence, upref.getAccessionId());
                 queries.addElement(
-                        upref.getAccessionId().toUpperCase());
+                        upref.getAccessionId().toUpperCase(Locale.ROOT));
               }
             }
             else
             {
+              Pattern possibleIds = Pattern.compile("[A-Za-z0-9_]+"); 
               // generate queries from sequence ID string
-              StringTokenizer st = new StringTokenizer(sequence.getName(),
-                      "|");
-              while (st.hasMoreTokens())
+              Matcher tokens = possibleIds.matcher(sequence.getName());
+              int p=0;
+              while (tokens.find(p))
               {
-                String token = st.nextToken();
+                String token = tokens.group();
+                p = tokens.end();
                 UPEntry[] presp = null;
                 if (picrClient != null)
                 {
@@ -436,7 +443,7 @@ public class DBRefFetcher implements Runnable
                           "Validated ID against PICR... (for what its worth):"
                                   + token);
                   addSeqId(sequence, token);
-                  queries.addElement(token.toUpperCase());
+                  queries.addElement(token.toUpperCase(Locale.ROOT));
                 }
                 else
                 {
@@ -444,7 +451,7 @@ public class DBRefFetcher implements Runnable
                   // System.out.println("Not querying source with
                   // token="+token+"\n");
                   addSeqId(sequence, token);
-                  queries.addElement(token.toUpperCase());
+                  queries.addElement(token.toUpperCase(Locale.ROOT));
                 }
               }
             }
@@ -540,7 +547,7 @@ public class DBRefFetcher implements Runnable
        DBRefEntry ref = entryRefs.get(j);
         String accessionId = ref.getAccessionId();
         // match up on accessionId
-        if (seqRefs.containsKey(accessionId.toUpperCase()))
+        if (seqRefs.containsKey(accessionId.toUpperCase(Locale.ROOT)))
         {
           Vector<SequenceI> seqs = seqRefs.get(accessionId);
           for (int jj = 0; jj < seqs.size(); jj++)
@@ -592,7 +599,7 @@ public class DBRefFetcher implements Runnable
       // sequenceMatches now contains the set of all sequences associated with
       // the returned db record
       final String retrievedSeqString = retrievedSeq.getSequenceAsString();
-      String entrySeq = retrievedSeqString.toUpperCase();
+      String entrySeq = retrievedSeqString.toUpperCase(Locale.ROOT);
       for (int m = 0; m < sequenceMatches.size(); m++)
       {
         sequence = sequenceMatches.elementAt(m);
@@ -611,7 +618,7 @@ public class DBRefFetcher implements Runnable
         boolean remoteEnclosesLocal = false;
         String nonGapped = AlignSeq
                 .extractGaps("-. ", sequence.getSequenceAsString())
-                .toUpperCase();
+                .toUpperCase(Locale.ROOT);
         int absStart = entrySeq.indexOf(nonGapped);
         if (absStart == -1)
         {
@@ -731,10 +738,10 @@ public class DBRefFetcher implements Runnable
               String ngAlsq = AlignSeq
                       .extractGaps("-. ",
                               alseqs[alsq].getSequenceAsString())
-                      .toUpperCase();
+                      .toUpperCase(Locale.ROOT);
               int oldstrt = alseqs[alsq].getStart();
               alseqs[alsq].setStart(sequence.getSequenceAsString()
-                      .toUpperCase().indexOf(ngAlsq) + sequence.getStart());
+                      .toUpperCase(Locale.ROOT).indexOf(ngAlsq) + sequence.getStart());
               if (oldstrt != alseqs[alsq].getStart())
               {
                 alseqs[alsq].setEnd(
index a864ced..60ae90e 100644 (file)
@@ -28,6 +28,7 @@ import jalview.ws.dbsources.Pdb;
 import jalview.ws.dbsources.PfamFull;
 import jalview.ws.dbsources.PfamSeed;
 import jalview.ws.dbsources.RfamSeed;
+import jalview.ws.dbsources.TDBeacons;
 import jalview.ws.dbsources.Uniprot;
 import jalview.ws.seqfetcher.ASequenceFetcher;
 import jalview.ws.seqfetcher.DbSourceProxy;
@@ -55,6 +56,8 @@ public class SequenceFetcher extends ASequenceFetcher
     addDBRefSourceImpl(EmblSource.class);
     addDBRefSourceImpl(EmblCdsSource.class);
     addDBRefSourceImpl(Uniprot.class);
+    // not a sequence source yet
+    // addDBRefSourceImpl(TDBeacons.class);
     addDBRefSourceImpl(Pdb.class);
     addDBRefSourceImpl(PfamFull.class);
     addDBRefSourceImpl(PfamSeed.class);
index 6c7818b..bbb1f8b 100644 (file)
@@ -23,6 +23,7 @@ package jalview.ws.dbsources;
 
 import jalview.api.FeatureSettingsModelI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ContactMatrix;
@@ -31,7 +32,9 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
+import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeaturesI;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
 import jalview.io.FileFormatI;
@@ -93,7 +96,9 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
   @Override
   public Regex getAccessionValidator()
   {
-    return new Regex("(AF-[A-Z]+[0-9]+[A-Z0-9]+-F1)");
+    Regex validator =  new Regex("(AF-[A-Z]+[0-9]+[A-Z0-9]+-F1)");
+    validator.setIgnoreCase(true);
+    return validator;
   }
 
   /*
@@ -137,6 +142,10 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
   @Override
   public AlignmentI getSequenceRecords(String queries) throws Exception
   {
+    return getSequenceRecords(queries, null);
+  }
+  public AlignmentI getSequenceRecords(String queries, String retrievalUrl) throws Exception
+  {
     AlignmentI pdbAlignment = null;
     String chain = null;
     String id = null;
@@ -158,84 +167,26 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
       return null;
     }
     String alphaFoldCif = getAlphaFoldCifDownloadUrl(id);
+    if (retrievalUrl != null)
+    {
+      alphaFoldCif = retrievalUrl;
+    }
 
     try
     {
-      File tmpFile = File.createTempFile(id, "cif");
+      File tmpFile = File.createTempFile(id, ".cif");
+      Console.debug("Retrieving structure file for "+id+" from "+alphaFoldCif);
       UrlDownloadClient.download(alphaFoldCif, tmpFile);
+      
+      // may not need this check ?
       file = tmpFile.getAbsolutePath();
       if (file == null)
       {
         return null;
       }
 
-      // todo get rid of Type and use FileFormatI instead?
-      FileFormatI fileFormat = FileFormat.MMCif;
-      pdbAlignment = new FormatAdapter().readFile(tmpFile,
-              DataSourceType.FILE, fileFormat);
-      if (pdbAlignment != null)
-      {
-        List<SequenceI> toremove = new ArrayList<SequenceI>();
-        for (SequenceI pdbcs : pdbAlignment.getSequences())
-        {
-          String chid = null;
-          // Mapping map=null;
-          for (PDBEntry pid : pdbcs.getAllPDBEntries())
-          {
-            if (pid.getFile() == file)
-            {
-              chid = pid.getChainCode();
-
-            }
-          }
-          if (chain == null || (chid != null && (chid.equals(chain)
-                  || chid.trim().equals(chain.trim())
-                  || (chain.trim().length() == 0 && chid.equals("_")))))
-          {
-            // FIXME seems to result in 'PDB|1QIP|1qip|A' - 1QIP is redundant.
-            // TODO: suggest simplify naming to 1qip|A as default name defined
-            pdbcs.setName(id + SEPARATOR + pdbcs.getName());
-            // Might need to add more metadata to the PDBEntry object
-            // like below
-            /*
-             * PDBEntry entry = new PDBEntry(); // Construct the PDBEntry
-             * entry.setId(id); if (entry.getProperty() == null)
-             * entry.setProperty(new Hashtable());
-             * entry.getProperty().put("chains", pdbchain.id + "=" +
-             * sq.getStart() + "-" + sq.getEnd());
-             * sq.getDatasetSequence().addPDBId(entry);
-             */
-            // Add PDB DB Refs
-            // We make a DBRefEtntry because we have obtained the PDB file from
-            // a
-            // verifiable source
-            // JBPNote - PDB DBRefEntry should also carry the chain and mapping
-            // information
-            DBRefEntry dbentry = new DBRefEntry(getDbSource(),
-                    getDbVersion(), (chid == null ? id : id + chid));
-            // dbentry.setMap()
-            pdbcs.addDBRef(dbentry);
-          }
-          else
-          {
-            // mark this sequence to be removed from the alignment
-            // - since it's not from the right chain
-            toremove.add(pdbcs);
-          }
-        }
-        // now remove marked sequences
-        for (SequenceI pdbcs : toremove)
-        {
-          pdbAlignment.deleteSequence(pdbcs);
-          if (pdbcs.getAnnotation() != null)
-          {
-            for (AlignmentAnnotation aa : pdbcs.getAnnotation())
-            {
-              pdbAlignment.deleteAnnotation(aa);
-            }
-          }
-        }
-      }
+      pdbAlignment = importDownloadedStructureFromUrl(alphaFoldCif, tmpFile, id, chain, getDbSource(),getDbVersion());
+      
 
       if (pdbAlignment == null || pdbAlignment.getHeight() < 1)
       {
@@ -248,12 +199,24 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
       // model
       File pae = File.createTempFile(id, "pae_json");
       String paeURL = getAlphaFoldPaeDownloadUrl(id);
-      UrlDownloadClient.download(paeURL, pae);
+      
+      if (retrievalUrl!=null) {
+        // manufacture the PAE url from a url like ...-model-vN.cif
+        paeURL = retrievalUrl.replace("model","predicted_aligned_error").replace(".cif",".json");
+      }
+      Console.debug("Downloading pae from " + paeURL
+              + " to " + pae.toString() + "");
+
+      try {
+        UrlDownloadClient.download(paeURL, pae);        
       if (!importPaeJSONAsContactMatrix(pdbAlignment, pae))
       {
-        Cache.log.debug("Couln't import contact matrix from " + paeURL
+        Console.warn("Couln't import contact matrix from " + paeURL
                 + " (stored in " + pae.toString() + ")");
       }
+      } catch (Exception pae_ex) {
+        Console.debug("Couldn't download PAE",pae_ex);
+      }
 
     } catch (Exception ex) // Problem parsing PDB file
     {
@@ -281,6 +244,110 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
     return true;
   }
 
+  /**
+   * general purpose structure importer - designed to yield alignment useful for transfer of annotation to associated sequences
+   * @param alphaFoldCif
+   * @param tmpFile
+   * @param id
+   * @param chain
+   * @param dbSource
+   * @param dbVersion
+   * @return
+   * @throws Exception
+   */
+  public static AlignmentI importDownloadedStructureFromUrl(String alphaFoldCif,
+          File tmpFile, String id, String chain, String dbSource, String dbVersion) throws Exception
+  {
+    String file = tmpFile.getAbsolutePath();
+    // todo get rid of Type and use FileFormatI instead?
+    FileFormatI fileFormat = FileFormat.MMCif;
+    AlignmentI pdbAlignment = new FormatAdapter().readFile(tmpFile,
+            DataSourceType.FILE, fileFormat);
+    if (pdbAlignment != null)
+    {
+      List<SequenceI> toremove = new ArrayList<SequenceI>();
+      for (SequenceI pdbcs : pdbAlignment.getSequences())
+      {
+        String chid = null;
+        // Mapping map=null;
+        for (PDBEntry pid : pdbcs.getAllPDBEntries())
+        {
+          if (pid.getFile() == file)
+          {
+            chid = pid.getChainCode();
+
+          }
+        }
+        if (chain == null || (chid != null && (chid.equals(chain)
+                || chid.trim().equals(chain.trim())
+                || (chain.trim().length() == 0 && chid.equals("_")))))
+        {
+          // FIXME seems to result in 'PDB|1QIP|1qip|A' - 1QIP is redundant.
+          // TODO: suggest simplify naming to 1qip|A as default name defined
+          pdbcs.setName(id + SEPARATOR + pdbcs.getName());
+          // Might need to add more metadata to the PDBEntry object
+          // like below
+          /*
+           * PDBEntry entry = new PDBEntry(); // Construct the PDBEntry
+           * entry.setId(id); if (entry.getProperty() == null)
+           * entry.setProperty(new Hashtable());
+           * entry.getProperty().put("chains", pdbchain.id + "=" +
+           * sq.getStart() + "-" + sq.getEnd());
+           * sq.getDatasetSequence().addPDBId(entry);
+           */
+          // Add PDB DB Refs
+          // We make a DBRefEtntry because we have obtained the PDB file from
+          // a
+          // verifiable source
+          // JBPNote - PDB DBRefEntry should also carry the chain and mapping
+          // information
+          if (dbSource != null)
+          {
+            DBRefEntry dbentry = new DBRefEntry(dbSource,
+
+                    dbVersion, (chid == null ? id : id + chid));
+            // dbentry.setMap()
+            pdbcs.addDBRef(dbentry);
+            // update any feature groups
+            List<SequenceFeature> allsf = pdbcs.getFeatures().getAllFeatures();
+            List<SequenceFeature> newsf = new ArrayList<SequenceFeature>();
+            if (allsf!=null && allsf.size()>0)
+            {
+              for (SequenceFeature f:allsf)
+              {
+                if (file.equals(f.getFeatureGroup()))
+                {
+                  f = new SequenceFeature(f, f.type, f.begin, f.end, id, f.score);
+                }
+                newsf.add(f);
+              }
+              pdbcs.setSequenceFeatures(newsf);
+            }
+          }
+        }
+        else
+        {
+          // mark this sequence to be removed from the alignment
+          // - since it's not from the right chain
+          toremove.add(pdbcs);
+        }
+      }
+      // now remove marked sequences
+      for (SequenceI pdbcs : toremove)
+      {
+        pdbAlignment.deleteSequence(pdbcs);
+        if (pdbcs.getAnnotation() != null)
+        {
+          for (AlignmentAnnotation aa : pdbcs.getAnnotation())
+          {
+            pdbAlignment.deleteAnnotation(aa);
+          }
+        }
+      }
+    }
+    return pdbAlignment;
+  }
+
   /*
    * (non-Javadoc)
    * 
@@ -328,4 +395,5 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy
   {
     return new PDBFeatureSettings();
   }
+
 }
index a73af61..d02910c 100644 (file)
@@ -23,9 +23,7 @@ package jalview.ws.dbsources;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefSource;
 
-import com.stevesoft.pat.Regex;
-
-public class EmblCdsSource extends EmblXmlSource
+public class EmblCdsSource extends EmblFlatfileSource // was EmblXmlSource
 {
 
   public EmblCdsSource()
@@ -34,31 +32,12 @@ public class EmblCdsSource extends EmblXmlSource
   }
 
   @Override
-  public String getAccessionSeparator()
-  {
-    return null;
-  }
-
-  @Override
-  public Regex getAccessionValidator()
-  {
-    return new Regex("^[A-Z]+[0-9]+");
-  }
-
-  @Override
   public String getDbSource()
   {
     return DBRefSource.EMBLCDS;
   }
 
   @Override
-  public String getDbVersion()
-  {
-    return "0"; // TODO : this is dynamically set for a returned record - not
-    // tied to proxy
-  }
-
-  @Override
   public AlignmentI getSequenceRecords(String queries) throws Exception
   {
     if (queries.indexOf(".") > -1)
@@ -68,15 +47,6 @@ public class EmblCdsSource extends EmblXmlSource
     return getEmblSequenceRecords(DBRefSource.EMBLCDS, queries);
   }
 
-  @Override
-  public boolean isValidReference(String accession)
-  {
-    // most embl CDS refs look like ..
-    // TODO: improve EMBLCDS regex
-    return (accession == null || accession.length() < 2) ? false
-            : getAccessionValidator().search(accession);
-  }
-
   /**
    * cDNA for LDHA_CHICK swissprot sequence
    */
@@ -92,10 +62,4 @@ public class EmblCdsSource extends EmblXmlSource
     return "EMBL (CDS)";
   }
 
-  @Override
-  public int getTier()
-  {
-    return 0;
-  }
-
 }
diff --git a/src/jalview/ws/dbsources/EmblFlatfileSource.java b/src/jalview/ws/dbsources/EmblFlatfileSource.java
new file mode 100644 (file)
index 0000000..7cb8f09
--- /dev/null
@@ -0,0 +1,122 @@
+package jalview.ws.dbsources;
+
+import java.util.Locale;
+
+import java.io.File;
+import java.io.IOException;
+
+import com.stevesoft.pat.Regex;
+
+import jalview.bin.Console;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.EmblFlatFile;
+import jalview.io.FileParse;
+import jalview.ws.ebi.EBIFetchClient;
+
+/**
+ * A class that does partial parsing of an EMBL flatfile.
+ * 
+ * @author gmcarstairs
+ *
+ */
+public abstract class EmblFlatfileSource extends EbiFileRetrievedProxy
+{
+  private static final Regex ACCESSION_REGEX = new Regex("^[A-Z]+[0-9]+");
+
+  @Override
+  public String getDbVersion()
+  {
+    return "0";
+  }
+
+  @Override
+  public String getAccessionSeparator()
+  {
+    return null;
+  }
+
+  @Override
+  public Regex getAccessionValidator()
+  {
+    return ACCESSION_REGEX;
+  }
+
+  @Override
+  public boolean isValidReference(String accession)
+  {
+    if (accession == null || accession.length() < 2)
+    {
+      return false;
+    }
+    return getAccessionValidator().search(accession);
+  }
+
+  @Override
+  public AlignmentI getSequenceRecords(String queries) throws Exception
+  {
+    return null;
+  }
+
+  @Override
+  public int getTier()
+  {
+    return 0;
+  }
+
+  protected AlignmentI getEmblSequenceRecords(String dbName, String query)
+          throws Exception
+  {
+    startQuery();
+    EBIFetchClient dbFetch = new EBIFetchClient();
+    File reply;
+    try
+    {
+      reply = dbFetch.fetchDataAsFile(
+              dbName.toLowerCase(Locale.ROOT) + ":" + query.trim(), null, "gz");
+    } catch (Exception e)
+    {
+      stopQuery();
+      throw new Exception(
+              String.format("EBI EMBL retrieval failed for %s:%s",
+                      dbName.toLowerCase(Locale.ROOT), query.trim()),
+              e);
+    }
+    return getEmblSequenceRecords(dbName, query, reply);
+  }
+
+  private AlignmentI getEmblSequenceRecords(String dbName, String query,
+          File reply) throws IOException
+  {
+    AlignmentI al = null;
+
+    if (reply != null && reply.exists())
+    {
+      file = reply.getAbsolutePath();
+      FileParse fp = new FileParse(file, DataSourceType.FILE);
+      EmblFlatFile emblParser = new EmblFlatFile(fp, getDbSource());
+      SequenceI[] seqs = emblParser.getSeqsAsArray();
+      if (seqs.length > 0)
+      {
+        al = new Alignment(seqs);
+      }
+
+      if (al == null)
+      {
+        Console.error(
+                "No record found for '" + dbName + ":" + query + "'");
+      }
+    }
+
+    stopQuery();
+    return al;
+  }
+
+  @Override
+  public boolean isDnaCoding()
+  {
+    return true;
+  }
+}
index 6bbe2e1..df43bc3 100644 (file)
@@ -23,13 +23,11 @@ package jalview.ws.dbsources;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefSource;
 
-import com.stevesoft.pat.Regex;
-
 /**
  * @author JimP
  * 
  */
-public class EmblSource extends EmblXmlSource
+public class EmblSource extends EmblFlatfileSource // was EmblXmlSource
 {
 
   public EmblSource()
@@ -40,29 +38,6 @@ public class EmblSource extends EmblXmlSource
   /*
    * (non-Javadoc)
    * 
-   * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
-   */
-  @Override
-  public String getAccessionSeparator()
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see jalview.ws.DbSourceProxy#getAccessionValidator()
-   */
-  @Override
-  public Regex getAccessionValidator()
-  {
-    return new Regex("^[A-Z]+[0-9]+");
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
    * @see jalview.ws.DbSourceProxy#getDbSource()
    */
   @Override
@@ -74,18 +49,6 @@ public class EmblSource extends EmblXmlSource
   /*
    * (non-Javadoc)
    * 
-   * @see jalview.ws.DbSourceProxy#getDbVersion()
-   */
-  @Override
-  public String getDbVersion()
-  {
-    // TODO Auto-generated method stub
-    return "0";
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
    * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
    */
   @Override
@@ -94,21 +57,6 @@ public class EmblSource extends EmblXmlSource
     return getEmblSequenceRecords(DBRefSource.EMBL, queries);
   }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
-   */
-  @Override
-  public boolean isValidReference(String accession)
-  {
-    // most embl refs look like ..
-
-    return (accession == null || accession.length() < 2) ? false
-            : getAccessionValidator().search(accession);
-
-  }
-
   /**
    * return LHD_CHICK coding gene
    */
@@ -123,10 +71,4 @@ public class EmblSource extends EmblXmlSource
   {
     return "EMBL"; // getDbSource();
   }
-
-  @Override
-  public int getTier()
-  {
-    return 0;
-  }
 }
index 19366e0..034ea4f 100644 (file)
  */
 package jalview.ws.dbsources;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import com.stevesoft.pat.Regex;
+
 import jalview.analysis.SequenceIdMatcher;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
@@ -35,36 +57,17 @@ import jalview.util.DBRefUtils;
 import jalview.util.DnaUtils;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
-import jalview.util.MessageManager;
 import jalview.ws.ebi.EBIFetchClient;
 import jalview.xml.binding.embl.EntryType;
 import jalview.xml.binding.embl.EntryType.Feature;
 import jalview.xml.binding.embl.EntryType.Feature.Qualifier;
-import jalview.xml.binding.jalview.JalviewModel;
 import jalview.xml.binding.embl.ROOT;
 import jalview.xml.binding.embl.XrefType;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.FactoryConfigurationError;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-
 public abstract class EmblXmlSource extends EbiFileRetrievedProxy
 {
+  private static final Regex ACCESSION_REGEX = new Regex("^[A-Z]+[0-9]+");
+
   /*
    * JAL-1856 Embl returns this text for query not found
    */
@@ -94,14 +97,15 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
     try
     {
       reply = dbFetch.fetchDataAsFile(
-              emprefx.toLowerCase() + ":" + query.trim(), "display=xml",
-              "xml");
+              emprefx.toLowerCase(Locale.ROOT) + ":" + query.trim(),
+              "display=xml", "xml");
     } catch (Exception e)
     {
       stopQuery();
-      throw new Exception(MessageManager.formatMessage(
-              "exception.ebiembl_retrieval_failed_on", new String[]
-              { emprefx.toLowerCase(), query.trim() }), e);
+      throw new Exception(
+              String.format("EBI EMBL XML retrieval failed for %s:%s",
+                      emprefx.toLowerCase(Locale.ROOT), query.trim()),
+              e);
     }
     return getEmblSequenceRecords(emprefx, query, reply);
   }
@@ -183,7 +187,8 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
       XMLStreamReader streamReader = XMLInputFactory.newInstance()
               .createXMLStreamReader(is);
       javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
-      JAXBElement<ROOT> rootElement =  um.unmarshal(streamReader, ROOT.class);
+      JAXBElement<ROOT> rootElement = um.unmarshal(streamReader,
+              ROOT.class);
       ROOT root = rootElement.getValue();
 
       /*
@@ -443,9 +448,8 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
         else
         {
           // final product length truncation check
-          int[] cdsRanges = adjustForProteinLength(translationLength,
-                  exons);
-          dnaToProteinMapping = new Mapping(product, cdsRanges,
+          int[] exons2 = adjustForProteinLength(translationLength, exons);
+          dnaToProteinMapping = new Mapping(product, exons2,
                   new int[]
                   { 1, translationLength }, 3, 1);
           if (product != null)
@@ -564,6 +568,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
               proteinSeq = new Sequence(proteinSeqName,
                       product.getSequenceAsString());
               matcher.add(proteinSeq);
+              proteinSeq.setDescription(product.getDescription());
               peptides.add(proteinSeq);
             }
             dnaToProteinMapping.setTo(proteinSeq);
@@ -617,8 +622,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
               && dnaToProteinMapping.getTo() != null)
       {
         DBRefEntry dnaToEmblProteinRef = new DBRefEntry(
-                DBRefSource.EMBLCDSProduct, sequenceVersion,
-                proteinId);
+                DBRefSource.EMBLCDSProduct, sequenceVersion, proteinId);
         dnaToEmblProteinRef.setMap(dnaToProteinMapping);
         dnaToProteinMapping.setMappedFromId(proteinId);
         dna.addDBRef(dnaToEmblProteinRef);
@@ -647,14 +651,14 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
     {
       return new int[] {};
     }
-  
+
     try
     {
       List<int[]> ranges = DnaUtils.parseLocation(location);
       return listToArray(ranges);
     } catch (ParseException e)
     {
-      Cache.log.warn(
+      Console.warn(
               String.format("Not parsing inexact CDS location %s in ENA %s",
                       location, accession));
       return new int[] {};
@@ -711,10 +715,43 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
     return sf;
   }
 
+  @Override
+  public String getAccessionSeparator()
+  {
+    return null;
+  }
+
+  @Override
+  public Regex getAccessionValidator()
+  {
+    return ACCESSION_REGEX;
+  }
+
+  @Override
+  public String getDbVersion()
+  {
+    return "0";
+  }
+
+  @Override
+  public int getTier()
+  {
+    return 0;
+  }
+
+  @Override
+  public boolean isValidReference(String accession)
+  {
+    if (accession == null || accession.length() < 2)
+    {
+      return false;
+    }
+    return getAccessionValidator().search(accession);
+  }
+
   /**
    * Truncates (if necessary) the exon intervals to match 3 times the length of
-   * the protein; also accepts 3 bases longer (for stop codon not included in
-   * protein)
+   * the protein (including truncation for stop codon included in exon)
    * 
    * @param proteinLength
    * @param exon
@@ -729,17 +766,15 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
     }
     int expectedCdsLength = proteinLength * 3;
     int exonLength = MappingUtils.getLength(Arrays.asList(exon));
-  
+
     /*
-     * if exon length matches protein, or is shorter, or longer by the 
-     * length of a stop codon (3 bases), then leave it unchanged
+     * if exon length matches protein, or is shorter, then leave it unchanged
      */
-    if (expectedCdsLength >= exonLength
-            || expectedCdsLength == exonLength - 3)
+    if (expectedCdsLength >= exonLength)
     {
       return exon;
     }
-  
+
     int origxon[];
     int sxpos = -1;
     int endxon = 0;
@@ -759,7 +794,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
           // .println("Truncating final exon interval on region by "
           // + (cdspos - cdslength));
         }
-  
+
         /*
          * shrink the final exon - reduce end position if forward
          * strand, increase it if reverse
@@ -775,7 +810,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
         break;
       }
     }
-  
+
     if (sxpos != -1)
     {
       // and trim the exon interval set if necessary
diff --git a/src/jalview/ws/dbsources/TDBeacons.java b/src/jalview/ws/dbsources/TDBeacons.java
new file mode 100644 (file)
index 0000000..345e217
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * 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.
+ */
+package jalview.ws.dbsources;
+
+import java.util.Locale;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.StringUtils;
+import jalview.ws.seqfetcher.DbSourceProxyImpl;
+import jalview.xml.binding.embl.ROOT;
+import jalview.xml.binding.uniprot.DbReferenceType;
+import jalview.xml.binding.uniprot.Entry;
+import jalview.xml.binding.uniprot.FeatureType;
+import jalview.xml.binding.uniprot.LocationType;
+import jalview.xml.binding.uniprot.PositionType;
+import jalview.xml.binding.uniprot.PropertyType;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import com.stevesoft.pat.Regex;
+
+/**
+ * This class queries the Uniprot database for sequence data, unmarshals the
+ * returned XML, and converts it to Jalview Sequence records (including attached
+ * database references and sequence features)
+ * 
+ * @author JimP
+ * 
+ */
+public class TDBeacons extends DbSourceProxyImpl
+{
+  private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org";
+
+  private static final String BAR_DELIMITER = "|";
+  
+  private static final String DEFAULT_THREEDBEACONS_DOMAIN = "https://wwwdev.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons-hub-api/uniprot/summary/";
+
+  /**
+   * Constructor
+   */
+  public TDBeacons()
+  {
+    super();
+  }
+
+  private String getDomain()
+  {
+    return Cache.getDefault("UNIPROT_DOMAIN", DEFAULT_UNIPROT_DOMAIN);
+    //return Cache.getDefault("3DB_DOMAIN", DEFAULT_THREEDBEACONS_DOMAIN );
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
+   */
+  @Override
+  public String getAccessionSeparator()
+  {
+    return null;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getAccessionValidator()
+   */
+  @Override
+  public Regex getAccessionValidator()
+  {
+    return new Regex("([A-Z]+[0-9]+[A-Z0-9]+|[A-Z0-9]+_[A-Z0-9]+)");
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getDbSource()
+   */
+  @Override
+  public String getDbSource()
+  {
+    return "3d-beacons";// DBRefSource.UNIPROT;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getDbVersion()
+   */
+  @Override
+  public String getDbVersion()
+  {
+    return "0"; // we really don't know what version we're on.
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
+   */
+  @Override
+  public AlignmentI getSequenceRecords(String queries) throws Exception
+  {
+    startQuery();
+    try
+    {
+      queries = queries.toUpperCase(Locale.ROOT).replaceAll(
+              "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
+      AlignmentI al = null;
+
+      String downloadstring = getDomain() + "/uniprot/" + queries
+              + ".xml";
+//      String downloadstring = getDomain() + queries + ".json";
+
+      URL url = new URL(downloadstring);
+      URLConnection urlconn = url.openConnection();
+      InputStream istr = urlconn.getInputStream();
+      List<Entry> entries = getUniprotEntries(istr);
+      if (entries != null)
+      {
+        List<SequenceI> seqs = new ArrayList<>();
+        for (Entry entry : entries)
+        {
+          seqs.add(uniprotEntryToSequence(entry));
+        }
+        al = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
+      }
+
+      stopQuery();
+      return al;
+    } catch (Exception e)
+    {
+      throw (e);
+    } finally
+    {
+      stopQuery();
+    }
+  }
+
+  /**
+   * Converts an Entry object (bound from Uniprot XML) to a Jalview Sequence
+   * 
+   * @param entry
+   * @return
+   */
+  SequenceI uniprotEntryToSequence(Entry entry)
+  {
+    String id = getUniprotEntryId(entry);
+    /*
+     * Sequence should not include any whitespace, but JAXB leaves these in
+     */
+    String seqString = entry.getSequence().getValue().replaceAll("\\s*",
+            "");
+
+    SequenceI sequence = new Sequence(id,
+            seqString);
+    sequence.setDescription(getUniprotEntryDescription(entry));
+
+    /*
+     * add a 'self' DBRefEntry for each accession
+     */
+    final String dbVersion = getDbVersion();
+    List<DBRefEntry> dbRefs = new ArrayList<>();
+    for (String accessionId : entry.getAccession())
+    {
+      DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
+              accessionId);
+      dbRefs.add(dbRef);
+    }
+
+    /*
+     * add a DBRefEntry for each dbReference element in the XML;
+     * also add a PDBEntry if type="PDB";
+     * also add an EMBLCDS dbref if protein sequence id is given
+     * also add an Ensembl dbref " " " " " "
+     */
+    Vector<PDBEntry> pdbRefs = new Vector<>();
+    for (DbReferenceType dbref : entry.getDbReference())
+    {
+      String type = dbref.getType();
+      DBRefEntry dbr = new DBRefEntry(type,
+              DBRefSource.UNIPROT + ":" + dbVersion, dbref.getId());
+      dbRefs.add(dbr);
+      if ("PDB".equals(type))
+      {
+        pdbRefs.add(new PDBEntry(dbr));
+      }
+      if ("EMBL".equals(type))
+      {
+        /*
+         * e.g. Uniprot accession Q9BXM7 has
+         * <dbReference type="EMBL" id="M19359">
+         *   <property type="protein sequence ID" value="AAA40981.1"/>
+         *   <property type="molecule type" value="Genomic_DNA"/>
+         * </dbReference> 
+         */
+        String cdsId = getProperty(dbref.getProperty(),
+                "protein sequence ID");
+        if (cdsId != null && cdsId.trim().length() > 0)
+        {
+          // remove version
+          String[] vrs = cdsId.split("\\.");
+          String version = vrs.length > 1 ? vrs[1]
+                  : DBRefSource.UNIPROT + ":" + dbVersion;
+          dbr = new DBRefEntry(DBRefSource.EMBLCDS, version, vrs[0]);
+          dbRefs.add(dbr);
+        }
+      }
+      if ("Ensembl".equals(type))
+      {
+        /*
+         * e.g. Uniprot accession Q9BXM7 has
+         * <dbReference type="Ensembl" id="ENST00000321556">
+         *   <molecule id="Q9BXM7-1"/>
+         *   <property type="protein sequence ID" value="ENSP00000364204"/>
+         *   <property type="gene ID" value="ENSG00000158828"/>
+         * </dbReference> 
+         */
+        String cdsId = getProperty(dbref.getProperty(),
+                "protein sequence ID");
+        if (cdsId != null && cdsId.trim().length() > 0)
+        {
+          dbr = new DBRefEntry(DBRefSource.ENSEMBL,
+                  DBRefSource.UNIPROT + ":" + dbVersion, cdsId.trim());
+          dbRefs.add(dbr);
+        }
+      }
+    }
+
+    /*
+     * create features; they have either begin and end, or position, in XML
+     */
+    sequence.setPDBId(pdbRefs);
+    if (entry.getFeature() != null)
+    {
+      for (FeatureType uf : entry.getFeature())
+      {
+        LocationType location = uf.getLocation();
+        int start = 0;
+        int end = 0;
+        if (location.getPosition() != null)
+        {
+          start = location.getPosition().getPosition().intValue();
+          end = start;
+        }
+        else
+        {
+          start = location.getBegin().getPosition().intValue();
+          end = location.getEnd().getPosition().intValue();
+        }
+        SequenceFeature sf = new SequenceFeature(uf.getType(),
+                getDescription(uf), start, end, "Uniprot");
+        sf.setStatus(uf.getStatus());
+        sequence.addSequenceFeature(sf);
+      }
+    }
+    for (DBRefEntry dbr : dbRefs)
+    {
+      sequence.addDBRef(dbr);
+    }
+    return sequence;
+  }
+
+  /**
+   * A helper method that builds a sequence feature description
+   * 
+   * @param feature
+   * @return
+   */
+  static String getDescription(FeatureType feature)
+  {
+    String orig = feature.getOriginal();
+    List<String> variants = feature.getVariation();
+    StringBuilder sb = new StringBuilder();
+
+    /*
+     * append variant in standard format if present
+     * e.g. p.Arg59Lys
+     * multiple variants are split over lines using <br>
+     */
+    boolean asHtml = false;
+    if (orig != null && !orig.isEmpty() && variants != null
+            && !variants.isEmpty())
+    {
+      int p = 0;
+      for (String var : variants)
+      {
+        // TODO proper HGVS nomenclature for delins structural variations
+        // http://varnomen.hgvs.org/recommendations/protein/variant/delins/
+        // for now we are pragmatic - any orig/variant sequence longer than
+        // three characters is shown with single-character notation rather than
+        // three-letter notation
+        sb.append("p.");
+        if (orig.length() < 4)
+        {
+          for (int c = 0, clen = orig.length(); c < clen; c++)
+          {
+            char origchar = orig.charAt(c);
+            String orig3 = ResidueProperties.aa2Triplet.get("" + origchar);
+            sb.append(orig3 == null ? origchar
+                    : StringUtils.toSentenceCase(orig3));
+          }
+        }
+        else
+        {
+          sb.append(orig);
+        }
+
+        LocationType location = feature.getLocation();
+        PositionType start = location.getPosition() == null
+                ? location.getBegin()
+                : location.getPosition();
+        sb.append(Integer.toString(start.getPosition().intValue()));
+
+        if (var.length() < 4)
+        {
+          for (int c = 0, clen = var.length(); c < clen; c++)
+          {
+            char varchar = var.charAt(c);
+            String var3 = ResidueProperties.aa2Triplet.get("" + varchar);
+
+            sb.append(var3 != null ? StringUtils.toSentenceCase(var3)
+                    : "" + varchar);
+          }
+        }
+        else
+        {
+          sb.append(var);
+        }
+        if (++p != variants.size())
+        {
+          sb.append("<br/>&nbsp;&nbsp;");
+          asHtml = true;
+        }
+        else
+        {
+          sb.append(" ");
+        }
+      }
+    }
+    String description = feature.getDescription();
+    if (description != null)
+    {
+      sb.append(description);
+    }
+    if (asHtml)
+    {
+      sb.insert(0, "<html>");
+      sb.append("</html>");
+    }
+
+    return sb.toString();
+  }
+
+  /**
+   * A helper method that searches the list of properties for one with the given
+   * key, and if found returns the property value, else returns null
+   * 
+   * @param properties
+   * @param key
+   * @return
+   */
+  static String getProperty(List<PropertyType> properties, String key)
+  {
+    String value = null;
+    if (properties != null)
+    {
+      for (PropertyType prop : properties)
+      {
+        if (key.equals(prop.getType()))
+        {
+          value = prop.getValue();
+          break;
+        }
+      }
+    }
+    return value;
+  }
+
+  /**
+   * Extracts xml element entry/protein/recommendedName/fullName
+   * 
+   * @param entry
+   * @return
+   */
+  static String getUniprotEntryDescription(Entry entry)
+  {
+    String desc = "";
+    if (entry.getProtein() != null
+            && entry.getProtein().getRecommendedName() != null)
+    {
+      // fullName is mandatory if recommendedName is present
+      desc = entry.getProtein().getRecommendedName().getFullName()
+              .getValue();
+    }
+    return desc;
+  }
+
+  /**
+   * Constructs a sequence id by concatenating all entry/name elements with '|'
+   * separator
+   * 
+   * @param entry
+   * @return
+   */
+  static String getUniprotEntryId(Entry entry)
+  {
+    StringBuilder name = new StringBuilder(32);
+    for (String n : entry.getName())
+    {
+      if (name.length() > 0)
+      {
+        name.append(BAR_DELIMITER);
+      }
+      name.append(n);
+    }
+    return name.toString();
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
+   */
+  @Override
+  public boolean isValidReference(String accession)
+  {
+    // TODO: make the following a standard validator
+    return (accession == null || accession.length() < 2) ? false
+            : getAccessionValidator().search(accession);
+  }
+
+  /**
+   * return LDHA_CHICK uniprot entry
+   */
+  @Override
+  public String getTestQuery()
+  {
+    return "P00340";
+  }
+
+  @Override
+  public String getDbName()
+  {
+    return "Uniprot"; // getDbSource();
+  }
+
+  @Override
+  public int getTier()
+  {
+    return 0;
+  }
+
+  /**
+   * Reads the reply to the EBI Fetch Uniprot data query, unmarshals it to an
+   * Uniprot object, and returns the enclosed Entry objects, or null on any
+   * failure
+   * 
+   * @param is
+   * @return
+   */
+  public List<Entry> getUniprotEntries(InputStream is)
+  {
+    List<Entry> entries = null;
+    try
+    {
+      JAXBContext jc = JAXBContext
+              .newInstance("jalview.xml.binding.uniprot");
+      XMLStreamReader streamReader = XMLInputFactory.newInstance()
+              .createXMLStreamReader(is);
+      javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
+      JAXBElement<jalview.xml.binding.uniprot.Uniprot> uniprotElement = 
+                 um.unmarshal(streamReader, jalview.xml.binding.uniprot.Uniprot.class);
+      jalview.xml.binding.uniprot.Uniprot uniprot = uniprotElement.getValue();
+      
+      if (uniprot != null && !uniprot.getEntry().isEmpty())
+      {
+        entries = uniprot.getEntry();
+      }
+    } catch (JAXBException | XMLStreamException
+            | FactoryConfigurationError e)
+    {
+      e.printStackTrace();
+    }
+    return entries;
+  }
+}
index 6f5f033..b9fe52f 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.dbsources;
 
+import java.util.Locale;
+
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -32,7 +34,6 @@ import jalview.datamodel.SequenceI;
 import jalview.schemes.ResidueProperties;
 import jalview.util.StringUtils;
 import jalview.ws.seqfetcher.DbSourceProxyImpl;
-import jalview.xml.binding.embl.ROOT;
 import jalview.xml.binding.uniprot.DbReferenceType;
 import jalview.xml.binding.uniprot.Entry;
 import jalview.xml.binding.uniprot.FeatureType;
@@ -41,8 +42,8 @@ import jalview.xml.binding.uniprot.PositionType;
 import jalview.xml.binding.uniprot.PropertyType;
 
 import java.io.InputStream;
+import java.net.HttpURLConnection;
 import java.net.URL;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Vector;
@@ -139,7 +140,7 @@ public class Uniprot extends DbSourceProxyImpl
     startQuery();
     try
     {
-      queries = queries.toUpperCase().replaceAll(
+      queries = queries.toUpperCase(Locale.ROOT).replaceAll(
               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
       AlignmentI al = null;
 
@@ -147,21 +148,27 @@ public class Uniprot extends DbSourceProxyImpl
               + ".xml";
 
       URL url = new URL(downloadstring);
-      URLConnection urlconn = url.openConnection();
-      InputStream istr = urlconn.getInputStream();
-      List<Entry> entries = getUniprotEntries(istr);
-      if (entries != null)
+      HttpURLConnection urlconn = (HttpURLConnection)url.openConnection();
+      // anything other than 200 means we don't have data
+      // TODO: JAL-3882 reuse the EnsemblRestClient's fair 
+      // use/backoff logic to retry when the server tells us to go away
+      if (urlconn.getResponseCode() == 200)
       {
-        List<SequenceI> seqs = new ArrayList<>();
-        for (Entry entry : entries)
+        InputStream istr = urlconn.getInputStream();
+        List<Entry> entries = getUniprotEntries(istr);
+        if (entries != null)
         {
-          seqs.add(uniprotEntryToSequence(entry));
+          List<SequenceI> seqs = new ArrayList<>();
+          for (Entry entry : entries)
+          {
+            seqs.add(uniprotEntryToSequence(entry));
+          }
+          al = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
         }
-        al = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
       }
-
       stopQuery();
       return al;
+      
     } catch (Exception e)
     {
       throw (e);
@@ -195,10 +202,12 @@ public class Uniprot extends DbSourceProxyImpl
      */
     final String dbVersion = getDbVersion();
     List<DBRefEntry> dbRefs = new ArrayList<>();
+    boolean canonical=true;
     for (String accessionId : entry.getAccession())
     {
       DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
-              accessionId);
+              accessionId,null,canonical);
+      canonical=false;
       dbRefs.add(dbRef);
     }
 
@@ -514,6 +523,11 @@ public class Uniprot extends DbSourceProxyImpl
     } catch (JAXBException | XMLStreamException
             | FactoryConfigurationError e)
     {
+      if (e instanceof javax.xml.bind.UnmarshalException && e.getCause()!=null && e.getCause() instanceof XMLStreamException && e.getCause().getMessage().contains("[row,col]:[1,1]"))
+      {
+        // trying to parse an empty stream
+        return null;
+      }
       e.printStackTrace();
     }
     return entries;
index f0cb14b..e39f0ab 100644 (file)
@@ -20,7 +20,9 @@
  */
 package jalview.ws.dbsources;
 
-import jalview.bin.Cache;
+import java.util.Locale;
+
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.io.DataSourceType;
@@ -63,10 +65,7 @@ public abstract class Xfam extends DbSourceProxyImpl
     // TODO: trap HTTP 404 exceptions and return null
     String xfamUrl = getURL(queries);
 
-    if (Cache.log != null)
-    {
-      Cache.log.debug("XFAM URL for retrieval is: " + xfamUrl);
-    }
+    Console.debug("XFAM URL for retrieval is: " + xfamUrl);
 
     AlignmentI rcds = new FormatAdapter().readFile(xfamUrl,
             DataSourceType.URL, FileFormat.Stockholm);
@@ -75,11 +74,11 @@ public abstract class Xfam extends DbSourceProxyImpl
     {
       rcds.getSequenceAt(s).addDBRef(new DBRefEntry(getXfamSource(),
               // getDbSource(),
-              getDbVersion(), queries.trim().toUpperCase()));
+              getDbVersion(), queries.trim().toUpperCase(Locale.ROOT)));
       if (!getDbSource().equals(getXfamSource()))
       { // add the specific ref too
         rcds.getSequenceAt(s).addDBRef(new DBRefEntry(getDbSource(),
-                getDbVersion(), queries.trim().toUpperCase()));
+                getDbVersion(), queries.trim().toUpperCase(Locale.ROOT)));
       }
     }
     stopQuery();
@@ -88,7 +87,7 @@ public abstract class Xfam extends DbSourceProxyImpl
 
   String getURL(String queries)
   {
-    return getURLPrefix() + "/family/" + queries.trim().toUpperCase()
+    return getURLPrefix() + "/family/" + queries.trim().toUpperCase(Locale.ROOT)
             + getURLSuffix();
   }
 
index b5a7328..1d04351 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.ebi;
 
+import java.util.Locale;
+
 import jalview.datamodel.DBRefSource;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
@@ -91,7 +93,7 @@ public class EBIFetchClient
    *          the query formatted as db:query1;query2;query3
    * @param format
    *          the format wanted
-   * @param extension
+   * @param ext
    *          for the temporary file to hold response (without separator)
    * @return the file holding the response
    * @throws OutOfMemoryError
@@ -202,6 +204,7 @@ public class EBIFetchClient
   {
     String url = buildUrl(ids, database, format);
     InputStream is = null;
+    BufferedReader br = null;
     try
     {
       URL rcall = new URL(url);
@@ -215,7 +218,7 @@ public class EBIFetchClient
           Platform.streamToFile(is, outFile);
           return null;
         }
-        BufferedReader br = new BufferedReader(new InputStreamReader(is));
+        br = new BufferedReader(new InputStreamReader(is));
         String rtn;
         List<String> arl = new ArrayList<>();
         while ((rtn = br.readLine()) != null)
@@ -251,6 +254,15 @@ public class EBIFetchClient
         {
         }
       }
+      if (br != null)
+      {
+        try
+        {
+          br.close();
+        } catch (IOException e)
+        {
+        }
+      }
     }
     return null;
   }
@@ -269,13 +281,13 @@ public class EBIFetchClient
     if (database.equalsIgnoreCase(DBRefSource.EMBL)
             || database.equalsIgnoreCase(DBRefSource.EMBLCDS))
     {
-      url = "https://www.ebi.ac.uk/ena/data/view/" + ids.toLowerCase()
-              + (format != null ? "&" + format : "");
+      url = "https://www.ebi.ac.uk/ena/browser/api/embl/"
+              + ids.toLowerCase(Locale.ROOT) + "?download=true&gzip=true";
     }
     else
     {
       url = "https://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
-              + database.toLowerCase() + "/" + ids.toLowerCase()
+              + database.toLowerCase(Locale.ROOT) + "/" + ids.toLowerCase(Locale.ROOT)
               + (format != null ? "/" + format : "");
     }
     return url;
index 83252d8..7e6e660 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.io.mime;
 
+import java.util.Locale;
+
 import jalview.io.packed.DataProvider.JvDataType;
 
 /**
@@ -53,7 +55,7 @@ public class MimeTypes
    */
   public static JvDataType getTypeOf(String mimeType)
   {
-    String mt = mimeType.toLowerCase();
+    String mt = mimeType.toLowerCase(Locale.ROOT);
     for (int i = 0; i < typemap.length; i += 2)
     {
       if (typemap[i].equals(mt))
index bee9fad..4a8f512 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.jws1;
 
+import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.JvOptionPane;
 import jalview.util.MessageManager;
 
@@ -98,7 +100,7 @@ public class Discoverer implements Runnable
       // timeout
     } catch (Exception ex)
     {
-      jalview.bin.Cache.log.error(
+      Console.error(
               "Serious!  Service location failed\nfor URL :" + WsURL + "\n",
               ex);
 
@@ -126,7 +128,7 @@ public class Discoverer implements Runnable
   static private Vector<URL> getDiscoveryURLS()
   {
     Vector<URL> urls = new Vector<>();
-    String RootServiceURLs = jalview.bin.Cache.getDefault("DISCOVERY_URLS",
+    String RootServiceURLs = Cache.getDefault("DISCOVERY_URLS",
             "http://www.compbio.dundee.ac.uk/JalviewWS/services/ServiceRegistry");
 
     try
@@ -144,23 +146,21 @@ public class Discoverer implements Runnable
           }
           else
           {
-            jalview.bin.Cache.log
-                    .info("Ignoring duplicate url in DISCOVERY_URLS list");
+            Console.info("Ignoring duplicate url in DISCOVERY_URLS list");
           }
         } catch (Exception ex)
         {
-          jalview.bin.Cache.log
-                  .warn("Problem whilst trying to make a URL from '"
+          Console.warn("Problem whilst trying to make a URL from '"
                           + ((url != null) ? url : "<null>") + "'");
-          jalview.bin.Cache.log.warn(
+          Console.warn(
                   "This was probably due to a malformed comma separated list"
                           + " in the DISCOVERY_URLS entry of $(HOME)/.jalview_properties)");
-          jalview.bin.Cache.log.debug("Exception was ", ex);
+          Console.debug("Exception was ", ex);
         }
       }
     } catch (Exception ex)
     {
-      jalview.bin.Cache.log.warn(
+      Console.warn(
               "Error parsing comma separated list of urls in DISCOVERY_URLS.",
               ex);
     }
@@ -176,11 +176,10 @@ public class Discoverer implements Runnable
    */
   static public void doDiscovery()
   {
-    jalview.bin.Cache.log
-            .debug("(Re)-Initialising the discovery URL list.");
+    Console.debug("(Re)-Initialising the discovery URL list.");
     try
     {
-      reallyDiscoverServices = jalview.bin.Cache
+      reallyDiscoverServices = Cache
               .getDefault("DISCOVERY_START", false);
       if (reallyDiscoverServices)
       {
@@ -188,7 +187,7 @@ public class Discoverer implements Runnable
       }
       else
       {
-        jalview.bin.Cache.log.debug("Setting default services");
+        Console.debug("Setting default services");
         services = new Hashtable<>();
         // Muscle, Clustal and JPred.
         ServiceHandle[] defServices = { new ServiceHandle("MsaWS",
@@ -239,7 +238,7 @@ public class Discoverer implements Runnable
     ServiceHandles shs = null;
     try
     {
-      jalview.bin.Cache.log.debug("Discovering services using " + location);
+      Console.debug("Discovering services using " + location);
       shs = locateWebService(location).getServices();
     } catch (org.apache.axis.AxisFault f)
     {
@@ -257,13 +256,13 @@ public class Discoverer implements Runnable
       }
       else
       {
-        jalview.bin.Cache.log.warn("No Discovery service at " + location);
-        jalview.bin.Cache.log.debug("Axis Fault", f);
+        Console.warn("No Discovery service at " + location);
+        Console.debug("Axis Fault", f);
       }
     } catch (Exception e)
     {
-      jalview.bin.Cache.log.warn("No Discovery service at " + location);
-      jalview.bin.Cache.log.debug("Discovery Service General Exception", e);
+      Console.warn("No Discovery service at " + location);
+      Console.debug("Discovery Service General Exception", e);
     }
     if ((shs != null) && shs.getServices().length > 0)
     {
@@ -293,7 +292,7 @@ public class Discoverer implements Runnable
     {
       if (!cat.contains(sh[i]))
       {
-        jalview.bin.Cache.log.debug("A " + sh[i].getAbstractName()
+        Console.debug("A " + sh[i].getAbstractName()
                 + " service called " + sh[i].getName() + " exists at "
                 + sh[i].getEndpointURL() + "\n");
         if (!sscat.containsKey(sh[i].getAbstractName()))
@@ -315,15 +314,14 @@ public class Discoverer implements Runnable
               disc_serv = new java.net.URL(sh[i].getEndpointURL());
               if (!ServiceURLList.contains(disc_serv))
               {
-                jalview.bin.Cache.log.debug(
+                Console.debug(
                         "Adding new discovery service at " + disc_serv);
                 ServiceURLList.add(disc_serv);
                 seenNewDiscovery = true;
               }
             } catch (Exception e)
             {
-              jalview.bin.Cache.log
-                      .debug("Ignoring bad discovery service URL "
+              Console.debug("Ignoring bad discovery service URL "
                               + sh[i].getEndpointURL(), e);
             }
           }
@@ -341,8 +339,7 @@ public class Discoverer implements Runnable
     int s_url = 0;
     if (ServiceURLList == null)
     {
-      jalview.bin.Cache.log
-              .debug("No service endpoints to use for service discovery.");
+      Console.debug("No service endpoints to use for service discovery.");
       return;
     }
     while (s_url < ServiceURLList.size())
@@ -355,7 +352,7 @@ public class Discoverer implements Runnable
       }
       else
       {
-        jalview.bin.Cache.log.warn("No services at "
+        Console.warn("No services at "
                 + (ServiceURLList.get(s_url))
                 + " - check DISCOVERY_URLS property in .jalview_properties");
       }
index 3b7bdb6..cc73d24 100644 (file)
  */
 package jalview.ws.jws1;
 
+import java.util.Locale;
+
 import jalview.analysis.AlignSeq;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SeqCigar;
 import jalview.datamodel.SequenceI;
@@ -99,7 +101,7 @@ public class JPredClient extends WS1Client
     Jpred server = locateWebService();
     if (server == null)
     {
-      Cache.log.warn("Couldn't find a Jpred webservice to invoke!");
+      Console.warn("Couldn't find a Jpred webservice to invoke!");
       return;
     }
     SeqCigar[] msf = null;
@@ -183,7 +185,7 @@ public class JPredClient extends WS1Client
 
   private String getPredictionName(String webServiceName)
   {
-    if (webServiceName.toLowerCase()
+    if (webServiceName.toLowerCase(Locale.ROOT)
             .indexOf("secondary structure prediction") > -1)
     {
       return webServiceName;
index 23d9eb0..a39945e 100644 (file)
@@ -22,7 +22,7 @@ package jalview.ws.jws1;
 
 import jalview.analysis.AlignSeq;
 import jalview.analysis.SeqsetUtils;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -119,17 +119,17 @@ class JPredThread extends JWS1Thread implements WSClientI
 
       JpredResult result = (JpredResult) this.result;
 
-      Cache.log.debug("Parsing output from JNet job.");
+      Console.debug("Parsing output from JNet job.");
       // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt",
       // "File");
       JPredFile prediction = new JPredFile(result.getPredfile(),
               DataSourceType.PASTE);
       SequenceI[] preds = prediction.getSeqsAsArray();
-      Cache.log.debug("Got prediction profile.");
+      Console.debug("Got prediction profile.");
 
       if ((this.msa != null) && (result.getAligfile() != null))
       {
-        Cache.log.debug("Getting associated alignment.");
+        Console.debug("Getting associated alignment.");
         // we ignore the returned alignment if we only predicted on a single
         // sequence
         FileFormatI format = new IdentifyFile()
@@ -461,7 +461,7 @@ class JPredThread extends JWS1Thread implements WSClientI
         {
           job.setSubmitted(true);
           job.setSubjobComplete(false);
-          Cache.log.info(WsUrl + " Job Id '" + job.getJobId() + "'");
+          Console.info(WsUrl + " Job Id '" + job.getJobId() + "'");
         }
       }
       else
@@ -484,7 +484,7 @@ class JPredThread extends JWS1Thread implements WSClientI
                 "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n"
                         + e.getMessage() + "\n");
 
-        jalview.bin.Cache.log.warn("Server Exception", e);
+        Console.warn("Server Exception", e);
       }
       else
       {
@@ -495,8 +495,7 @@ class JPredThread extends JWS1Thread implements WSClientI
                         "info.failed_to_submit_prediction", new String[]
                         { e.getMessage(), wsInfo.getProgressText() }));
 
-        jalview.bin.Cache.log
-                .debug("Failed Submission of job " + j.getJobnum(), e);
+        Console.debug("Failed Submission of job " + j.getJobnum(), e);
 
       }
       j.setAllowedServerExceptions(-1);
@@ -523,7 +522,7 @@ class JPredThread extends JWS1Thread implements WSClientI
     } catch (Exception ex)
     {
 
-      Cache.log.error(
+      Console.error(
               "Unexpected exception when processing results for " + altitle,
               ex);
       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
@@ -577,9 +576,9 @@ class JPredThread extends JWS1Thread implements WSClientI
           msa = (j.msa != null) ? true : msa;
           try
           {
-            jalview.bin.Cache.log.debug("Parsing output of job " + jn);
+            Console.debug("Parsing output of job " + jn);
             jobres = j.getResultSet();
-            jalview.bin.Cache.log.debug("Finished parsing output.");
+            Console.debug("Finished parsing output.");
             if (jobs.length == 1)
             {
               res = jobres;
@@ -592,8 +591,7 @@ class JPredThread extends JWS1Thread implements WSClientI
             }
           } catch (Exception e)
           {
-            jalview.bin.Cache.log
-                    .error("JNet Client: JPred Annotation Parse Error", e);
+            Console.error("JNet Client: JPred Annotation Parse Error", e);
             wsInfo.setStatus(j.getJobnum(),
                     WebserviceInfo.STATE_STOPPED_ERROR);
             wsInfo.appendProgressText(j.getJobnum(),
@@ -652,7 +650,7 @@ class JPredThread extends JWS1Thread implements WSClientI
         }
         else
         {
-          Cache.log.info("Append results onto existing alignment.");
+          Console.info("Append results onto existing alignment.");
         }
       }
     }
index 4a09625..dad314b 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.jws1;
 
+import java.util.Locale;
+
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.gui.AlignFrame;
@@ -119,7 +121,7 @@ public class MsaWSClient extends WS1Client
 
     wsInfo.setProgressText(((submitGaps) ? "Re-alignment" : "Alignment")
             + " of " + altitle + "\nJob details\n");
-    String jobtitle = WebServiceName.toLowerCase();
+    String jobtitle = WebServiceName.toLowerCase(Locale.ROOT);
     if (jobtitle.endsWith("alignment"))
     {
       if (submitGaps && (!jobtitle.endsWith("realignment")
index 006f014..e027038 100644 (file)
@@ -21,7 +21,7 @@
 package jalview.ws.jws1;
 
 import jalview.analysis.AlignSeq;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
@@ -410,7 +410,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
           {
             cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
                     + exc + "\n");
-            Cache.log.warn(
+            Console.warn(
                     "Exception whilst cancelling " + jobs[job].getJobId(),
                     exc);
           }
@@ -453,9 +453,9 @@ class MsaWSThread extends JWS1Thread implements WSClientI
     MsaWSJob j = (MsaWSJob) job;
     if (j.isSubmitted())
     {
-      if (Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        Cache.log.debug(
+        Console.debug(
                 "Tried to submit an already submitted job " + j.getJobId());
       }
       return;
@@ -542,7 +542,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
                 && jobs[j].hasResults())
         {
           results++;
-          // if (Cache.log.isDebugEnabled())
+          // if (Cache.isDebugEnabled())
           // {
           // System.out.println("Job lob for job
           // "+jobs[j].getJobId()+":"+jobs[j].getJobnum());
@@ -571,7 +571,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
     } catch (Exception ex)
     {
 
-      Cache.log.error(
+      Console.error(
               "Unexpected exception when processing results for " + alTitle,
               ex);
       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
index 53338d3..0c67063 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.ws.jws1;
 
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.gui.AlignFrame;
@@ -272,7 +273,7 @@ public class SeqSearchWSClient extends WS1Client
               .getSupportedDatabases();
     } catch (Exception e)
     {
-      jalview.bin.Cache.log.warn(
+      Console.warn(
               "Database list request failed, so disabling SeqSearch Service client "
                       + sh.getName() + " at " + sh.getEndpointURL(),
               e);
index 761b758..0f28230 100644 (file)
@@ -22,7 +22,7 @@ package jalview.ws.jws1;
 
 import jalview.analysis.AlignSeq;
 import jalview.api.FeatureColourI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
@@ -425,7 +425,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
           {
             cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
                     + exc + "\n");
-            Cache.log.warn(
+            Console.warn(
                     "Exception whilst cancelling " + jobs[job].getJobId(),
                     exc);
           }
@@ -469,9 +469,9 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
     SeqSearchWSJob j = (SeqSearchWSJob) job;
     if (j.isSubmitted())
     {
-      if (Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        Cache.log.debug(
+        Console.debug(
                 "Tried to submit an already submitted job " + j.getJobId());
       }
       return;
@@ -579,7 +579,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
     } catch (Exception ex)
     {
 
-      Cache.log.error(
+      Console.error(
               "Unexpected exception when processing results for " + alTitle,
               ex);
       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
index a1b8e7a..315e69f 100644 (file)
@@ -21,7 +21,7 @@
 package jalview.ws.jws2;
 
 import jalview.api.FeatureColourI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.SequenceFeature;
@@ -207,8 +207,7 @@ public class AADisorderClient extends JabawsCalcWorker
           scores = scoremanager.getAnnotationForSequence(seqId);
         } catch (Exception q)
         {
-          Cache.log
-                  .info("Couldn't recover disorder prediction for sequence "
+          Console.info("Couldn't recover disorder prediction for sequence "
                           + seq.getName() + "(Prediction name was " + seqId
                           + ")"
                           + "\nSee http://issues.jalview.org/browse/JAL-1319 for one possible reason why disorder predictions might fail.");
index dd64e77..4ed92fb 100644 (file)
@@ -24,6 +24,7 @@ import jalview.analysis.AlignSeq;
 import jalview.analysis.SeqsetUtils;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AnnotatedCollectionI;
@@ -344,7 +345,7 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
         }
         if (collectAnnotationResultsFor(rslt))
         {
-          jalview.bin.Cache.log.debug("Updating result annotation from Job "
+          Console.debug("Updating result annotation from Job "
                   + rslt + " at " + service.getUri());
           updateResultAnnotation(true);
           ap.adjustAnnotationHeight();
index d06c3f0..5831df8 100644 (file)
@@ -23,7 +23,7 @@
  */
 package jalview.ws.jws2;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.jws2.jabaws2.Jws2InstanceFactory;
 
@@ -212,16 +212,16 @@ public class JabaWsServerQuery implements Runnable
       else
       {
         jws2Discoverer.addInvalidServiceUrl(jwsserver);
-        Cache.log.warn("Ignoring invalid Jws2 service url " + jwsserver);
+        Console.warn("Ignoring invalid Jws2 service url " + jwsserver);
       }
     } catch (Exception e)
     {
       e.printStackTrace();
-      Cache.log.warn("Exception when discovering Jws2 services.", e);
+      Console.warn("Exception when discovering Jws2 services.", e);
       jws2Discoverer.addInvalidServiceUrl(jwsserver);
     } catch (Error e)
     {
-      Cache.log.error("Exception when discovering Jws2 services.", e);
+      Console.error("Exception when discovering Jws2 services.", e);
       jws2Discoverer.addInvalidServiceUrl(jwsserver);
     }
     running = false;
index 0f1a25e..2f996bd 100644 (file)
  */
 package jalview.ws.jws2;
 
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
+
+import compbio.metadata.Argument;
 import jalview.api.AlignCalcWorkerI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.JvSwingUtils;
@@ -34,18 +45,6 @@ import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.WsParamSetI;
 import jalview.ws.uimodel.AlignAnalysisUIText;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.List;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.event.MenuEvent;
-import javax.swing.event.MenuListener;
-
-import compbio.metadata.Argument;
-
 /**
  * provides metadata for a jabaws2 service instance - resolves names, etc.
  * 
@@ -122,9 +121,10 @@ public abstract class Jws2Client extends jalview.ws.WSClient
       WsParamSetI prset = jobParams.getPreset();
       if (prset == null)
       {
-        paramset = jobParams.isServiceDefaults() ? null
-                : JabaParamStore
-                        .getJabafromJwsArgs(jobParams.getJobParams());
+        paramset =
+                /* JAL-3739 always take values from input form */
+                /* jobParams.isServiceDefaults() ? null : */
+                JabaParamStore.getJabafromJwsArgs(jobParams.getJobParams());
         this.preset = null;
       }
       else
@@ -367,7 +367,7 @@ public abstract class Jws2Client extends jalview.ws.WSClient
       if (service != null
               && !fave.getService().hosturl.equals(service.hosturl))
       {
-        Cache.log.debug("Changing AACon service to " + service.hosturl
+        Console.debug("Changing AACon service to " + service.hosturl
                 + " from " + fave.getService().hosturl);
         fave.setService(service);
       }
@@ -389,7 +389,7 @@ public abstract class Jws2Client extends jalview.ws.WSClient
       if (!service.serviceType.toString()
               .equals(compbio.ws.client.Services.AAConWS.toString()))
       {
-        Cache.log.warn(
+        Console.warn(
                 "Ignoring invalid preferred service for AACon calculations (service type was "
                         + service.serviceType + ")");
         service = null;
index 516a719..d624c5c 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.ws.jws2;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.JvSwingUtils;
@@ -164,7 +165,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
       {
         try
         {
-          Cache.log.debug(
+          Console.debug(
                   "Waiting around for old discovery thread to finish.");
           // wait around until old discoverer dies
           Thread.sleep(100);
@@ -173,7 +174,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
         }
       }
       aborted = false;
-      Cache.log.debug("Old discovery thread has finished.");
+      Console.debug("Old discovery thread has finished.");
     }
     running = true;
 
@@ -258,7 +259,7 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
       }
       if (aborted)
       {
-        Cache.log.debug(
+        Console.debug(
                 "Aborting " + qrys.size() + " JABAWS discovery threads.");
         for (JabaWsServerQuery squery : qrys)
         {
@@ -711,23 +712,23 @@ public class Jws2Discoverer implements Runnable, WSMenuEntryProviderI
           }
           else
           {
-            Cache.log.warn("Ignoring duplicate url " + url + " in "
+            Console.warn("Ignoring duplicate url " + url + " in "
                     + JWS2HOSTURLS + " list");
           }
         } catch (MalformedURLException ex)
         {
-          Cache.log.warn("Problem whilst trying to make a URL from '"
+          Console.warn("Problem whilst trying to make a URL from '"
                   + ((url != null) ? url : "<null>") + "'");
-          Cache.log.warn(
+          Console.warn(
                   "This was probably due to a malformed comma separated list"
                           + " in the " + JWS2HOSTURLS
                           + " entry of $(HOME)/.jalview_properties)");
-          Cache.log.debug("Exception was ", ex);
+          Console.debug("Exception was ", ex);
         }
       }
     } catch (Exception ex)
     {
-      Cache.log.warn("Error parsing comma separated list of urls in "
+      Console.warn("Error parsing comma separated list of urls in "
               + JWS2HOSTURLS + " preference.", ex);
     }
     return urls;
index 23c6949..8ed4a36 100644 (file)
  */
 package jalview.ws.jws2;
 
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.AlignmentView;
-import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
-import jalview.gui.JvOptionPane;
-import jalview.gui.JvSwingUtils;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
+import java.util.Locale;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -42,6 +34,15 @@ import javax.swing.ToolTipManager;
 
 import compbio.data.msa.MsaWS;
 import compbio.metadata.Argument;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.gui.JvSwingUtils;
+import jalview.util.MessageManager;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.params.WsParamSetI;
 
 /**
  * DOCUMENT ME!
@@ -149,7 +150,7 @@ public class MsaWSClient extends Jws2Client
 
     wsInfo.setProgressText(((submitGaps) ? "Re-alignment" : "Alignment")
             + " of " + altitle + "\nJob details\n");
-    String jobtitle = WebServiceName.toLowerCase();
+    String jobtitle = WebServiceName.toLowerCase(Locale.ROOT);
     if (jobtitle.endsWith("alignment"))
     {
       if (submitGaps && (!jobtitle.endsWith("realignment")
@@ -214,9 +215,9 @@ public class MsaWSClient extends Jws2Client
 
   @Override
   public void attachWSMenuEntry(JMenu rmsawsmenu,
-          final Jws2Instance service, final AlignFrame alignFrame)
+          final Jws2Instance service, final AlignFrame af)
   {
-    if (registerAAConWSInstance(rmsawsmenu, service, alignFrame))
+    if (registerAAConWSInstance(rmsawsmenu, service, af))
     {
       // Alignment dependent analysis calculation WS gui
       return;
@@ -264,14 +265,14 @@ public class MsaWSClient extends Jws2Client
         @Override
         public void actionPerformed(ActionEvent e)
         {
-          AlignmentView msa = alignFrame.gatherSequencesForAlignment();
+          AlignmentView msa = af.gatherSequencesForAlignment();
 
           if (msa != null)
           {
-            new MsaWSClient(service, alignFrame.getTitle(), msa, withGaps,
+            new MsaWSClient(service, af.getTitle(), msa, withGaps,
                     true,
-                    alignFrame.getViewport().getAlignment().getDataset(),
-                    alignFrame);
+                    af.getViewport().getAlignment().getDataset(),
+                    af);
           }
 
         }
@@ -291,13 +292,10 @@ public class MsaWSClient extends Jws2Client
           @Override
           public void actionPerformed(ActionEvent e)
           {
-            AlignmentView msa = alignFrame.gatherSequencesForAlignment();
+            AlignmentView msa = af.gatherSequencesForAlignment();
             if (msa != null)
             {
-              new MsaWSClient(service, null, null, true,
-                      alignFrame.getTitle(), msa, withGaps, true,
-                      alignFrame.getViewport().getAlignment().getDataset(),
-                      alignFrame);
+              startJob(service, af, withGaps, msa);
             }
 
           }
@@ -312,9 +310,9 @@ public class MsaWSClient extends Jws2Client
 
           final int showToolTipFor = ToolTipManager.sharedInstance()
                   .getDismissDelay();
-          for (final WsParamSetI preset : presets)
+          for (final WsParamSetI preSet : presets)
           {
-            final JMenuItem methodR = new JMenuItem(preset.getName());
+            final JMenuItem methodR = new JMenuItem(preSet.getName());
             final int QUICK_TOOLTIP = 1500;
             // JAL-1582 shorten tooltip display time in these menu items as
             // they can obscure other options
@@ -336,27 +334,27 @@ public class MsaWSClient extends Jws2Client
 
             });
             String tooltip = JvSwingUtils.wrapTooltip(true, "<strong>"
-                    + (preset.isModifiable()
+                    + (preSet.isModifiable()
                             ? MessageManager.getString("label.user_preset")
                             : MessageManager
                                     .getString("label.service_preset"))
-                    + "</strong><br/>" + preset.getDescription());
+                    + "</strong><br/>" + preSet.getDescription());
             methodR.setToolTipText(tooltip);
             methodR.addActionListener(new ActionListener()
             {
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                AlignmentView msa = alignFrame
+                AlignmentView msa = af
                         .gatherSequencesForAlignment();
 
                 if (msa != null)
                 {
-                  MsaWSClient msac = new MsaWSClient(service, preset,
-                          alignFrame.getTitle(), msa, false, true,
-                          alignFrame.getViewport().getAlignment()
+                  MsaWSClient msac = new MsaWSClient(service, preSet,
+                          af.getTitle(), msa, false, true,
+                          af.getViewport().getAlignment()
                                   .getDataset(),
-                          alignFrame);
+                          af);
                 }
 
               }
@@ -378,4 +376,20 @@ public class MsaWSClient extends Jws2Client
       }
     } while (!finished);
   }
+
+  protected void startJob(final Jws2Instance service, final AlignFrame af,
+          final boolean withGaps, AlignmentView msa)
+  {
+    try {
+    new MsaWSClient(service, null, null, true,
+            af.getTitle(), msa, withGaps, true,
+            af.getViewport().getAlignment().getDataset(),
+            af);
+    } catch (Exception e) {
+      JvOptionPane.showMessageDialog(alignFrame, e.getMessage(),
+              MessageManager.getString("label.state_job_error"),
+              JvOptionPane.WARNING_MESSAGE);
+
+    }
+  }
 }
index db6e03f..ee0fbc5 100644 (file)
@@ -21,7 +21,7 @@
 package jalview.ws.jws2;
 
 import jalview.analysis.AlignSeq;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
@@ -574,7 +574,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
           {
             cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
                     + exc + "\n");
-            Cache.log.warn(
+            Console.warn(
                     "Exception whilst cancelling " + jobs[job].getJobId(),
                     exc);
           }
@@ -667,9 +667,9 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     MsaWSJob j = (MsaWSJob) job;
     if (j.isSubmitted())
     {
-      if (Cache.log.isDebugEnabled())
+      if (Console.isDebugEnabled())
       {
-        Cache.log.debug(
+        Console.debug(
                 "Tried to submit an already submitted job " + j.getJobId());
       }
       return;
@@ -811,7 +811,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
             } catch (Exception e)
             {
 
-              Cache.log.warn(
+              Console.warn(
                       "Exception when retrieving remaining Job progress data for job "
                               + msjob.getJobId() + " on server " + WsUrl);
               e.printStackTrace();
@@ -835,7 +835,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
             }
           } while (nunchanged > 0 && nexcept > 0);
 
-          if (Cache.log.isDebugEnabled())
+          if (Console.isDebugEnabled())
           {
             System.out.println("Job Execution file for job: "
                     + msjob.getJobId() + " on server " + WsUrl);
@@ -850,7 +850,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
           {
             // job has failed for some reason - probably due to invalid
             // parameters
-            Cache.log.debug(
+            Console.debug(
                     "Results not available for finished job - marking as broken job.",
                     e);
             msjob.jobProgress.append(
@@ -859,7 +859,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
             msjob.setjobStatus(JobStatus.FAILED);
           } catch (Exception e)
           {
-            Cache.log.error("Couldn't get Alignment for job.", e);
+            Console.error("Couldn't get Alignment for job.", e);
             // TODO: Increment count and retry ?
             msjob.setjobStatus(JobStatus.UNDEFINED);
           }
@@ -887,7 +887,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     } catch (Exception ex)
     {
 
-      Cache.log.error(
+      Console.error(
               "Unexpected exception when processing results for " + alTitle,
               ex);
       wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
index 45bddac..a30a09c 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.jws2;
 
+import java.util.Locale;
+
 import jalview.api.AlignCalcWorkerI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
@@ -128,7 +130,7 @@ public class SequenceAnnotationWSClient extends Jws2Client
         worker.updateParameters(this.preset, paramset);
       }
     }
-    if (sh.action.toLowerCase().contains("disorder"))
+    if (sh.action.toLowerCase(Locale.ROOT).contains("disorder"))
     {
       // build IUPred style client. take sequences, returns annotation per
       // sequence.
index cbfbd3b..5a3fb35 100644 (file)
  */
 package jalview.ws.jws2.dm;
 
-import jalview.util.MessageManager;
-import jalview.ws.jws2.ParameterUtils;
-import jalview.ws.params.OptionI;
-
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.List;
 
 import compbio.metadata.Option;
+import jalview.util.MessageManager;
+import jalview.ws.jws2.ParameterUtils;
+import jalview.ws.params.OptionI;
 
 public class JabaOption implements jalview.ws.params.OptionI
 {
@@ -94,9 +93,9 @@ public class JabaOption implements jalview.ws.params.OptionI
       opt.setDefaultValue(selectedItem);
     } catch (Exception e)
     {
-      e.printStackTrace();
-      throw new Error(MessageManager.getString(
-              "error.implementation_error_cannot_set_jaba_option"));
+      throw new IllegalArgumentException(MessageManager
+              .formatMessage("error.invalid_value_for_option", new String[]
+              { selectedItem, opt.getName() }));
     }
   }
 
index 5bfe3b5..bd2f664 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ws.rest;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.io.FileParse;
 import jalview.io.packed.DataProvider;
 import jalview.io.packed.DataProvider.JvDataType;
@@ -131,7 +131,7 @@ public class HttpResultSet extends FileParse implements AutoCloseable
       {
         error = true;
         errormessage = "Couldn't parse message from web service.";
-        Cache.log.warn("Failed to parse MIME multipart content", me);
+        Console.warn("Failed to parse MIME multipart content", me);
         en.consumeContent();
       }
       return new ParsePackedSet().getAlignment(ds,
@@ -158,19 +158,19 @@ public class HttpResultSet extends FileParse implements AutoCloseable
               : en.getContentEncoding().getValue();
       if (en.getContentType() != null)
       {
-        Cache.log.debug("Result Type: " + en.getContentType().toString());
+        Console.debug("Result Type: " + en.getContentType().toString());
       }
       else
       {
-        Cache.log.debug("No Result Type Specified.");
+        Console.debug("No Result Type Specified.");
       }
       if (enc == null || enc.length() < 1)
       {
-        Cache.log.debug("Assuming 'Default' Result Encoding.");
+        Console.debug("Assuming 'Default' Result Encoding.");
       }
       else
       {
-        Cache.log.debug("Result Encoded as : " + enc);
+        Console.debug("Result Encoded as : " + enc);
       }
       // attempt to identify file and construct an appropriate DataSource
       // identifier for it.
@@ -184,7 +184,7 @@ public class HttpResultSet extends FileParse implements AutoCloseable
                 : new InputStreamReader(en.getContent());
       } catch (UnsupportedEncodingException e)
       {
-        Cache.log.error("Can't handle encoding '" + enc
+        Console.error("Can't handle encoding '" + enc
                 + "' for response from webservice.", e);
         en.consumeContent();
         error = true;
index 88431a6..a96b6d9 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.rest;
 
+import java.util.Locale;
+
 import jalview.ws.params.ArgumentI;
 import jalview.ws.params.InvalidArgumentException;
 import jalview.ws.params.OptionI;
@@ -232,7 +234,7 @@ public abstract class InputType
         {
           valid = false;
           warnings.append("Invalid value for parameter "
-                  + mtch.group(1).toLowerCase() + " '" + mtch.group(2)
+                  + mtch.group(1).toLowerCase(Locale.ROOT) + " '" + mtch.group(2)
                   + "' (expected an integer)\n");
         }
 
index a71b70d..fdab105 100644 (file)
@@ -412,7 +412,7 @@ public class RestClient extends WSClient
       {
         for (RestServiceDescription descr : RestServiceDescription
                 .parseDescriptions(
-                        jalview.bin.Cache.getDefault(RSBS_SERVICES,
+                        Cache.getDefault(RSBS_SERVICES,
                                 makeShmmrRestClient().service.toString())))
         {
           services.add(descr.toString());
index acb7904..f32535c 100644 (file)
@@ -20,7 +20,9 @@
  */
 package jalview.ws.rest;
 
-import jalview.bin.Cache;
+import java.util.Locale;
+
+import jalview.bin.Console;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -266,7 +268,7 @@ public class RestJobThread extends AWSThread
                 + "</a><br>See Console output for details.";
         rj.setAllowedServerExceptions(0);// unrecoverable;
         rj.error = true;
-        Cache.log.fatal("Unexpected REST Job " + getStage(stg)
+        Console.fatal("Unexpected REST Job " + getStage(stg)
                 + "exception for URL " + rj.rsd.postUrl);
         throw (he);
       } catch (IOException e)
@@ -275,7 +277,7 @@ public class RestJobThread extends AWSThread
                 + "Job. <br>Problematic url was <a href=\""
                 + request.getURI() + "\">" + request.getURI()
                 + "</a><br>See Console output for details.";
-        Cache.log.warn("IO Exception for REST Job " + getStage(stg)
+        Console.warn("IO Exception for REST Job " + getStage(stg)
                 + "exception for URL " + rj.rsd.postUrl);
 
         throw (e);
@@ -284,7 +286,7 @@ public class RestJobThread extends AWSThread
       {
       case 200:
         rj.running = false;
-        Cache.log.debug("Processing result set.");
+        Console.debug("Processing result set.");
         processResultSet(rj, response, request);
         break;
       case 202:
@@ -302,7 +304,7 @@ public class RestJobThread extends AWSThread
         {
           if (loc.length > 1)
           {
-            Cache.log.warn("Ignoring additional " + (loc.length - 1)
+            Console.warn("Ignoring additional " + (loc.length - 1)
                     + " location(s) provided in response header ( next one is '"
                     + loc[1].getValue() + "' )");
           }
@@ -324,7 +326,7 @@ public class RestJobThread extends AWSThread
       default:
         // Some other response. Probably need to pop up the content in a window.
         // TODO: deal with all other HTTP response codes from server.
-        Cache.log.warn("Unhandled response status when " + getStage(stg)
+        Console.warn("Unhandled response status when " + getStage(stg)
                 + "for " + postUrl + ": " + response.getStatusLine());
         rj.error = true;
         rj.setAllowedServerExceptions(0);
@@ -338,7 +340,7 @@ public class RestJobThread extends AWSThread
                   + "</a><br/>Filtered response content below:<br/>");
         } catch (IOException e)
         {
-          Cache.log.debug("IOException when consuming unhandled response",
+          Console.debug("IOException when consuming unhandled response",
                   e);
         }
         ;
@@ -401,7 +403,7 @@ public class RestJobThread extends AWSThread
      */
     String f;
     StringBuffer content = new StringBuffer(f = EntityUtils.toString(en));
-    f = f.toLowerCase();
+    f = f.toLowerCase(Locale.ROOT);
     int body = f.indexOf("<body");
     if (body > -1)
     {
@@ -445,7 +447,7 @@ public class RestJobThread extends AWSThread
     {
       job.setSubjobComplete(true);
       job.setAllowedServerExceptions(-1);
-      Cache.log.error("Exception when trying to start Rest Job.", ex);
+      Console.error("Exception when trying to start Rest Job.", ex);
     }
   }
 
@@ -454,7 +456,7 @@ public class RestJobThread extends AWSThread
   {
     // crazy users will see this message
     // TODO: finish this! and remove the message below!
-    Cache.log.warn("Rest job result parser is currently INCOMPLETE!");
+    Console.warn("Rest job result parser is currently INCOMPLETE!");
     int validres = 0;
     for (RestJob rj : (RestJob[]) jobs)
     {
@@ -463,22 +465,22 @@ public class RestJobThread extends AWSThread
         String ln = null;
         try
         {
-          Cache.log.debug("Parsing data for job " + rj.getJobId());
+          Console.debug("Parsing data for job " + rj.getJobId());
           rj.parseResultSet();
           if (rj.hasResults())
           {
             validres++;
           }
-          Cache.log.debug("Finished parsing data for job " + rj.getJobId());
+          Console.debug("Finished parsing data for job " + rj.getJobId());
 
         } catch (Error ex)
         {
-          Cache.log.warn(
+          Console.warn(
                   "Failed to finish parsing data for job " + rj.getJobId());
           ex.printStackTrace();
         } catch (Exception ex)
         {
-          Cache.log.warn(
+          Console.warn(
                   "Failed to finish parsing data for job " + rj.getJobId());
           ex.printStackTrace();
         } finally
@@ -754,7 +756,7 @@ public class RestJobThread extends AWSThread
               {
                 // TODO: decide if multiple multiple alignments returned by
                 // non-vseparable services are allowed.
-                Cache.log.warn(
+                Console.warn(
                         "dealing with multiple alignment products returned by non-vertically separable service.");
               }
               // recover reference to last alignment created for this rest frame
@@ -868,7 +870,7 @@ public class RestJobThread extends AWSThread
                     }
                     else
                     {
-                      Cache.log.warn(
+                      Console.warn(
                               "Couldn't resolve original sequence for new sequence.");
                     }
                   }
@@ -946,7 +948,7 @@ public class RestJobThread extends AWSThread
                   grass = groupNames.get(alan[nrj][an].groupRef.getName());
                   if (grass == null)
                   {
-                    Cache.log.error(
+                    Console.error(
                             "Couldn't relocate group referemce for group "
                                     + alan[nrj][an].groupRef.getName());
                   }
@@ -997,7 +999,7 @@ public class RestJobThread extends AWSThread
               {
                 // TODO: process each newick file, lifting over sequence refs to
                 // current alignment, if necessary.
-                Cache.log.error(
+                Console.error(
                         "Tree recovery from restjob not yet implemented.");
               }
             }
index 2a27cce..5b80541 100644 (file)
@@ -21,7 +21,7 @@
 package jalview.ws.seqfetcher;
 
 import jalview.api.FeatureSettingsModelI;
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
@@ -112,7 +112,7 @@ public class ASequenceFetcher
         return true;
       }
     }
-    Cache.log.warn("isFetchable doesn't know about '" + source + "'");
+    Console.warn("isFetchable doesn't know about '" + source + "'");
     return false;
   }
 
index ae58082..5a03aea 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ws.sifts;
 
+import java.util.Locale;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -219,7 +221,7 @@ public class SiftsClient implements SiftsClientI
     }
 
     String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase() + ".xml.gz";
+            + pdbId.toLowerCase(Locale.ROOT) + ".xml.gz";
     File siftsFile = new File(siftsFileName);
     if (siftsFile.exists())
     {
@@ -233,7 +235,7 @@ public class SiftsClient implements SiftsClientI
         BackupFiles.moveFileToFile(siftsFile, oldSiftsFile);
         try
         {
-          siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+          siftsFile = downloadSiftsFile(pdbId.toLowerCase(Locale.ROOT));
           oldSiftsFile.delete();
           return siftsFile;
         } catch (IOException e)
@@ -250,7 +252,7 @@ public class SiftsClient implements SiftsClientI
     }
     try
     {
-      siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+      siftsFile = downloadSiftsFile(pdbId.toLowerCase(Locale.ROOT));
     } catch (IOException e)
     {
       throw new SiftsException(e.getMessage());
@@ -356,7 +358,7 @@ public class SiftsClient implements SiftsClientI
   public static boolean deleteSiftsFileByPDBId(String pdbId)
   {
     File siftsFile = new File(SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase() + ".xml.gz");
+            + pdbId.toLowerCase(Locale.ROOT) + ".xml.gz");
     if (siftsFile.exists())
     {
       return siftsFile.delete();
@@ -431,7 +433,7 @@ public class SiftsClient implements SiftsClientI
         for (MapRegion mapRegion : mapRegions)
         {
           accessions
-                  .add(mapRegion.getDb().getDbAccessionId().toLowerCase());
+                  .add(mapRegion.getDb().getDbAccessionId().toLowerCase(Locale.ROOT));
         }
       }
     }
@@ -501,9 +503,9 @@ public class SiftsClient implements SiftsClientI
     HashSet<String> dbRefAccessionIdsString = new HashSet<String>();
     for (DBRefEntry dbref : seq.getDBRefs())
     {
-      dbRefAccessionIdsString.add(dbref.getAccessionId().toLowerCase());
+      dbRefAccessionIdsString.add(dbref.getAccessionId().toLowerCase(Locale.ROOT));
     }
-    dbRefAccessionIdsString.add(sourceDBRef.getAccessionId().toLowerCase());
+    dbRefAccessionIdsString.add(sourceDBRef.getAccessionId().toLowerCase(Locale.ROOT));
 
     curDBRefAccessionIdsString = dbRefAccessionIdsString;
     curSourceDBRef = sourceDBRef.getAccessionId();
@@ -891,14 +893,14 @@ public class SiftsClient implements SiftsClientI
   {
     boolean isStrictMatch = true;
     return isStrictMatch ? curSourceDBRef.equalsIgnoreCase(accession)
-            : curDBRefAccessionIdsString.contains(accession.toLowerCase());
+            : curDBRefAccessionIdsString.contains(accession.toLowerCase(Locale.ROOT));
   }
 
   private boolean isFoundInSiftsEntry(String accessionId)
   {
     Set<String> siftsDBRefs = getAllMappingAccession();
     return accessionId != null
-            && siftsDBRefs.contains(accessionId.toLowerCase());
+            && siftsDBRefs.contains(accessionId.toLowerCase(Locale.ROOT));
   }
 
   /**
index cb90984..e52eefb 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -20,43 +20,43 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for anonymous complex type.
+ * &lt;p&gt;Java class for anonymous complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType>
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="alcodon" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="pos1" type="{http://www.w3.org/2001/XMLSchema}integer" />
- *                 &lt;attribute name="pos2" type="{http://www.w3.org/2001/XMLSchema}integer" />
- *                 &lt;attribute name="pos3" type="{http://www.w3.org/2001/XMLSchema}integer" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *         &lt;element name="alcodMap" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;sequence>
- *                   &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping"/>
- *                 &lt;/sequence>
- *                 &lt;attribute name="dnasq" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="alcodon" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="pos1" type="{http://www.w3.org/2001/XMLSchema}integer" /&amp;gt;
+ *                 &amp;lt;attribute name="pos2" type="{http://www.w3.org/2001/XMLSchema}integer" /&amp;gt;
+ *                 &amp;lt;attribute name="pos3" type="{http://www.w3.org/2001/XMLSchema}integer" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *         &amp;lt;element name="alcodMap" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;sequence&amp;gt;
+ *                   &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping"/&amp;gt;
+ *                 &amp;lt;/sequence&amp;gt;
+ *                 &amp;lt;attribute name="dnasq" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -74,20 +74,20 @@ public class AlcodonFrame {
     /**
      * Gets the value of the alcodon property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 alcodon property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the alcodon property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getAlcodon().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link AlcodonFrame.Alcodon }
      * 
@@ -103,20 +103,20 @@ public class AlcodonFrame {
     /**
      * Gets the value of the alcodMap property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 alcodMap property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the alcodMap property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getAlcodMap().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link AlcodonFrame.AlcodMap }
      * 
@@ -131,22 +131,22 @@ public class AlcodonFrame {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="dnasq" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="dnasq" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -220,21 +220,21 @@ public class AlcodonFrame {
      *                                                                 Element may have either all pos1,2,3 attributes specified, or none at all (indicating a gapped column with no translated peptide).
      *                                                         
      * 
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="pos1" type="{http://www.w3.org/2001/XMLSchema}integer" />
-     *       &lt;attribute name="pos2" type="{http://www.w3.org/2001/XMLSchema}integer" />
-     *       &lt;attribute name="pos3" type="{http://www.w3.org/2001/XMLSchema}integer" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="pos1" type="{http://www.w3.org/2001/XMLSchema}integer" /&amp;gt;
+     *       &amp;lt;attribute name="pos2" type="{http://www.w3.org/2001/XMLSchema}integer" /&amp;gt;
+     *       &amp;lt;attribute name="pos3" type="{http://www.w3.org/2001/XMLSchema}integer" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index 35f78f3..6c1573f 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -19,61 +19,61 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for anonymous complex type.
+ * &lt;p&gt;Java class for anonymous complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType>
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}annotationElement" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="label" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         &lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="thresholdLine" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="label" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                 &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *         &lt;element name="property" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *       &lt;attribute name="graph" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="graphType" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="groupRef" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="graphColour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="graphGroup" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="graphHeight" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="scoreOnly" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *       &lt;attribute name="score" type="{http://www.w3.org/2001/XMLSchema}double" />
- *       &lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="centreColLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="scaleColLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="showAllColLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="autoCalculated" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *       &lt;attribute name="belowAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *       &lt;attribute name="calcId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}annotationElement" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="label" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *         &amp;lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="thresholdLine" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="label" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                 &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *         &amp;lt;element name="property" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="graph" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *       &amp;lt;attribute name="graphType" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="groupRef" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="graphColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="graphGroup" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="graphHeight" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="scoreOnly" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *       &amp;lt;attribute name="score" type="{http://www.w3.org/2001/XMLSchema}double" /&amp;gt;
+ *       &amp;lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *       &amp;lt;attribute name="centreColLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *       &amp;lt;attribute name="scaleColLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *       &amp;lt;attribute name="showAllColLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *       &amp;lt;attribute name="autoCalculated" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *       &amp;lt;attribute name="belowAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *       &amp;lt;attribute name="calcId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -132,20 +132,20 @@ public class Annotation {
     /**
      * Gets the value of the annotationElement property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 annotationElement property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the annotationElement property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getAnnotationElement().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link AnnotationElement }
      * 
@@ -233,20 +233,20 @@ public class Annotation {
     /**
      * Gets the value of the property property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 property property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the property property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getProperty().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Annotation.Property }
      * 
@@ -673,20 +673,20 @@ public class Annotation {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -751,21 +751,21 @@ public class Annotation {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="label" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="label" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *       &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index 6f5ef65..1b31b22 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -15,26 +15,26 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for AnnotationColourScheme complex type.
+ * &lt;p&gt;Java class for AnnotationColourScheme complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="AnnotationColourScheme">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;attribute name="aboveThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="annotation" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="minColour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="maxColour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="colourScheme" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
- *       &lt;attribute name="perSequence" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="predefinedColours" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="AnnotationColourScheme"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;attribute name="aboveThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="annotation" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="minColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="maxColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="colourScheme" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *       &amp;lt;attribute name="perSequence" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *       &amp;lt;attribute name="predefinedColours" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
index 6780323..d141272 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -16,32 +16,32 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for anonymous complex type.
+ * &lt;p&gt;Java class for anonymous complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType>
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="displayCharacter" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="secondaryStructure" minOccurs="0">
- *           &lt;simpleType>
- *             &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *               &lt;length value="1"/>
- *             &lt;/restriction>
- *           &lt;/simpleType>
- *         &lt;/element>
- *         &lt;element name="value" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="position" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="displayCharacter" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="secondaryStructure" minOccurs="0"&amp;gt;
+ *           &amp;lt;simpleType&amp;gt;
+ *             &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}string"&amp;gt;
+ *               &amp;lt;length value="1"/&amp;gt;
+ *             &amp;lt;/restriction&amp;gt;
+ *           &amp;lt;/simpleType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *         &amp;lt;element name="value" type="{http://www.w3.org/2001/XMLSchema}float" minOccurs="0"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="position" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
index 5edb2e8..bff4959 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -18,25 +18,25 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for DoubleMatrix complex type.
+ * &lt;p&gt;Java class for DoubleMatrix complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="DoubleMatrix">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="row" type="{www.jalview.org}DoubleVector" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="D" type="{www.jalview.org}DoubleVector" minOccurs="0"/>
- *         &lt;element name="E" type="{www.jalview.org}DoubleVector" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="rows" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="columns" type="{http://www.w3.org/2001/XMLSchema}int" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="DoubleMatrix"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="row" type="{www.jalview.org}DoubleVector" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="D" type="{www.jalview.org}DoubleVector" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="E" type="{www.jalview.org}DoubleVector" minOccurs="0"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="rows" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="columns" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -61,20 +61,20 @@ public class DoubleMatrix {
     /**
      * Gets the value of the row property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 row property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the row property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getRow().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link DoubleVector }
      * 
index 68ebf9b..a255c74 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -17,21 +17,21 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for DoubleVector complex type.
+ * &lt;p&gt;Java class for DoubleVector complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="DoubleVector">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="v" type="{http://www.w3.org/2001/XMLSchema}double" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="DoubleVector"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="v" type="{http://www.w3.org/2001/XMLSchema}double" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -47,20 +47,20 @@ public class DoubleVector {
     /**
      * Gets the value of the v property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 v property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the v property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getV().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Double }
      * 
index 39fc0c3..73468c9 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -17,38 +17,38 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for feature complex type.
+ * &lt;p&gt;Java class for feature complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="feature">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="otherData" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="key" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="key2" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *       &lt;attribute name="begin" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="status" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="featureGroup" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="score" type="{http://www.w3.org/2001/XMLSchema}float" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="feature"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="otherData" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="key" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="key2" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="begin" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *       &amp;lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="status" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="featureGroup" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="score" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -77,20 +77,20 @@ public class Feature {
     /**
      * Gets the value of the otherData property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 otherData property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the otherData property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getOtherData().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Feature.OtherData }
      * 
@@ -257,21 +257,21 @@ public class Feature {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="key" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="key2" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="key" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="key2" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index c92f72c..dee9bc1 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -18,24 +18,24 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for FeatureMatcher complex type.
+ * &lt;p&gt;Java class for FeatureMatcher complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="FeatureMatcher">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
- *         &lt;element name="condition" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         &lt;element name="value" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *       &lt;/sequence>
- *       &lt;attribute name="by" type="{www.jalview.org/colours}FilterBy" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="FeatureMatcher"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="condition" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *         &amp;lt;element name="value" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="by" type="{www.jalview.org/colours}FilterBy" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -59,20 +59,20 @@ public class FeatureMatcher {
     /**
      * Gets the value of the attributeName property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the attributeName property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getAttributeName().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link String }
      * 
index 0c21215..4c0848f 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -20,33 +20,33 @@ import javax.xml.bind.annotation.XmlType;
 /**
  * A feature match condition, which may be simple or compound
  * 
- * <p>Java class for FeatureMatcherSet complex type.
+ * &lt;p&gt;Java class for FeatureMatcherSet complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="FeatureMatcherSet">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;choice>
- *         &lt;element name="matchCondition" type="{www.jalview.org/colours}FeatureMatcher"/>
- *         &lt;element name="compoundMatcher">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;sequence>
- *                   &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" maxOccurs="2" minOccurs="2"/>
- *                 &lt;/sequence>
- *                 &lt;attribute name="and" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/choice>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="FeatureMatcherSet"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;choice&amp;gt;
+ *         &amp;lt;element name="matchCondition" type="{www.jalview.org/colours}FeatureMatcher"/&amp;gt;
+ *         &amp;lt;element name="compoundMatcher"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;sequence&amp;gt;
+ *                   &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" maxOccurs="2" minOccurs="2"/&amp;gt;
+ *                 &amp;lt;/sequence&amp;gt;
+ *                 &amp;lt;attribute name="and" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/choice&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -112,22 +112,22 @@ public class FeatureMatcherSet {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" maxOccurs="2" minOccurs="2"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="and" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" maxOccurs="2" minOccurs="2"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="and" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -145,20 +145,20 @@ public class FeatureMatcherSet {
         /**
          * Gets the value of the matcherSet property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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 matcherSet property.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the matcherSet property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getMatcherSet().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link FeatureMatcherSet }
          * 
index 36b454f..bbb84a4 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -14,19 +14,18 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for FilterBy.
+ * &lt;p&gt;Java class for FilterBy.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * <p>
- * <pre>
- * &lt;simpleType name="FilterBy">
- *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *     &lt;enumeration value="byLabel"/>
- *     &lt;enumeration value="byScore"/>
- *     &lt;enumeration value="byAttribute"/>
- *   &lt;/restriction>
- * &lt;/simpleType>
- * </pre>
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
+ * &lt;pre&gt;
+ * &amp;lt;simpleType name="FilterBy"&amp;gt;
+ *   &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}string"&amp;gt;
+ *     &amp;lt;enumeration value="byLabel"/&amp;gt;
+ *     &amp;lt;enumeration value="byScore"/&amp;gt;
+ *     &amp;lt;enumeration value="byAttribute"/&amp;gt;
+ *   &amp;lt;/restriction&amp;gt;
+ * &amp;lt;/simpleType&amp;gt;
+ * &lt;/pre&gt;
  * 
  */
 @XmlType(name = "FilterBy", namespace = "www.jalview.org/colours")
index 0ea2491..90819d7 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -24,341 +24,341 @@ import javax.xml.datatype.XMLGregorianCalendar;
 
 
 /**
- * <p>Java class for JalviewModel complex type.
+ * &lt;p&gt;Java class for JalviewModel complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="JalviewModel">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="creationDate" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
- *         &lt;element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         &lt;element name="vamsasModel" type="{www.vamsas.ac.uk/jalview/version2}VAMSAS"/>
- *         &lt;sequence>
- *           &lt;element name="JSeq" maxOccurs="unbounded" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence>
- *                     &lt;element name="features" type="{www.jalview.org}feature" maxOccurs="unbounded" minOccurs="0"/>
- *                     &lt;element name="pdbids" maxOccurs="unbounded" minOccurs="0">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;extension base="{www.jalview.org}pdbentry">
- *                             &lt;sequence>
- *                               &lt;element name="structureState" maxOccurs="unbounded" minOccurs="0">
- *                                 &lt;complexType>
- *                                   &lt;simpleContent>
- *                                     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
- *                                       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
- *                                       &lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                                       &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                                       &lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                                       &lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                                       &lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                                       &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                                     &lt;/extension>
- *                                   &lt;/simpleContent>
- *                                 &lt;/complexType>
- *                               &lt;/element>
- *                             &lt;/sequence>
- *                           &lt;/extension>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="hiddenSequences" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
- *                     &lt;element name="rnaViewer" maxOccurs="unbounded" minOccurs="0">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;sequence>
- *                               &lt;element name="secondaryStructure" maxOccurs="unbounded">
- *                                 &lt;complexType>
- *                                   &lt;complexContent>
- *                                     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                                       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                                       &lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                                       &lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                                       &lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                                     &lt;/restriction>
- *                                   &lt;/complexContent>
- *                                 &lt;/complexType>
- *                               &lt;/element>
- *                             &lt;/sequence>
- *                             &lt;attGroup ref="{www.jalview.org}swingwindow"/>
- *                             &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                             &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                             &lt;attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                             &lt;attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                   &lt;/sequence>
- *                   &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="hidden" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="viewreference" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *           &lt;element name="JGroup" maxOccurs="unbounded" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence>
- *                     &lt;element name="seq" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/>
- *                     &lt;element name="annotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
- *                   &lt;/sequence>
- *                   &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="outlineColour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="displayBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="displayText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="colourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *           &lt;element name="Viewport" maxOccurs="unbounded" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence>
- *                     &lt;element name="AnnotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
- *                     &lt;element name="hiddenColumns" maxOccurs="unbounded" minOccurs="0">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                             &lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="calcIdParam" maxOccurs="unbounded" minOccurs="0">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet">
- *                             &lt;attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                             &lt;attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                             &lt;attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                           &lt;/extension>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                   &lt;/sequence>
- *                   &lt;attGroup ref="{www.jalview.org}swingwindow"/>
- *                   &lt;attribute name="conservationSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="pidSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="showFullId" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="rightAlignIds" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showColourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="showBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="wrapAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="renderGaps" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showSequenceFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showNPfeatureTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showDbRefTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="followHighlight" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="followSelection" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="showAnnotation" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="centreColumnLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="showGroupConservation" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="showGroupConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="startRes" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="startSeq" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="scaleProteinAsCdna" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
- *                   &lt;attribute name="viewName" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="sequenceSetId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="gatheredViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
- *                   &lt;attribute name="complementId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="showComplementFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                   &lt;attribute name="showComplementFeaturesOnTop" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *           &lt;element name="UserColours" maxOccurs="unbounded" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence>
- *                     &lt;element name="UserColourScheme" type="{www.jalview.org/colours}JalviewUserColours"/>
- *                   &lt;/sequence>
- *                   &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *           &lt;element name="tree" maxOccurs="unbounded" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence minOccurs="0">
- *                     &lt;element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *                     &lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *                   &lt;/sequence>
- *                   &lt;attGroup ref="{www.jalview.org}swingwindow"/>
- *                   &lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                   &lt;attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
- *                   &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *           &lt;element name="PcaViewer" maxOccurs="unbounded" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence>
- *                     &lt;element name="sequencePoint" maxOccurs="unbounded">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;attGroup ref="{www.jalview.org}position"/>
- *                             &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="axis" maxOccurs="3" minOccurs="3">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;attGroup ref="{www.jalview.org}position"/>
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="seqPointMin">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;attGroup ref="{www.jalview.org}position"/>
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="seqPointMax">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;attGroup ref="{www.jalview.org}position"/>
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/>
- *                   &lt;/sequence>
- *                   &lt;attGroup ref="{www.jalview.org}swingwindow"/>
- *                   &lt;attGroup ref="{www.jalview.org}SimilarityParams"/>
- *                   &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                   &lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="yDim" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="zDim" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                   &lt;attribute name="scaleFactor" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                   &lt;attribute name="showLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                   &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *           &lt;element name="FeatureSettings" minOccurs="0">
- *             &lt;complexType>
- *               &lt;complexContent>
- *                 &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                   &lt;sequence>
- *                     &lt;element name="setting" maxOccurs="unbounded" minOccurs="0">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;sequence>
- *                               &lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
- *                               &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/>
- *                             &lt;/sequence>
- *                             &lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                             &lt;attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                             &lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                             &lt;attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                             &lt;attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                             &lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
- *                             &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                             &lt;attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                             &lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                             &lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                             &lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                             &lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                     &lt;element name="group" maxOccurs="unbounded" minOccurs="0">
- *                       &lt;complexType>
- *                         &lt;complexContent>
- *                           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                             &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                             &lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                           &lt;/restriction>
- *                         &lt;/complexContent>
- *                       &lt;/complexType>
- *                     &lt;/element>
- *                   &lt;/sequence>
- *                 &lt;/restriction>
- *               &lt;/complexContent>
- *             &lt;/complexType>
- *           &lt;/element>
- *         &lt;/sequence>
- *       &lt;/sequence>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="JalviewModel"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="creationDate" type="{http://www.w3.org/2001/XMLSchema}dateTime"/&amp;gt;
+ *         &amp;lt;element name="version" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *         &amp;lt;element name="vamsasModel" type="{www.vamsas.ac.uk/jalview/version2}VAMSAS"/&amp;gt;
+ *         &amp;lt;sequence&amp;gt;
+ *           &amp;lt;element name="JSeq" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence&amp;gt;
+ *                     &amp;lt;element name="features" type="{www.jalview.org}feature" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *                     &amp;lt;element name="pdbids" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;extension base="{www.jalview.org}pdbentry"&amp;gt;
+ *                             &amp;lt;sequence&amp;gt;
+ *                               &amp;lt;element name="structureState" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                                 &amp;lt;complexType&amp;gt;
+ *                                   &amp;lt;simpleContent&amp;gt;
+ *                                     &amp;lt;extension base="&amp;lt;http://www.w3.org/2001/XMLSchema&amp;gt;string"&amp;gt;
+ *                                       &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+ *                                       &amp;lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                                       &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                                       &amp;lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                                       &amp;lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                                       &amp;lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                                       &amp;lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                                     &amp;lt;/extension&amp;gt;
+ *                                   &amp;lt;/simpleContent&amp;gt;
+ *                                 &amp;lt;/complexType&amp;gt;
+ *                               &amp;lt;/element&amp;gt;
+ *                             &amp;lt;/sequence&amp;gt;
+ *                           &amp;lt;/extension&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="hiddenSequences" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *                     &amp;lt;element name="rnaViewer" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;sequence&amp;gt;
+ *                               &amp;lt;element name="secondaryStructure" maxOccurs="unbounded"&amp;gt;
+ *                                 &amp;lt;complexType&amp;gt;
+ *                                   &amp;lt;complexContent&amp;gt;
+ *                                     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                                       &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                                       &amp;lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                                       &amp;lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                                       &amp;lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                                     &amp;lt;/restriction&amp;gt;
+ *                                   &amp;lt;/complexContent&amp;gt;
+ *                                 &amp;lt;/complexType&amp;gt;
+ *                               &amp;lt;/element&amp;gt;
+ *                             &amp;lt;/sequence&amp;gt;
+ *                             &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+ *                             &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                             &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                             &amp;lt;attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                             &amp;lt;attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                   &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="hidden" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="viewreference" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *           &amp;lt;element name="JGroup" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence&amp;gt;
+ *                     &amp;lt;element name="seq" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/&amp;gt;
+ *                     &amp;lt;element name="annotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                   &amp;lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="outlineColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="displayBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="displayText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="colourText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *           &amp;lt;element name="Viewport" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence&amp;gt;
+ *                     &amp;lt;element name="AnnotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/&amp;gt;
+ *                     &amp;lt;element name="hiddenColumns" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                             &amp;lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="calcIdParam" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet"&amp;gt;
+ *                             &amp;lt;attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                             &amp;lt;attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                             &amp;lt;attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                           &amp;lt;/extension&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                   &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+ *                   &amp;lt;attribute name="conservationSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="pidSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="showFullId" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="rightAlignIds" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showColourText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="showBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="wrapAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="renderGaps" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showSequenceFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showNPfeatureTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showDbRefTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="followHighlight" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="followSelection" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="showAnnotation" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="centreColumnLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="showGroupConservation" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="showGroupConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="startRes" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="startSeq" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="scaleProteinAsCdna" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+ *                   &amp;lt;attribute name="viewName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="sequenceSetId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="gatheredViews" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" /&amp;gt;
+ *                   &amp;lt;attribute name="complementId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="showComplementFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                   &amp;lt;attribute name="showComplementFeaturesOnTop" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *           &amp;lt;element name="UserColours" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence&amp;gt;
+ *                     &amp;lt;element name="UserColourScheme" type="{www.jalview.org/colours}JalviewUserColours"/&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                   &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *           &amp;lt;element name="tree" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence minOccurs="0"&amp;gt;
+ *                     &amp;lt;element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *                     &amp;lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                   &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+ *                   &amp;lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                   &amp;lt;attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" /&amp;gt;
+ *                   &amp;lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *           &amp;lt;element name="PcaViewer" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence&amp;gt;
+ *                     &amp;lt;element name="sequencePoint" maxOccurs="unbounded"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+ *                             &amp;lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="axis" maxOccurs="3" minOccurs="3"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="seqPointMin"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="seqPointMax"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                   &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+ *                   &amp;lt;attGroup ref="{www.jalview.org}SimilarityParams"/&amp;gt;
+ *                   &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                   &amp;lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="yDim" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="zDim" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                   &amp;lt;attribute name="scaleFactor" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                   &amp;lt;attribute name="showLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                   &amp;lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *           &amp;lt;element name="FeatureSettings" minOccurs="0"&amp;gt;
+ *             &amp;lt;complexType&amp;gt;
+ *               &amp;lt;complexContent&amp;gt;
+ *                 &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                   &amp;lt;sequence&amp;gt;
+ *                     &amp;lt;element name="setting" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;sequence&amp;gt;
+ *                               &amp;lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/&amp;gt;
+ *                               &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/&amp;gt;
+ *                             &amp;lt;/sequence&amp;gt;
+ *                             &amp;lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                             &amp;lt;attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                             &amp;lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                             &amp;lt;attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                             &amp;lt;attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                             &amp;lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" /&amp;gt;
+ *                             &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                             &amp;lt;attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                             &amp;lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                             &amp;lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                             &amp;lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                             &amp;lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                     &amp;lt;element name="group" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *                       &amp;lt;complexType&amp;gt;
+ *                         &amp;lt;complexContent&amp;gt;
+ *                           &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                             &amp;lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                             &amp;lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                           &amp;lt;/restriction&amp;gt;
+ *                         &amp;lt;/complexContent&amp;gt;
+ *                       &amp;lt;/complexType&amp;gt;
+ *                     &amp;lt;/element&amp;gt;
+ *                   &amp;lt;/sequence&amp;gt;
+ *                 &amp;lt;/restriction&amp;gt;
+ *               &amp;lt;/complexContent&amp;gt;
+ *             &amp;lt;/complexType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *         &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -473,20 +473,20 @@ public class JalviewModel {
     /**
      * Gets the value of the jSeq property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the jSeq property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getJSeq().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewModel.JSeq }
      * 
@@ -502,20 +502,20 @@ public class JalviewModel {
     /**
      * Gets the value of the jGroup property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the jGroup property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getJGroup().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewModel.JGroup }
      * 
@@ -531,20 +531,20 @@ public class JalviewModel {
     /**
      * Gets the value of the viewport property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the viewport property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getViewport().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewModel.Viewport }
      * 
@@ -560,20 +560,20 @@ public class JalviewModel {
     /**
      * Gets the value of the userColours property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the userColours property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getUserColours().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewModel.UserColours }
      * 
@@ -589,20 +589,20 @@ public class JalviewModel {
     /**
      * Gets the value of the tree property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the tree property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getTree().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewModel.Tree }
      * 
@@ -618,20 +618,20 @@ public class JalviewModel {
     /**
      * Gets the value of the pcaViewer property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 pcaViewer property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the pcaViewer property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getPcaViewer().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewModel.PcaViewer }
      * 
@@ -670,54 +670,54 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="setting" maxOccurs="unbounded" minOccurs="0">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;sequence>
-     *                   &lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
-     *                   &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/>
-     *                 &lt;/sequence>
-     *                 &lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                 &lt;attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *                 &lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *                 &lt;attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *                 &lt;attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *                 &lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
-     *                 &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *                 &lt;attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *                 &lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *                 &lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *                 &lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *                 &lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="group" maxOccurs="unbounded" minOccurs="0">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                 &lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *       &lt;/sequence>
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="setting" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;sequence&amp;gt;
+     *                   &amp;lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/&amp;gt;
+     *                   &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/&amp;gt;
+     *                 &amp;lt;/sequence&amp;gt;
+     *                 &amp;lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                 &amp;lt;attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *                 &amp;lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *                 &amp;lt;attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *                 &amp;lt;attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *                 &amp;lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" /&amp;gt;
+     *                 &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *                 &amp;lt;attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *                 &amp;lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *                 &amp;lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *                 &amp;lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *                 &amp;lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="group" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                 &amp;lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -736,20 +736,20 @@ public class JalviewModel {
         /**
          * Gets the value of the setting property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the setting property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getSetting().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.FeatureSettings.Setting }
          * 
@@ -765,20 +765,20 @@ public class JalviewModel {
         /**
          * Gets the value of the group property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the group property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getGroup().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.FeatureSettings.Group }
          * 
@@ -793,20 +793,20 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *       &lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *       &amp;lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -863,34 +863,34 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;sequence>
-         *         &lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
-         *         &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/>
-         *       &lt;/sequence>
-         *       &lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *       &lt;attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *       &lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *       &lt;attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" />
-         *       &lt;attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *       &lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
-         *       &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
-         *       &lt;attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *       &lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
-         *       &lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
-         *       &lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *       &lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;sequence&amp;gt;
+         *         &amp;lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/&amp;gt;
+         *         &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet" minOccurs="0"/&amp;gt;
+         *       &amp;lt;/sequence&amp;gt;
+         *       &amp;lt;attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *       &amp;lt;attribute name="colour" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *       &amp;lt;attribute name="display" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *       &amp;lt;attribute name="order" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+         *       &amp;lt;attribute name="mincolour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *       &amp;lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" /&amp;gt;
+         *       &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+         *       &amp;lt;attribute name="threshstate" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *       &amp;lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+         *       &amp;lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+         *       &amp;lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *       &amp;lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -933,20 +933,20 @@ public class JalviewModel {
             /**
              * Gets the value of the attributeName property.
              * 
-             * <p>
+             * &lt;p&gt;
              * 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.
+             * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the attributeName property.
              * 
-             * <p>
+             * &lt;p&gt;
              * For example, to add a new item, do as follows:
-             * <pre>
+             * &lt;pre&gt;
              *    getAttributeName().add(newItem);
-             * </pre>
+             * &lt;/pre&gt;
              * 
              * 
-             * <p>
+             * &lt;p&gt;
              * Objects of the following type(s) are allowed in the list
              * {@link String }
              * 
@@ -1265,41 +1265,41 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="seq" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/>
-     *         &lt;element name="annotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="outlineColour" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="displayBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="displayText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="colourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="seq" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded"/&amp;gt;
+     *         &amp;lt;element name="annotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="outlineColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="displayBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="displayText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="colourText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -1356,20 +1356,20 @@ public class JalviewModel {
         /**
          * Gets the value of the seq property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the seq property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getSeq().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link String }
          * 
@@ -1882,80 +1882,80 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="features" type="{www.jalview.org}feature" maxOccurs="unbounded" minOccurs="0"/>
-     *         &lt;element name="pdbids" maxOccurs="unbounded" minOccurs="0">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;extension base="{www.jalview.org}pdbentry">
-     *                 &lt;sequence>
-     *                   &lt;element name="structureState" maxOccurs="unbounded" minOccurs="0">
-     *                     &lt;complexType>
-     *                       &lt;simpleContent>
-     *                         &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
-     *                           &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-     *                           &lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *                           &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                           &lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *                           &lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *                           &lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *                           &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                         &lt;/extension>
-     *                       &lt;/simpleContent>
-     *                     &lt;/complexType>
-     *                   &lt;/element>
-     *                 &lt;/sequence>
-     *               &lt;/extension>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="hiddenSequences" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
-     *         &lt;element name="rnaViewer" maxOccurs="unbounded" minOccurs="0">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;sequence>
-     *                   &lt;element name="secondaryStructure" maxOccurs="unbounded">
-     *                     &lt;complexType>
-     *                       &lt;complexContent>
-     *                         &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                           &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                           &lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                           &lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *                           &lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                         &lt;/restriction>
-     *                       &lt;/complexContent>
-     *                     &lt;/complexType>
-     *                   &lt;/element>
-     *                 &lt;/sequence>
-     *                 &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-     *                 &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                 &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                 &lt;attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *                 &lt;attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *       &lt;/sequence>
-     *       &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="hidden" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="viewreference" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="features" type="{www.jalview.org}feature" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+     *         &amp;lt;element name="pdbids" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;extension base="{www.jalview.org}pdbentry"&amp;gt;
+     *                 &amp;lt;sequence&amp;gt;
+     *                   &amp;lt;element name="structureState" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *                     &amp;lt;complexType&amp;gt;
+     *                       &amp;lt;simpleContent&amp;gt;
+     *                         &amp;lt;extension base="&amp;lt;http://www.w3.org/2001/XMLSchema&amp;gt;string"&amp;gt;
+     *                           &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+     *                           &amp;lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *                           &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                           &amp;lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *                           &amp;lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *                           &amp;lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *                           &amp;lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                         &amp;lt;/extension&amp;gt;
+     *                       &amp;lt;/simpleContent&amp;gt;
+     *                     &amp;lt;/complexType&amp;gt;
+     *                   &amp;lt;/element&amp;gt;
+     *                 &amp;lt;/sequence&amp;gt;
+     *               &amp;lt;/extension&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="hiddenSequences" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+     *         &amp;lt;element name="rnaViewer" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;sequence&amp;gt;
+     *                   &amp;lt;element name="secondaryStructure" maxOccurs="unbounded"&amp;gt;
+     *                     &amp;lt;complexType&amp;gt;
+     *                       &amp;lt;complexContent&amp;gt;
+     *                         &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                           &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                           &amp;lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                           &amp;lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *                           &amp;lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                         &amp;lt;/restriction&amp;gt;
+     *                       &amp;lt;/complexContent&amp;gt;
+     *                     &amp;lt;/complexType&amp;gt;
+     *                   &amp;lt;/element&amp;gt;
+     *                 &amp;lt;/sequence&amp;gt;
+     *                 &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+     *                 &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                 &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                 &amp;lt;attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *                 &amp;lt;attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="hidden" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="viewreference" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -1992,20 +1992,20 @@ public class JalviewModel {
         /**
          * Gets the value of the features property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the features property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getFeatures().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link Feature }
          * 
@@ -2021,20 +2021,20 @@ public class JalviewModel {
         /**
          * Gets the value of the pdbids property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the pdbids property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getPdbids().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.JSeq.Pdbids }
          * 
@@ -2050,20 +2050,20 @@ public class JalviewModel {
         /**
          * Gets the value of the hiddenSequences property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the hiddenSequences property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getHiddenSequences().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link Integer }
          * 
@@ -2079,20 +2079,20 @@ public class JalviewModel {
         /**
          * Gets the value of the rnaViewer property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the rnaViewer property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getRnaViewer().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.JSeq.RnaViewer }
          * 
@@ -2235,35 +2235,35 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;extension base="{www.jalview.org}pdbentry">
-         *       &lt;sequence>
-         *         &lt;element name="structureState" maxOccurs="unbounded" minOccurs="0">
-         *           &lt;complexType>
-         *             &lt;simpleContent>
-         *               &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
-         *                 &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-         *                 &lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *                 &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *                 &lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-         *                 &lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-         *                 &lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-         *                 &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *               &lt;/extension>
-         *             &lt;/simpleContent>
-         *           &lt;/complexType>
-         *         &lt;/element>
-         *       &lt;/sequence>
-         *     &lt;/extension>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;extension base="{www.jalview.org}pdbentry"&amp;gt;
+         *       &amp;lt;sequence&amp;gt;
+         *         &amp;lt;element name="structureState" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+         *           &amp;lt;complexType&amp;gt;
+         *             &amp;lt;simpleContent&amp;gt;
+         *               &amp;lt;extension base="&amp;lt;http://www.w3.org/2001/XMLSchema&amp;gt;string"&amp;gt;
+         *                 &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+         *                 &amp;lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *                 &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *                 &amp;lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+         *                 &amp;lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+         *                 &amp;lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+         *                 &amp;lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *               &amp;lt;/extension&amp;gt;
+         *             &amp;lt;/simpleContent&amp;gt;
+         *           &amp;lt;/complexType&amp;gt;
+         *         &amp;lt;/element&amp;gt;
+         *       &amp;lt;/sequence&amp;gt;
+         *     &amp;lt;/extension&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -2281,20 +2281,20 @@ public class JalviewModel {
             /**
              * Gets the value of the structureState property.
              * 
-             * <p>
+             * &lt;p&gt;
              * 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.
+             * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the structureState property.
              * 
-             * <p>
+             * &lt;p&gt;
              * For example, to add a new item, do as follows:
-             * <pre>
+             * &lt;pre&gt;
              *    getStructureState().add(newItem);
-             * </pre>
+             * &lt;/pre&gt;
              * 
              * 
-             * <p>
+             * &lt;p&gt;
              * Objects of the following type(s) are allowed in the list
              * {@link JalviewModel.JSeq.Pdbids.StructureState }
              * 
@@ -2309,25 +2309,25 @@ public class JalviewModel {
 
 
             /**
-             * <p>Java class for anonymous complex type.
+             * &lt;p&gt;Java class for anonymous complex type.
              * 
-             * <p>The following schema fragment specifies the expected content contained within this class.
+             * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
              * 
-             * <pre>
-             * &lt;complexType>
-             *   &lt;simpleContent>
-             *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
-             *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-             *       &lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-             *       &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
-             *       &lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-             *       &lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-             *       &lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-             *       &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
-             *     &lt;/extension>
-             *   &lt;/simpleContent>
-             * &lt;/complexType>
-             * </pre>
+             * &lt;pre&gt;
+             * &amp;lt;complexType&amp;gt;
+             *   &amp;lt;simpleContent&amp;gt;
+             *     &amp;lt;extension base="&amp;lt;http://www.w3.org/2001/XMLSchema&amp;gt;string"&amp;gt;
+             *       &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+             *       &amp;lt;attribute name="visible" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+             *       &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+             *       &amp;lt;attribute name="alignwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+             *       &amp;lt;attribute name="colourwithAlignPanel" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+             *       &amp;lt;attribute name="colourByJmol" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+             *       &amp;lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+             *     &amp;lt;/extension&amp;gt;
+             *   &amp;lt;/simpleContent&amp;gt;
+             * &amp;lt;/complexType&amp;gt;
+             * &lt;/pre&gt;
              * 
              * 
              */
@@ -2642,37 +2642,37 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;sequence>
-         *         &lt;element name="secondaryStructure" maxOccurs="unbounded">
-         *           &lt;complexType>
-         *             &lt;complexContent>
-         *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *                 &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *                 &lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *                 &lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *                 &lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *               &lt;/restriction>
-         *             &lt;/complexContent>
-         *           &lt;/complexType>
-         *         &lt;/element>
-         *       &lt;/sequence>
-         *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-         *       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *       &lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *       &lt;attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *       &lt;attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;sequence&amp;gt;
+         *         &amp;lt;element name="secondaryStructure" maxOccurs="unbounded"&amp;gt;
+         *           &amp;lt;complexType&amp;gt;
+         *             &amp;lt;complexContent&amp;gt;
+         *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *                 &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *                 &amp;lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *                 &amp;lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *                 &amp;lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *               &amp;lt;/restriction&amp;gt;
+         *             &amp;lt;/complexContent&amp;gt;
+         *           &amp;lt;/complexType&amp;gt;
+         *         &amp;lt;/element&amp;gt;
+         *       &amp;lt;/sequence&amp;gt;
+         *       &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+         *       &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *       &amp;lt;attribute name="viewId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *       &amp;lt;attribute name="dividerLocation" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *       &amp;lt;attribute name="selectedRna" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -2704,20 +2704,20 @@ public class JalviewModel {
             /**
              * Gets the value of the secondaryStructure property.
              * 
-             * <p>
+             * &lt;p&gt;
              * 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.
+             * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the secondaryStructure property.
              * 
-             * <p>
+             * &lt;p&gt;
              * For example, to add a new item, do as follows:
-             * <pre>
+             * &lt;pre&gt;
              *    getSecondaryStructure().add(newItem);
-             * </pre>
+             * &lt;/pre&gt;
              * 
              * 
-             * <p>
+             * &lt;p&gt;
              * Objects of the following type(s) are allowed in the list
              * {@link JalviewModel.JSeq.RnaViewer.SecondaryStructure }
              * 
@@ -2924,22 +2924,22 @@ public class JalviewModel {
 
 
             /**
-             * <p>Java class for anonymous complex type.
+             * &lt;p&gt;Java class for anonymous complex type.
              * 
-             * <p>The following schema fragment specifies the expected content contained within this class.
+             * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
              * 
-             * <pre>
-             * &lt;complexType>
-             *   &lt;complexContent>
-             *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-             *       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-             *       &lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-             *       &lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-             *       &lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" />
-             *     &lt;/restriction>
-             *   &lt;/complexContent>
-             * &lt;/complexType>
-             * </pre>
+             * &lt;pre&gt;
+             * &amp;lt;complexType&amp;gt;
+             *   &amp;lt;complexContent&amp;gt;
+             *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+             *       &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+             *       &amp;lt;attribute name="annotationId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+             *       &amp;lt;attribute name="gapped" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+             *       &amp;lt;attribute name="viewerState" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+             *     &amp;lt;/restriction&amp;gt;
+             *   &amp;lt;/complexContent&amp;gt;
+             * &amp;lt;/complexType&amp;gt;
+             * &lt;/pre&gt;
              * 
              * 
              */
@@ -3060,69 +3060,69 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="sequencePoint" maxOccurs="unbounded">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;attGroup ref="{www.jalview.org}position"/>
-     *                 &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="axis" maxOccurs="3" minOccurs="3">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;attGroup ref="{www.jalview.org}position"/>
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="seqPointMin">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;attGroup ref="{www.jalview.org}position"/>
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="seqPointMax">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;attGroup ref="{www.jalview.org}position"/>
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/>
-     *       &lt;/sequence>
-     *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-     *       &lt;attGroup ref="{www.jalview.org}SimilarityParams"/>
-     *       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="yDim" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="zDim" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="scaleFactor" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="showLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="sequencePoint" maxOccurs="unbounded"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+     *                 &amp;lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="axis" maxOccurs="3" minOccurs="3"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="seqPointMin"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="seqPointMax"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="pcaData" type="{www.jalview.org}PcaDataType"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+     *       &amp;lt;attGroup ref="{www.jalview.org}SimilarityParams"/&amp;gt;
+     *       &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="scoreModelName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="xDim" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="yDim" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="zDim" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="scaleFactor" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *       &amp;lt;attribute name="showLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -3184,20 +3184,20 @@ public class JalviewModel {
         /**
          * Gets the value of the sequencePoint property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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 sequencePoint property.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the sequencePoint property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getSequencePoint().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.PcaViewer.SequencePoint }
          * 
@@ -3213,20 +3213,20 @@ public class JalviewModel {
         /**
          * Gets the value of the axis property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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 axis property.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the axis property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getAxis().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.PcaViewer.Axis }
          * 
@@ -3721,19 +3721,19 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;attGroup ref="{www.jalview.org}position"/>
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -3824,19 +3824,19 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;attGroup ref="{www.jalview.org}position"/>
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -3927,19 +3927,19 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;attGroup ref="{www.jalview.org}position"/>
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -4030,20 +4030,20 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;attGroup ref="{www.jalview.org}position"/>
-         *       &lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;attGroup ref="{www.jalview.org}position"/&amp;gt;
+         *       &amp;lt;attribute name="sequenceRef" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -4162,34 +4162,34 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence minOccurs="0">
-     *         &lt;element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
-     *         &lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/>
-     *       &lt;/sequence>
-     *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-     *       &lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
-     *       &lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence minOccurs="0"&amp;gt;
+     *         &amp;lt;element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+     *         &amp;lt;element name="newick" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+     *       &amp;lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *       &amp;lt;attribute name="showBootstrap" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showDistances" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="markUnlinked" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="fitToWindow" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="currentTree" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" /&amp;gt;
+     *       &amp;lt;attribute name="linkToAllViews" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -4654,22 +4654,22 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="UserColourScheme" type="{www.jalview.org/colours}JalviewUserColours"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="UserColourScheme" type="{www.jalview.org/colours}JalviewUserColours"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -4736,86 +4736,86 @@ public class JalviewModel {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="AnnotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/>
-     *         &lt;element name="hiddenColumns" maxOccurs="unbounded" minOccurs="0">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *                 &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *                 &lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *               &lt;/restriction>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *         &lt;element name="calcIdParam" maxOccurs="unbounded" minOccurs="0">
-     *           &lt;complexType>
-     *             &lt;complexContent>
-     *               &lt;extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet">
-     *                 &lt;attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *                 &lt;attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *                 &lt;attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *               &lt;/extension>
-     *             &lt;/complexContent>
-     *           &lt;/complexType>
-     *         &lt;/element>
-     *       &lt;/sequence>
-     *       &lt;attGroup ref="{www.jalview.org}swingwindow"/>
-     *       &lt;attribute name="conservationSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="pidSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="showFullId" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="rightAlignIds" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showColourText" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="showBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="wrapAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="renderGaps" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showSequenceFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showNPfeatureTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="showDbRefTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="followHighlight" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="followSelection" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="showAnnotation" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="centreColumnLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="showGroupConservation" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="showGroupConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="startRes" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="startSeq" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="scaleProteinAsCdna" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
-     *       &lt;attribute name="viewName" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="sequenceSetId" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="gatheredViews" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" />
-     *       &lt;attribute name="complementId" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="showComplementFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *       &lt;attribute name="showComplementFeaturesOnTop" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="AnnotationColours" type="{www.jalview.org}AnnotationColourScheme" minOccurs="0"/&amp;gt;
+     *         &amp;lt;element name="hiddenColumns" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *                 &amp;lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *                 &amp;lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *               &amp;lt;/restriction&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *         &amp;lt;element name="calcIdParam" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+     *           &amp;lt;complexType&amp;gt;
+     *             &amp;lt;complexContent&amp;gt;
+     *               &amp;lt;extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet"&amp;gt;
+     *                 &amp;lt;attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *                 &amp;lt;attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *                 &amp;lt;attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *               &amp;lt;/extension&amp;gt;
+     *             &amp;lt;/complexContent&amp;gt;
+     *           &amp;lt;/complexType&amp;gt;
+     *         &amp;lt;/element&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attGroup ref="{www.jalview.org}swingwindow"/&amp;gt;
+     *       &amp;lt;attribute name="conservationSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="pidSelected" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="bgColour" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="consThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="pidThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="showFullId" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="rightAlignIds" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showColourText" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showUnconserved" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="showBoxes" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="wrapAlignment" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="renderGaps" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showSequenceFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showNPfeatureTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="showDbRefTooltip" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="followHighlight" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="followSelection" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="showAnnotation" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="centreColumnLabels" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="showGroupConservation" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="showGroupConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="showConsensusHistogram" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="showSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="normaliseSequenceLogo" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="ignoreGapsinConsensus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="startRes" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="startSeq" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="fontName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="fontSize" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="fontStyle" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="scaleProteinAsCdna" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" /&amp;gt;
+     *       &amp;lt;attribute name="viewName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="sequenceSetId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="gatheredViews" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="textCol1" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="textCol2" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="textColThreshold" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}ID" /&amp;gt;
+     *       &amp;lt;attribute name="complementId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="showComplementFeatures" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="showComplementFeaturesOnTop" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -4958,20 +4958,20 @@ public class JalviewModel {
         /**
          * Gets the value of the hiddenColumns property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the hiddenColumns property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getHiddenColumns().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.Viewport.HiddenColumns }
          * 
@@ -4987,20 +4987,20 @@ public class JalviewModel {
         /**
          * Gets the value of the calcIdParam property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the calcIdParam property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getCalcIdParam().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link JalviewModel.Viewport.CalcIdParam }
          * 
@@ -6195,21 +6195,21 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet">
-         *       &lt;attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-         *       &lt;attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-         *       &lt;attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-         *     &lt;/extension>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;extension base="{www.jalview.org/xml/wsparamset}WebServiceParameterSet"&amp;gt;
+         *       &amp;lt;attribute name="calcId" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+         *       &amp;lt;attribute name="needsUpdate" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+         *       &amp;lt;attribute name="autoUpdate" use="required" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+         *     &amp;lt;/extension&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
@@ -6298,20 +6298,20 @@ public class JalviewModel {
 
 
         /**
-         * <p>Java class for anonymous complex type.
+         * &lt;p&gt;Java class for anonymous complex type.
          * 
-         * <p>The following schema fragment specifies the expected content contained within this class.
+         * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
          * 
-         * <pre>
-         * &lt;complexType>
-         *   &lt;complexContent>
-         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-         *       &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *       &lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" />
-         *     &lt;/restriction>
-         *   &lt;/complexContent>
-         * &lt;/complexType>
-         * </pre>
+         * &lt;pre&gt;
+         * &amp;lt;complexType&amp;gt;
+         *   &amp;lt;complexContent&amp;gt;
+         *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+         *       &amp;lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *       &amp;lt;attribute name="end" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+         *     &amp;lt;/restriction&amp;gt;
+         *   &amp;lt;/complexContent&amp;gt;
+         * &amp;lt;/complexType&amp;gt;
+         * &lt;/pre&gt;
          * 
          * 
          */
index c43e04c..e1ee27e 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -18,55 +18,55 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for JalviewUserColours complex type.
+ * &lt;p&gt;Java class for JalviewUserColours complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="JalviewUserColours">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="Version" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="colour" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;sequence>
- *                   &lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
- *                 &lt;/sequence>
- *                 &lt;attribute name="Name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="RGB" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="minRGB" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
- *                 &lt;attribute name="threshType" type="{www.jalview.org/colours}ThresholdType" />
- *                 &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                 &lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                 &lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
- *                 &lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *                 &lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *         &lt;element name="filter" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;sequence>
- *                   &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet"/>
- *                 &lt;/sequence>
- *                 &lt;attribute name="featureType" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *       &lt;attribute name="schemeName" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="JalviewUserColours"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="Version" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="colour" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;sequence&amp;gt;
+ *                   &amp;lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/&amp;gt;
+ *                 &amp;lt;/sequence&amp;gt;
+ *                 &amp;lt;attribute name="Name" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="RGB" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="minRGB" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" /&amp;gt;
+ *                 &amp;lt;attribute name="threshType" type="{www.jalview.org/colours}ThresholdType" /&amp;gt;
+ *                 &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                 &amp;lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                 &amp;lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+ *                 &amp;lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *                 &amp;lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *         &amp;lt;element name="filter" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;sequence&amp;gt;
+ *                   &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet"/&amp;gt;
+ *                 &amp;lt;/sequence&amp;gt;
+ *                 &amp;lt;attribute name="featureType" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="schemeName" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -114,20 +114,20 @@ public class JalviewUserColours {
     /**
      * Gets the value of the colour property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 colour property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the colour property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getColour().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewUserColours.Colour }
      * 
@@ -143,20 +143,20 @@ public class JalviewUserColours {
     /**
      * Gets the value of the filter property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 filter property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the filter property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getFilter().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link JalviewUserColours.Filter }
      * 
@@ -195,31 +195,31 @@ public class JalviewUserColours {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="Name" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="RGB" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="minRGB" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" />
-     *       &lt;attribute name="threshType" type="{www.jalview.org/colours}ThresholdType" />
-     *       &lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" />
-     *       &lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *       &lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="attributeName" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="2" minOccurs="0"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="Name" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="RGB" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="minRGB" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="noValueColour" type="{www.jalview.org/colours}NoValueColour" default="Min" /&amp;gt;
+     *       &amp;lt;attribute name="threshType" type="{www.jalview.org/colours}ThresholdType" /&amp;gt;
+     *       &amp;lt;attribute name="threshold" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *       &amp;lt;attribute name="max" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *       &amp;lt;attribute name="min" type="{http://www.w3.org/2001/XMLSchema}float" /&amp;gt;
+     *       &amp;lt;attribute name="colourByLabel" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *       &amp;lt;attribute name="autoScale" type="{http://www.w3.org/2001/XMLSchema}boolean" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -255,20 +255,20 @@ public class JalviewUserColours {
         /**
          * Gets the value of the attributeName property.
          * 
-         * <p>
+         * &lt;p&gt;
          * 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.
+         * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the attributeName property.
          * 
-         * <p>
+         * &lt;p&gt;
          * For example, to add a new item, do as follows:
-         * <pre>
+         * &lt;pre&gt;
          *    getAttributeName().add(newItem);
-         * </pre>
+         * &lt;/pre&gt;
          * 
          * 
-         * <p>
+         * &lt;p&gt;
          * Objects of the following type(s) are allowed in the list
          * {@link String }
          * 
@@ -529,22 +529,22 @@ public class JalviewUserColours {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="featureType" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element name="matcherSet" type="{www.jalview.org/colours}FeatureMatcherSet"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="featureType" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index 1a31d82..c93112c 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -24,42 +24,42 @@ import javax.xml.bind.annotation.XmlType;
  *                             This effectively represents a java.util.MapList object
  *                     
  * 
- * <p>Java class for mapListType complex type.
+ * &lt;p&gt;Java class for mapListType complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="mapListType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="mapListFrom" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                 &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *         &lt;element name="mapListTo" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *                 &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *       &lt;attribute name="mapFromUnit" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
- *       &lt;attribute name="mapToUnit" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="mapListType"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="mapListFrom" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                 &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *         &amp;lt;element name="mapListTo" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *                 &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="mapFromUnit" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" /&amp;gt;
+ *       &amp;lt;attribute name="mapToUnit" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -85,20 +85,20 @@ public class MapListType {
     /**
      * Gets the value of the mapListFrom property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 mapListFrom property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the mapListFrom property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getMapListFrom().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link MapListType.MapListFrom }
      * 
@@ -114,20 +114,20 @@ public class MapListType {
     /**
      * Gets the value of the mapListTo property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 mapListTo property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the mapListTo property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getMapListTo().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link MapListType.MapListTo }
      * 
@@ -190,20 +190,20 @@ public class MapListType {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -252,20 +252,20 @@ public class MapListType {
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *       &lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *       &amp;lt;attribute name="end" use="required" type="{http://www.w3.org/2001/XMLSchema}int" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index 5ebeb7e..24f5b01 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -23,30 +23,30 @@ import javax.xml.bind.annotation.XmlType;
  *                                     to the sequence set (which will mean they are then added to the alignment too).
  *                             
  * 
- * <p>Java class for anonymous complex type.
+ * &lt;p&gt;Java class for anonymous complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType>
- *   &lt;complexContent>
- *     &lt;extension base="{www.vamsas.ac.uk/jalview/version2}mapListType">
- *       &lt;sequence>
- *         &lt;choice minOccurs="0">
- *           &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Sequence"/>
- *           &lt;element name="dseqFor">
- *             &lt;simpleType>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *               &lt;/restriction>
- *             &lt;/simpleType>
- *           &lt;/element>
- *         &lt;/choice>
- *       &lt;/sequence>
- *       &lt;attribute name="mappingType" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/extension>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;extension base="{www.vamsas.ac.uk/jalview/version2}mapListType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;choice minOccurs="0"&amp;gt;
+ *           &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Sequence"/&amp;gt;
+ *           &amp;lt;element name="dseqFor"&amp;gt;
+ *             &amp;lt;simpleType&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}string"&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/simpleType&amp;gt;
+ *           &amp;lt;/element&amp;gt;
+ *         &amp;lt;/choice&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="mappingType" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/extension&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
index 9db4ea3..7e42db8 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -14,19 +14,18 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for NoValueColour.
+ * &lt;p&gt;Java class for NoValueColour.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * <p>
- * <pre>
- * &lt;simpleType name="NoValueColour">
- *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *     &lt;enumeration value="None"/>
- *     &lt;enumeration value="Min"/>
- *     &lt;enumeration value="Max"/>
- *   &lt;/restriction>
- * &lt;/simpleType>
- * </pre>
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
+ * &lt;pre&gt;
+ * &amp;lt;simpleType name="NoValueColour"&amp;gt;
+ *   &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}string"&amp;gt;
+ *     &amp;lt;enumeration value="None"/&amp;gt;
+ *     &amp;lt;enumeration value="Min"/&amp;gt;
+ *     &amp;lt;enumeration value="Max"/&amp;gt;
+ *   &amp;lt;/restriction&amp;gt;
+ * &amp;lt;/simpleType&amp;gt;
+ * &lt;/pre&gt;
  * 
  */
 @XmlType(name = "NoValueColour", namespace = "www.jalview.org/colours")
index e0b2127..b6ea489 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -18,7 +18,7 @@ import javax.xml.namespace.QName;
  * This object contains factory methods for each 
  * Java content interface and Java element interface 
  * generated in the jalview.xml.binding.jalview package. 
- * <p>An ObjectFactory allows you to programatically 
+ * &lt;p&gt;An ObjectFactory allows you to programatically 
  * construct new instances of the Java representation 
  * for XML content. The Java representation of XML 
  * content can consist of schema derived interfaces 
@@ -31,9 +31,9 @@ import javax.xml.namespace.QName;
 @XmlRegistry
 public class ObjectFactory {
 
-    private final static QName _WebServiceParameterSet_QNAME = new QName("www.jalview.org/xml/wsparamset", "WebServiceParameterSet");
     private final static QName _JalviewModel_QNAME = new QName("www.jalview.org", "JalviewModel");
     private final static QName _JalviewUserColours_QNAME = new QName("www.jalview.org/colours", "JalviewUserColours");
+    private final static QName _WebServiceParameterSet_QNAME = new QName("www.jalview.org/xml/wsparamset", "WebServiceParameterSet");
 
     /**
      * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: jalview.xml.binding.jalview
@@ -43,14 +43,6 @@ public class ObjectFactory {
     }
 
     /**
-     * Create an instance of {@link AlcodonFrame }
-     * 
-     */
-    public AlcodonFrame createAlcodonFrame() {
-        return new AlcodonFrame();
-    }
-
-    /**
      * Create an instance of {@link MapListType }
      * 
      */
@@ -67,6 +59,14 @@ public class ObjectFactory {
     }
 
     /**
+     * Create an instance of {@link AlcodonFrame }
+     * 
+     */
+    public AlcodonFrame createAlcodonFrame() {
+        return new AlcodonFrame();
+    }
+
+    /**
      * Create an instance of {@link Annotation }
      * 
      */
@@ -171,14 +171,6 @@ public class ObjectFactory {
     }
 
     /**
-     * Create an instance of {@link DoubleMatrix }
-     * 
-     */
-    public DoubleMatrix createDoubleMatrix() {
-        return new DoubleMatrix();
-    }
-
-    /**
      * Create an instance of {@link AnnotationColourScheme }
      * 
      */
@@ -203,27 +195,11 @@ public class ObjectFactory {
     }
 
     /**
-     * Create an instance of {@link AlcodonFrame.Alcodon }
-     * 
-     */
-    public AlcodonFrame.Alcodon createAlcodonFrameAlcodon() {
-        return new AlcodonFrame.Alcodon();
-    }
-
-    /**
-     * Create an instance of {@link AlcodonFrame.AlcodMap }
-     * 
-     */
-    public AlcodonFrame.AlcodMap createAlcodonFrameAlcodMap() {
-        return new AlcodonFrame.AlcodMap();
-    }
-
-    /**
-     * Create an instance of {@link AnnotationElement }
+     * Create an instance of {@link DoubleMatrix }
      * 
      */
-    public AnnotationElement createAnnotationElement() {
-        return new AnnotationElement();
+    public DoubleMatrix createDoubleMatrix() {
+        return new DoubleMatrix();
     }
 
     /**
@@ -267,6 +243,30 @@ public class ObjectFactory {
     }
 
     /**
+     * Create an instance of {@link AlcodonFrame.Alcodon }
+     * 
+     */
+    public AlcodonFrame.Alcodon createAlcodonFrameAlcodon() {
+        return new AlcodonFrame.Alcodon();
+    }
+
+    /**
+     * Create an instance of {@link AlcodonFrame.AlcodMap }
+     * 
+     */
+    public AlcodonFrame.AlcodMap createAlcodonFrameAlcodMap() {
+        return new AlcodonFrame.AlcodMap();
+    }
+
+    /**
+     * Create an instance of {@link AnnotationElement }
+     * 
+     */
+    public AnnotationElement createAnnotationElement() {
+        return new AnnotationElement();
+    }
+
+    /**
      * Create an instance of {@link Annotation.ThresholdLine }
      * 
      */
@@ -459,17 +459,12 @@ public class ObjectFactory {
     }
 
     /**
-     * Create an instance of {@link JAXBElement }{@code <}{@link WebServiceParameterSet }{@code >}}
-     * 
-     */
-    @XmlElementDecl(namespace = "www.jalview.org/xml/wsparamset", name = "WebServiceParameterSet")
-    public JAXBElement<WebServiceParameterSet> createWebServiceParameterSet(WebServiceParameterSet value) {
-        return new JAXBElement<WebServiceParameterSet>(_WebServiceParameterSet_QNAME, WebServiceParameterSet.class, null, value);
-    }
-
-    /**
-     * Create an instance of {@link JAXBElement }{@code <}{@link JalviewModel }{@code >}}
+     * Create an instance of {@link JAXBElement }{@code <}{@link JalviewModel }{@code >}
      * 
+     * @param value
+     *     Java instance representing xml element's value.
+     * @return
+     *     the new instance of {@link JAXBElement }{@code <}{@link JalviewModel }{@code >}
      */
     @XmlElementDecl(namespace = "www.jalview.org", name = "JalviewModel")
     public JAXBElement<JalviewModel> createJalviewModel(JalviewModel value) {
@@ -477,12 +472,29 @@ public class ObjectFactory {
     }
 
     /**
-     * Create an instance of {@link JAXBElement }{@code <}{@link JalviewUserColours }{@code >}}
+     * Create an instance of {@link JAXBElement }{@code <}{@link JalviewUserColours }{@code >}
      * 
+     * @param value
+     *     Java instance representing xml element's value.
+     * @return
+     *     the new instance of {@link JAXBElement }{@code <}{@link JalviewUserColours }{@code >}
      */
     @XmlElementDecl(namespace = "www.jalview.org/colours", name = "JalviewUserColours")
     public JAXBElement<JalviewUserColours> createJalviewUserColours(JalviewUserColours value) {
         return new JAXBElement<JalviewUserColours>(_JalviewUserColours_QNAME, JalviewUserColours.class, null, value);
     }
 
+    /**
+     * Create an instance of {@link JAXBElement }{@code <}{@link WebServiceParameterSet }{@code >}
+     * 
+     * @param value
+     *     Java instance representing xml element's value.
+     * @return
+     *     the new instance of {@link JAXBElement }{@code <}{@link WebServiceParameterSet }{@code >}
+     */
+    @XmlElementDecl(namespace = "www.jalview.org/xml/wsparamset", name = "WebServiceParameterSet")
+    public JAXBElement<WebServiceParameterSet> createWebServiceParameterSet(WebServiceParameterSet value) {
+        return new JAXBElement<WebServiceParameterSet>(_WebServiceParameterSet_QNAME, WebServiceParameterSet.class, null, value);
+    }
+
 }
index 6234f32..717ce89 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -19,23 +19,23 @@ import javax.xml.bind.annotation.XmlType;
  *                             The results of a PCA calculation
  *                     
  * 
- * <p>Java class for PcaDataType complex type.
+ * &lt;p&gt;Java class for PcaDataType complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="PcaDataType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="pairwiseMatrix" type="{www.jalview.org}DoubleMatrix"/>
- *         &lt;element name="tridiagonalMatrix" type="{www.jalview.org}DoubleMatrix"/>
- *         &lt;element name="eigenMatrix" type="{www.jalview.org}DoubleMatrix"/>
- *       &lt;/sequence>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="PcaDataType"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="pairwiseMatrix" type="{www.jalview.org}DoubleMatrix"/&amp;gt;
+ *         &amp;lt;element name="tridiagonalMatrix" type="{www.jalview.org}DoubleMatrix"/&amp;gt;
+ *         &amp;lt;element name="eigenMatrix" type="{www.jalview.org}DoubleMatrix"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
index d5132ab..6983c04 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -18,33 +18,33 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for pdbentry complex type.
+ * &lt;p&gt;Java class for pdbentry complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="pdbentry">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence maxOccurs="unbounded" minOccurs="0">
- *         &lt;element name="property" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *       &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="file" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="pdbentry"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *         &amp;lt;element name="property" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="file" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -68,20 +68,20 @@ public class Pdbentry {
     /**
      * Gets the value of the property property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 property property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the property property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getProperty().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Pdbentry.Property }
      * 
@@ -168,20 +168,20 @@ public class Pdbentry {
 
 
     /**
-     * <p>Java class for anonymous complex type.
-     * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
-     * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;p&gt;Java class for anonymous complex type.
+     * 
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
+     * 
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index b842947..5381c32 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -19,37 +19,38 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for anonymous complex type.
+ * &lt;p&gt;Java class for anonymous complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType>
- *   &lt;complexContent>
- *     &lt;extension base="{www.vamsas.ac.uk/jalview/version2}SequenceType">
- *       &lt;sequence>
- *         &lt;element name="DBRef" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;sequence>
- *                   &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping" minOccurs="0"/>
- *                 &lt;/sequence>
- *                 &lt;attribute name="source" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="accessionId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="locus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *       &lt;/sequence>
- *       &lt;attribute name="dsseqid" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="biotype" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/extension>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;extension base="{www.vamsas.ac.uk/jalview/version2}SequenceType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="DBRef" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;sequence&amp;gt;
+ *                   &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping" minOccurs="0"/&amp;gt;
+ *                 &amp;lt;/sequence&amp;gt;
+ *                 &amp;lt;attribute name="source" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="accessionId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="locus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *                 &amp;lt;attribute name="canonical" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="dsseqid" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="biotype" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/extension&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -72,20 +73,20 @@ public class Sequence
     /**
      * Gets the value of the dbRef property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 dbRef property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the dbRef property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getDBRef().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Sequence.DBRef }
      * 
@@ -148,25 +149,26 @@ public class Sequence
 
 
     /**
-     * <p>Java class for anonymous complex type.
+     * &lt;p&gt;Java class for anonymous complex type.
      * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
      * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;sequence>
-     *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping" minOccurs="0"/>
-     *       &lt;/sequence>
-     *       &lt;attribute name="source" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="accessionId" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="locus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;sequence&amp;gt;
+     *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Mapping" minOccurs="0"/&amp;gt;
+     *       &amp;lt;/sequence&amp;gt;
+     *       &amp;lt;attribute name="source" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="accessionId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="locus" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *       &amp;lt;attribute name="canonical" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
@@ -186,6 +188,8 @@ public class Sequence
         protected String accessionId;
         @XmlAttribute(name = "locus")
         protected Boolean locus;
+        @XmlAttribute(name = "canonical")
+        protected Boolean canonical;
 
         /**
          * Gets the value of the mapping property.
@@ -311,6 +315,34 @@ public class Sequence
             this.locus = value;
         }
 
+        /**
+         * Gets the value of the canonical property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link Boolean }
+         *     
+         */
+        public boolean isCanonical() {
+            if (canonical == null) {
+                return false;
+            } else {
+                return canonical;
+            }
+        }
+
+        /**
+         * Sets the value of the canonical property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link Boolean }
+         *     
+         */
+        public void setCanonical(Boolean value) {
+            this.canonical = value;
+        }
+
     }
 
 }
index 6aee6ac..c69334e 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -19,35 +19,35 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for anonymous complex type.
+ * &lt;p&gt;Java class for anonymous complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType>
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Sequence" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}Annotation" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="sequenceSetProperties" maxOccurs="unbounded" minOccurs="0">
- *           &lt;complexType>
- *             &lt;complexContent>
- *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *                 &lt;attribute name="key" type="{http://www.w3.org/2001/XMLSchema}string" />
- *                 &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
- *               &lt;/restriction>
- *             &lt;/complexContent>
- *           &lt;/complexType>
- *         &lt;/element>
- *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}AlcodonFrame" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="gapChar" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="datasetId" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Sequence" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}Annotation" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="sequenceSetProperties" maxOccurs="unbounded" minOccurs="0"&amp;gt;
+ *           &amp;lt;complexType&amp;gt;
+ *             &amp;lt;complexContent&amp;gt;
+ *               &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *                 &amp;lt;attribute name="key" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *                 &amp;lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *               &amp;lt;/restriction&amp;gt;
+ *             &amp;lt;/complexContent&amp;gt;
+ *           &amp;lt;/complexType&amp;gt;
+ *         &amp;lt;/element&amp;gt;
+ *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}AlcodonFrame" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="gapChar" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="datasetId" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -76,20 +76,20 @@ public class SequenceSet {
     /**
      * Gets the value of the sequence property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 sequence property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the sequence property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getSequence().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Sequence }
      * 
@@ -105,20 +105,20 @@ public class SequenceSet {
     /**
      * Gets the value of the annotation property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 annotation property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the annotation property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getAnnotation().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link Annotation }
      * 
@@ -134,20 +134,20 @@ public class SequenceSet {
     /**
      * Gets the value of the sequenceSetProperties property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 sequenceSetProperties property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the sequenceSetProperties property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getSequenceSetProperties().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link SequenceSet.SequenceSetProperties }
      * 
@@ -163,20 +163,20 @@ public class SequenceSet {
     /**
      * Gets the value of the alcodonFrame property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 alcodonFrame property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the alcodonFrame property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getAlcodonFrame().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link AlcodonFrame }
      * 
@@ -239,20 +239,20 @@ public class SequenceSet {
 
 
     /**
-     * <p>Java class for anonymous complex type.
-     * 
-     * <p>The following schema fragment specifies the expected content contained within this class.
-     * 
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="key" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
+     * &lt;p&gt;Java class for anonymous complex type.
+     * 
+     * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
+     * 
+     * &lt;pre&gt;
+     * &amp;lt;complexType&amp;gt;
+     *   &amp;lt;complexContent&amp;gt;
+     *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+     *       &amp;lt;attribute name="key" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *       &amp;lt;attribute name="value" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+     *     &amp;lt;/restriction&amp;gt;
+     *   &amp;lt;/complexContent&amp;gt;
+     * &amp;lt;/complexType&amp;gt;
+     * &lt;/pre&gt;
      * 
      * 
      */
index aef7543..29982ae 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -16,24 +16,24 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for SequenceType complex type.
+ * &lt;p&gt;Java class for SequenceType complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="SequenceType">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="sequence" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="SequenceType"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="sequence" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *       &amp;lt;attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
index 1b3d6d4..edb9152 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -13,19 +13,18 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for ThresholdType.
+ * &lt;p&gt;Java class for ThresholdType.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * <p>
- * <pre>
- * &lt;simpleType name="ThresholdType">
- *   &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *     &lt;enumeration value="NONE"/>
- *     &lt;enumeration value="ABOVE"/>
- *     &lt;enumeration value="BELOW"/>
- *   &lt;/restriction>
- * &lt;/simpleType>
- * </pre>
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
+ * &lt;pre&gt;
+ * &amp;lt;simpleType name="ThresholdType"&amp;gt;
+ *   &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}string"&amp;gt;
+ *     &amp;lt;enumeration value="NONE"/&amp;gt;
+ *     &amp;lt;enumeration value="ABOVE"/&amp;gt;
+ *     &amp;lt;enumeration value="BELOW"/&amp;gt;
+ *   &amp;lt;/restriction&amp;gt;
+ * &amp;lt;/simpleType&amp;gt;
+ * &lt;/pre&gt;
  * 
  */
 @XmlType(name = "ThresholdType", namespace = "www.jalview.org/colours")
index 5d341c3..48b2012 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -17,22 +17,22 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for VAMSAS complex type.
+ * &lt;p&gt;Java class for VAMSAS complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="VAMSAS">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="Tree" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element ref="{www.vamsas.ac.uk/jalview/version2}SequenceSet" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="VAMSAS"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="Tree" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element ref="{www.vamsas.ac.uk/jalview/version2}SequenceSet" maxOccurs="unbounded" minOccurs="0"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -51,20 +51,20 @@ public class VAMSAS {
     /**
      * Gets the value of the tree property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the tree property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getTree().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link String }
      * 
@@ -80,20 +80,20 @@ public class VAMSAS {
     /**
      * Gets the value of the sequenceSet property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 sequenceSet property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the sequenceSet property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getSequenceSet().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link SequenceSet }
      * 
index 659eab9..87e275d 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 
@@ -20,25 +20,25 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * <p>Java class for WebServiceParameterSet complex type.
+ * &lt;p&gt;Java class for WebServiceParameterSet complex type.
  * 
- * <p>The following schema fragment specifies the expected content contained within this class.
+ * &lt;p&gt;The following schema fragment specifies the expected content contained within this class.
  * 
- * <pre>
- * &lt;complexType name="WebServiceParameterSet">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="Version" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="serviceURL" type="{http://www.w3.org/2001/XMLSchema}anyURI" maxOccurs="unbounded"/>
- *         &lt;element name="parameters" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *       &lt;/sequence>
- *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
+ * &lt;pre&gt;
+ * &amp;lt;complexType name="WebServiceParameterSet"&amp;gt;
+ *   &amp;lt;complexContent&amp;gt;
+ *     &amp;lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&amp;gt;
+ *       &amp;lt;sequence&amp;gt;
+ *         &amp;lt;element name="Version" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&amp;gt;
+ *         &amp;lt;element name="serviceURL" type="{http://www.w3.org/2001/XMLSchema}anyURI" maxOccurs="unbounded"/&amp;gt;
+ *         &amp;lt;element name="parameters" type="{http://www.w3.org/2001/XMLSchema}string"/&amp;gt;
+ *       &amp;lt;/sequence&amp;gt;
+ *       &amp;lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /&amp;gt;
+ *     &amp;lt;/restriction&amp;gt;
+ *   &amp;lt;/complexContent&amp;gt;
+ * &amp;lt;/complexType&amp;gt;
+ * &lt;/pre&gt;
  * 
  * 
  */
@@ -117,20 +117,20 @@ public class WebServiceParameterSet {
     /**
      * Gets the value of the serviceURL property.
      * 
-     * <p>
+     * &lt;p&gt;
      * 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 serviceURL property.
+     * This is why there is not a &lt;CODE&gt;set&lt;/CODE&gt; method for the serviceURL property.
      * 
-     * <p>
+     * &lt;p&gt;
      * For example, to add a new item, do as follows:
-     * <pre>
+     * &lt;pre&gt;
      *    getServiceURL().add(newItem);
-     * </pre>
+     * &lt;/pre&gt;
      * 
      * 
-     * <p>
+     * &lt;p&gt;
      * Objects of the following type(s) are allowed in the list
      * {@link String }
      * 
index 3ed532d..2700ffa 100644 (file)
@@ -1,8 +1,8 @@
 //
-// 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> 
+// This file was generated by the Eclipse Implementation of JAXB, v2.3.3 
+// See https://eclipse-ee4j.github.io/jaxb-ri 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2021.08.30 at 11:05:22 AM BST 
 //
 
 @javax.xml.bind.annotation.XmlSchema(namespace = "www.vamsas.ac.uk/jalview/version2", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
index a3c8bee..425bc18 100755 (executable)
@@ -78,10 +78,27 @@ public class PDBChain
 
   public String pdbid = "";
 
-  public PDBChain(String thePdbid, String theId)
+  String tfacName = "Temperature Factor";
+
+
+  public PDBChain(String thePdbid, String theId, String tempFactorColumnName)
   {
     this.pdbid = thePdbid == null ? thePdbid : thePdbid.toLowerCase();
     this.id = theId;
+    if (tempFactorColumnName!=null && tempFactorColumnName.length()>0)
+    {
+      tfacName = tempFactorColumnName;
+    }
+  }
+
+  /**
+   * import chain data assuming Temperature Factor is in the Temperature Factor column
+   * @param thePdbid
+   * @param theId
+   */
+  public PDBChain(String thePdbid, String theId)
+  {
+    this(thePdbid,theId, null);
   }
 
   /**
@@ -212,10 +229,16 @@ public class PDBChain
    * @param seq
    * @param status
    *          The Status of the transferred annotation
+   * 
+   * @param altPDBID the group id for the features on the destination sequence (e.g. the official accession ID)
    */
   public void transferRESNUMFeatures(SequenceI seq,
-          String status)
+          String status, String altPDBID)
   {
+    if (altPDBID==null)
+    {
+      altPDBID = pdbid;
+    }
     SequenceI sq = seq;
     while (sq != null && sq.getDatasetSequence() != null)
     {
@@ -248,7 +271,7 @@ public class PDBChain
         int newEnd = 1 + residues.elementAt(feature.getEnd() - offset).atoms
                 .elementAt(0).alignmentMapping;
         SequenceFeature tx = new SequenceFeature(feature, newBegin, newEnd,
-                feature.getFeatureGroup(), feature.getScore());
+                altPDBID, feature.getScore());
         tx.setStatus(status
                 + ((tx.getStatus() == null || tx.getStatus().length() == 0)
                         ? ""
@@ -490,15 +513,18 @@ public class PDBChain
         min = Math.min(min, annots[i].value);
         resAnnotation.setElementAt(null, i);
       }
-
       AlignmentAnnotation tfactorann = new AlignmentAnnotation(
-              "Temperature Factor", "Temperature Factor for " + pdbid + id,
+              tfacName, tfacName + " for " + pdbid + id,
               annots, min, max, AlignmentAnnotation.LINE_GRAPH);
+      
+      tfactorann.setCalcId(getClass().getName());
+
       tfactorann.setSequenceRef(sequence);
       sequence.addAlignmentAnnotation(tfactorann);
     }
   }
 
+
   /**
    * Colour start/end of bonds by charge
    * <ul>
@@ -615,8 +641,10 @@ public class PDBChain
 
         for (AlignmentAnnotation ana : shadow.getAnnotation())
         {
-          List<AlignmentAnnotation> transfer = sq
-                  .getAlignmentAnnotations(ana.getCalcId(), ana.label);
+          // match on calcId, label and description so annotations from
+          // different structures are preserved
+          List<AlignmentAnnotation> transfer = sq.getAlignmentAnnotations(
+                  ana.getCalcId(), ana.label, ana.description);
           if (transfer == null || transfer.size() == 0)
           {
             ana = new AlignmentAnnotation(ana);
@@ -636,8 +664,11 @@ public class PDBChain
         {
           for (AlignmentAnnotation ana : sequence.getAnnotation())
           {
+            // match on calcId, label and description so annotations from
+            // different structures are preserved
             List<AlignmentAnnotation> transfer = dsq
-                    .getAlignmentAnnotations(ana.getCalcId(), ana.label);
+                    .getAlignmentAnnotations(ana.getCalcId(), ana.label,
+                            ana.description);
             if (transfer == null || transfer.size() == 0)
             {
               ana = new AlignmentAnnotation(ana);
index 04eda42..0eb14cd 100755 (executable)
@@ -154,6 +154,7 @@ public class PDBfile extends StructureFile
             tmpchain.atoms.addElement(tmpatom);
           } else
           {
+            // PDBfile never handles alphafold models
             tmpchain = new PDBChain(getId(), tmpatom.chain);
             getChains().add(tmpchain);
             tmpchain.atoms.addElement(tmpatom);
index f12fcb1..f6fdabe 100644 (file)
Binary files a/swingjs/SwingJS-site.zip and b/swingjs/SwingJS-site.zip differ
index 60f5fcc..c9ec027 100644 (file)
@@ -1,10 +1,29 @@
-Notes
-=====
+java2script/SwingJS Notes
+=========================
+
+updated 12/31/2020 -- full support for 64-bit long
+updated 12/6/2020 -- note about restrictions on long, including BitSet and Scanner
+updated 3/21/2020 -- adds note about HashMap, Hashtable, and HashSet iterator ordering
+updated 3/20/2020 -- adds note about interning, new String("xxx"), and "xxx"
+updated 2/26/2020 -- adds Graphics.setClip issue
+updated 12/22/19 -- additional issues
+updated 11/03/19 -- adds information about File.exists() and points to src/javajs/async
+updated 10/26/19 -- adds information about File.createTempFile()
+updated 8/16/19 -- minor typos and added summary paragraph
+updated 7/19/19 -- clarification that AWT and Swing classes are supported directly
+updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long
+updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages
+updated 1/4/19 -- nio
+updated 9/15/18 -- adds integer 1/0 == Infinity
+updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk
+updated 6/5/17 -- reserved package name "window"
+updated 3/11/17 -- myClass.getField
+updated 3/7/17 -- overloading of JSplitPane.setDividerLocation
+updated 3/2/17 -- more indication of classes not implemented (KeyListener)
 
 ---IMPORTANT CHARACTER SET NOTE---
 
-It is critical that all development work in Java2Script 
-be done in UTF-8. This means:
+It is critical that all development work in Java2Script be done in UTF-8. This means:
 
 - making sure your Eclipse project is set up for UTF-8 (not the Eclipse default?)
 - making sure your server can serve up UTF-8 by default for any browser-loaded files
@@ -20,8 +39,6 @@ be done in UTF-8. This means:
 Note that the DOCTYPE tag is critical for some browsers to switch into HTML5 mode. (MSIE?)
 
 
-
-  
 In particular, the Mandarin character ç§˜ (mi; "secret") is used extensively throughout
 the SwingJS class files to distinguish j2s-specific fields and methods that must not 
 ever be shadowed or overridden by subclasses. For example, we see in java.lang.Thread.java:
@@ -31,24 +48,6 @@ ever be shadowed or overridden by subclasses. For example, we see in java.lang.T
 ----------------------------------
 
 
-updated 12/6/2020 -- note about restrictions on long, including BitSet and Scanner
-updated 3/21/2020 -- adds note about HashMap, Hashtable, and HashSet iterator ordering
-updated 3/20/2020 -- adds note about interning, new String("xxx"), and "xxx"
-updated 2/26/2020 -- adds Graphics.setClip issue
-updated 12/22/19 -- additional issues
-updated 11/03/19 -- adds information about File.exists() and points to src/javajs/async
-updated 10/26/19 -- adds information about File.createTempFile()
-updated 8/16/19 -- minor typos and added summary paragraph
-updated 7/19/19 -- clarification that AWT and Swing classes are supported directly
-updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long
-updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages
-updated 1/4/19 -- nio
-updated 9/15/18 -- adds integer 1/0 == Infinity
-updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk
-updated 6/5/17 -- reserved package name "window"
-updated 3/11/17 -- myClass.getField
-updated 3/7/17 -- overloading of JSplitPane.setDividerLocation
-updated 3/2/17 -- more indication of classes not implemented (KeyListener)
 
 =============================================================================
 SwingJS and OpenJDK 8+
@@ -73,11 +72,38 @@ that one can call in JavaScript
   
 and for all practical purposes it will appear that Java is running.
 
+The goal of java2script/SwingJS is NOT to reproduce Java byte code processing in a 
+browser. We leave that task and its own issues to others. Here, instead, we have a 
+working JavaScript version of the Java classes along with runtime assistance in the
+j2sClazz.js library. This design has several advantages:
+
+ 1) It leads to much smaller downloads, since the class loader can dynamically load
+    code at the class level. 
+    
+ 2) It allow the browser to use its own optimizations and features, not to ignore those. 
+    This leads to huge performance gains and in many cases much simpler coding.
+ 3) It allows for in-browser debugging and analysis. 
+ 4) It allows for code switching between Java and JavaScript. Working Java code 
+    can be annotated (@j2sNative, @j2sAlias, @j2sIgnore) in a fashion that 
+    allows the code to run slightly differently in a Java than a JavaScript environment.
+    For example:
+    
+       int delayMS = /** @j2sNative 10 ||*/2;
+    
+    will read "var delayMS = 10 || 2;"  (i.e. 10) in JavaScript but read by the Java
+    compiler as "int delayMS = 2". 
+    
+ 5) Just generally, it allows for a much more integrated environment. JavaScript on
+    the page can call into any SwingJS program, and, likewise, any SwingJS code can 
+    access anything on the page.    
+
 
 Method and Field Disambiguation
 -------------------------------
 
-SwingJS has no problem with the overloading of methods, for example:
+This is no problem. SwingJS has no problem with the overloading of methods, for example:
 
   public void print(int b);
   public void print(float b);
@@ -139,8 +165,9 @@ becomes:
 
   Clazz.newMeth(C$, 'c$$S', function (text) {...});
 
-Field disambiguation involves prepending. In Java, a class and its subclass 
-can both have the same field name, such as 
+Field disambiguation involves prepending. 
+
+In Java, a class and its subclass can both have the same field name, such as 
 
  boolean visible;
  
@@ -157,8 +184,6 @@ while in SwingJS we will see:
 
 since JavaScript does not have the "super" keyword.
 
-
-
 Parameterless methods such as toString() are appended with "$" to become toString$().
 The one exception to this rule is private methods, which are saved in (truly) private 
 array in the class (and are not accessible by reflection). Private parameterless 
@@ -167,9 +192,8 @@ methods retain their simple Java name, since they cannot conflict with field nam
 This renaming of methods has a few consequences, which are discussed more fully below.
 See particularly the section on "qualified field and method names", where it is described
 how you can use packages or classes or interfaces with ".api.js" in them to represent JavaScript
-objects for which all method names are to be left unqualified. Note that it is not 
-possible to cherry-pick methods to be unqualified; only full packages, classes or 
-interfaces can hold this status.
+objects for which all method names are to be left unqualified, and how individual methods
+can have more than one name using @j2sAlias. 
 
 The swingjs.api.js package in particular contains a number of useful interfaces that
 you can import into your project for JavaScript-specific capabilities.
@@ -195,8 +219,7 @@ performance at 1/6 - 1/3 the speed of Java. Achieving this performance may requi
 some refactoring of the Java to make it more efficient in both Java and JavaScript. 
 "for" loops need to be more carefully crafted; use of "new" and "instanceof" need to be
 minimized in critical areas. Note that method overloading -- that is, the same method name
-with different parameters, such as read(int) and read(byte) -- is no longer any problem. 
-  
+with different parameters, such as read(int) and read(byte) -- is no longer any problem.   
 
 Threads
 -------
@@ -209,6 +232,10 @@ they must allow full exit and re-entry of Thread.run(), not the typical while/sl
 
 The key is to create a state-based run() that can be exited and re-entered in JavaScript.
 
+The javajs.async package can be added to any Java program to provide Java+JavaScript asynchronous
+classes, including AsyncColorChooser, AsyncDialog, AsyncFileChooser, and AsyncSwingWorker. All
+of these classes work just as well in Java as in JavaScript. There is no need to run them 
+only when in JavaScript.
 
 Static fields
 -------------
@@ -284,7 +311,8 @@ Helper Packages -- swingjs/ and javajs/
 
 The SwingJS library is the swingjs/ package. There are interfaces that may be of assistance
 in swingjs/api, but other than that, it is not recommended that developers access classes in 
-this package. The "public" nature of their methods is really an internal necessity.
+this package. The "public" nature of their methods is really an internal necessity. Most access 
+to this package in working Java should be via the swingjs.api.JSUtilI interface.
 
 In addition to swingjs/, though, there are several useful classes in the javajs/ package
 that could be very useful. This package is a stand-alone package that can be 
@@ -324,26 +352,31 @@ has no access to these, of course, and they must all be replaced by JavaScript e
 Fortunately, they are not common, and those that are present in Java (for example, in calculating
 checksums in ZIP file creation) are at a low enough level that most developers do not utilize them
 or do not even have access to them. All native calls in Java classes have been replaced by 
-Java equivalents.
+Java or JavaScript equivalents.
 
 
 Swing GUI Peers and UIClasses
 -----------------------------
 
 One of the biggest adaptations introduced in SwingJS is in the area of the graphical 
-user interface. The issue here is complex but workable. In Java there are two background 
-concepts -- the Component "peer" (one per "heavy-weight" component, such as a Frame) and the 
-component "uiClass" (one per component, such as JButton or JTextField).
+user interface. Basically, what we have is a Java Swing "LookAndFeel" customized for HTML.
+
+The issue here is complex but workable. In Java there are two background concepts -- the 
+Component "peer" (one per "heavy-weight" component, such as a Frame) and the 
+component "uiClass" (one per component, such as BasicButtonUI or BasicTextFieldUI).
 
 Peers are native objects of the operating system. These are the virtual buttons and text areas
-that the user is interacting with at a very base level. Their events are being passed on to 
-Java or the browser by the operating system. UI classes provide a consistent "look and feel" 
-for these native objects, rendering them onto the native window canvas and handling all 
-user-generated events. They paint the borders, the backgrounds, the highlights, of every 
-control you see in Java. There is one-to-one correspondence of Swing classes and UI classes. 
-Setting the Look and Feel for a project amounts to selecting the directory from which to draw 
-these UI classes. The UI classes can be found in the javax.swing.plaf ("platform look and feel") 
-package.
+that the user is interacting with at a very base level. They are chunks of low-level code that
+paint the screen to give the illusion that you really are pressing a button or typing text 
+ot the screen. Their events are being passed on to Java or the browser by the operating system. 
+
+UI classes provide a consistent "look and feel" for these native objects, rendering them onto 
+the native window canvas and handling all user-generated events. They paint the borders, 
+the backgrounds, the highlights, of every control you see in Java. There is one-to-one 
+correspondence of Swing classes and UI classes. Setting the Look and Feel for a project amounts 
+to selecting the directory from which to draw these UI classes. Java's UI class interfaces can
+be found in the javax.swing.plaf ("platform look and feel") package. Individual look and feel
+implementations are found in sun.plaf.basic, sun.plaf.metal, and other such specialized packages.
 
 Early on in the development of SwingJS, we decided not to fully reproduce the painfully detailed 
 bit-by-bit painting of controls as is done in Java. Instead, we felt it was wiser to utilize the standard
@@ -378,10 +411,11 @@ alongside their Swing counterparts JButton and JList. Reading the code, it is cl
 design choice posed a huge headache for Swing class developers. 
 
 For SwingJS, we decided from the beginning NOT to allow this mixed-mode programming and 
-instead to require that all components be Swing components. 
-
-However, this is no longer an issue. All AWT components in SwingJS are now subclasses of 
-javax.swing.JComponent. So far, we have found no problem with this.
+instead to require that all components be Swing components. However, this is not really an
+issue. We have reconfigured the class relationships a bit. In SwingJS, all AWT components
+are now subclasses of javax.swing.JComponent. While this might seem error prone, so far we have 
+found no problem with this arrangement. It's a little surprising to me that the original developers
+of Swing did not think of this.
 
  
 The a2s Adapter Package
@@ -395,37 +429,23 @@ that we also wanted it to be possible to quickly adapt these applets to JavaScri
 The solution turned out to be simple: Write a package (a2s) that recreates the interface for 
 non-Swing components as subclasses of Swing components. Thus, a2s.Button subclasses javax.swing.JButton
 but also accepts all of the methods of java.awt.Button. This works amazingly well, with a few
-special adaptations to the core javax.swing to be "AWT-aware." All AWT components now subclass 
-a2s components, which in turn subclass JComponents. So no changes in code are necessary. We have
-successfully transpiled over 500 applets using this strategy. (Kind of surprising, actually, that
-the original Java developers did not see that option. But we have a hindsight advantage here.)
+special adaptations to the core javax.swing to be "AWT-aware." 
 
+Then, to tie it all togeter, all AWT components such as java.awt.Button now subclass their respective
+a2s components, which in turn subclass JComponents. So no changes in code are necessary. We have
+successfully transpiled over 500 applets using this strategy. 
 
 Working with Files
 ==================
 
 Simple String file names are not optimal for passing information about
-read files within SwingJS applications. 
+files read by SwingJS applications. That is because just peeking at a file 
+in SwingJS will load its entire byte[] data. 
  
-All work with files should either use Path or File objects exclusively. 
+Optimally, all work with files should either use Path or File objects exclusively. 
 These objects, after a file is read or checked for existence, will already 
-contain the file byte[] data. Doing something like this:
-
-File f = File("./test.dat");
-boolean isOK = f.exists();
-
-will load f with its byte[] data, if the file exists. 
-
-But if after that, we use:
-
-File f2 = new File(f.getAbsolutePath());
-
-f2 will not contain that data. Such copying should be done as:
-
-File f2 = new File(f);
-
-in which case, the byte[] data will be transferred.
-
+contain the file byte[] data. The string name can be used alone, since SwingJS will
+cache the files itself and not reload them -- just as the browser normally does.
 
 SwingJS uses the following criteria to determine if File.exists() returns true:
 
@@ -446,7 +466,13 @@ or
 
 Temporary files can be created in SwingJS. SwingJS will maintain a pseudo-filesystem for files 
 created with File.createTempFile(). This is useful in that closure of writing to a temporary file 
-does not generate a pseudo-download to the user's machine.
+does not generate a pseudo-download to the user's machine. Temporary files will be placed in the 
+"/TEMP/" directory, as seen from the running Java program. Any file written to this directory will
+simply be stored in memory; files written to any other directory, when closed, will appear to the 
+user as a download, often involving a "What do you want to do with this file" dialog. 
+
+
+See below for details relating to each of the subjects below:
 
 
 UNIMPLEMENTED CLASSES BY DESIGN
@@ -464,10 +490,9 @@ serialization
 TODO LIST FOR UNIMPLEMENTED CLASSES
 ===================================
 
-JEditorPane (minimal implementation) - DONE 12/2018; some issues still
-JSplitPane - DONE 8/2018
-JTabbedPane - DONE 10/2018
-JTree - done 12/2019
+none as of 2020.12.31. Source code for classes and methods missing
+from Java 8 or from Java 9+ can be inserted by any developer along 
+with their running code source, and they should run.  
 
 
 MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
@@ -481,12 +506,10 @@ MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS
 
 See below for a full discussion.
 
-Restrictions on long
-Restriction on BitSet and Scanner
+primitive type restrictions - int, long, and float
 HashMap, Hashtable, and HashSet iterator ordering
 interning, new String("xxx") vs "xxx"
 Names with "$" and "_"
-positive integers do not add to give negative numbers
 ArrayIndexOutOfBounds
 java.awt.Color
 native methods
@@ -499,7 +522,6 @@ myClass.getField not implemented
 "window" and other reserved JavaScript names
 reserved field and method names
 qualified field and method names
-missing Math methods
 Component.getGraphics(), Graphics.dispose()
 Graphics.setClip()
 
@@ -518,12 +540,10 @@ fonts
 threads
 modal dialogs
 image loading
-BigDecimal not fully implemented 
 no format internationalization
-no winding rules
+Graphics2D: missing winding rules
 text-related field implementation
 Formatter/Regex limitations
-integer 1/0 == Infinity
 
 ======================================================================== 
 
@@ -532,10 +552,6 @@ DISCUSS
 
 Table row/col sorter needs checking after removal of java.text.Collator references
 
-I had to move all of SunHints class to RenderingHints, or the 
-two classes could not be loaded. Shouldn't be a problem, I think. The sun classes are
-not accessible to developers in Java anyway, since they are generally package private.
-
 ========================================================================== 
 
 //////////////////////////////////////////////////////////////////////////////
@@ -589,58 +605,88 @@ changed to JSToolkit.isDispatchThread()
 MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
 =====================================================================
 
-restrictions on long
---------------------
+primitive restrictions - int, long, and float
+---------------------------------------------
 
-Java's 64-bit long type is not supported in JavaScript. There is no Int64Array in JavaScript,
-and 0x20000000000000 + 1 evaluates to 0x20000000000000, not 0x20000000000001. 
-(Likewise, -0x20000000000000 - 1 is left unchanged.) 
+int
 
-The largest "integer" value in JavaScript is 9007199254740991 (9.007199254740991E13, or 0x1FFFFFFFFFFFFFF).
-Effectively, you get to use only 53 bits of the long, not 64. Trying to set a long larger than
-0x1FFFFFFFFFFFFFF or smaller than -0x1FFFFFFFFFFFFFF will result in a NumberFormatException.
+For performance reasons, int addition and multiplication do not by default overflow to 
+negative values. Instead, they just get bigger. Java code that relies on overflow to 
+negative values should be surrounded by ()|0 -- an OR with integer 0:
 
-The transpiler handles conversion to long the same as Java for all cases other than from double. 
 
-For small double values, there is no problem, and, in fact, this is a known trick used to round 
-doubles and floats toward zero:
+int bigI, bigJ;
+...
 
-double d;
-d = (long) 3.8;
-assert(d == 3);
-d = (long) -3.8;
-assert(d == -3);
+bigI = (bigI + bigJ)|0;
 
-SwingJS will evaluate (long) d as 0 for d > 9007199254740991 
-or d < -9007199254740991, same as Java returns for Double.NaN.
-So, in Java we have:
+bigI = (bigI + 1)|0;   //instead of bigI++
 
-               assert(((long) Double.NaN) == 0);
-               assert(((int) Double.NaN) == 0);
-               assert(((long) Float.NaN) == 0);
-               assert(((int) Float.NaN) == 0);
 
-and also, in JavaScript only, we also have:
+Thus, in Java, the following is true:
 
-               double d = 0x2000000000000L;
-               assert(((long) d) == 0);
+  2000000000 + 2000000000 == -294967296
 
+But in SwingJS, that will be 4000000000. So, for example, the following
+strategy will fail in SwingJS:
 
-restrictions on BitSet and Scanner
-----------------------------------
+               int newLength = lineBuf.length * 2;
+               if (newLength < 0) {
+                       newLength = Integer.MAX_VALUE;
+               }
+
+This is because, generally, "-1" in JavaScript is not 0xFFFFFFFF. The simple ()|0 takes
+caes of this:
 
-Because of the issue of long being only 53 bits, any time a method returns a long value, considerations must
-be made as to whether this will work in JavaScript. In particular, BitSet and Scanner have issues. 
+               int newLength = (lineBuf.length * 2)|0;
+               if (newLength < 0) {
+                       newLength = Integer.MAX_VALUE;
+               }
 
-In SwingJS, java.util.BitSet has been implemented as a 32-bit integer-based bitset. This was no problem in
-Java 6, but starting with Java 7, a method was added to BitSet that allows for the extraction of the 
-underlying long[] word data. This is not work in JavaScript. Instead, SwingJS java.util.Bitset.toLongArray() will deliver 
-32-bit int[] data.
+JavaScript does process bitwise operators & | ^ ~ properly for int values. There is no issue using
+these operations. 
 
-SwingJS Scanner has hasNextLong() and nextLong(), and although it will scan through long numbers,
-Scanner will choke on long numbers greater than the JavaScript 53-bit limit. hasNextLong() will 
-return false, and nextLong() will throw an InputMismatchException triggered by the NumberFormatException
-thrown by Long.parseLong(). 
+Note that int 1/0 in Java throws "java.lang.ArithmeticException: / by zero", but in JavaScript is just Infinity. 
+
+Importantly, the JavaScript Int32Array does behave properly. From the Firefox developer console:
+
+>> x = new Int32Array(1)
+<- Int32Array(1) [ 0 ]
+>> x[0] = 4000000000
+<- 4000000000
+>> x[0]
+<- -294967296
+
+Notice that, perhaps unexpectedly, the following two constructs produce 
+different results in JavaScript:
+
+x = new Int32Array(1);
+b = x[0] = 4000000000;
+
+(b will be 4000000000)
+
+and
+
+x = new Int32Array(1);
+x[0] = 4000000000;
+b = x[0];
+
+(b will be -294967296)
+
+
+SwingJS leverages array typing to handle all byte and short arithmetic so as
+to ensure that any byte or short operation in JavaScript does give the same 
+result in Java. 
+
+long
+
+Java's 64-bit long type is fully supported, starting with java2script 3.3.1 (2020.12.31)
+The transpiler handles all conversions to and from long appropriately. See the discussion
+at https://github.com/BobHanson/java2script/issues/202 for how this is done.
+
+float
+
+SwingJS does not distinguish between float and double. Everything is double.
 
 
 HashMap, Hashtable, and HashSet iterator ordering
@@ -663,10 +709,8 @@ Starting with java2script 3.2.9.v1, these classes use the JavaScript Map object
 whenever all keys are strictly of JavaScript typeof "string". If any key is introduced that is not a string, the
 implementation falls back to using hash codes, the same as Java. 
 
-Note strings created using new String("xxxx") are NOT typeof "string"; they are typeof "object".
-
 The result is significantly faster performance (3-12 x faster) than originally, and up to 3 x faster
-performance in JavaScript than in Java itself. Right. Faster than Java. 
+performance in JavaScript than in Java itself. That is not a misprint. Faster than Java. 
 
 The JavaScript Map implementation is implemented UNLESS the constructor used is the one that
 specifies both initial capacity and load factor in their constructor. Thus, 
@@ -709,7 +753,7 @@ The reason for this design is that several classes in the Java core use toString
 methods that return new String(), and those classes that do that would cause a JavaScript error
 if implicitly stringified if new String() returned a JavaScript String object. 
 
-This is fine in JavaScript
+This is fine in JavaScript:
 
 test1 = function() { return { toString:function(){ return "OK" } } }
 "testing" + new test1()
@@ -766,12 +810,12 @@ and both of these do as well:
                assert(new String("xxx") != "xxx"); 
                assert(new String("xxx") != new String("xxx")); 
 
-But the following two fail to assert true:
+But the following two fail to assert true in SwingJS:
 
         assert("xxx" != "xx" + a);
         assert("xxx" != "xx" + a.toString());
 
-because in JavaScript, both of these right-side expressions evaluate to a simple "interned" string.
+because, in JavaScript, both of these right-side expressions evaluate to a simple "interned" string.
 
 In Java, however, these assertions are true because Java implicitly "boxes" String 
 concatentaion as a String object, not a literal. 
@@ -782,7 +826,7 @@ System.identityHashCode(), which is not the same for different objects or their
 
 My recommendation, if you need to use IdentityHashMap with strings is to always use an explicit String.intern()
 for any keys -- unless you really want to keep every string as separate keys even if they are the same sequence, 
-in which case, use new String(). This will work in Java and in  JavaScript.
+in which case, use new String(). This will work in Java and in JavaScript.
 
 Be aware when working with strings that come from SwingJS and are being used by other JavaScript modules
 that those that are String objects will return "object" for the JavaScript typeof operator, not "string".
@@ -793,6 +837,7 @@ The easy way to ensure this is no problem is to concatenate strings with "" to f
 
 unless you are certain that the string is being returned is a raw JavaScript string.   
 
+
 Names with "$" and "_"
 ----------------------
 
@@ -830,71 +875,6 @@ Some impacts of transpiling method names with full qualification:
    creating the fully qualified JavaScript name.
 
 
-positive integers do not add to give negative numbers
------------------------------------------------------
-
-In Java, the following is true:
-
-  2000000000 + 2000000000 == -294967296
-
-But in SwingJS, that will be 4000000000. So, for example, the following
-strategy will fail in SwingJS:
-
-               int newLength = lineBuf.length * 2;
-               if (newLength < 0) {
-                       newLength = Integer.MAX_VALUE;
-               }
-
-"-1" in JavaScript is not 0xFFFFFFFF.
-
-And one must take care to not compare a negative number with a 32-bit mask. So
-
-(b & 0xFF000000) == 0xFF000000
-
-is true in Java for (int) b = -1, but is false in JavaScript, because 0xFF000000 is 4278190080, 
-while (-1 & 0xFF000000) is, strangely enough, -16777216, and, in fact, 
-
-(0xFF000000 & 0xFF000000) != 0xFF000000
-
-because -16777216 is not 4278190080.
-
-The fix is that one must compare similar operations:
-
-if ((b & 0xFF000000) == (0xFF000000 & 0xFF000000)) .....
-
-Importantly, the JavaScript Int32Array does behave properly. From 
-the Firefox developer console:
-
->> x = new Int32Array(1)
-<- Int32Array(1) [ 0 ]
->> x[0] = 4000000000
-<- 4000000000
->> x[0]
-<- -294967296
-
-Notice that, perhaps unexpectedly, the following two constructs produce 
-different results in JavaScript:
-
-x = new Int32Array(1);
-b = x[0] = 4000000000;
-
-(b will be 4000000000)
-
-and
-
-x = new Int32Array(1);
-x[0] = 4000000000;
-b = x[0];
-
-(b will be -294967296)
-
-
-SwingJS leverages array typing to handle all byte and short arithmetic so as
-to ensure that any byte or short operation in JavaScript does give the same 
-result in Java. The design decision to not also do this with integer math was
-a trade-off between performance and handling edge cases.
-
-
 ArrayIndexOutOfBounds
 ---------------------
 
@@ -912,6 +892,7 @@ boolean notAGoodIdeaIsOutOfBounds(String[] sa, int i) {
 will work in Java but not in JavaScript. Code should not depend upon this sort 
 of trap anyway, if you ask me. 
 
+
 Throwable vs Error vs Exception
 -------------------------------
 
@@ -919,8 +900,7 @@ True JavaScript errors are trapped as Throwable, whereas you can still trap
 Error and Exception as well. So if you want to be sure to catch any JavaScript
 error, use try{}catch (Throwable t){}, not try{}catch (Exception e){}. 
 
-j
-ava.awt.Color
+java.awt.Color
 --------------
 
 ColorSpace: only "support" CS_sRGB.
@@ -1008,7 +988,9 @@ An example class can be found in the SwingJS distribution as
 javax.swing.JOptionPane dialogs
 -------------------------------
 
-For this action to work, the parentComponent must implement
+For a full discussion of modal dialogs, see the javajs.asyc.AsyncDialog.java discussion.
+
+For this action to work, the parent component must implement
 propertyChangeListener, and any call to JOptionPanel should allow for
 an asynchronous response, meaning that there is no actionable code following the
 call to the dialog opening. 
@@ -1047,11 +1029,9 @@ The initial return will be the one and only modal final return.
 
 
 
-For full compatibility, The calling method must not continue beyond this
-call.
+For full compatibility, The calling method must not continue beyond this call.
 
-All of the standard Java events associated with Components are also
-available.
+All of the standard Java events associated with Components are also available.
 
 Certain fall back mechanisms are possible, where onReturn does not exist, but
 only for the following cases:
@@ -1133,7 +1113,7 @@ using j2sNative blocks:
  */
  
  Note that if you follow that directly with a {...} block, then 
- the javadoc code will run in JavaScript, and the {...} code will run in Java.
+ only the javadoc code will run in JavaScript, and only the {...} code will run in Java.
  
  
 key Focus
@@ -1192,6 +1172,7 @@ But that is not a java.lang.reflection.Field object.
 No reserved top-level JavaScript name is allowed for a package name. So, for example, 
 one must rename packages such as "window" or "document" to names such as "win" or "doc".
 
+
 reserved field and method names
 -------------------------------
 
@@ -1201,6 +1182,7 @@ developers might use in subclassing Java classes, we have added U+79D8 (first ch
 would be if you use that character followed by certain English words in certain classes. For example
 \u79D8canvas for JComponents (in java.awt.JSComponent) and \u79D8byte (in java.io.File).
 
+
 qualified field and method names
 --------------------------------
 
@@ -1208,10 +1190,25 @@ Method names in SwingJS are fully qualified, meaning two methods with the same J
 parameters, such as write(int) and write(double), must not have the same name in JavaScript. (In this
 case, we will have write$I and write$D.) However, in certain cases it may be desirable to leave the
 method names unqualified. In particular, when an interface actually represents a JavaScript object, 
-the transpiler can leave a method name unqualified. The default situation for this is a class name 
-includes ".api.js" (case-sensitive). This means that any method in any class in a package js within 
-a package api, or any private interface js that has an outer interface api, will have all-unqualified
-methods. An example of this is swingjs.plaf.JSComboPopupList, which needs to communicate with a jQuery 
+the transpiler can leave a method name unqualified. 
+
+You can implement a simple name for a method using the @j2sAlias annoation in the javadoc for the 
+method involved. For example:
+
+
+/**
+ * @j2sAlias read
+ *
+ */
+public void read(byte[] buf, int pos, int len) {...}
+
+will allow the method to be accesible either as "read" or "read$BA$I$I" in JavaScript. 
+
+
+The default situation for this is a class name includes ".api.js" (case-sensitive). 
+This means that any method in any class in a package js within a package api, or any private interface js 
+that has an outer interface api, will have all-unqualified methods. An example of this is 
+swingjs.plaf.JSComboPopupList, which needs to communicate with a jQuery 
 object directly using the following interface:
 
        private interface api {
@@ -1234,24 +1231,13 @@ object directly using the following interface:
 Notice that all these variants of j2sCB() will call the same method in JavaScript by design.
 
 
-missing Math methods
---------------------
-
-java.lang.Math is worked out, but some methods are missing, either because they
-involve long integer value that are inaccessible in JavaScript, or because I just
-didn't implement them. This is a result of continued Java development. 
-It is easy enough to add these methods if you have the source. They go into j2sClazz.js, 
-which is combined with other initial libraries into swingjs2.js by build_site.xml
-
-
 Component.getGraphics(), Graphics.dispose()
 -------------------------------------------
 
 Use of component.getGraphics() is discouraged in Java and in SwingJS. 
 Specifically in SwingJS, any call to component.getGraphics() or 
 BufferedImage.createGraphics() or Graphics.create(...) should be matched with graphics.dispose(), 
-particularly when it is called outside the context of a paint(Graphics)
-call from the system. 
+particularly when it is called outside the context of a paint(Graphics) call from the system. 
 
 If you see your graphics scrolling down the page with each repaint, 
 look for where you have used Component.getGraphics() and not Graphics.dispose().
@@ -1280,8 +1266,7 @@ save/restore. This is different from Java, where you can temporarily change it u
    ...
   Graphics.setClip(oldClip); 
 
-If you need to do something like this, you must schedule the paints
-to not have overlapping clip needs.
+If you need to do something like this, you must schedule the paints to not have overlapping clip needs.
 
 
 MAJOR ISSUES--for Bob and Udo within SwingJS
@@ -1306,11 +1291,10 @@ Static classes such as:
 
    java.awt.Toolkit
    java.awt.GraphicsEnvironment
-   
-   
+      
 which are created using Class.forName are implemented using classes in the swingjs package.
 
-AWTAccessor is not implemented. 
+sun.awt.AWTAccessor is not implemented. 
 
    
 AWT component peers and component "ui" user interfaces
@@ -1324,7 +1308,6 @@ Java Swing implements peers only for JApplet, JDialog, JFrame, and JWindow.
 References to such objects have been removed, but clearly there must be 
 some connection to similar DOM objects, even for "light-weight" components. 
 
-
   
 MAJOR ISSUES--to be resolved by implementers
 ============================================
@@ -1419,6 +1402,7 @@ action through an asynchronous function run1(mode). For example:
                }
        }
 
+
 image loading
 -------------
 - All image loading in SwingJS is synchronous. A MediaTracker call will immediately return "complete".
@@ -1436,36 +1420,19 @@ image loading
 BigInteger and BigDecimal
 -------------------------
 
-java.math.BigInteger is fully supported; java.math.BigDecimal is roughed 
-in and not fully tested (07/2019). 
+java.math.BigInteger and java.math.BigDecimal are fully supported. 
 
-Both classes present significant issues for JavaScript, as they are based in 
-Java's 64-bit long for all their operations. Here is the JavaDoc note I added
-to BigInteger:
-
- * SwingJS note: Because of the limitations of JavaScript with regard
- * to long-integer bit storage as a double, this implementation drops
- * the integer storage bit length to 24, giving 48 for long and leaving
- * the last 16 bits clear for the exponent of the double number. This should
- * not affect performance significantly. It does increase the storage 
- * size by about 33%. By bringing an "int" to 3 bytes, we can easily construct
- * and use byte[] data intended for the original BitSet.  
-
-"Easily" may be a bit strong there. This was a serious challenge.
-
-BigDecimal seems to run normally, but in order to do that, my hack involves
-reducing the size of an integer that is allowed to be stored as such and not
-in byte[] as a BigInteger. I'm sure there is a performance hit, but it does work.
 
 no format internationalization
 ------------------------------
 
-For now, just en for number and date formatters
+For now, just "en" for number and date formatters
 
-no winding rules
-----------------
 
-  When filling a graphic, only nonzero winding rule is implemented in HTML5 Canvas2D.
+missing winding rules
+---------------------
+
+When filling a graphic, only nonzero winding rule is implemented in HTML5 Canvas2D.
 
 
 
@@ -1494,6 +1461,7 @@ the keypressed event, so Java actions that are keyed to KEY_PRESSED may not pick
 key value even after SwingUtilities.invokeLater() is called. Thus, key pressed actions may need
 to be recorded after a key released event instead. 
 
+
 Formatter/Regex limitations
 ---------------------------
 
@@ -1504,11 +1472,42 @@ Matcher.start(groupID) is not supported.
 
 java.util.Formatter will function correctly for all standard %... patterns.
 
-integer 1/0 == Infinity
------------------------
+In addition, JavaScript does not implement some of the more arcane POSIX {...} formats. 
+From java.util.regex.Pattern.java, we find the listing of conversions SwingJS does use:
+
+               "\\p{javaWhitespace}","\\s",
+               "\\p{javaDigit}","\\d",
+               "\\p{Lower}", "[a-z]",
+               "\\p{Upper}", "[A-Z]",
+               "\\p{ASCII}", "[\u0000-\u007F]",
+               "\\p{Alpha}", "[A-Za-z]",
+               "\\p{Digit}", "[0-9]",
+               "\\p{Alnum}", "[A-Za-z0-9]",
+               "\\p{Punct}", "[!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Graph}", "[A-Za-z0-9]!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Print}", "[A-Za-z0-9]!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Blank}", "[ \t]",
+               "\\p{Cntrl}", "[\u0000-\u001F\u007F]",
+               "\\p{XDigit}", "[0-9a-fA-F]",
+               "\\p{Space}", "[ \t\n\u000B\f\r]",
+               "\\p{javaLowerCase}", "[a-z]",
+               "\\p{javaUpperCase}", "[A-Z]",
+               "\\p{Sc}", "[\u0024\u00A2\u00A3\u00A4\u00A5\u058F\u060B\u07FE\u07FF\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u20A0\u20A1\u20A2\u20A3\u20A4\u20A5\u20A6\u20A7\u20A8\u20A9\u20AA\u20AB\u20AC\u20AD\u20AE\u20AF\u20B0\u20B1\u20B2\u20B3\u20B4\u20B5\u20B6\u20B7\u20B8\u20B9\u20BA\u20BB\u20BC\u20BD\u20BE\u20BF\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]"
+
+Java's \Q \E quoting is handled appropriately.
 
-1/0 in Java throws "java.lang.ArithmeticException: / by zero", but in JavaScript is just Infinity. 
+Additional Issues
+-----------------
+
+Method reflection is limited. Fields and methods do not retain public or default characteristics. 
+(This could be easily adapted, though.) Interfaces do not expose their methods, as the transpiler does not 
+actually transpile the interfaces themselves unless they contain default methods. 
+And method reflection only includes annotated methods.
+
+java.util.concurrent is not fully elaborated. This package is rewritten to not actually use the
+memory handling capabilities of concurrency, which JavaScript does not have access to.
+
+System.getProperties() just returns a minimal set of properties.
 
 
 Summary
@@ -1523,19 +1522,5 @@ source is by far superior. It's generally prettier, and it has the license infor
 may or may not be present with the JAR or class files. Use class files at your own risk.
 
 Bob Hanson
-2019.08.16
-
-
-Additional Issues
------------------
-
-Annotation is working for classes, methods, and fields (12/22/19). Method reflection, however,
-is limited. Interfaces do not expose their methods, as the transpiler does not actually transpile
-the interfaces themselves. And method reflection only includes annotated methods.
-
-java.util.concurrent is not fully elaborated. This package is rewritten to not actually use the
-memory handling capabilities of concurrency, which JavaScript does not have access to.
-
-System.getProperties() just returns a minimal set of properties.
 
 
index a999edf..53e50c6 100644 (file)
Binary files a/swingjs/net.sf.j2s.core-j11.jar and b/swingjs/net.sf.j2s.core-j11.jar differ
index 30390e0..ced2ae7 100644 (file)
Binary files a/swingjs/net.sf.j2s.core.jar and b/swingjs/net.sf.j2s.core.jar differ
index 39964d7..204bf8d 100644 (file)
@@ -1 +1 @@
-20201222130550 
+20210728172208 
diff --git a/swingjs/ver/3.3.1-j11/DEV_NOTES.txt b/swingjs/ver/3.3.1-j11/DEV_NOTES.txt
new file mode 100644 (file)
index 0000000..751d81c
--- /dev/null
@@ -0,0 +1,10 @@
+This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
+
+_j2sclasslist.txt 
+
+the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
+
+
+SwingJS-site.zip
+
+the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.3.1-j11/SwingJS-site.zip b/swingjs/ver/3.3.1-j11/SwingJS-site.zip
new file mode 100644 (file)
index 0000000..dafdec9
Binary files /dev/null and b/swingjs/ver/3.3.1-j11/SwingJS-site.zip differ
diff --git a/swingjs/ver/3.3.1-j11/_j2sclasslist.txt b/swingjs/ver/3.3.1-j11/_j2sclasslist.txt
new file mode 100644 (file)
index 0000000..076f300
--- /dev/null
@@ -0,0 +1,412 @@
+java/applet/Applet.js
+java/applet/AppletContext.js
+java/applet/AppletStub.js
+java/applet/JSApplet.js
+java/awt/ActiveEvent.js
+java/awt/Adjustable.js
+java/awt/AWTEvent.js
+java/awt/AWTEventMulticaster.js
+java/awt/AWTKeyStroke.js
+java/awt/BasicStroke.js
+java/awt/BorderLayout.js
+java/awt/Button.js
+java/awt/Color.js
+java/awt/color/ColorSpace.js
+java/awt/Component.js
+java/awt/ComponentOrientation.js
+java/awt/ContainerOrderFocusTraversalPolicy.js
+java/awt/Container.js
+java/awt/Cursor.js
+java/awt/DefaultFocusTraversalPolicy.js
+java/awt/DefaultKeyboardFocusManager.js
+java/awt/Dialog.js
+java/awt/Dimension.js
+java/awt/dnd/peer/DropTargetPeer.js
+java/awt/event/ActionListener.js
+java/awt/event/AdjustmentEvent.js
+java/awt/event/AdjustmentListener.js
+java/awt/event/AWTEventListener.js
+java/awt/event/ComponentAdapter.js
+java/awt/event/ComponentEvent.js
+java/awt/event/ComponentListener.js
+java/awt/event/ContainerListener.js
+java/awt/event/FocusEvent.js
+java/awt/event/FocusListener.js
+java/awt/event/HierarchyBoundsListener.js
+java/awt/event/HierarchyListener.js
+java/awt/event/InputEvent.js
+java/awt/event/InputMethodListener.js
+java/awt/event/InvocationEvent.js
+java/awt/event/ItemEvent.js
+java/awt/event/ItemListener.js
+java/awt/event/KeyListener.js
+java/awt/event/MouseEvent.js
+java/awt/event/MouseListener.js
+java/awt/event/MouseMotionListener.js
+java/awt/event/MouseWheelListener.js
+java/awt/event/TextListener.js
+java/awt/event/WindowAdapter.js
+java/awt/event/WindowEvent.js
+java/awt/event/WindowFocusListener.js
+java/awt/event/WindowListener.js
+java/awt/event/WindowStateListener.js
+java/awt/EventDispatchThread.js
+java/awt/EventFilter.js
+java/awt/EventQueue.js
+java/awt/EventQueueItem.js
+java/awt/FlowLayout.js
+java/awt/FocusTraversalPolicy.js
+java/awt/Font.js
+java/awt/font/FontRenderContext.js
+java/awt/FontMetrics.js
+java/awt/Frame.js
+java/awt/geom/AffineTransform.js
+java/awt/geom/Dimension2D.js
+java/awt/geom/Path2D.js
+java/awt/geom/PathIterator.js
+java/awt/geom/Point2D.js
+java/awt/geom/Rectangle2D.js
+java/awt/geom/RectangularShape.js
+java/awt/geom/RectIterator.js
+java/awt/GraphicsCallback.js
+java/awt/GraphicsConfiguration.js
+java/awt/GraphicsDevice.js
+java/awt/GraphicsEnvironment.js
+java/awt/Image.js
+java/awt/image/ImageObserver.js
+java/awt/Insets.js
+java/awt/ItemSelectable.js
+java/awt/JSComponent.js
+java/awt/JSDialog.js
+java/awt/JSFrame.js
+java/awt/JSPanel.js
+java/awt/KeyboardFocusManager.js
+java/awt/KeyEventDispatcher.js
+java/awt/KeyEventPostProcessor.js
+java/awt/Label.js
+java/awt/LayoutManager.js
+java/awt/LayoutManager2.js
+java/awt/LightweightDispatcher.js
+java/awt/Paint.js
+java/awt/Panel.js
+java/awt/peer/ComponentPeer.js
+java/awt/peer/ContainerPeer.js
+java/awt/peer/FramePeer.js
+java/awt/peer/KeyboardFocusManagerPeer.js
+java/awt/peer/LightweightPeer.js
+java/awt/peer/WindowPeer.js
+java/awt/Point.js
+java/awt/Queue.js
+java/awt/Rectangle.js
+java/awt/RenderingHints.js
+java/awt/Scrollbar.js
+java/awt/ScrollPane.js
+java/awt/Shape.js
+java/awt/Stroke.js
+java/awt/TextArea.js
+java/awt/TextComponent.js
+java/awt/TextField.js
+java/awt/Toolkit.js
+java/awt/Transparency.js
+java/awt/Window.js
+java/beans/ChangeListenerMap.js
+java/beans/PropertyChangeEvent.js
+java/beans/PropertyChangeListener.js
+java/beans/PropertyChangeSupport.js
+java/lang/AbstractStringBuilder.js
+java/lang/Class.js
+java/lang/Enum.js
+java/lang/Iterable.js
+java/lang/reflect/Constructor.js
+java/lang/reflect/Method.js
+java/lang/StringBuffer.js
+java/lang/StringBuilder.js
+java/lang/Thread.js
+java/lang/ThreadGroup.js
+java/math/RoundingMode.js
+java/net/URL.js
+java/net/URLStreamHandlerFactory.js
+java/net/HttpURLConnection.js
+java/net/URLStreamHandler.js
+javax/net/ssl/HttpsUrlConnection.js
+java/text/CharacterIterator.js
+java/text/DecimalFormat.js
+java/text/DecimalFormatSymbols.js
+java/text/DigitList.js
+java/text/FieldPosition.js
+java/text/Format.js
+java/text/NumberFormat.js
+java/util/AbstractCollection.js
+java/util/AbstractList.js
+java/util/AbstractMap.js
+java/util/AbstractSequentialList.js
+java/util/AbstractSet.js
+java/util/ArrayList.js
+java/util/Arrays.js
+java/util/Collection.js
+java/util/Collections.js
+java/util/Comparator.js
+java/util/Deque.js
+java/util/Dictionary.js
+java/util/Enumeration.js
+java/util/EventListener.js
+java/util/EventObject.js
+java/util/HashMap.js
+java/util/HashSet.js
+java/util/Hashtable.js
+java/util/IdentityHashMap.js
+java/util/Iterator.js
+java/util/LinkedHashMap.js
+java/util/LinkedList.js
+java/util/List.js
+java/util/ListResourceBundle.js
+java/util/Locale.js
+java/util/Map.js
+java/util/Objects.js
+java/util/Queue.js
+java/util/Random.js
+java/util/RandomAccess.js
+java/util/ResourceBundle.js
+java/util/Set.js
+java/util/TimSort.js
+java/util/Vector.js
+javajs/api/JSFunction.js
+javajs/util/AjaxURLConnection.js
+javajs/util/AjaxURLStreamHandlerFactory.js
+javajs/util/AU.js
+javajs/util/JSThread.js
+javajs/util/Lst.js
+javajs/util/PT.js
+javajs/util/Rdr.js
+javajs/util/SB.js
+javax/swing/AbstractAction.js
+javax/swing/AbstractButton.js
+javax/swing/AbstractListModel.js
+javax/swing/Action.js
+javax/swing/ActionMap.js
+javax/swing/AncestorNotifier.js
+javax/swing/ArrayTable.js
+javax/swing/border/AbstractBorder.js
+javax/swing/border/BevelBorder.js
+javax/swing/border/Border.js
+javax/swing/border/CompoundBorder.js
+javax/swing/border/EmptyBorder.js
+javax/swing/border/EtchedBorder.js
+javax/swing/border/LineBorder.js
+javax/swing/border/TitledBorder.js
+javax/swing/BorderFactory.js
+javax/swing/BoundedRangeModel.js
+javax/swing/BoxLayout.js
+javax/swing/ButtonGroup.js
+javax/swing/ButtonModel.js
+javax/swing/ClientPropertyKey.js
+javax/swing/ComboBoxModel.js
+javax/swing/DefaultBoundedRangeModel.js
+javax/swing/DefaultButtonModel.js
+javax/swing/DefaultComboBoxModel.js
+javax/swing/DefaultSingleSelectionModel.js
+javax/swing/DropMode.js
+javax/swing/event/AncestorEvent.js
+javax/swing/event/AncestorListener.js
+javax/swing/event/CaretEvent.js
+javax/swing/event/CaretListener.js
+javax/swing/event/ChangeEvent.js
+javax/swing/event/ChangeListener.js
+javax/swing/event/DocumentEvent.js
+javax/swing/event/DocumentListener.js
+javax/swing/event/EventListenerList.js
+javax/swing/event/ListDataEvent.js
+javax/swing/event/ListDataListener.js
+javax/swing/event/UndoableEditEvent.js
+javax/swing/event/UndoableEditListener.js
+javax/swing/FocusManager.js
+javax/swing/InternalFrameFocusTraversalPolicy.js
+javax/swing/LayoutComparator.js
+javax/swing/LayoutFocusTraversalPolicy.js
+javax/swing/SortingFocusTraversalPolicy.js
+javax/swing/SwingContainerOrderFocusTraversalPolicy.js
+javax/swing/SwingDefaultFocusTraversalPolicy.js
+javax/swing/Icon.js
+javax/swing/ImageIcon.js
+javax/swing/InputMap.js
+javax/swing/JApplet.js
+javax/swing/JButton.js
+javax/swing/JCheckBox.js
+javax/swing/JCheckBoxMenuItem.js
+javax/swing/JComboBox.js
+javax/swing/JComponent.js
+javax/swing/JFrame.js
+javax/swing/JLabel.js
+javax/swing/JLayeredPane.js
+javax/swing/JMenu.js
+javax/swing/JMenuBar.js
+javax/swing/JMenuItem.js
+javax/swing/JPanel.js
+javax/swing/JPopupMenu.js
+javax/swing/JRadioButtonMenuItem.js
+javax/swing/JRootPane.js
+javax/swing/JScrollBar.js
+javax/swing/JScrollPane.js
+javax/swing/JSeparator.js
+javax/swing/JTextArea.js
+javax/swing/JTextField.js
+javax/swing/JToggleButton.js
+javax/swing/JViewport.js
+javax/swing/KeyboardManager.js
+javax/swing/KeyStroke.js
+javax/swing/ListModel.js
+javax/swing/LookAndFeel.js
+javax/swing/MenuElement.js
+javax/swing/MutableComboBoxModel.js
+javax/swing/plaf/ActionMapUIResource.js
+javax/swing/plaf/basic/BasicBorders.js
+javax/swing/plaf/BorderUIResource.js
+javax/swing/plaf/ColorUIResource.js
+javax/swing/plaf/ComponentUI.js
+javax/swing/plaf/DimensionUIResource.js
+javax/swing/plaf/FontUIResource.js
+javax/swing/plaf/InputMapUIResource.js
+javax/swing/plaf/InsetsUIResource.js
+javax/swing/plaf/UIResource.js
+javax/swing/RepaintManager.js
+javax/swing/RootPaneContainer.js
+javax/swing/Scrollable.js
+javax/swing/ScrollPaneConstants.js
+javax/swing/ScrollPaneLayout.js
+javax/swing/SingleSelectionModel.js
+javax/swing/SizeRequirements.js
+javax/swing/SwingConstants.js
+javax/swing/SwingPaintEventDispatcher.js
+javax/swing/SwingUtilities.js
+javax/swing/text/AbstractDocument.js
+javax/swing/text/AttributeSet.js
+javax/swing/text/Caret.js
+javax/swing/text/DefaultCaret.js
+javax/swing/text/DefaultEditorKit.js
+javax/swing/text/Document.js
+javax/swing/text/EditorKit.js
+javax/swing/text/Element.js
+javax/swing/text/GapContent.js
+javax/swing/text/GapVector.js
+javax/swing/text/JTextComponent.js
+javax/swing/text/MutableAttributeSet.js
+javax/swing/text/PlainDocument.js
+javax/swing/text/PlainView.js
+javax/swing/text/Position.js
+javax/swing/text/Segment.js
+javax/swing/text/SegmentCache.js
+javax/swing/text/SimpleAttributeSet.js
+javax/swing/text/Style.js
+javax/swing/text/StyleConstants.js
+javax/swing/text/StyleContext.js
+javax/swing/text/TabExpander.js
+javax/swing/text/TextAction.js
+javax/swing/text/Utilities.js
+javax/swing/text/View.js
+javax/swing/tree/TreeNode.js
+javax/swing/UIDefaults.js
+javax/swing/UIManager.js
+javax/swing/undo/AbstractUndoableEdit.js
+javax/swing/undo/CompoundEdit.js
+javax/swing/undo/UndoableEdit.js
+javax/swing/ViewportLayout.js
+javax/swing/WindowConstants.js
+sun/awt/AppContext.js
+sun/awt/AWTAutoShutdown.js
+sun/awt/CausedFocusEvent.js
+sun/awt/ComponentFactory.js
+sun/awt/KeyboardFocusManagerPeerProvider.js
+sun/awt/MostRecentKeyValue.js
+sun/awt/MostRecentThreadAppContext.js
+sun/awt/PaintEventDispatcher.js
+sun/awt/PostEventQueue.js
+sun/awt/RequestFocusController.js
+sun/awt/SunToolkit.js
+sun/awt/WindowClosingListener.js
+sun/awt/WindowClosingSupport.js
+sun/awt/image/DataStealer.js
+sun/awt/image/IntegerComponentRaster.js
+sun/awt/image/IntegerInterleavedRaster.js
+sun/awt/image/SunWritableRaster.js
+sun/font/FontDesignMetrics.js
+sun/swing/DefaultLookup.js
+sun/swing/SwingLazyValue.js
+sun/text/resources/FormatData.js
+sun/text/resources/en/FormatData_en.js
+sun/util/resources/LocaleData.js
+sun/util/locale/BaseLocale.js
+sun/util/locale/LocaleUtils.js
+sun/util/locale/provider/LocaleProviderAdapter.js
+sun/util/locale/provider/LocaleDataMetaInfo.js
+swingjs/a2s/A2SContainer.js
+swingjs/a2s/A2SEvent.js
+swingjs/a2s/A2SListener.js
+swingjs/a2s/Applet.js
+swingjs/a2s/Button.js
+swingjs/a2s/Label.js
+swingjs/a2s/Panel.js
+swingjs/a2s/Scrollbar.js
+swingjs/a2s/ScrollPane.js
+swingjs/a2s/TextArea.js
+swingjs/a2s/TextField.js
+swingjs/api/Interface.js
+swingjs/api/js/DOMNode.js
+swingjs/api/js/HTML5CanvasContext2D.js
+swingjs/api/js/JSInterface.js
+swingjs/jquery/JQueryUI.js
+swingjs/JSApp.js
+swingjs/JSAppletThread.js
+swingjs/JSAppletViewer.js
+swingjs/JSFocusPeer.js
+swingjs/JSFontMetrics.js
+swingjs/JSFrameViewer.js
+swingjs/JSGraphics2D.js
+swingjs/JSGraphicsConfiguration.js
+swingjs/JSGraphicsEnvironment.js
+swingjs/JSImage.js
+swingjs/JSImagekit.js
+swingjs/JSMouse.js
+swingjs/JSNullComponentPeer.js
+swingjs/JSScreenDevice.js
+swingjs/JSThreadGroup.js
+swingjs/JSToolkit.js
+swingjs/JSUtil.js
+swingjs/plaf/ButtonListener.js
+swingjs/plaf/DefaultMenuLayout.js
+swingjs/plaf/HTML5LookAndFeel.js
+swingjs/plaf/JSAppletUI.js
+swingjs/plaf/JSButtonUI.js
+swingjs/plaf/JSCheckBoxMenuItemUI.js
+swingjs/plaf/JSCheckBoxUI.js
+swingjs/plaf/JSComboBoxUI.js
+swingjs/plaf/JSComponentUI.js
+swingjs/plaf/JSEventHandler.js
+swingjs/plaf/JSFrameUI.js
+swingjs/plaf/JSGraphicsUtils.js
+swingjs/plaf/JSLabelUI.js
+swingjs/plaf/JSLayeredPaneUI.js
+swingjs/plaf/JSLightweightUI.js
+swingjs/plaf/JSMenuBarUI.js
+swingjs/plaf/JSMenuItemUI.js
+swingjs/plaf/JSMenuUI.js
+swingjs/plaf/JSPanelUI.js
+swingjs/plaf/JSPopupMenuSeparatorUI.js
+swingjs/plaf/JSPopupMenuUI.js
+swingjs/plaf/JSRadioButtonMenuItemUI.js
+swingjs/plaf/JSRadioButtonUI.js
+swingjs/plaf/JSRootPaneUI.js
+swingjs/plaf/JSScrollBarUI.js
+swingjs/plaf/JSScrollPaneUI.js
+swingjs/plaf/JSSeparatorUI.js
+swingjs/plaf/JSSliderUI.js
+swingjs/plaf/JSTextAreaUI.js
+swingjs/plaf/JSTextFieldUI.js
+swingjs/plaf/JSTextUI.js
+swingjs/plaf/JSTextViewUI.js
+swingjs/plaf/JSViewportUI.js
+swingjs/plaf/JSWindowUI.js
+swingjs/plaf/LazyActionMap.js
+swingjs/plaf/Resizer.js
+swingjs/plaf/TextListener.js
+
+
diff --git a/swingjs/ver/3.3.1-j11/differences.txt b/swingjs/ver/3.3.1-j11/differences.txt
new file mode 100644 (file)
index 0000000..c9ec027
--- /dev/null
@@ -0,0 +1,1526 @@
+java2script/SwingJS Notes
+=========================
+
+updated 12/31/2020 -- full support for 64-bit long
+updated 12/6/2020 -- note about restrictions on long, including BitSet and Scanner
+updated 3/21/2020 -- adds note about HashMap, Hashtable, and HashSet iterator ordering
+updated 3/20/2020 -- adds note about interning, new String("xxx"), and "xxx"
+updated 2/26/2020 -- adds Graphics.setClip issue
+updated 12/22/19 -- additional issues
+updated 11/03/19 -- adds information about File.exists() and points to src/javajs/async
+updated 10/26/19 -- adds information about File.createTempFile()
+updated 8/16/19 -- minor typos and added summary paragraph
+updated 7/19/19 -- clarification that AWT and Swing classes are supported directly
+updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long
+updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages
+updated 1/4/19 -- nio
+updated 9/15/18 -- adds integer 1/0 == Infinity
+updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk
+updated 6/5/17 -- reserved package name "window"
+updated 3/11/17 -- myClass.getField
+updated 3/7/17 -- overloading of JSplitPane.setDividerLocation
+updated 3/2/17 -- more indication of classes not implemented (KeyListener)
+
+---IMPORTANT CHARACTER SET NOTE---
+
+It is critical that all development work in Java2Script be done in UTF-8. This means:
+
+- making sure your Eclipse project is set up for UTF-8 (not the Eclipse default?)
+- making sure your server can serve up UTF-8 by default for any browser-loaded files
+- making sure you don't edit a Java2Script class file or one of the site .js files
+    using a non-UTF-8 editor. It may replace non-Latin characters with "?" or garbage.
+- making sure that your web pages are delivered with proper headings indicating HTML5 and UTF-8
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+
+Note that the DOCTYPE tag is critical for some browsers to switch into HTML5 mode. (MSIE?)
+
+
+In particular, the Mandarin character ç§˜ (mi; "secret") is used extensively throughout
+the SwingJS class files to distinguish j2s-specific fields and methods that must not 
+ever be shadowed or overridden by subclasses. For example, we see in java.lang.Thread.java:
+
+               public static JSThread ç§˜thisThread;
+
+----------------------------------
+
+
+
+=============================================================================
+SwingJS and OpenJDK 8+
+=============================================================================
+
+SwingJS implements a wide range of the Java language in JavaScript. The base
+version for this implementation is OpenJDK8. some classes are implemented using 
+older source code, and there are some missing methods. For the most part, this is 
+no real problem. You can add or modify any java class just be adding it as source
+in your project. Or (preferably) you can contact me, and I can get it into the 
+distribution. Or (even more preferably) you can do that via a patch submission. 
+
+=================
+DESIGN PHILOSOPHY
+=================
+
+The java2script/SwingJS design goal is to recreate a recognizable, easily debuggable
+equivalent in JavaScript for as much of Java as practical. This means, for example, 
+that one can call in JavaScript 
+
+  new java.util.Hashtable()
+  
+and for all practical purposes it will appear that Java is running.
+
+The goal of java2script/SwingJS is NOT to reproduce Java byte code processing in a 
+browser. We leave that task and its own issues to others. Here, instead, we have a 
+working JavaScript version of the Java classes along with runtime assistance in the
+j2sClazz.js library. This design has several advantages:
+
+ 1) It leads to much smaller downloads, since the class loader can dynamically load
+    code at the class level. 
+    
+ 2) It allow the browser to use its own optimizations and features, not to ignore those. 
+    This leads to huge performance gains and in many cases much simpler coding.
+ 3) It allows for in-browser debugging and analysis. 
+ 4) It allows for code switching between Java and JavaScript. Working Java code 
+    can be annotated (@j2sNative, @j2sAlias, @j2sIgnore) in a fashion that 
+    allows the code to run slightly differently in a Java than a JavaScript environment.
+    For example:
+    
+       int delayMS = /** @j2sNative 10 ||*/2;
+    
+    will read "var delayMS = 10 || 2;"  (i.e. 10) in JavaScript but read by the Java
+    compiler as "int delayMS = 2". 
+    
+ 5) Just generally, it allows for a much more integrated environment. JavaScript on
+    the page can call into any SwingJS program, and, likewise, any SwingJS code can 
+    access anything on the page.    
+
+
+Method and Field Disambiguation
+-------------------------------
+
+This is no problem. SwingJS has no problem with the overloading of methods, for example:
+
+  public void print(int b);
+  public void print(float b);
+
+JavaScript does not allow overloading of methods, and the common practice in
+Java of naming a field the same as a method -- isAllowed and isAllowed() -- is
+not possible in JavaScript. As a result, SwingJS implements "fully-qualified" 
+method names using "$" parameter type separation. Thus, these methods in SwingJS
+will be referred to as print$I and print$F. The rules for this encoding are
+relatively simple: 
+
+1. The seven primitive types in Java are encoded $I (int), $L (long), $F (float), 
+$D (double), $B (byte) $Z (boolean), and $H (short). 
+
+2. String and Object are encoded as $S and $O, respectively.
+
+3. "java_lang_" is dropped for all other classes in the java.lang package (as in Java).
+   For example:  $StringBuffer, not $java_lang_StringBuffer
+
+4. All other classes are encoded as 
+
+ "$" + Class.getName().replace(".","_")
+
+For example, in Java we see:
+
+  public void equals(Object o) {...}
+
+Whereas in SwingJS we have:
+
+  Clazz.newMeth(C$, 'equals$O', function (o) {...}
+
+And 
+
+ this.getContentPane().add(bar, "North");
+
+becomes
+
+ this.getContentPane$().add$java_awt_Component$O(bar, "North");
+
+5. Arrays are indicated with appended "A" for each level. So
+
+  setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
+  
+becomes
+
+  setDataVector$OAA$OA(dataVector, columnIdentifiers)
+
+(It is recognized that this design does introduce a bit of ambiguity, in that
+ in principal there could be user class named XA and X in the same package,
+ and methods a(X[]) and a(XA) in the same class that cannot be distinguished.
+ The benefit of this simple system, however, triumphed over the unlikelyhood
+ of that scenario.) The transpiler could be set to flag this possibility.
+
+6. Constructors are prepended with "c$". So 
+
+  public JLabel(String text) {...}
+  
+becomes:
+
+  Clazz.newMeth(C$, 'c$$S', function (text) {...});
+
+Field disambiguation involves prepending. 
+
+In Java, a class and its subclass can both have the same field name, such as 
+
+ boolean visible;
+When this happens, it is called "shadowing", and though not recommended, Java allows
+it. The Java2Script transpiler will prepend such shadowing fields with "$" so that the
+subclass instance has both "visible" (for use in its methods inherited from its
+superclass) and "$visible" (for its own methods). Thus, we might see in Java:
+
+  this.visible = super.visible;
+  
+while in SwingJS we will see:
+
+  this.$visible=this.visible;
+
+since JavaScript does not have the "super" keyword.
+
+Parameterless methods such as toString() are appended with "$" to become toString$().
+The one exception to this rule is private methods, which are saved in (truly) private 
+array in the class (and are not accessible by reflection). Private parameterless 
+methods retain their simple Java name, since they cannot conflict with field names.
+
+This renaming of methods has a few consequences, which are discussed more fully below.
+See particularly the section on "qualified field and method names", where it is described
+how you can use packages or classes or interfaces with ".api.js" in them to represent JavaScript
+objects for which all method names are to be left unqualified, and how individual methods
+can have more than one name using @j2sAlias. 
+
+The swingjs.api.js package in particular contains a number of useful interfaces that
+you can import into your project for JavaScript-specific capabilities.
+
+
+Applet vs. Application
+----------------------
+
+One of the very cool aspects of SwingJS is that it doesn't particularly matter if a browser-based
+Java app is an "applet" or an "application". We don't need JNLP (Java Network Launch Protocol) 
+because now we can just start up any Java application in a browser just as easily as any applet.
+The associative array that passes information to the SwingJS applet (information that formerly
+might have been part of the APPLET tag, such as width, height, and codebase, always referred to 
+in our writing as "the Info array") allows the option to specify the JApplet/Applet "code" 
+class or the application "main" class. Either one will run just fine.
+
+
+Performance
+-----------
+
+Obviously, there are limitations. One is performance, but we have seen reproducible 
+performance at 1/6 - 1/3 the speed of Java. Achieving this performance may require
+some refactoring of the Java to make it more efficient in both Java and JavaScript. 
+"for" loops need to be more carefully crafted; use of "new" and "instanceof" need to be
+minimized in critical areas. Note that method overloading -- that is, the same method name
+with different parameters, such as read(int) and read(byte) -- is no longer any problem.   
+
+Threads
+-------
+
+Although there is only a single thread in JavaScript, meaning Thread.wait(), Thread.sleep(int) and 
+Thread.notify() cannot be reproduced, we have found that this is not a serious limitation. 
+For example, javax.swing.Timer() works perfectly in JavaScript. All it means is that threads 
+that use sleep(int) or notify() must be refactored to allow Timer-like callbacks. That is, 
+they must allow full exit and re-entry of Thread.run(), not the typical while/sleep motif. 
+
+The key is to create a state-based run() that can be exited and re-entered in JavaScript.
+
+The javajs.async package can be added to any Java program to provide Java+JavaScript asynchronous
+classes, including AsyncColorChooser, AsyncDialog, AsyncFileChooser, and AsyncSwingWorker. All
+of these classes work just as well in Java as in JavaScript. There is no need to run them 
+only when in JavaScript.
+
+Static fields
+-------------
+
+Final static primitive "constant" fields (String, boolean, int, etc.) such as 
+
+static final int TEST = 3;
+static final String MY_STRING = "my " + "string";
+
+are converted to their primitive form automatically by the Eclipse Java compiler 
+and do not appear in the JavaScript by their names. 
+
+Other static fields are properties of their class and can be used as expected.
+
+Note, however, that SwingJS runs all "Java" code on a page in a common "jvm" 
+(like older versions of Java). So, like the older Java schema, the JavaScript 
+equivalents of both applets and applications will share all of their static 
+fields and methods. This includes java.lang.System. 
+
+Basically, SwingJS implementations of Java run in a browser page-based sandbox 
+instead of an applet-specific one.
+
+In general, this is no problem. But if we are to implement pages with 
+multiple applets present, we must be sure to only have static references 
+that are "final" or specifically meant to be shared in a JavaScript 
+environment only (since they will not be shared in Java).
+
+A simple solution, if static non-constant references are needed, is to attach the 
+field to Thread.currentThread.threadGroup(), which is an applet-specific reference.
+Be sure, if you do this, that you use explicit setters and getters:
+
+For example, 
+
+private static String myvar;
+
+...
+
+public void setMyVar(String x) {
+  ThreadGroup g = Thread.currentThread().threadGroup();
+  /**
+   * @j2sNative g._myvar = x;
+   * 
+   */
+   {
+     myvar = x;
+   }
+}
+
+public String getMyVar() {
+  ThreadGroup g = Thread.currentThread().threadGroup();
+  /**
+   * @j2sNative return g._myvar || null;
+   * 
+   */
+   {
+     return myvar;
+   }
+}
+ in Java will get and set x the same in JavaScript and in Java. 
+A convenient way to do this in general is to supply a singleton class with
+explicitly private-only constructors and then refer to it in Java and in JavaScript
+instead of using static field, referring to myclass.getIntance().xxx instead of 
+myclass.xxx in Java (and JavaScript). 
+
+This was done extensively in the Jalview project. See jalview.bin.Instance.
+
+
+Helper Packages -- swingjs/ and javajs/
+---------------------------------------
+
+The SwingJS library is the swingjs/ package. There are interfaces that may be of assistance
+in swingjs/api, but other than that, it is not recommended that developers access classes in 
+this package. The "public" nature of their methods is really an internal necessity. Most access 
+to this package in working Java should be via the swingjs.api.JSUtilI interface.
+
+In addition to swingjs/, though, there are several useful classes in the javajs/ package
+that could be very useful. This package is a stand-alone package that can be 
+cloned in any Java project that also would be great to have in any JavaScript project
+-- SwingJS-related or not. Functionality ranges from reading and writing various file 
+formats, including PDF, BMP, PNG, GIF, JPG, JSON, ZIP, and CompoundDocument formats.
+
+A variety of highly efficient three- and four-dimensional point, vector, matrix, and 
+quaternion classes are included, as they were developed for JSmol and inherited from that
+project. 
+
+Of particular interest should be javajs/async/, which includes
+
+javajs.async.Async
+javajs.async.AsyncColorChooser
+javajs.async.AsyncDialog
+javajs.async.AsyncFileChooser
+
+See javajs.async.Async JavaDoc comments for a full description of 
+these useful classes.
+
+
+Modal Dialogs
+-------------
+
+Although true modal dialogs are not possible with only one thread, a functional equivalent -- 
+asynchronous modal dialogs -- is relatively easy to set up. All the JOptionPane dialogs will
+return PropertyChangeEvents to signal that they have been disposed of and containing the results. 
+See below and classes in the javajs.async package.
+
+
+Native calls
+------------
+
+Native calls in Java are calls to operating system methods that are not in Java. JavaScript
+has no access to these, of course, and they must all be replaced by JavaScript equivalents.
+Fortunately, they are not common, and those that are present in Java (for example, in calculating
+checksums in ZIP file creation) are at a low enough level that most developers do not utilize them
+or do not even have access to them. All native calls in Java classes have been replaced by 
+Java or JavaScript equivalents.
+
+
+Swing GUI Peers and UIClasses
+-----------------------------
+
+One of the biggest adaptations introduced in SwingJS is in the area of the graphical 
+user interface. Basically, what we have is a Java Swing "LookAndFeel" customized for HTML.
+
+The issue here is complex but workable. In Java there are two background concepts -- the 
+Component "peer" (one per "heavy-weight" component, such as a Frame) and the 
+component "uiClass" (one per component, such as BasicButtonUI or BasicTextFieldUI).
+
+Peers are native objects of the operating system. These are the virtual buttons and text areas
+that the user is interacting with at a very base level. They are chunks of low-level code that
+paint the screen to give the illusion that you really are pressing a button or typing text 
+ot the screen. Their events are being passed on to Java or the browser by the operating system. 
+
+UI classes provide a consistent "look and feel" for these native objects, rendering them onto 
+the native window canvas and handling all user-generated events. They paint the borders, 
+the backgrounds, the highlights, of every control you see in Java. There is one-to-one 
+correspondence of Swing classes and UI classes. Setting the Look and Feel for a project amounts 
+to selecting the directory from which to draw these UI classes. Java's UI class interfaces can
+be found in the javax.swing.plaf ("platform look and feel") package. Individual look and feel
+implementations are found in sun.plaf.basic, sun.plaf.metal, and other such specialized packages.
+
+Early on in the development of SwingJS, we decided not to fully reproduce the painfully detailed 
+bit-by-bit painting of controls as is done in Java. Instead, we felt it was wiser to utilize the standard
+HTML5 UI capabilities as much as possible, using DIV, and INPUT especially, with extensive use
+of CSS and sometimes jQuery (menus, and sliders, for example). Thus, we have created a new 
+set of UIs -- the "HTML5 Look and Feel". These classes can be found in swingjs.plaf. Besides being
+more adaptable, this approach allows far more versatility to SwingJS developers, allowing them
+to modify the GUI to suit their needs if desired.
+
+In SwingJS, since we have no access to native peers except through the browser DOM,
+it seemed logical to merge the peer and UI idea. So instead of having one peer per heavy-weight control and
+one UI class instance for each control type, we just have one UI class instance per control, and
+that UI class instance is what is being referred to when a "peer" is notified. 
+
+In some ways this is a throw back to when all of Swing's components were subclasses of
+specific AWT components such as Button and List. These "heavy-weight components" all had their 
+own individual native peers and thus automatically took on the look and feel provided by the OS. 
+Later Swing versions implemented full look and feel for all peers, leaving only JDialog, JFrame,
+and a few other classes to have native peers. But in SwingJS we have again a 1:1 map of component
+and UI class/peer instance.
+
+The origin of most issues (read "bugs") in relation to the GUI will probably be found in the
+swingjs.plaf JSxxxxUI.java code.
+
+  
+Swing-only Components -- no longer an issue
+-------------------------------------------
+
+Swing was introduced into Java well after the Java Abstract Window Toolkit (AWT) was well
+established. As such, its designers chose to allow AWT controls such as Button and List to be used 
+alongside their Swing counterparts JButton and JList. Reading the code, it is clear that this 
+design choice posed a huge headache for Swing class developers. 
+
+For SwingJS, we decided from the beginning NOT to allow this mixed-mode programming and 
+instead to require that all components be Swing components. However, this is not really an
+issue. We have reconfigured the class relationships a bit. In SwingJS, all AWT components
+are now subclasses of javax.swing.JComponent. While this might seem error prone, so far we have 
+found no problem with this arrangement. It's a little surprising to me that the original developers
+of Swing did not think of this.
+
+The a2s Adapter Package
+-----------------------
+
+Originally, we thought that we would restrict ourselves to JApplets only. That is, only
+Swing-based applets. But as we worked, we discovered that there are a lot of great 
+applets out there that are pre-Swing pure-AWT java.applet.Applet applets. Our problem was 
+that we also wanted it to be possible to quickly adapt these applets to JavaScript as well.
+The solution turned out to be simple: Write a package (a2s) that recreates the interface for 
+non-Swing components as subclasses of Swing components. Thus, a2s.Button subclasses javax.swing.JButton
+but also accepts all of the methods of java.awt.Button. This works amazingly well, with a few
+special adaptations to the core javax.swing to be "AWT-aware." 
+
+Then, to tie it all togeter, all AWT components such as java.awt.Button now subclass their respective
+a2s components, which in turn subclass JComponents. So no changes in code are necessary. We have
+successfully transpiled over 500 applets using this strategy. 
+
+Working with Files
+==================
+
+Simple String file names are not optimal for passing information about
+files read by SwingJS applications. That is because just peeking at a file 
+in SwingJS will load its entire byte[] data. 
+Optimally, all work with files should either use Path or File objects exclusively. 
+These objects, after a file is read or checked for existence, will already 
+contain the file byte[] data. The string name can be used alone, since SwingJS will
+cache the files itself and not reload them -- just as the browser normally does.
+
+SwingJS uses the following criteria to determine if File.exists() returns true:
+
+(1) if this File object has been used directly to read data, or 
+(2) if reading data using this File object is successful.
+
+Note that you cannot check to see if a file exists before input or if it 
+was actually written or if it already exists prior to writing in SwingJS.  
+
+Thus, you should check each use of file.exists() carefully, and if necessary, provide a J2sNative 
+block that gives an appropriate "OK" message, for example:
+
+(/** @j2sNative 1 ? false : */ outputfile.exits())
+
+or 
+
+(/** @j2sNative 1 ? true : */ inputfile.exits())
+
+Temporary files can be created in SwingJS. SwingJS will maintain a pseudo-filesystem for files 
+created with File.createTempFile(). This is useful in that closure of writing to a temporary file 
+does not generate a pseudo-download to the user's machine. Temporary files will be placed in the 
+"/TEMP/" directory, as seen from the running Java program. Any file written to this directory will
+simply be stored in memory; files written to any other directory, when closed, will appear to the 
+user as a download, often involving a "What do you want to do with this file" dialog. 
+
+
+See below for details relating to each of the subjects below:
+
+
+UNIMPLEMENTED CLASSES BY DESIGN
+===============================
+
+The SwingJS implementation of the following classes are present 
+in a way that gracefully bypasses their functionality:
+
+accessibility
+security
+serialization
+
+
+
+TODO LIST FOR UNIMPLEMENTED CLASSES
+===================================
+
+none as of 2020.12.31. Source code for classes and methods missing
+from Java 8 or from Java 9+ can be inserted by any developer along 
+with their running code source, and they should run.  
+
+
+MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
+================================================================
+
+Thread.currentThread() == dispatchThread
+
+
+MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
+=====================================================================
+
+See below for a full discussion.
+
+primitive type restrictions - int, long, and float
+HashMap, Hashtable, and HashSet iterator ordering
+interning, new String("xxx") vs "xxx"
+Names with "$" and "_"
+ArrayIndexOutOfBounds
+java.awt.Color
+native methods
+javax.swing.JFileDialog
+key focus
+LookAndFeel and UI Classes
+System.exit(0) does not stop all processes
+list cell renderers must be JComponents
+myClass.getField not implemented
+"window" and other reserved JavaScript names
+reserved field and method names
+qualified field and method names
+Component.getGraphics(), Graphics.dispose()
+Graphics.setClip()
+
+MAJOR ISSUES--for Bob and Udo within SwingJS
+============================================
+
+fonts
+OS-dependent classes
+AWT component peers
+some aspects of reflection
+
+MAJOR ISSUES--to be resolved by implementers
+============================================
+
+fonts
+threads
+modal dialogs
+image loading
+no format internationalization
+Graphics2D: missing winding rules
+text-related field implementation
+Formatter/Regex limitations
+
+======================================================================== 
+
+DISCUSS
+=======
+
+Table row/col sorter needs checking after removal of java.text.Collator references
+
+========================================================================== 
+
+//////////////////////////////////////////////////////////////////////////////
+
+UNIMPLEMENTED CLASSES
+=====================
+
+accessibility
+-------------
+
+All Accessibility handling has been commented out to save the download footprint.
+This removes the need for sun.misc.SharedSecrets as well. 
+Nothing says we could not implement accessibility. We just didn't.
+
+
+security
+--------
+
+All JavaScript security is handled by the browser natively. 
+Thus, Java security checking is no longer necessary, and 
+java.security.AccessController has been simplified to work without
+native security checking.
+
+Note that private methods in a class are REALLY private. 
+
+
+serialization
+-------------
+
+All serialization has been removed. It was never very useful for Swing anyway, 
+because one needs exactly the same Java version to save and restore serialized objects.
+
+
+keyboard accelerators and mnemonics
+-----------------------------------
+
+This work was completed in the spring of 2019. Note that in a browser, some 
+key strokes, particularly CTRL-keys, are not available. Bummer.
+
+
+MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
+================================================================
+
+
+Thread.currentThread() == dispatchThread
+----------------------------------------
+
+changed to JSToolkit.isDispatchThread()
+
+
+MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
+=====================================================================
+
+primitive restrictions - int, long, and float
+---------------------------------------------
+
+int
+
+For performance reasons, int addition and multiplication do not by default overflow to 
+negative values. Instead, they just get bigger. Java code that relies on overflow to 
+negative values should be surrounded by ()|0 -- an OR with integer 0:
+
+
+int bigI, bigJ;
+...
+
+bigI = (bigI + bigJ)|0;
+
+bigI = (bigI + 1)|0;   //instead of bigI++
+
+
+Thus, in Java, the following is true:
+
+  2000000000 + 2000000000 == -294967296
+
+But in SwingJS, that will be 4000000000. So, for example, the following
+strategy will fail in SwingJS:
+
+               int newLength = lineBuf.length * 2;
+               if (newLength < 0) {
+                       newLength = Integer.MAX_VALUE;
+               }
+
+This is because, generally, "-1" in JavaScript is not 0xFFFFFFFF. The simple ()|0 takes
+caes of this:
+
+               int newLength = (lineBuf.length * 2)|0;
+               if (newLength < 0) {
+                       newLength = Integer.MAX_VALUE;
+               }
+
+JavaScript does process bitwise operators & | ^ ~ properly for int values. There is no issue using
+these operations. 
+
+Note that int 1/0 in Java throws "java.lang.ArithmeticException: / by zero", but in JavaScript is just Infinity. 
+
+Importantly, the JavaScript Int32Array does behave properly. From the Firefox developer console:
+
+>> x = new Int32Array(1)
+<- Int32Array(1) [ 0 ]
+>> x[0] = 4000000000
+<- 4000000000
+>> x[0]
+<- -294967296
+
+Notice that, perhaps unexpectedly, the following two constructs produce 
+different results in JavaScript:
+
+x = new Int32Array(1);
+b = x[0] = 4000000000;
+
+(b will be 4000000000)
+
+and
+
+x = new Int32Array(1);
+x[0] = 4000000000;
+b = x[0];
+
+(b will be -294967296)
+
+
+SwingJS leverages array typing to handle all byte and short arithmetic so as
+to ensure that any byte or short operation in JavaScript does give the same 
+result in Java. 
+
+long
+
+Java's 64-bit long type is fully supported, starting with java2script 3.3.1 (2020.12.31)
+The transpiler handles all conversions to and from long appropriately. See the discussion
+at https://github.com/BobHanson/java2script/issues/202 for how this is done.
+
+float
+
+SwingJS does not distinguish between float and double. Everything is double.
+
+
+HashMap, Hashtable, and HashSet iterator ordering
+-------------------------------------------------
+
+In Java, iterators for HashMap, Hashtable, and HashSet do not guarantee any particular order. 
+From the HashMap documentation for Java 8:
+
+       This class makes no guarantees as to the order of the map; in particular, it does not 
+       guarantee that the order will remain constant over time.
+Likewise, for HashSet (because it is simply a convenience method for HashMap<Object,PRESENT>:
+
+       [HashSet] makes no guarantees as to the iteration order of the set.
+
+JavaScript's Map object is different. It is basically a LinkedHashMap, so it guarantees iteration
+in order of object addition.
+
+Starting with java2script 3.2.9.v1, these classes use the JavaScript Map object rather than hash codes
+whenever all keys are strictly of JavaScript typeof "string". If any key is introduced that is not a string, the
+implementation falls back to using hash codes, the same as Java. 
+
+The result is significantly faster performance (3-12 x faster) than originally, and up to 3 x faster
+performance in JavaScript than in Java itself. That is not a misprint. Faster than Java. 
+
+The JavaScript Map implementation is implemented UNLESS the constructor used is the one that
+specifies both initial capacity and load factor in their constructor. Thus, 
+
+new Hashtable()
+new HashMap()
+new HashMap(16)
+new HashSet()
+
+all use the JavaScript Map. But
+
+new Hashtable(11, 0.75f)
+new HashMap(16, 0.75f)
+new HashSet(16, 0.75f)
+
+do not. 
+
+This design allows for opting out of the JavaScript Map use in order to retain the exact behavior of 
+iterators in JavaScript as in Java.
+
+
+interning, new String("xxx") vs "xxx"
+-------------------------------------
+
+Note that the following are true in JavaScript:
+
+typeof new String("xxxx") == "object"
+typeof "xxxx" == "string"
+var s = "x";typeof ("xxx" + s) == "string"
+
+There is no equivalence to this behavior in Java, where a String is a String is a String.
+
+Be aware that SwingJS does not always create a JavaScript String object using JavaScript's 
+new String(...) constructor. It only does this for Java new String("xxxx") or new String(new String()). 
+
+In all other cases, new String(...) (in Java) results in a simple "xxxx" string in JavaScript. 
+That is, it will be JavaScript typeof "string", not typeof "object". 
+
+The reason for this design is that several classes in the Java core use toString() 
+methods that return new String(), and those classes that do that would cause a JavaScript error
+if implicitly stringified if new String() returned a JavaScript String object. 
+
+This is fine in JavaScript:
+
+test1 = function() { return { toString:function(){ return "OK" } } }
+"testing" + new test1()
+>> "testingOK"
+
+But for whatever reason in JavaScript:
+
+test2 = function() { return { toString:function(){ return new String("OK") } } }
+"testing" + new test2()
+>> Uncaught TypeError: Cannot convert object to primitive value
+
+The lesson here is never to use 
+
+  return new String("...");
+
+in a Java toString() method. In Java it will be fine; in JavaScript it will also be fine as long as
+that method is never called in JavaScript implicitly in the context of string concatenation.
+
+A note about interning. Consider the following six Java constructions, where we have a == "x";
+
+"xxx"
+"xx" + "x"
+new String("xxx").intern()
+
+new String("xxx")
+"xx" + a.toString()
+"xx" + a
+
+All six of these will return java.lang.String for .getClass().getName().
+However, the first three are String literals, while the last three are String objects. 
+Thus:
+        "xxx" == "xxx"
+        "xxx" == "xx" + "x"
+        "xxx" == new String("xxx").intern()
+
+but none of the other three are equivalent to "xxx" or each other:
+
+              "xxx" != new String("xxx")
+              "xxx" != "xx" + a.toString()
+              "xxx" != "xx" + a
+  new String("xxx") != new String("xxx") 
+           "xx" + a != new String("xxx") 
+
+etc.
+
+As in Java, in SwingJS, all of the following Java assertions pass as true:
+
+               assert("xxx" == "xx" + "x"); 
+               assert("xxx" == ("xx" + a).intern()); 
+               assert("xxx" === new String("xxx").intern()); 
+               
+and both of these do as well:
+
+               assert(new String("xxx") != "xxx"); 
+               assert(new String("xxx") != new String("xxx")); 
+
+But the following two fail to assert true in SwingJS:
+
+        assert("xxx" != "xx" + a);
+        assert("xxx" != "xx" + a.toString());
+
+because, in JavaScript, both of these right-side expressions evaluate to a simple "interned" string.
+
+In Java, however, these assertions are true because Java implicitly "boxes" String 
+concatentaion as a String object, not a literal. 
+
+Most of us know not to generally use == with Strings unless they are explicitly interned. 
+Where this problem may arise, though, is in IdentityHashMap, which compares objects using 
+System.identityHashCode(), which is not the same for different objects or their string literal equivalents.
+
+My recommendation, if you need to use IdentityHashMap with strings is to always use an explicit String.intern()
+for any keys -- unless you really want to keep every string as separate keys even if they are the same sequence, 
+in which case, use new String(). This will work in Java and in JavaScript.
+
+Be aware when working with strings that come from SwingJS and are being used by other JavaScript modules
+that those that are String objects will return "object" for the JavaScript typeof operator, not "string".
+
+The easy way to ensure this is no problem is to concatenate strings with "" to force immediate interning:
+
+  var x = aJavaObject.getString() + "";
+
+unless you are certain that the string is being returned is a raw JavaScript string.   
+
+
+Names with "$" and "_"
+----------------------
+
+For the most part, this should be no problem. 
+
+Note that the use of $ and _ in Java field names has always been discouraged:
+[https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html]
+
+       You may find some situations where auto-generated names will contain the dollar sign, 
+       but your variable names should always avoid using it. A similar convention 
+       exists for the underscore character; while it's technically legal to begin your 
+       variable's name with "_", this practice is discouraged.
+
+Some impacts of transpiling method names with full qualification:
+
+1) SwingJS will introduce fields that start with $ or _. These will not conflict
+   if the above convention is followed.
+   
+2) Fields that have the same Java name as a method are not an issue. 
+
+3) Fields that have a Java name with $ that matches a transpiled method name, 
+   such as toString$, will need to be refactored in Java to not have that name collision.
+   
+4) Fields in a subclass that have the same name as private fields in a superclass
+   represent a name collision, because the superclass method needs to call its private
+   field even if invoked from a subclass. The solution was to modify the subclass field
+   name using one or more prepended $.
+   
+5) Use of Class.getDeclaredMethods() reflection will return Method objects having the transpiled 
+   name, not the Java name. This could require some j2sNative adjustment 
+   to strip the $... parameters from the name if that is needed. 
+
+6) Use of Method.getParameterTypes() should work fine, provided class names
+   do not contain "_". This is because the transpiler converts "." to "_" when
+   creating the fully qualified JavaScript name.
+
+
+ArrayIndexOutOfBounds
+---------------------
+
+You cannot implicitly throw an ArrayIndexOutOfBoundsException in JavaScript.
+JavaScript will simply return "undefined", not throw an Exception. So:
+
+boolean notAGoodIdeaIsOutOfBounds(String[] sa, int i) {
+  try {
+     return (sa[i] == sa[i]);
+  } catch (ArrayIndexOutOfBoundsException e) {
+       return false;
+  }
+}
+
+will work in Java but not in JavaScript. Code should not depend upon this sort 
+of trap anyway, if you ask me. 
+
+
+Throwable vs Error vs Exception
+-------------------------------
+
+True JavaScript errors are trapped as Throwable, whereas you can still trap
+Error and Exception as well. So if you want to be sure to catch any JavaScript
+error, use try{}catch (Throwable t){}, not try{}catch (Exception e){}. 
+
+java.awt.Color
+--------------
+
+ColorSpace: only "support" CS_sRGB.
+
+ TODO -- any volunteers??
+
+javax.swing.JFileDialog
+-----------------------
+
+HTML5 cannot expose a file reading directory structure. But you certainly 
+can still do file reading and writing. It just works a little differently.
+It's a simple modification:
+
+               b = new JButton("FileOpenDialog");
+               b.addActionListener(new ActionListener() {
+
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               JFileChooser fc = new JFileChooser();
+                               Test_Dialog.this.onDialogReturn(fc.showOpenDialog(Test_Dialog.this));
+                               // Java will wait until the dialog is closed, then enter the onDialogReturn method.
+                               // JavaScript will exit with NaN immediately, and then call back with its actual value
+                               // asynchronously.
+                       }
+
+               });
+       
+               public void onDialogReturn(int value) {
+                       if (value != Math.floor(value))
+                               return; // in JavaScript, this will be NaN, indicating the dialog has been opened
+                       // If we are here, the dialog has closed, in both Java and JavaScript.
+                       System.out.println("int value is " + value);
+               }
+
+
+       @Override
+       public void propertyChange(PropertyChangeEvent event) {
+               Object val = event.getNewValue();
+               String name = event.getPropertyName();
+               System.out.println(name);
+               switch (event.getSource().getClass().getName()) {
+               case "javax.swing.JOptionPane":
+                       switch (name) {
+                       case "inputValue":
+                               onDialogReturn(val);
+                               return;
+                       case "value":
+                               if (val instanceof Integer)
+                                       onDialogReturn(((Integer) val).intValue());
+                               else
+                                       onDialogReturn(val);
+                               return;
+                       }
+                       break;
+               case "javax.swing.ColorChooserDialog":
+                       switch (name) {
+                       case "SelectedColor":
+                               onDialogReturn(val);
+                               return;
+                       }
+                       break;
+               case "javax.swing.JFileChooser":
+                       switch (name) {
+                       case "SelectedFile":
+                               File file = (File) val;
+                               byte[] array = (val == null ? null : /** @j2sNative file.秘bytes || */
+                                               null);
+                               onDialogReturn("fileName is '" + file.getName() + "'\n\n" + new String(array));
+                               return;
+                       }
+                       break;
+               }
+               System.out.println(
+                               event.getSource().getClass().getName() + " " + event.getPropertyName() + ": " + event.getNewValue());
+       }
+
+
+Developers are encouraged to create a separate class that handles general calls to JFileDialog. 
+An example class can be found in the SwingJS distribution as 
+
+/sources/net.sf.j2s.java.core/src/javajs/async/AsyncFileChooser.java.
+
+
+javax.swing.JOptionPane dialogs
+-------------------------------
+
+For a full discussion of modal dialogs, see the javajs.asyc.AsyncDialog.java discussion.
+
+For this action to work, the parent component must implement
+propertyChangeListener, and any call to JOptionPanel should allow for
+an asynchronous response, meaning that there is no actionable code following the
+call to the dialog opening. 
+
+In addition, for compatibility with the Java version, implementation should
+wrap the call to getConfirmDialog or getOptionDialog in a method call to
+handle the Java:
+
+onDialogReturn(JOptionPane.showConfirmDialog(parentFrame,
+messageOrMessagePanel, "title", JOptionPane.OK_CANCEL_OPTION));
+
+Then parentFrame.propertyChange(event) should also call onDialogReturn.
+
+This will then work in both Java and JavaScript.
+
+Note that there is an int and an Object version of onDialogReturn().
+
+
+In JavaScript:
+
+The initial return from JOptionPane.showConfirmDialog and showMessageDialog
+will be (SwingJS) JDialog.ASYNCHRONOUS_INTEGER (NaN), testable as an impossible 
+Java int value using ret != -(-ret) if the parent implements PropertyChangeListener, or -1
+(CLOSE_OPTION) if not.
+
+For showOptionDialog (which returns Object) or showInputDialog (which returns
+String), the initial return will be (SwingJS) JDialog.ASYNCHRONOUS_OBJECT, testable as
+((Object) ret) instanceof javax.swing.plaf.UIResource if the parent implements
+PropertyChangeListeneer, or null if not.
+
+The second return will be the desired return.
+
+In Java:
+
+The initial return will be the one and only modal final return.
+
+
+
+For full compatibility, The calling method must not continue beyond this call.
+
+All of the standard Java events associated with Components are also available.
+
+Certain fall back mechanisms are possible, where onReturn does not exist, but
+only for the following cases:
+
+
+For showMessageDialog, for WARNING_MESSAGE and ERROR_MESSAGE, a simple
+JavaScript alert() is used, returning 0 (OK_OPTION) or -1 (CLOSED_OPTION).
+
+For showInputDialog, if the message is a string, a simple JavaScript prompt()
+with input box is used, returning the entered string or null.
+
+For showConfirmDialog, a simple JavaScript confirm() is used, in which case:
+
+for YES_NO_OPTION: YES_OPTION or NO_OPTION
+
+for YES_NO_CANCEL_OPTION: YES_OPTION or CANCEL_OPTION
+
+for OK_CANCEL_OPTION or any other: OK_OPTION or CANCEL_OPTION
+
+Note that you should implement a response for CLOSED_OPTION for
+showConfirmDialog. For other dialogs, a null return indicates the dialog was
+closed, just as for Java.
+
+Developers are encouraged to create a separate class that handles general calls. 
+An example class can be found in the SwingJS distribution as src/javajs/async/AsyncDialog.java.
+Very simple modifications to the Java allows asynchronous operation using AsyncDialog. Here
+is a simple "do you want to close this frame" example, where you can see that what we have
+done is to set the reply into an ActionListener that is defined in the constructor of 
+the AsyncDisplay object:
+
+// Original:
+//
+//     private void promptQuit() {
+//             int sel = JOptionPane.showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION);
+//             switch (sel) {
+//             case JOptionPane.YES_OPTION:
+//                     resultsTab.clean();
+//                     seqs.dispose();
+//                     if (fromMain) {
+//                             System.exit(0);
+//                     }
+//                     break;
+//             }
+//     }
+
+       private void promptQuitAsync() {
+               new AsyncDialog(new ActionListener() {
+
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                           int sel = ((AsyncDialog)e.getSource()).getOption();
+                               switch (sel) {
+                               case JOptionPane.YES_OPTION:
+                                       resultsTab.clean();
+                                       seqs.dispose();
+                                       if (fromMain) {
+                                               System.exit(0);
+                                       }
+                                       break;
+                               }
+                       }}).showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION);
+       }
+
+Very simple! 
+
+
+native methods
+--------------
+
+The J2S compiler ignores all static native method declarations.
+Anything of this nature needs to be implemented in JavaScript if it is needed,
+using j2sNative blocks:
+
+/**
+ * @j2sNative
+ *
+ *    var putYourJavaScriptCodeHere
+ *
+ */
+ Note that if you follow that directly with a {...} block, then 
+ only the javadoc code will run in JavaScript, and only the {...} code will run in Java.
+key Focus
+---------
+
+As of June, 2019, the keyboard focus manager is fully implemented. 
+The one catch is that JTextPane and JTextArea, which already consume
+VK_TAB in Java, cannot use CTRL-TAB to continue a tabbing cycle around
+the components in a window. Instead, CTRL-TAB is absorbed by the browser. 
+
+
+LookAndFeel and UI Classes
+--------------------------
+
+SwingJS implements the native browser look and feel as swingjs.plaf.HTML5LookAndFeel. 
+There are small differences between all look and feels -- MacOS, Windows, SwingJS.
+
+Expert developers know how to coerce changes in the UI by subclassing the UI for a 
+component. This probably will not work in SwingJS. 
+
+Note that LookAndFeel in Java usually determines canvas size in a Frame because 
+different operating systems (Mac OS vs Windows vs HTML5) will have 
+different edge sizes on their frames. If you want to ensure a component size, 
+use getContentPane().setPreferredSize().
+
+
+System.exit(0) does not stop all processes
+------------------------------------------
+
+Although System.ext(int) has been implemented in JavaScript, it just closes the 
+frames, stops all pending javax.swing.Timer objects in the queue, and runs any 
+threads added using Runtime.getRuntime().addShutdownHook(Thread).
+It may not stop all "threads." So don't rely on that.
+Applications are responsible for shutting down prior to executing System.exit(0). 
+
+
+myClass.getField not implemented
+--------------------------------
+
+java.lang.reflect.Field is implemented minimally. It is not
+certain that Field.getDeclaringClass() will work. If you just want a 
+value of a field, you can do this:
+
+/**
+ *@j2sNative
+ *
+ * return myClass[name]
+ */   
+
+But that is not a java.lang.reflection.Field object.
+
+
+"window" and other reserved JavaScript names
+--------------------------------------------
+
+No reserved top-level JavaScript name is allowed for a package name. So, for example, 
+one must rename packages such as "window" or "document" to names such as "win" or "doc".
+
+
+reserved field and method names
+-------------------------------
+
+In order to minimize the chance of added SwingJS field and method names colliding with ones 
+developers might use in subclassing Java classes, we have added U+79D8 (first character of Mandarin 
+"secret") to the characters already disrecommended by Java documentation ("$" and "_"). The only problem
+would be if you use that character followed by certain English words in certain classes. For example
+\u79D8canvas for JComponents (in java.awt.JSComponent) and \u79D8byte (in java.io.File).
+
+
+qualified field and method names
+--------------------------------
+
+Method names in SwingJS are fully qualified, meaning two methods with the same Java name but different
+parameters, such as write(int) and write(double), must not have the same name in JavaScript. (In this
+case, we will have write$I and write$D.) However, in certain cases it may be desirable to leave the
+method names unqualified. In particular, when an interface actually represents a JavaScript object, 
+the transpiler can leave a method name unqualified. 
+
+You can implement a simple name for a method using the @j2sAlias annoation in the javadoc for the 
+method involved. For example:
+
+
+/**
+ * @j2sAlias read
+ *
+ */
+public void read(byte[] buf, int pos, int len) {...}
+
+will allow the method to be accesible either as "read" or "read$BA$I$I" in JavaScript. 
+
+
+The default situation for this is a class name includes ".api.js" (case-sensitive). 
+This means that any method in any class in a package js within a package api, or any private interface js 
+that has an outer interface api, will have all-unqualified methods. An example of this is 
+swingjs.plaf.JSComboPopupList, which needs to communicate with a jQuery 
+object directly using the following interface:
+
+       private interface api {
+
+               interface js extends JQueryObject {
+
+                       abstract js j2sCB(Object options);
+
+                       abstract Object[] j2sCB(String method);
+
+                       abstract Object[] j2sCB(String method, Object o);
+
+                       abstract Object[] j2sCB(String method, int i);
+
+                       abstract int j2sCB(String OPTION, String name);
+
+               }
+       }
+
+Notice that all these variants of j2sCB() will call the same method in JavaScript by design.
+
+
+Component.getGraphics(), Graphics.dispose()
+-------------------------------------------
+
+Use of component.getGraphics() is discouraged in Java and in SwingJS. 
+Specifically in SwingJS, any call to component.getGraphics() or 
+BufferedImage.createGraphics() or Graphics.create(...) should be matched with graphics.dispose(), 
+particularly when it is called outside the context of a paint(Graphics) call from the system. 
+
+If you see your graphics scrolling down the page with each repaint, 
+look for where you have used Component.getGraphics() and not Graphics.dispose().
+For example, this will definitely NOT work in SwingJS:
+
+  this.paint(getGraphics())
+  
+and really should not work in Java, either, as it is technically a resource memory leak.
+
+Instead, if you really do not want to use repaint(), use this:
+
+  Graphics g = getGraphics();
+  paint(g);
+  g.dispose();
+
+
+
+Graphics.setClip()
+------------------
+
+The HTML5 canvas.clip() method is permanent. You can only reset the clip using
+save/restore. This is different from Java, where you can temporarily change it using
+
+  Shape oldClip = Graphics.getClip();
+  Graphics.setClip(newClip);
+   ...
+  Graphics.setClip(oldClip); 
+
+If you need to do something like this, you must schedule the paints to not have overlapping clip needs.
+
+
+MAJOR ISSUES--for Bob and Udo within SwingJS
+============================================
+
+fonts
+-----
+
+Fonts and FontMetrics will all be handled in JavaScript. Font matching will 
+not be exact, and composite (drawn) fonts will not be supported. 
+
+SwingJS handles calls such as font.getFontMetrics(g).stringWidth("xxx") by 
+creating a <div> containing that text, placing it in an obscure location on 
+the page, and reading div.getBoundingClientRect(). This is a VERY precise
+value, but can be a pixel or two off from what Java reports for the same font.
+OS-dependent classes
+--------------------
+
+Static classes such as:
+
+   java.awt.Toolkit
+   java.awt.GraphicsEnvironment
+      
+which are created using Class.forName are implemented using classes in the swingjs package.
+
+sun.awt.AWTAccessor is not implemented. 
+
+   
+AWT component peers and component "ui" user interfaces
+------------------------------------------------------
+
+ComponentPeer is a class that represents a native AWT component.
+Components with such peers are called "heavy-weight" components.
+They are expected to do the dirty work of graphics drawing. 
+
+Java Swing implements peers only for JApplet, JDialog, JFrame, and JWindow. 
+References to such objects have been removed, but clearly there must be 
+some connection to similar DOM objects, even for "light-weight" components. 
+
+  
+MAJOR ISSUES--to be resolved by implementers
+============================================
+
+fonts
+-----
+
+Glyph/composite/outline fonts are not supported.
+   
+
+
+threads
+-------
+
+Thread locking and synchronization are not relevant to JavaScript.
+Thus, anything requiring "notify.." or "waitFor.." could be a serious issue.
+All threading must be "faked" in JavaScript. Specifically not available is:
+
+  Thread.sleep()
+  
+javax.swing.AbstractButton#doClick(pressTime) will not work, as it requires Thread.sleep();
+    
+However, java.lang.Thread itself is implemented and used extensively. 
+
+Methods thread.start() and thread.run() both work fine. 
+
+For simple applications that use Thread.sleep() just to have a delay, as in a frame rate, for 
+example, one can use javax.swing.Timer instead. That is fully implemented. 
+
+Likewise, java.util.Timer can be replaced with no loss of performance with javax.Swing.Timer.
+Note that java.util.TimerTask is implemented, but it can also be replaced by an implementation of Runnable.
+
+task = new TimerTask(){....};
+t = new java.util.Timer();
+t.schedule(task, 0, 1);
+
+becomes
+
+task = new TimerTask(){....}; // or task = new Runnable() {...}
+t = new javax.swing.Timer(1, new ActionListener() {
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               task.run();
+       }
+};
+t.setInitialDelay(0); // not particularly necessary
+t.start();
+
+In addition, SwingJS provides swingjs.JSThread, which can be subclassed
+if desired. This class allows simple 
+
+  while(!interrupted()){
+       wait()
+       ...
+  }  
+
+action through an asynchronous function run1(mode). For example:
+
+       protected void run1(int mode) {
+               try {
+                       while (true)
+                               switch (mode) {
+                               case INIT:
+                                       // once-through stuff here
+                                       mode = LOOP;
+                                       break;
+                               case LOOP:
+                                       if (!doDispatch || isInterrupted()) {
+                                               mode = DONE;
+                                       } else {
+                                               Runnable r = new Runnable() {
+                                                       public void run() {
+                                                               // put the loop code here
+                                                       }
+                                               };
+                                               dispatchAndReturn(r);
+                                               if (isJS)
+                                                       return;
+                                       }
+                                       break;
+                               // add more cases as needed
+                               case DONE:
+                                       // finish up here
+                                       if (isInterrupted())
+                                               return;
+                                       // or here
+                                       break;
+                               }
+               } finally {
+                       // stuff here to be executed after each loop in JS or at the end in Java
+               }
+       }
+
+
+image loading
+-------------
+- All image loading in SwingJS is synchronous. A MediaTracker call will immediately return "complete".
+  However, it still may take one system clock tick to fully load images. Thus, it is recommended that
+  images be preloaded in the static block of the applet if it is necessary that they be available in init().
+  This is only an issue if you are trying to access the pixel buffer of the image in JavaScript. 
+  
+- Applet.getImage(path, name) will return null if the image does not exist. 
+
+- BufferedImage: only "support" imageType RGB and ARGB
+
+  -BH: This is a temporary edit, just to get us started. Certainly GRAY will be needed
+
+
+BigInteger and BigDecimal
+-------------------------
+
+java.math.BigInteger and java.math.BigDecimal are fully supported. 
+
+
+no format internationalization
+------------------------------
+
+For now, just "en" for number and date formatters
+
+
+missing winding rules
+---------------------
+
+When filling a graphic, only nonzero winding rule is implemented in HTML5 Canvas2D.
+
+
+
+text-related field implementation
+---------------------------------
+
+Text fields are:
+
+JTextField   (JavaScript <input type="text">)
+JTextArea    (JavaScript <textarea>)
+JTextPane    (JavaScript <div>)
+JEditorPane  (JavaScript <div>)
+
+For the initial implementation, we don't implement infinite undo/redo, and the abstract 
+document model is much less elaborate. Only PlainDocument (in the form of JSPlainDocument)
+is implemented. The Document returned by JTextField.getDocument() is a javax.swing.text.Document.
+
+All scrolling is handled by HTML5. javax.swing.AutoScroller is not implemented.
+public static methods .stop, .isRunning, .processMouseDragged require true Java threading
+and so are not implmented. javax.swing.text.View and its subclasses are not implemented. 
+
+The JS document model does not allow two text fields to address the same underlying document. 
+
+JavaScript is slightly different from Java in that the field value is changed asynchronously after
+the keypressed event, so Java actions that are keyed to KEY_PRESSED may not pick up the new 
+key value even after SwingUtilities.invokeLater() is called. Thus, key pressed actions may need
+to be recorded after a key released event instead. 
+
+
+Formatter/Regex limitations
+---------------------------
+
+Some browsers cannot process Regex "look-behind" process such as (?<=\W)
+java.util.regex.Matcher and Pattern use JavaScript's RegExp object rather than
+the native Java object. These are not identical. Only flags /igm are supported.
+Matcher.start(groupID) is not supported.
+
+java.util.Formatter will function correctly for all standard %... patterns.
+
+In addition, JavaScript does not implement some of the more arcane POSIX {...} formats. 
+From java.util.regex.Pattern.java, we find the listing of conversions SwingJS does use:
+
+               "\\p{javaWhitespace}","\\s",
+               "\\p{javaDigit}","\\d",
+               "\\p{Lower}", "[a-z]",
+               "\\p{Upper}", "[A-Z]",
+               "\\p{ASCII}", "[\u0000-\u007F]",
+               "\\p{Alpha}", "[A-Za-z]",
+               "\\p{Digit}", "[0-9]",
+               "\\p{Alnum}", "[A-Za-z0-9]",
+               "\\p{Punct}", "[!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Graph}", "[A-Za-z0-9]!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Print}", "[A-Za-z0-9]!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Blank}", "[ \t]",
+               "\\p{Cntrl}", "[\u0000-\u001F\u007F]",
+               "\\p{XDigit}", "[0-9a-fA-F]",
+               "\\p{Space}", "[ \t\n\u000B\f\r]",
+               "\\p{javaLowerCase}", "[a-z]",
+               "\\p{javaUpperCase}", "[A-Z]",
+               "\\p{Sc}", "[\u0024\u00A2\u00A3\u00A4\u00A5\u058F\u060B\u07FE\u07FF\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u20A0\u20A1\u20A2\u20A3\u20A4\u20A5\u20A6\u20A7\u20A8\u20A9\u20AA\u20AB\u20AC\u20AD\u20AE\u20AF\u20B0\u20B1\u20B2\u20B3\u20B4\u20B5\u20B6\u20B7\u20B8\u20B9\u20BA\u20BB\u20BC\u20BD\u20BE\u20BF\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]"
+
+Java's \Q \E quoting is handled appropriately.
+
+Additional Issues
+-----------------
+
+Method reflection is limited. Fields and methods do not retain public or default characteristics. 
+(This could be easily adapted, though.) Interfaces do not expose their methods, as the transpiler does not 
+actually transpile the interfaces themselves unless they contain default methods. 
+And method reflection only includes annotated methods.
+
+java.util.concurrent is not fully elaborated. This package is rewritten to not actually use the
+memory handling capabilities of concurrency, which JavaScript does not have access to.
+
+System.getProperties() just returns a minimal set of properties.
+
+
+Summary
+-------
+
+These are all the known limitations of SwingJS. We have not found any of these limitations
+to be show-stoppers. The primary issue for newcomers to SwingJS is having the source code.
+You must check that source code for all your library jar files is available or, if you
+choose, you will need to decompile those classes. We have used decompilation on some projects,
+and it works just fine. So, technically, all we really need are JAR/class files. But the 
+source is by far superior. It's generally prettier, and it has the license information that
+may or may not be present with the JAR or class files. Use class files at your own risk.
+
+Bob Hanson
+
+
diff --git a/swingjs/ver/3.3.1-j11/net.sf.j2s.core-j11.jar b/swingjs/ver/3.3.1-j11/net.sf.j2s.core-j11.jar
new file mode 100644 (file)
index 0000000..53e50c6
Binary files /dev/null and b/swingjs/ver/3.3.1-j11/net.sf.j2s.core-j11.jar differ
diff --git a/swingjs/ver/3.3.1-j11/timestamp b/swingjs/ver/3.3.1-j11/timestamp
new file mode 100644 (file)
index 0000000..9b5ac4e
--- /dev/null
@@ -0,0 +1 @@
+20210208070817 
diff --git a/swingjs/ver/3.3.1/DEV_NOTES.txt b/swingjs/ver/3.3.1/DEV_NOTES.txt
new file mode 100644 (file)
index 0000000..751d81c
--- /dev/null
@@ -0,0 +1,10 @@
+This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
+
+_j2sclasslist.txt 
+
+the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
+
+
+SwingJS-site.zip
+
+the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.3.1/SwingJS-site.zip b/swingjs/ver/3.3.1/SwingJS-site.zip
new file mode 100644 (file)
index 0000000..f6fdabe
Binary files /dev/null and b/swingjs/ver/3.3.1/SwingJS-site.zip differ
diff --git a/swingjs/ver/3.3.1/_j2sclasslist.txt b/swingjs/ver/3.3.1/_j2sclasslist.txt
new file mode 100644 (file)
index 0000000..076f300
--- /dev/null
@@ -0,0 +1,412 @@
+java/applet/Applet.js
+java/applet/AppletContext.js
+java/applet/AppletStub.js
+java/applet/JSApplet.js
+java/awt/ActiveEvent.js
+java/awt/Adjustable.js
+java/awt/AWTEvent.js
+java/awt/AWTEventMulticaster.js
+java/awt/AWTKeyStroke.js
+java/awt/BasicStroke.js
+java/awt/BorderLayout.js
+java/awt/Button.js
+java/awt/Color.js
+java/awt/color/ColorSpace.js
+java/awt/Component.js
+java/awt/ComponentOrientation.js
+java/awt/ContainerOrderFocusTraversalPolicy.js
+java/awt/Container.js
+java/awt/Cursor.js
+java/awt/DefaultFocusTraversalPolicy.js
+java/awt/DefaultKeyboardFocusManager.js
+java/awt/Dialog.js
+java/awt/Dimension.js
+java/awt/dnd/peer/DropTargetPeer.js
+java/awt/event/ActionListener.js
+java/awt/event/AdjustmentEvent.js
+java/awt/event/AdjustmentListener.js
+java/awt/event/AWTEventListener.js
+java/awt/event/ComponentAdapter.js
+java/awt/event/ComponentEvent.js
+java/awt/event/ComponentListener.js
+java/awt/event/ContainerListener.js
+java/awt/event/FocusEvent.js
+java/awt/event/FocusListener.js
+java/awt/event/HierarchyBoundsListener.js
+java/awt/event/HierarchyListener.js
+java/awt/event/InputEvent.js
+java/awt/event/InputMethodListener.js
+java/awt/event/InvocationEvent.js
+java/awt/event/ItemEvent.js
+java/awt/event/ItemListener.js
+java/awt/event/KeyListener.js
+java/awt/event/MouseEvent.js
+java/awt/event/MouseListener.js
+java/awt/event/MouseMotionListener.js
+java/awt/event/MouseWheelListener.js
+java/awt/event/TextListener.js
+java/awt/event/WindowAdapter.js
+java/awt/event/WindowEvent.js
+java/awt/event/WindowFocusListener.js
+java/awt/event/WindowListener.js
+java/awt/event/WindowStateListener.js
+java/awt/EventDispatchThread.js
+java/awt/EventFilter.js
+java/awt/EventQueue.js
+java/awt/EventQueueItem.js
+java/awt/FlowLayout.js
+java/awt/FocusTraversalPolicy.js
+java/awt/Font.js
+java/awt/font/FontRenderContext.js
+java/awt/FontMetrics.js
+java/awt/Frame.js
+java/awt/geom/AffineTransform.js
+java/awt/geom/Dimension2D.js
+java/awt/geom/Path2D.js
+java/awt/geom/PathIterator.js
+java/awt/geom/Point2D.js
+java/awt/geom/Rectangle2D.js
+java/awt/geom/RectangularShape.js
+java/awt/geom/RectIterator.js
+java/awt/GraphicsCallback.js
+java/awt/GraphicsConfiguration.js
+java/awt/GraphicsDevice.js
+java/awt/GraphicsEnvironment.js
+java/awt/Image.js
+java/awt/image/ImageObserver.js
+java/awt/Insets.js
+java/awt/ItemSelectable.js
+java/awt/JSComponent.js
+java/awt/JSDialog.js
+java/awt/JSFrame.js
+java/awt/JSPanel.js
+java/awt/KeyboardFocusManager.js
+java/awt/KeyEventDispatcher.js
+java/awt/KeyEventPostProcessor.js
+java/awt/Label.js
+java/awt/LayoutManager.js
+java/awt/LayoutManager2.js
+java/awt/LightweightDispatcher.js
+java/awt/Paint.js
+java/awt/Panel.js
+java/awt/peer/ComponentPeer.js
+java/awt/peer/ContainerPeer.js
+java/awt/peer/FramePeer.js
+java/awt/peer/KeyboardFocusManagerPeer.js
+java/awt/peer/LightweightPeer.js
+java/awt/peer/WindowPeer.js
+java/awt/Point.js
+java/awt/Queue.js
+java/awt/Rectangle.js
+java/awt/RenderingHints.js
+java/awt/Scrollbar.js
+java/awt/ScrollPane.js
+java/awt/Shape.js
+java/awt/Stroke.js
+java/awt/TextArea.js
+java/awt/TextComponent.js
+java/awt/TextField.js
+java/awt/Toolkit.js
+java/awt/Transparency.js
+java/awt/Window.js
+java/beans/ChangeListenerMap.js
+java/beans/PropertyChangeEvent.js
+java/beans/PropertyChangeListener.js
+java/beans/PropertyChangeSupport.js
+java/lang/AbstractStringBuilder.js
+java/lang/Class.js
+java/lang/Enum.js
+java/lang/Iterable.js
+java/lang/reflect/Constructor.js
+java/lang/reflect/Method.js
+java/lang/StringBuffer.js
+java/lang/StringBuilder.js
+java/lang/Thread.js
+java/lang/ThreadGroup.js
+java/math/RoundingMode.js
+java/net/URL.js
+java/net/URLStreamHandlerFactory.js
+java/net/HttpURLConnection.js
+java/net/URLStreamHandler.js
+javax/net/ssl/HttpsUrlConnection.js
+java/text/CharacterIterator.js
+java/text/DecimalFormat.js
+java/text/DecimalFormatSymbols.js
+java/text/DigitList.js
+java/text/FieldPosition.js
+java/text/Format.js
+java/text/NumberFormat.js
+java/util/AbstractCollection.js
+java/util/AbstractList.js
+java/util/AbstractMap.js
+java/util/AbstractSequentialList.js
+java/util/AbstractSet.js
+java/util/ArrayList.js
+java/util/Arrays.js
+java/util/Collection.js
+java/util/Collections.js
+java/util/Comparator.js
+java/util/Deque.js
+java/util/Dictionary.js
+java/util/Enumeration.js
+java/util/EventListener.js
+java/util/EventObject.js
+java/util/HashMap.js
+java/util/HashSet.js
+java/util/Hashtable.js
+java/util/IdentityHashMap.js
+java/util/Iterator.js
+java/util/LinkedHashMap.js
+java/util/LinkedList.js
+java/util/List.js
+java/util/ListResourceBundle.js
+java/util/Locale.js
+java/util/Map.js
+java/util/Objects.js
+java/util/Queue.js
+java/util/Random.js
+java/util/RandomAccess.js
+java/util/ResourceBundle.js
+java/util/Set.js
+java/util/TimSort.js
+java/util/Vector.js
+javajs/api/JSFunction.js
+javajs/util/AjaxURLConnection.js
+javajs/util/AjaxURLStreamHandlerFactory.js
+javajs/util/AU.js
+javajs/util/JSThread.js
+javajs/util/Lst.js
+javajs/util/PT.js
+javajs/util/Rdr.js
+javajs/util/SB.js
+javax/swing/AbstractAction.js
+javax/swing/AbstractButton.js
+javax/swing/AbstractListModel.js
+javax/swing/Action.js
+javax/swing/ActionMap.js
+javax/swing/AncestorNotifier.js
+javax/swing/ArrayTable.js
+javax/swing/border/AbstractBorder.js
+javax/swing/border/BevelBorder.js
+javax/swing/border/Border.js
+javax/swing/border/CompoundBorder.js
+javax/swing/border/EmptyBorder.js
+javax/swing/border/EtchedBorder.js
+javax/swing/border/LineBorder.js
+javax/swing/border/TitledBorder.js
+javax/swing/BorderFactory.js
+javax/swing/BoundedRangeModel.js
+javax/swing/BoxLayout.js
+javax/swing/ButtonGroup.js
+javax/swing/ButtonModel.js
+javax/swing/ClientPropertyKey.js
+javax/swing/ComboBoxModel.js
+javax/swing/DefaultBoundedRangeModel.js
+javax/swing/DefaultButtonModel.js
+javax/swing/DefaultComboBoxModel.js
+javax/swing/DefaultSingleSelectionModel.js
+javax/swing/DropMode.js
+javax/swing/event/AncestorEvent.js
+javax/swing/event/AncestorListener.js
+javax/swing/event/CaretEvent.js
+javax/swing/event/CaretListener.js
+javax/swing/event/ChangeEvent.js
+javax/swing/event/ChangeListener.js
+javax/swing/event/DocumentEvent.js
+javax/swing/event/DocumentListener.js
+javax/swing/event/EventListenerList.js
+javax/swing/event/ListDataEvent.js
+javax/swing/event/ListDataListener.js
+javax/swing/event/UndoableEditEvent.js
+javax/swing/event/UndoableEditListener.js
+javax/swing/FocusManager.js
+javax/swing/InternalFrameFocusTraversalPolicy.js
+javax/swing/LayoutComparator.js
+javax/swing/LayoutFocusTraversalPolicy.js
+javax/swing/SortingFocusTraversalPolicy.js
+javax/swing/SwingContainerOrderFocusTraversalPolicy.js
+javax/swing/SwingDefaultFocusTraversalPolicy.js
+javax/swing/Icon.js
+javax/swing/ImageIcon.js
+javax/swing/InputMap.js
+javax/swing/JApplet.js
+javax/swing/JButton.js
+javax/swing/JCheckBox.js
+javax/swing/JCheckBoxMenuItem.js
+javax/swing/JComboBox.js
+javax/swing/JComponent.js
+javax/swing/JFrame.js
+javax/swing/JLabel.js
+javax/swing/JLayeredPane.js
+javax/swing/JMenu.js
+javax/swing/JMenuBar.js
+javax/swing/JMenuItem.js
+javax/swing/JPanel.js
+javax/swing/JPopupMenu.js
+javax/swing/JRadioButtonMenuItem.js
+javax/swing/JRootPane.js
+javax/swing/JScrollBar.js
+javax/swing/JScrollPane.js
+javax/swing/JSeparator.js
+javax/swing/JTextArea.js
+javax/swing/JTextField.js
+javax/swing/JToggleButton.js
+javax/swing/JViewport.js
+javax/swing/KeyboardManager.js
+javax/swing/KeyStroke.js
+javax/swing/ListModel.js
+javax/swing/LookAndFeel.js
+javax/swing/MenuElement.js
+javax/swing/MutableComboBoxModel.js
+javax/swing/plaf/ActionMapUIResource.js
+javax/swing/plaf/basic/BasicBorders.js
+javax/swing/plaf/BorderUIResource.js
+javax/swing/plaf/ColorUIResource.js
+javax/swing/plaf/ComponentUI.js
+javax/swing/plaf/DimensionUIResource.js
+javax/swing/plaf/FontUIResource.js
+javax/swing/plaf/InputMapUIResource.js
+javax/swing/plaf/InsetsUIResource.js
+javax/swing/plaf/UIResource.js
+javax/swing/RepaintManager.js
+javax/swing/RootPaneContainer.js
+javax/swing/Scrollable.js
+javax/swing/ScrollPaneConstants.js
+javax/swing/ScrollPaneLayout.js
+javax/swing/SingleSelectionModel.js
+javax/swing/SizeRequirements.js
+javax/swing/SwingConstants.js
+javax/swing/SwingPaintEventDispatcher.js
+javax/swing/SwingUtilities.js
+javax/swing/text/AbstractDocument.js
+javax/swing/text/AttributeSet.js
+javax/swing/text/Caret.js
+javax/swing/text/DefaultCaret.js
+javax/swing/text/DefaultEditorKit.js
+javax/swing/text/Document.js
+javax/swing/text/EditorKit.js
+javax/swing/text/Element.js
+javax/swing/text/GapContent.js
+javax/swing/text/GapVector.js
+javax/swing/text/JTextComponent.js
+javax/swing/text/MutableAttributeSet.js
+javax/swing/text/PlainDocument.js
+javax/swing/text/PlainView.js
+javax/swing/text/Position.js
+javax/swing/text/Segment.js
+javax/swing/text/SegmentCache.js
+javax/swing/text/SimpleAttributeSet.js
+javax/swing/text/Style.js
+javax/swing/text/StyleConstants.js
+javax/swing/text/StyleContext.js
+javax/swing/text/TabExpander.js
+javax/swing/text/TextAction.js
+javax/swing/text/Utilities.js
+javax/swing/text/View.js
+javax/swing/tree/TreeNode.js
+javax/swing/UIDefaults.js
+javax/swing/UIManager.js
+javax/swing/undo/AbstractUndoableEdit.js
+javax/swing/undo/CompoundEdit.js
+javax/swing/undo/UndoableEdit.js
+javax/swing/ViewportLayout.js
+javax/swing/WindowConstants.js
+sun/awt/AppContext.js
+sun/awt/AWTAutoShutdown.js
+sun/awt/CausedFocusEvent.js
+sun/awt/ComponentFactory.js
+sun/awt/KeyboardFocusManagerPeerProvider.js
+sun/awt/MostRecentKeyValue.js
+sun/awt/MostRecentThreadAppContext.js
+sun/awt/PaintEventDispatcher.js
+sun/awt/PostEventQueue.js
+sun/awt/RequestFocusController.js
+sun/awt/SunToolkit.js
+sun/awt/WindowClosingListener.js
+sun/awt/WindowClosingSupport.js
+sun/awt/image/DataStealer.js
+sun/awt/image/IntegerComponentRaster.js
+sun/awt/image/IntegerInterleavedRaster.js
+sun/awt/image/SunWritableRaster.js
+sun/font/FontDesignMetrics.js
+sun/swing/DefaultLookup.js
+sun/swing/SwingLazyValue.js
+sun/text/resources/FormatData.js
+sun/text/resources/en/FormatData_en.js
+sun/util/resources/LocaleData.js
+sun/util/locale/BaseLocale.js
+sun/util/locale/LocaleUtils.js
+sun/util/locale/provider/LocaleProviderAdapter.js
+sun/util/locale/provider/LocaleDataMetaInfo.js
+swingjs/a2s/A2SContainer.js
+swingjs/a2s/A2SEvent.js
+swingjs/a2s/A2SListener.js
+swingjs/a2s/Applet.js
+swingjs/a2s/Button.js
+swingjs/a2s/Label.js
+swingjs/a2s/Panel.js
+swingjs/a2s/Scrollbar.js
+swingjs/a2s/ScrollPane.js
+swingjs/a2s/TextArea.js
+swingjs/a2s/TextField.js
+swingjs/api/Interface.js
+swingjs/api/js/DOMNode.js
+swingjs/api/js/HTML5CanvasContext2D.js
+swingjs/api/js/JSInterface.js
+swingjs/jquery/JQueryUI.js
+swingjs/JSApp.js
+swingjs/JSAppletThread.js
+swingjs/JSAppletViewer.js
+swingjs/JSFocusPeer.js
+swingjs/JSFontMetrics.js
+swingjs/JSFrameViewer.js
+swingjs/JSGraphics2D.js
+swingjs/JSGraphicsConfiguration.js
+swingjs/JSGraphicsEnvironment.js
+swingjs/JSImage.js
+swingjs/JSImagekit.js
+swingjs/JSMouse.js
+swingjs/JSNullComponentPeer.js
+swingjs/JSScreenDevice.js
+swingjs/JSThreadGroup.js
+swingjs/JSToolkit.js
+swingjs/JSUtil.js
+swingjs/plaf/ButtonListener.js
+swingjs/plaf/DefaultMenuLayout.js
+swingjs/plaf/HTML5LookAndFeel.js
+swingjs/plaf/JSAppletUI.js
+swingjs/plaf/JSButtonUI.js
+swingjs/plaf/JSCheckBoxMenuItemUI.js
+swingjs/plaf/JSCheckBoxUI.js
+swingjs/plaf/JSComboBoxUI.js
+swingjs/plaf/JSComponentUI.js
+swingjs/plaf/JSEventHandler.js
+swingjs/plaf/JSFrameUI.js
+swingjs/plaf/JSGraphicsUtils.js
+swingjs/plaf/JSLabelUI.js
+swingjs/plaf/JSLayeredPaneUI.js
+swingjs/plaf/JSLightweightUI.js
+swingjs/plaf/JSMenuBarUI.js
+swingjs/plaf/JSMenuItemUI.js
+swingjs/plaf/JSMenuUI.js
+swingjs/plaf/JSPanelUI.js
+swingjs/plaf/JSPopupMenuSeparatorUI.js
+swingjs/plaf/JSPopupMenuUI.js
+swingjs/plaf/JSRadioButtonMenuItemUI.js
+swingjs/plaf/JSRadioButtonUI.js
+swingjs/plaf/JSRootPaneUI.js
+swingjs/plaf/JSScrollBarUI.js
+swingjs/plaf/JSScrollPaneUI.js
+swingjs/plaf/JSSeparatorUI.js
+swingjs/plaf/JSSliderUI.js
+swingjs/plaf/JSTextAreaUI.js
+swingjs/plaf/JSTextFieldUI.js
+swingjs/plaf/JSTextUI.js
+swingjs/plaf/JSTextViewUI.js
+swingjs/plaf/JSViewportUI.js
+swingjs/plaf/JSWindowUI.js
+swingjs/plaf/LazyActionMap.js
+swingjs/plaf/Resizer.js
+swingjs/plaf/TextListener.js
+
+
diff --git a/swingjs/ver/3.3.1/differences.txt b/swingjs/ver/3.3.1/differences.txt
new file mode 100644 (file)
index 0000000..c9ec027
--- /dev/null
@@ -0,0 +1,1526 @@
+java2script/SwingJS Notes
+=========================
+
+updated 12/31/2020 -- full support for 64-bit long
+updated 12/6/2020 -- note about restrictions on long, including BitSet and Scanner
+updated 3/21/2020 -- adds note about HashMap, Hashtable, and HashSet iterator ordering
+updated 3/20/2020 -- adds note about interning, new String("xxx"), and "xxx"
+updated 2/26/2020 -- adds Graphics.setClip issue
+updated 12/22/19 -- additional issues
+updated 11/03/19 -- adds information about File.exists() and points to src/javajs/async
+updated 10/26/19 -- adds information about File.createTempFile()
+updated 8/16/19 -- minor typos and added summary paragraph
+updated 7/19/19 -- clarification that AWT and Swing classes are supported directly
+updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long
+updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages
+updated 1/4/19 -- nio
+updated 9/15/18 -- adds integer 1/0 == Infinity
+updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk
+updated 6/5/17 -- reserved package name "window"
+updated 3/11/17 -- myClass.getField
+updated 3/7/17 -- overloading of JSplitPane.setDividerLocation
+updated 3/2/17 -- more indication of classes not implemented (KeyListener)
+
+---IMPORTANT CHARACTER SET NOTE---
+
+It is critical that all development work in Java2Script be done in UTF-8. This means:
+
+- making sure your Eclipse project is set up for UTF-8 (not the Eclipse default?)
+- making sure your server can serve up UTF-8 by default for any browser-loaded files
+- making sure you don't edit a Java2Script class file or one of the site .js files
+    using a non-UTF-8 editor. It may replace non-Latin characters with "?" or garbage.
+- making sure that your web pages are delivered with proper headings indicating HTML5 and UTF-8
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+
+Note that the DOCTYPE tag is critical for some browsers to switch into HTML5 mode. (MSIE?)
+
+
+In particular, the Mandarin character ç§˜ (mi; "secret") is used extensively throughout
+the SwingJS class files to distinguish j2s-specific fields and methods that must not 
+ever be shadowed or overridden by subclasses. For example, we see in java.lang.Thread.java:
+
+               public static JSThread ç§˜thisThread;
+
+----------------------------------
+
+
+
+=============================================================================
+SwingJS and OpenJDK 8+
+=============================================================================
+
+SwingJS implements a wide range of the Java language in JavaScript. The base
+version for this implementation is OpenJDK8. some classes are implemented using 
+older source code, and there are some missing methods. For the most part, this is 
+no real problem. You can add or modify any java class just be adding it as source
+in your project. Or (preferably) you can contact me, and I can get it into the 
+distribution. Or (even more preferably) you can do that via a patch submission. 
+
+=================
+DESIGN PHILOSOPHY
+=================
+
+The java2script/SwingJS design goal is to recreate a recognizable, easily debuggable
+equivalent in JavaScript for as much of Java as practical. This means, for example, 
+that one can call in JavaScript 
+
+  new java.util.Hashtable()
+  
+and for all practical purposes it will appear that Java is running.
+
+The goal of java2script/SwingJS is NOT to reproduce Java byte code processing in a 
+browser. We leave that task and its own issues to others. Here, instead, we have a 
+working JavaScript version of the Java classes along with runtime assistance in the
+j2sClazz.js library. This design has several advantages:
+
+ 1) It leads to much smaller downloads, since the class loader can dynamically load
+    code at the class level. 
+    
+ 2) It allow the browser to use its own optimizations and features, not to ignore those. 
+    This leads to huge performance gains and in many cases much simpler coding.
+ 3) It allows for in-browser debugging and analysis. 
+ 4) It allows for code switching between Java and JavaScript. Working Java code 
+    can be annotated (@j2sNative, @j2sAlias, @j2sIgnore) in a fashion that 
+    allows the code to run slightly differently in a Java than a JavaScript environment.
+    For example:
+    
+       int delayMS = /** @j2sNative 10 ||*/2;
+    
+    will read "var delayMS = 10 || 2;"  (i.e. 10) in JavaScript but read by the Java
+    compiler as "int delayMS = 2". 
+    
+ 5) Just generally, it allows for a much more integrated environment. JavaScript on
+    the page can call into any SwingJS program, and, likewise, any SwingJS code can 
+    access anything on the page.    
+
+
+Method and Field Disambiguation
+-------------------------------
+
+This is no problem. SwingJS has no problem with the overloading of methods, for example:
+
+  public void print(int b);
+  public void print(float b);
+
+JavaScript does not allow overloading of methods, and the common practice in
+Java of naming a field the same as a method -- isAllowed and isAllowed() -- is
+not possible in JavaScript. As a result, SwingJS implements "fully-qualified" 
+method names using "$" parameter type separation. Thus, these methods in SwingJS
+will be referred to as print$I and print$F. The rules for this encoding are
+relatively simple: 
+
+1. The seven primitive types in Java are encoded $I (int), $L (long), $F (float), 
+$D (double), $B (byte) $Z (boolean), and $H (short). 
+
+2. String and Object are encoded as $S and $O, respectively.
+
+3. "java_lang_" is dropped for all other classes in the java.lang package (as in Java).
+   For example:  $StringBuffer, not $java_lang_StringBuffer
+
+4. All other classes are encoded as 
+
+ "$" + Class.getName().replace(".","_")
+
+For example, in Java we see:
+
+  public void equals(Object o) {...}
+
+Whereas in SwingJS we have:
+
+  Clazz.newMeth(C$, 'equals$O', function (o) {...}
+
+And 
+
+ this.getContentPane().add(bar, "North");
+
+becomes
+
+ this.getContentPane$().add$java_awt_Component$O(bar, "North");
+
+5. Arrays are indicated with appended "A" for each level. So
+
+  setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
+  
+becomes
+
+  setDataVector$OAA$OA(dataVector, columnIdentifiers)
+
+(It is recognized that this design does introduce a bit of ambiguity, in that
+ in principal there could be user class named XA and X in the same package,
+ and methods a(X[]) and a(XA) in the same class that cannot be distinguished.
+ The benefit of this simple system, however, triumphed over the unlikelyhood
+ of that scenario.) The transpiler could be set to flag this possibility.
+
+6. Constructors are prepended with "c$". So 
+
+  public JLabel(String text) {...}
+  
+becomes:
+
+  Clazz.newMeth(C$, 'c$$S', function (text) {...});
+
+Field disambiguation involves prepending. 
+
+In Java, a class and its subclass can both have the same field name, such as 
+
+ boolean visible;
+When this happens, it is called "shadowing", and though not recommended, Java allows
+it. The Java2Script transpiler will prepend such shadowing fields with "$" so that the
+subclass instance has both "visible" (for use in its methods inherited from its
+superclass) and "$visible" (for its own methods). Thus, we might see in Java:
+
+  this.visible = super.visible;
+  
+while in SwingJS we will see:
+
+  this.$visible=this.visible;
+
+since JavaScript does not have the "super" keyword.
+
+Parameterless methods such as toString() are appended with "$" to become toString$().
+The one exception to this rule is private methods, which are saved in (truly) private 
+array in the class (and are not accessible by reflection). Private parameterless 
+methods retain their simple Java name, since they cannot conflict with field names.
+
+This renaming of methods has a few consequences, which are discussed more fully below.
+See particularly the section on "qualified field and method names", where it is described
+how you can use packages or classes or interfaces with ".api.js" in them to represent JavaScript
+objects for which all method names are to be left unqualified, and how individual methods
+can have more than one name using @j2sAlias. 
+
+The swingjs.api.js package in particular contains a number of useful interfaces that
+you can import into your project for JavaScript-specific capabilities.
+
+
+Applet vs. Application
+----------------------
+
+One of the very cool aspects of SwingJS is that it doesn't particularly matter if a browser-based
+Java app is an "applet" or an "application". We don't need JNLP (Java Network Launch Protocol) 
+because now we can just start up any Java application in a browser just as easily as any applet.
+The associative array that passes information to the SwingJS applet (information that formerly
+might have been part of the APPLET tag, such as width, height, and codebase, always referred to 
+in our writing as "the Info array") allows the option to specify the JApplet/Applet "code" 
+class or the application "main" class. Either one will run just fine.
+
+
+Performance
+-----------
+
+Obviously, there are limitations. One is performance, but we have seen reproducible 
+performance at 1/6 - 1/3 the speed of Java. Achieving this performance may require
+some refactoring of the Java to make it more efficient in both Java and JavaScript. 
+"for" loops need to be more carefully crafted; use of "new" and "instanceof" need to be
+minimized in critical areas. Note that method overloading -- that is, the same method name
+with different parameters, such as read(int) and read(byte) -- is no longer any problem.   
+
+Threads
+-------
+
+Although there is only a single thread in JavaScript, meaning Thread.wait(), Thread.sleep(int) and 
+Thread.notify() cannot be reproduced, we have found that this is not a serious limitation. 
+For example, javax.swing.Timer() works perfectly in JavaScript. All it means is that threads 
+that use sleep(int) or notify() must be refactored to allow Timer-like callbacks. That is, 
+they must allow full exit and re-entry of Thread.run(), not the typical while/sleep motif. 
+
+The key is to create a state-based run() that can be exited and re-entered in JavaScript.
+
+The javajs.async package can be added to any Java program to provide Java+JavaScript asynchronous
+classes, including AsyncColorChooser, AsyncDialog, AsyncFileChooser, and AsyncSwingWorker. All
+of these classes work just as well in Java as in JavaScript. There is no need to run them 
+only when in JavaScript.
+
+Static fields
+-------------
+
+Final static primitive "constant" fields (String, boolean, int, etc.) such as 
+
+static final int TEST = 3;
+static final String MY_STRING = "my " + "string";
+
+are converted to their primitive form automatically by the Eclipse Java compiler 
+and do not appear in the JavaScript by their names. 
+
+Other static fields are properties of their class and can be used as expected.
+
+Note, however, that SwingJS runs all "Java" code on a page in a common "jvm" 
+(like older versions of Java). So, like the older Java schema, the JavaScript 
+equivalents of both applets and applications will share all of their static 
+fields and methods. This includes java.lang.System. 
+
+Basically, SwingJS implementations of Java run in a browser page-based sandbox 
+instead of an applet-specific one.
+
+In general, this is no problem. But if we are to implement pages with 
+multiple applets present, we must be sure to only have static references 
+that are "final" or specifically meant to be shared in a JavaScript 
+environment only (since they will not be shared in Java).
+
+A simple solution, if static non-constant references are needed, is to attach the 
+field to Thread.currentThread.threadGroup(), which is an applet-specific reference.
+Be sure, if you do this, that you use explicit setters and getters:
+
+For example, 
+
+private static String myvar;
+
+...
+
+public void setMyVar(String x) {
+  ThreadGroup g = Thread.currentThread().threadGroup();
+  /**
+   * @j2sNative g._myvar = x;
+   * 
+   */
+   {
+     myvar = x;
+   }
+}
+
+public String getMyVar() {
+  ThreadGroup g = Thread.currentThread().threadGroup();
+  /**
+   * @j2sNative return g._myvar || null;
+   * 
+   */
+   {
+     return myvar;
+   }
+}
+ in Java will get and set x the same in JavaScript and in Java. 
+A convenient way to do this in general is to supply a singleton class with
+explicitly private-only constructors and then refer to it in Java and in JavaScript
+instead of using static field, referring to myclass.getIntance().xxx instead of 
+myclass.xxx in Java (and JavaScript). 
+
+This was done extensively in the Jalview project. See jalview.bin.Instance.
+
+
+Helper Packages -- swingjs/ and javajs/
+---------------------------------------
+
+The SwingJS library is the swingjs/ package. There are interfaces that may be of assistance
+in swingjs/api, but other than that, it is not recommended that developers access classes in 
+this package. The "public" nature of their methods is really an internal necessity. Most access 
+to this package in working Java should be via the swingjs.api.JSUtilI interface.
+
+In addition to swingjs/, though, there are several useful classes in the javajs/ package
+that could be very useful. This package is a stand-alone package that can be 
+cloned in any Java project that also would be great to have in any JavaScript project
+-- SwingJS-related or not. Functionality ranges from reading and writing various file 
+formats, including PDF, BMP, PNG, GIF, JPG, JSON, ZIP, and CompoundDocument formats.
+
+A variety of highly efficient three- and four-dimensional point, vector, matrix, and 
+quaternion classes are included, as they were developed for JSmol and inherited from that
+project. 
+
+Of particular interest should be javajs/async/, which includes
+
+javajs.async.Async
+javajs.async.AsyncColorChooser
+javajs.async.AsyncDialog
+javajs.async.AsyncFileChooser
+
+See javajs.async.Async JavaDoc comments for a full description of 
+these useful classes.
+
+
+Modal Dialogs
+-------------
+
+Although true modal dialogs are not possible with only one thread, a functional equivalent -- 
+asynchronous modal dialogs -- is relatively easy to set up. All the JOptionPane dialogs will
+return PropertyChangeEvents to signal that they have been disposed of and containing the results. 
+See below and classes in the javajs.async package.
+
+
+Native calls
+------------
+
+Native calls in Java are calls to operating system methods that are not in Java. JavaScript
+has no access to these, of course, and they must all be replaced by JavaScript equivalents.
+Fortunately, they are not common, and those that are present in Java (for example, in calculating
+checksums in ZIP file creation) are at a low enough level that most developers do not utilize them
+or do not even have access to them. All native calls in Java classes have been replaced by 
+Java or JavaScript equivalents.
+
+
+Swing GUI Peers and UIClasses
+-----------------------------
+
+One of the biggest adaptations introduced in SwingJS is in the area of the graphical 
+user interface. Basically, what we have is a Java Swing "LookAndFeel" customized for HTML.
+
+The issue here is complex but workable. In Java there are two background concepts -- the 
+Component "peer" (one per "heavy-weight" component, such as a Frame) and the 
+component "uiClass" (one per component, such as BasicButtonUI or BasicTextFieldUI).
+
+Peers are native objects of the operating system. These are the virtual buttons and text areas
+that the user is interacting with at a very base level. They are chunks of low-level code that
+paint the screen to give the illusion that you really are pressing a button or typing text 
+ot the screen. Their events are being passed on to Java or the browser by the operating system. 
+
+UI classes provide a consistent "look and feel" for these native objects, rendering them onto 
+the native window canvas and handling all user-generated events. They paint the borders, 
+the backgrounds, the highlights, of every control you see in Java. There is one-to-one 
+correspondence of Swing classes and UI classes. Setting the Look and Feel for a project amounts 
+to selecting the directory from which to draw these UI classes. Java's UI class interfaces can
+be found in the javax.swing.plaf ("platform look and feel") package. Individual look and feel
+implementations are found in sun.plaf.basic, sun.plaf.metal, and other such specialized packages.
+
+Early on in the development of SwingJS, we decided not to fully reproduce the painfully detailed 
+bit-by-bit painting of controls as is done in Java. Instead, we felt it was wiser to utilize the standard
+HTML5 UI capabilities as much as possible, using DIV, and INPUT especially, with extensive use
+of CSS and sometimes jQuery (menus, and sliders, for example). Thus, we have created a new 
+set of UIs -- the "HTML5 Look and Feel". These classes can be found in swingjs.plaf. Besides being
+more adaptable, this approach allows far more versatility to SwingJS developers, allowing them
+to modify the GUI to suit their needs if desired.
+
+In SwingJS, since we have no access to native peers except through the browser DOM,
+it seemed logical to merge the peer and UI idea. So instead of having one peer per heavy-weight control and
+one UI class instance for each control type, we just have one UI class instance per control, and
+that UI class instance is what is being referred to when a "peer" is notified. 
+
+In some ways this is a throw back to when all of Swing's components were subclasses of
+specific AWT components such as Button and List. These "heavy-weight components" all had their 
+own individual native peers and thus automatically took on the look and feel provided by the OS. 
+Later Swing versions implemented full look and feel for all peers, leaving only JDialog, JFrame,
+and a few other classes to have native peers. But in SwingJS we have again a 1:1 map of component
+and UI class/peer instance.
+
+The origin of most issues (read "bugs") in relation to the GUI will probably be found in the
+swingjs.plaf JSxxxxUI.java code.
+
+  
+Swing-only Components -- no longer an issue
+-------------------------------------------
+
+Swing was introduced into Java well after the Java Abstract Window Toolkit (AWT) was well
+established. As such, its designers chose to allow AWT controls such as Button and List to be used 
+alongside their Swing counterparts JButton and JList. Reading the code, it is clear that this 
+design choice posed a huge headache for Swing class developers. 
+
+For SwingJS, we decided from the beginning NOT to allow this mixed-mode programming and 
+instead to require that all components be Swing components. However, this is not really an
+issue. We have reconfigured the class relationships a bit. In SwingJS, all AWT components
+are now subclasses of javax.swing.JComponent. While this might seem error prone, so far we have 
+found no problem with this arrangement. It's a little surprising to me that the original developers
+of Swing did not think of this.
+
+The a2s Adapter Package
+-----------------------
+
+Originally, we thought that we would restrict ourselves to JApplets only. That is, only
+Swing-based applets. But as we worked, we discovered that there are a lot of great 
+applets out there that are pre-Swing pure-AWT java.applet.Applet applets. Our problem was 
+that we also wanted it to be possible to quickly adapt these applets to JavaScript as well.
+The solution turned out to be simple: Write a package (a2s) that recreates the interface for 
+non-Swing components as subclasses of Swing components. Thus, a2s.Button subclasses javax.swing.JButton
+but also accepts all of the methods of java.awt.Button. This works amazingly well, with a few
+special adaptations to the core javax.swing to be "AWT-aware." 
+
+Then, to tie it all togeter, all AWT components such as java.awt.Button now subclass their respective
+a2s components, which in turn subclass JComponents. So no changes in code are necessary. We have
+successfully transpiled over 500 applets using this strategy. 
+
+Working with Files
+==================
+
+Simple String file names are not optimal for passing information about
+files read by SwingJS applications. That is because just peeking at a file 
+in SwingJS will load its entire byte[] data. 
+Optimally, all work with files should either use Path or File objects exclusively. 
+These objects, after a file is read or checked for existence, will already 
+contain the file byte[] data. The string name can be used alone, since SwingJS will
+cache the files itself and not reload them -- just as the browser normally does.
+
+SwingJS uses the following criteria to determine if File.exists() returns true:
+
+(1) if this File object has been used directly to read data, or 
+(2) if reading data using this File object is successful.
+
+Note that you cannot check to see if a file exists before input or if it 
+was actually written or if it already exists prior to writing in SwingJS.  
+
+Thus, you should check each use of file.exists() carefully, and if necessary, provide a J2sNative 
+block that gives an appropriate "OK" message, for example:
+
+(/** @j2sNative 1 ? false : */ outputfile.exits())
+
+or 
+
+(/** @j2sNative 1 ? true : */ inputfile.exits())
+
+Temporary files can be created in SwingJS. SwingJS will maintain a pseudo-filesystem for files 
+created with File.createTempFile(). This is useful in that closure of writing to a temporary file 
+does not generate a pseudo-download to the user's machine. Temporary files will be placed in the 
+"/TEMP/" directory, as seen from the running Java program. Any file written to this directory will
+simply be stored in memory; files written to any other directory, when closed, will appear to the 
+user as a download, often involving a "What do you want to do with this file" dialog. 
+
+
+See below for details relating to each of the subjects below:
+
+
+UNIMPLEMENTED CLASSES BY DESIGN
+===============================
+
+The SwingJS implementation of the following classes are present 
+in a way that gracefully bypasses their functionality:
+
+accessibility
+security
+serialization
+
+
+
+TODO LIST FOR UNIMPLEMENTED CLASSES
+===================================
+
+none as of 2020.12.31. Source code for classes and methods missing
+from Java 8 or from Java 9+ can be inserted by any developer along 
+with their running code source, and they should run.  
+
+
+MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
+================================================================
+
+Thread.currentThread() == dispatchThread
+
+
+MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
+=====================================================================
+
+See below for a full discussion.
+
+primitive type restrictions - int, long, and float
+HashMap, Hashtable, and HashSet iterator ordering
+interning, new String("xxx") vs "xxx"
+Names with "$" and "_"
+ArrayIndexOutOfBounds
+java.awt.Color
+native methods
+javax.swing.JFileDialog
+key focus
+LookAndFeel and UI Classes
+System.exit(0) does not stop all processes
+list cell renderers must be JComponents
+myClass.getField not implemented
+"window" and other reserved JavaScript names
+reserved field and method names
+qualified field and method names
+Component.getGraphics(), Graphics.dispose()
+Graphics.setClip()
+
+MAJOR ISSUES--for Bob and Udo within SwingJS
+============================================
+
+fonts
+OS-dependent classes
+AWT component peers
+some aspects of reflection
+
+MAJOR ISSUES--to be resolved by implementers
+============================================
+
+fonts
+threads
+modal dialogs
+image loading
+no format internationalization
+Graphics2D: missing winding rules
+text-related field implementation
+Formatter/Regex limitations
+
+======================================================================== 
+
+DISCUSS
+=======
+
+Table row/col sorter needs checking after removal of java.text.Collator references
+
+========================================================================== 
+
+//////////////////////////////////////////////////////////////////////////////
+
+UNIMPLEMENTED CLASSES
+=====================
+
+accessibility
+-------------
+
+All Accessibility handling has been commented out to save the download footprint.
+This removes the need for sun.misc.SharedSecrets as well. 
+Nothing says we could not implement accessibility. We just didn't.
+
+
+security
+--------
+
+All JavaScript security is handled by the browser natively. 
+Thus, Java security checking is no longer necessary, and 
+java.security.AccessController has been simplified to work without
+native security checking.
+
+Note that private methods in a class are REALLY private. 
+
+
+serialization
+-------------
+
+All serialization has been removed. It was never very useful for Swing anyway, 
+because one needs exactly the same Java version to save and restore serialized objects.
+
+
+keyboard accelerators and mnemonics
+-----------------------------------
+
+This work was completed in the spring of 2019. Note that in a browser, some 
+key strokes, particularly CTRL-keys, are not available. Bummer.
+
+
+MINOR ISSUES--required some rewriting/refactoring by Bob and Udo  
+================================================================
+
+
+Thread.currentThread() == dispatchThread
+----------------------------------------
+
+changed to JSToolkit.isDispatchThread()
+
+
+MINOR ISSUES--requiring some rewriting/refactoring outside of SwingJS  
+=====================================================================
+
+primitive restrictions - int, long, and float
+---------------------------------------------
+
+int
+
+For performance reasons, int addition and multiplication do not by default overflow to 
+negative values. Instead, they just get bigger. Java code that relies on overflow to 
+negative values should be surrounded by ()|0 -- an OR with integer 0:
+
+
+int bigI, bigJ;
+...
+
+bigI = (bigI + bigJ)|0;
+
+bigI = (bigI + 1)|0;   //instead of bigI++
+
+
+Thus, in Java, the following is true:
+
+  2000000000 + 2000000000 == -294967296
+
+But in SwingJS, that will be 4000000000. So, for example, the following
+strategy will fail in SwingJS:
+
+               int newLength = lineBuf.length * 2;
+               if (newLength < 0) {
+                       newLength = Integer.MAX_VALUE;
+               }
+
+This is because, generally, "-1" in JavaScript is not 0xFFFFFFFF. The simple ()|0 takes
+caes of this:
+
+               int newLength = (lineBuf.length * 2)|0;
+               if (newLength < 0) {
+                       newLength = Integer.MAX_VALUE;
+               }
+
+JavaScript does process bitwise operators & | ^ ~ properly for int values. There is no issue using
+these operations. 
+
+Note that int 1/0 in Java throws "java.lang.ArithmeticException: / by zero", but in JavaScript is just Infinity. 
+
+Importantly, the JavaScript Int32Array does behave properly. From the Firefox developer console:
+
+>> x = new Int32Array(1)
+<- Int32Array(1) [ 0 ]
+>> x[0] = 4000000000
+<- 4000000000
+>> x[0]
+<- -294967296
+
+Notice that, perhaps unexpectedly, the following two constructs produce 
+different results in JavaScript:
+
+x = new Int32Array(1);
+b = x[0] = 4000000000;
+
+(b will be 4000000000)
+
+and
+
+x = new Int32Array(1);
+x[0] = 4000000000;
+b = x[0];
+
+(b will be -294967296)
+
+
+SwingJS leverages array typing to handle all byte and short arithmetic so as
+to ensure that any byte or short operation in JavaScript does give the same 
+result in Java. 
+
+long
+
+Java's 64-bit long type is fully supported, starting with java2script 3.3.1 (2020.12.31)
+The transpiler handles all conversions to and from long appropriately. See the discussion
+at https://github.com/BobHanson/java2script/issues/202 for how this is done.
+
+float
+
+SwingJS does not distinguish between float and double. Everything is double.
+
+
+HashMap, Hashtable, and HashSet iterator ordering
+-------------------------------------------------
+
+In Java, iterators for HashMap, Hashtable, and HashSet do not guarantee any particular order. 
+From the HashMap documentation for Java 8:
+
+       This class makes no guarantees as to the order of the map; in particular, it does not 
+       guarantee that the order will remain constant over time.
+Likewise, for HashSet (because it is simply a convenience method for HashMap<Object,PRESENT>:
+
+       [HashSet] makes no guarantees as to the iteration order of the set.
+
+JavaScript's Map object is different. It is basically a LinkedHashMap, so it guarantees iteration
+in order of object addition.
+
+Starting with java2script 3.2.9.v1, these classes use the JavaScript Map object rather than hash codes
+whenever all keys are strictly of JavaScript typeof "string". If any key is introduced that is not a string, the
+implementation falls back to using hash codes, the same as Java. 
+
+The result is significantly faster performance (3-12 x faster) than originally, and up to 3 x faster
+performance in JavaScript than in Java itself. That is not a misprint. Faster than Java. 
+
+The JavaScript Map implementation is implemented UNLESS the constructor used is the one that
+specifies both initial capacity and load factor in their constructor. Thus, 
+
+new Hashtable()
+new HashMap()
+new HashMap(16)
+new HashSet()
+
+all use the JavaScript Map. But
+
+new Hashtable(11, 0.75f)
+new HashMap(16, 0.75f)
+new HashSet(16, 0.75f)
+
+do not. 
+
+This design allows for opting out of the JavaScript Map use in order to retain the exact behavior of 
+iterators in JavaScript as in Java.
+
+
+interning, new String("xxx") vs "xxx"
+-------------------------------------
+
+Note that the following are true in JavaScript:
+
+typeof new String("xxxx") == "object"
+typeof "xxxx" == "string"
+var s = "x";typeof ("xxx" + s) == "string"
+
+There is no equivalence to this behavior in Java, where a String is a String is a String.
+
+Be aware that SwingJS does not always create a JavaScript String object using JavaScript's 
+new String(...) constructor. It only does this for Java new String("xxxx") or new String(new String()). 
+
+In all other cases, new String(...) (in Java) results in a simple "xxxx" string in JavaScript. 
+That is, it will be JavaScript typeof "string", not typeof "object". 
+
+The reason for this design is that several classes in the Java core use toString() 
+methods that return new String(), and those classes that do that would cause a JavaScript error
+if implicitly stringified if new String() returned a JavaScript String object. 
+
+This is fine in JavaScript:
+
+test1 = function() { return { toString:function(){ return "OK" } } }
+"testing" + new test1()
+>> "testingOK"
+
+But for whatever reason in JavaScript:
+
+test2 = function() { return { toString:function(){ return new String("OK") } } }
+"testing" + new test2()
+>> Uncaught TypeError: Cannot convert object to primitive value
+
+The lesson here is never to use 
+
+  return new String("...");
+
+in a Java toString() method. In Java it will be fine; in JavaScript it will also be fine as long as
+that method is never called in JavaScript implicitly in the context of string concatenation.
+
+A note about interning. Consider the following six Java constructions, where we have a == "x";
+
+"xxx"
+"xx" + "x"
+new String("xxx").intern()
+
+new String("xxx")
+"xx" + a.toString()
+"xx" + a
+
+All six of these will return java.lang.String for .getClass().getName().
+However, the first three are String literals, while the last three are String objects. 
+Thus:
+        "xxx" == "xxx"
+        "xxx" == "xx" + "x"
+        "xxx" == new String("xxx").intern()
+
+but none of the other three are equivalent to "xxx" or each other:
+
+              "xxx" != new String("xxx")
+              "xxx" != "xx" + a.toString()
+              "xxx" != "xx" + a
+  new String("xxx") != new String("xxx") 
+           "xx" + a != new String("xxx") 
+
+etc.
+
+As in Java, in SwingJS, all of the following Java assertions pass as true:
+
+               assert("xxx" == "xx" + "x"); 
+               assert("xxx" == ("xx" + a).intern()); 
+               assert("xxx" === new String("xxx").intern()); 
+               
+and both of these do as well:
+
+               assert(new String("xxx") != "xxx"); 
+               assert(new String("xxx") != new String("xxx")); 
+
+But the following two fail to assert true in SwingJS:
+
+        assert("xxx" != "xx" + a);
+        assert("xxx" != "xx" + a.toString());
+
+because, in JavaScript, both of these right-side expressions evaluate to a simple "interned" string.
+
+In Java, however, these assertions are true because Java implicitly "boxes" String 
+concatentaion as a String object, not a literal. 
+
+Most of us know not to generally use == with Strings unless they are explicitly interned. 
+Where this problem may arise, though, is in IdentityHashMap, which compares objects using 
+System.identityHashCode(), which is not the same for different objects or their string literal equivalents.
+
+My recommendation, if you need to use IdentityHashMap with strings is to always use an explicit String.intern()
+for any keys -- unless you really want to keep every string as separate keys even if they are the same sequence, 
+in which case, use new String(). This will work in Java and in JavaScript.
+
+Be aware when working with strings that come from SwingJS and are being used by other JavaScript modules
+that those that are String objects will return "object" for the JavaScript typeof operator, not "string".
+
+The easy way to ensure this is no problem is to concatenate strings with "" to force immediate interning:
+
+  var x = aJavaObject.getString() + "";
+
+unless you are certain that the string is being returned is a raw JavaScript string.   
+
+
+Names with "$" and "_"
+----------------------
+
+For the most part, this should be no problem. 
+
+Note that the use of $ and _ in Java field names has always been discouraged:
+[https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html]
+
+       You may find some situations where auto-generated names will contain the dollar sign, 
+       but your variable names should always avoid using it. A similar convention 
+       exists for the underscore character; while it's technically legal to begin your 
+       variable's name with "_", this practice is discouraged.
+
+Some impacts of transpiling method names with full qualification:
+
+1) SwingJS will introduce fields that start with $ or _. These will not conflict
+   if the above convention is followed.
+   
+2) Fields that have the same Java name as a method are not an issue. 
+
+3) Fields that have a Java name with $ that matches a transpiled method name, 
+   such as toString$, will need to be refactored in Java to not have that name collision.
+   
+4) Fields in a subclass that have the same name as private fields in a superclass
+   represent a name collision, because the superclass method needs to call its private
+   field even if invoked from a subclass. The solution was to modify the subclass field
+   name using one or more prepended $.
+   
+5) Use of Class.getDeclaredMethods() reflection will return Method objects having the transpiled 
+   name, not the Java name. This could require some j2sNative adjustment 
+   to strip the $... parameters from the name if that is needed. 
+
+6) Use of Method.getParameterTypes() should work fine, provided class names
+   do not contain "_". This is because the transpiler converts "." to "_" when
+   creating the fully qualified JavaScript name.
+
+
+ArrayIndexOutOfBounds
+---------------------
+
+You cannot implicitly throw an ArrayIndexOutOfBoundsException in JavaScript.
+JavaScript will simply return "undefined", not throw an Exception. So:
+
+boolean notAGoodIdeaIsOutOfBounds(String[] sa, int i) {
+  try {
+     return (sa[i] == sa[i]);
+  } catch (ArrayIndexOutOfBoundsException e) {
+       return false;
+  }
+}
+
+will work in Java but not in JavaScript. Code should not depend upon this sort 
+of trap anyway, if you ask me. 
+
+
+Throwable vs Error vs Exception
+-------------------------------
+
+True JavaScript errors are trapped as Throwable, whereas you can still trap
+Error and Exception as well. So if you want to be sure to catch any JavaScript
+error, use try{}catch (Throwable t){}, not try{}catch (Exception e){}. 
+
+java.awt.Color
+--------------
+
+ColorSpace: only "support" CS_sRGB.
+
+ TODO -- any volunteers??
+
+javax.swing.JFileDialog
+-----------------------
+
+HTML5 cannot expose a file reading directory structure. But you certainly 
+can still do file reading and writing. It just works a little differently.
+It's a simple modification:
+
+               b = new JButton("FileOpenDialog");
+               b.addActionListener(new ActionListener() {
+
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               JFileChooser fc = new JFileChooser();
+                               Test_Dialog.this.onDialogReturn(fc.showOpenDialog(Test_Dialog.this));
+                               // Java will wait until the dialog is closed, then enter the onDialogReturn method.
+                               // JavaScript will exit with NaN immediately, and then call back with its actual value
+                               // asynchronously.
+                       }
+
+               });
+       
+               public void onDialogReturn(int value) {
+                       if (value != Math.floor(value))
+                               return; // in JavaScript, this will be NaN, indicating the dialog has been opened
+                       // If we are here, the dialog has closed, in both Java and JavaScript.
+                       System.out.println("int value is " + value);
+               }
+
+
+       @Override
+       public void propertyChange(PropertyChangeEvent event) {
+               Object val = event.getNewValue();
+               String name = event.getPropertyName();
+               System.out.println(name);
+               switch (event.getSource().getClass().getName()) {
+               case "javax.swing.JOptionPane":
+                       switch (name) {
+                       case "inputValue":
+                               onDialogReturn(val);
+                               return;
+                       case "value":
+                               if (val instanceof Integer)
+                                       onDialogReturn(((Integer) val).intValue());
+                               else
+                                       onDialogReturn(val);
+                               return;
+                       }
+                       break;
+               case "javax.swing.ColorChooserDialog":
+                       switch (name) {
+                       case "SelectedColor":
+                               onDialogReturn(val);
+                               return;
+                       }
+                       break;
+               case "javax.swing.JFileChooser":
+                       switch (name) {
+                       case "SelectedFile":
+                               File file = (File) val;
+                               byte[] array = (val == null ? null : /** @j2sNative file.秘bytes || */
+                                               null);
+                               onDialogReturn("fileName is '" + file.getName() + "'\n\n" + new String(array));
+                               return;
+                       }
+                       break;
+               }
+               System.out.println(
+                               event.getSource().getClass().getName() + " " + event.getPropertyName() + ": " + event.getNewValue());
+       }
+
+
+Developers are encouraged to create a separate class that handles general calls to JFileDialog. 
+An example class can be found in the SwingJS distribution as 
+
+/sources/net.sf.j2s.java.core/src/javajs/async/AsyncFileChooser.java.
+
+
+javax.swing.JOptionPane dialogs
+-------------------------------
+
+For a full discussion of modal dialogs, see the javajs.asyc.AsyncDialog.java discussion.
+
+For this action to work, the parent component must implement
+propertyChangeListener, and any call to JOptionPanel should allow for
+an asynchronous response, meaning that there is no actionable code following the
+call to the dialog opening. 
+
+In addition, for compatibility with the Java version, implementation should
+wrap the call to getConfirmDialog or getOptionDialog in a method call to
+handle the Java:
+
+onDialogReturn(JOptionPane.showConfirmDialog(parentFrame,
+messageOrMessagePanel, "title", JOptionPane.OK_CANCEL_OPTION));
+
+Then parentFrame.propertyChange(event) should also call onDialogReturn.
+
+This will then work in both Java and JavaScript.
+
+Note that there is an int and an Object version of onDialogReturn().
+
+
+In JavaScript:
+
+The initial return from JOptionPane.showConfirmDialog and showMessageDialog
+will be (SwingJS) JDialog.ASYNCHRONOUS_INTEGER (NaN), testable as an impossible 
+Java int value using ret != -(-ret) if the parent implements PropertyChangeListener, or -1
+(CLOSE_OPTION) if not.
+
+For showOptionDialog (which returns Object) or showInputDialog (which returns
+String), the initial return will be (SwingJS) JDialog.ASYNCHRONOUS_OBJECT, testable as
+((Object) ret) instanceof javax.swing.plaf.UIResource if the parent implements
+PropertyChangeListeneer, or null if not.
+
+The second return will be the desired return.
+
+In Java:
+
+The initial return will be the one and only modal final return.
+
+
+
+For full compatibility, The calling method must not continue beyond this call.
+
+All of the standard Java events associated with Components are also available.
+
+Certain fall back mechanisms are possible, where onReturn does not exist, but
+only for the following cases:
+
+
+For showMessageDialog, for WARNING_MESSAGE and ERROR_MESSAGE, a simple
+JavaScript alert() is used, returning 0 (OK_OPTION) or -1 (CLOSED_OPTION).
+
+For showInputDialog, if the message is a string, a simple JavaScript prompt()
+with input box is used, returning the entered string or null.
+
+For showConfirmDialog, a simple JavaScript confirm() is used, in which case:
+
+for YES_NO_OPTION: YES_OPTION or NO_OPTION
+
+for YES_NO_CANCEL_OPTION: YES_OPTION or CANCEL_OPTION
+
+for OK_CANCEL_OPTION or any other: OK_OPTION or CANCEL_OPTION
+
+Note that you should implement a response for CLOSED_OPTION for
+showConfirmDialog. For other dialogs, a null return indicates the dialog was
+closed, just as for Java.
+
+Developers are encouraged to create a separate class that handles general calls. 
+An example class can be found in the SwingJS distribution as src/javajs/async/AsyncDialog.java.
+Very simple modifications to the Java allows asynchronous operation using AsyncDialog. Here
+is a simple "do you want to close this frame" example, where you can see that what we have
+done is to set the reply into an ActionListener that is defined in the constructor of 
+the AsyncDisplay object:
+
+// Original:
+//
+//     private void promptQuit() {
+//             int sel = JOptionPane.showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION);
+//             switch (sel) {
+//             case JOptionPane.YES_OPTION:
+//                     resultsTab.clean();
+//                     seqs.dispose();
+//                     if (fromMain) {
+//                             System.exit(0);
+//                     }
+//                     break;
+//             }
+//     }
+
+       private void promptQuitAsync() {
+               new AsyncDialog(new ActionListener() {
+
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                           int sel = ((AsyncDialog)e.getSource()).getOption();
+                               switch (sel) {
+                               case JOptionPane.YES_OPTION:
+                                       resultsTab.clean();
+                                       seqs.dispose();
+                                       if (fromMain) {
+                                               System.exit(0);
+                                       }
+                                       break;
+                               }
+                       }}).showConfirmDialog(null, PROMPT_EXIT, NAME, JOptionPane.YES_NO_OPTION);
+       }
+
+Very simple! 
+
+
+native methods
+--------------
+
+The J2S compiler ignores all static native method declarations.
+Anything of this nature needs to be implemented in JavaScript if it is needed,
+using j2sNative blocks:
+
+/**
+ * @j2sNative
+ *
+ *    var putYourJavaScriptCodeHere
+ *
+ */
+ Note that if you follow that directly with a {...} block, then 
+ only the javadoc code will run in JavaScript, and only the {...} code will run in Java.
+key Focus
+---------
+
+As of June, 2019, the keyboard focus manager is fully implemented. 
+The one catch is that JTextPane and JTextArea, which already consume
+VK_TAB in Java, cannot use CTRL-TAB to continue a tabbing cycle around
+the components in a window. Instead, CTRL-TAB is absorbed by the browser. 
+
+
+LookAndFeel and UI Classes
+--------------------------
+
+SwingJS implements the native browser look and feel as swingjs.plaf.HTML5LookAndFeel. 
+There are small differences between all look and feels -- MacOS, Windows, SwingJS.
+
+Expert developers know how to coerce changes in the UI by subclassing the UI for a 
+component. This probably will not work in SwingJS. 
+
+Note that LookAndFeel in Java usually determines canvas size in a Frame because 
+different operating systems (Mac OS vs Windows vs HTML5) will have 
+different edge sizes on their frames. If you want to ensure a component size, 
+use getContentPane().setPreferredSize().
+
+
+System.exit(0) does not stop all processes
+------------------------------------------
+
+Although System.ext(int) has been implemented in JavaScript, it just closes the 
+frames, stops all pending javax.swing.Timer objects in the queue, and runs any 
+threads added using Runtime.getRuntime().addShutdownHook(Thread).
+It may not stop all "threads." So don't rely on that.
+Applications are responsible for shutting down prior to executing System.exit(0). 
+
+
+myClass.getField not implemented
+--------------------------------
+
+java.lang.reflect.Field is implemented minimally. It is not
+certain that Field.getDeclaringClass() will work. If you just want a 
+value of a field, you can do this:
+
+/**
+ *@j2sNative
+ *
+ * return myClass[name]
+ */   
+
+But that is not a java.lang.reflection.Field object.
+
+
+"window" and other reserved JavaScript names
+--------------------------------------------
+
+No reserved top-level JavaScript name is allowed for a package name. So, for example, 
+one must rename packages such as "window" or "document" to names such as "win" or "doc".
+
+
+reserved field and method names
+-------------------------------
+
+In order to minimize the chance of added SwingJS field and method names colliding with ones 
+developers might use in subclassing Java classes, we have added U+79D8 (first character of Mandarin 
+"secret") to the characters already disrecommended by Java documentation ("$" and "_"). The only problem
+would be if you use that character followed by certain English words in certain classes. For example
+\u79D8canvas for JComponents (in java.awt.JSComponent) and \u79D8byte (in java.io.File).
+
+
+qualified field and method names
+--------------------------------
+
+Method names in SwingJS are fully qualified, meaning two methods with the same Java name but different
+parameters, such as write(int) and write(double), must not have the same name in JavaScript. (In this
+case, we will have write$I and write$D.) However, in certain cases it may be desirable to leave the
+method names unqualified. In particular, when an interface actually represents a JavaScript object, 
+the transpiler can leave a method name unqualified. 
+
+You can implement a simple name for a method using the @j2sAlias annoation in the javadoc for the 
+method involved. For example:
+
+
+/**
+ * @j2sAlias read
+ *
+ */
+public void read(byte[] buf, int pos, int len) {...}
+
+will allow the method to be accesible either as "read" or "read$BA$I$I" in JavaScript. 
+
+
+The default situation for this is a class name includes ".api.js" (case-sensitive). 
+This means that any method in any class in a package js within a package api, or any private interface js 
+that has an outer interface api, will have all-unqualified methods. An example of this is 
+swingjs.plaf.JSComboPopupList, which needs to communicate with a jQuery 
+object directly using the following interface:
+
+       private interface api {
+
+               interface js extends JQueryObject {
+
+                       abstract js j2sCB(Object options);
+
+                       abstract Object[] j2sCB(String method);
+
+                       abstract Object[] j2sCB(String method, Object o);
+
+                       abstract Object[] j2sCB(String method, int i);
+
+                       abstract int j2sCB(String OPTION, String name);
+
+               }
+       }
+
+Notice that all these variants of j2sCB() will call the same method in JavaScript by design.
+
+
+Component.getGraphics(), Graphics.dispose()
+-------------------------------------------
+
+Use of component.getGraphics() is discouraged in Java and in SwingJS. 
+Specifically in SwingJS, any call to component.getGraphics() or 
+BufferedImage.createGraphics() or Graphics.create(...) should be matched with graphics.dispose(), 
+particularly when it is called outside the context of a paint(Graphics) call from the system. 
+
+If you see your graphics scrolling down the page with each repaint, 
+look for where you have used Component.getGraphics() and not Graphics.dispose().
+For example, this will definitely NOT work in SwingJS:
+
+  this.paint(getGraphics())
+  
+and really should not work in Java, either, as it is technically a resource memory leak.
+
+Instead, if you really do not want to use repaint(), use this:
+
+  Graphics g = getGraphics();
+  paint(g);
+  g.dispose();
+
+
+
+Graphics.setClip()
+------------------
+
+The HTML5 canvas.clip() method is permanent. You can only reset the clip using
+save/restore. This is different from Java, where you can temporarily change it using
+
+  Shape oldClip = Graphics.getClip();
+  Graphics.setClip(newClip);
+   ...
+  Graphics.setClip(oldClip); 
+
+If you need to do something like this, you must schedule the paints to not have overlapping clip needs.
+
+
+MAJOR ISSUES--for Bob and Udo within SwingJS
+============================================
+
+fonts
+-----
+
+Fonts and FontMetrics will all be handled in JavaScript. Font matching will 
+not be exact, and composite (drawn) fonts will not be supported. 
+
+SwingJS handles calls such as font.getFontMetrics(g).stringWidth("xxx") by 
+creating a <div> containing that text, placing it in an obscure location on 
+the page, and reading div.getBoundingClientRect(). This is a VERY precise
+value, but can be a pixel or two off from what Java reports for the same font.
+OS-dependent classes
+--------------------
+
+Static classes such as:
+
+   java.awt.Toolkit
+   java.awt.GraphicsEnvironment
+      
+which are created using Class.forName are implemented using classes in the swingjs package.
+
+sun.awt.AWTAccessor is not implemented. 
+
+   
+AWT component peers and component "ui" user interfaces
+------------------------------------------------------
+
+ComponentPeer is a class that represents a native AWT component.
+Components with such peers are called "heavy-weight" components.
+They are expected to do the dirty work of graphics drawing. 
+
+Java Swing implements peers only for JApplet, JDialog, JFrame, and JWindow. 
+References to such objects have been removed, but clearly there must be 
+some connection to similar DOM objects, even for "light-weight" components. 
+
+  
+MAJOR ISSUES--to be resolved by implementers
+============================================
+
+fonts
+-----
+
+Glyph/composite/outline fonts are not supported.
+   
+
+
+threads
+-------
+
+Thread locking and synchronization are not relevant to JavaScript.
+Thus, anything requiring "notify.." or "waitFor.." could be a serious issue.
+All threading must be "faked" in JavaScript. Specifically not available is:
+
+  Thread.sleep()
+  
+javax.swing.AbstractButton#doClick(pressTime) will not work, as it requires Thread.sleep();
+    
+However, java.lang.Thread itself is implemented and used extensively. 
+
+Methods thread.start() and thread.run() both work fine. 
+
+For simple applications that use Thread.sleep() just to have a delay, as in a frame rate, for 
+example, one can use javax.swing.Timer instead. That is fully implemented. 
+
+Likewise, java.util.Timer can be replaced with no loss of performance with javax.Swing.Timer.
+Note that java.util.TimerTask is implemented, but it can also be replaced by an implementation of Runnable.
+
+task = new TimerTask(){....};
+t = new java.util.Timer();
+t.schedule(task, 0, 1);
+
+becomes
+
+task = new TimerTask(){....}; // or task = new Runnable() {...}
+t = new javax.swing.Timer(1, new ActionListener() {
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               task.run();
+       }
+};
+t.setInitialDelay(0); // not particularly necessary
+t.start();
+
+In addition, SwingJS provides swingjs.JSThread, which can be subclassed
+if desired. This class allows simple 
+
+  while(!interrupted()){
+       wait()
+       ...
+  }  
+
+action through an asynchronous function run1(mode). For example:
+
+       protected void run1(int mode) {
+               try {
+                       while (true)
+                               switch (mode) {
+                               case INIT:
+                                       // once-through stuff here
+                                       mode = LOOP;
+                                       break;
+                               case LOOP:
+                                       if (!doDispatch || isInterrupted()) {
+                                               mode = DONE;
+                                       } else {
+                                               Runnable r = new Runnable() {
+                                                       public void run() {
+                                                               // put the loop code here
+                                                       }
+                                               };
+                                               dispatchAndReturn(r);
+                                               if (isJS)
+                                                       return;
+                                       }
+                                       break;
+                               // add more cases as needed
+                               case DONE:
+                                       // finish up here
+                                       if (isInterrupted())
+                                               return;
+                                       // or here
+                                       break;
+                               }
+               } finally {
+                       // stuff here to be executed after each loop in JS or at the end in Java
+               }
+       }
+
+
+image loading
+-------------
+- All image loading in SwingJS is synchronous. A MediaTracker call will immediately return "complete".
+  However, it still may take one system clock tick to fully load images. Thus, it is recommended that
+  images be preloaded in the static block of the applet if it is necessary that they be available in init().
+  This is only an issue if you are trying to access the pixel buffer of the image in JavaScript. 
+  
+- Applet.getImage(path, name) will return null if the image does not exist. 
+
+- BufferedImage: only "support" imageType RGB and ARGB
+
+  -BH: This is a temporary edit, just to get us started. Certainly GRAY will be needed
+
+
+BigInteger and BigDecimal
+-------------------------
+
+java.math.BigInteger and java.math.BigDecimal are fully supported. 
+
+
+no format internationalization
+------------------------------
+
+For now, just "en" for number and date formatters
+
+
+missing winding rules
+---------------------
+
+When filling a graphic, only nonzero winding rule is implemented in HTML5 Canvas2D.
+
+
+
+text-related field implementation
+---------------------------------
+
+Text fields are:
+
+JTextField   (JavaScript <input type="text">)
+JTextArea    (JavaScript <textarea>)
+JTextPane    (JavaScript <div>)
+JEditorPane  (JavaScript <div>)
+
+For the initial implementation, we don't implement infinite undo/redo, and the abstract 
+document model is much less elaborate. Only PlainDocument (in the form of JSPlainDocument)
+is implemented. The Document returned by JTextField.getDocument() is a javax.swing.text.Document.
+
+All scrolling is handled by HTML5. javax.swing.AutoScroller is not implemented.
+public static methods .stop, .isRunning, .processMouseDragged require true Java threading
+and so are not implmented. javax.swing.text.View and its subclasses are not implemented. 
+
+The JS document model does not allow two text fields to address the same underlying document. 
+
+JavaScript is slightly different from Java in that the field value is changed asynchronously after
+the keypressed event, so Java actions that are keyed to KEY_PRESSED may not pick up the new 
+key value even after SwingUtilities.invokeLater() is called. Thus, key pressed actions may need
+to be recorded after a key released event instead. 
+
+
+Formatter/Regex limitations
+---------------------------
+
+Some browsers cannot process Regex "look-behind" process such as (?<=\W)
+java.util.regex.Matcher and Pattern use JavaScript's RegExp object rather than
+the native Java object. These are not identical. Only flags /igm are supported.
+Matcher.start(groupID) is not supported.
+
+java.util.Formatter will function correctly for all standard %... patterns.
+
+In addition, JavaScript does not implement some of the more arcane POSIX {...} formats. 
+From java.util.regex.Pattern.java, we find the listing of conversions SwingJS does use:
+
+               "\\p{javaWhitespace}","\\s",
+               "\\p{javaDigit}","\\d",
+               "\\p{Lower}", "[a-z]",
+               "\\p{Upper}", "[A-Z]",
+               "\\p{ASCII}", "[\u0000-\u007F]",
+               "\\p{Alpha}", "[A-Za-z]",
+               "\\p{Digit}", "[0-9]",
+               "\\p{Alnum}", "[A-Za-z0-9]",
+               "\\p{Punct}", "[!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Graph}", "[A-Za-z0-9]!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Print}", "[A-Za-z0-9]!\"#$%&'\\(\\)\\*\\+,-./:;<=>?@\\[\\\\\\]^_`{\\|}~]",
+               "\\p{Blank}", "[ \t]",
+               "\\p{Cntrl}", "[\u0000-\u001F\u007F]",
+               "\\p{XDigit}", "[0-9a-fA-F]",
+               "\\p{Space}", "[ \t\n\u000B\f\r]",
+               "\\p{javaLowerCase}", "[a-z]",
+               "\\p{javaUpperCase}", "[A-Z]",
+               "\\p{Sc}", "[\u0024\u00A2\u00A3\u00A4\u00A5\u058F\u060B\u07FE\u07FF\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u20A0\u20A1\u20A2\u20A3\u20A4\u20A5\u20A6\u20A7\u20A8\u20A9\u20AA\u20AB\u20AC\u20AD\u20AE\u20AF\u20B0\u20B1\u20B2\u20B3\u20B4\u20B5\u20B6\u20B7\u20B8\u20B9\u20BA\u20BB\u20BC\u20BD\u20BE\u20BF\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]"
+
+Java's \Q \E quoting is handled appropriately.
+
+Additional Issues
+-----------------
+
+Method reflection is limited. Fields and methods do not retain public or default characteristics. 
+(This could be easily adapted, though.) Interfaces do not expose their methods, as the transpiler does not 
+actually transpile the interfaces themselves unless they contain default methods. 
+And method reflection only includes annotated methods.
+
+java.util.concurrent is not fully elaborated. This package is rewritten to not actually use the
+memory handling capabilities of concurrency, which JavaScript does not have access to.
+
+System.getProperties() just returns a minimal set of properties.
+
+
+Summary
+-------
+
+These are all the known limitations of SwingJS. We have not found any of these limitations
+to be show-stoppers. The primary issue for newcomers to SwingJS is having the source code.
+You must check that source code for all your library jar files is available or, if you
+choose, you will need to decompile those classes. We have used decompilation on some projects,
+and it works just fine. So, technically, all we really need are JAR/class files. But the 
+source is by far superior. It's generally prettier, and it has the license information that
+may or may not be present with the JAR or class files. Use class files at your own risk.
+
+Bob Hanson
+
+
diff --git a/swingjs/ver/3.3.1/net.sf.j2s.core.jar b/swingjs/ver/3.3.1/net.sf.j2s.core.jar
new file mode 100644 (file)
index 0000000..ced2ae7
Binary files /dev/null and b/swingjs/ver/3.3.1/net.sf.j2s.core.jar differ
diff --git a/swingjs/ver/3.3.1/timestamp b/swingjs/ver/3.3.1/timestamp
new file mode 100644 (file)
index 0000000..204bf8d
--- /dev/null
@@ -0,0 +1 @@
+20210728172208 
index 9d3877c..d01b23e 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Sequence;
@@ -91,7 +93,7 @@ public class AlignmentGenerator
       ps = new PrintStream(new File(args[6]));
     }
 
-    boolean nucleotide = args[0].toLowerCase().startsWith("n");
+    boolean nucleotide = args[0].toLowerCase(Locale.ROOT).startsWith("n");
     int width = Integer.parseInt(args[1]);
     int height = Integer.parseInt(args[2]);
     long randomSeed = Long.valueOf(args[3]);
index 2ca112f..4bd38d2 100644 (file)
@@ -415,15 +415,19 @@ public class CrossRefTest
   @Test(groups = { "Functional_Failing" })
   public void testFindXrefSequences_withFetch()
   {
+    // JBPNote: this fails because pep1 and pep2 do not have DbRefEntrys with mappings
+    // Fix#1 would be to revise the test data so it fits with 2.11.2+ Jalview assumptions
+    // that ENA retrievals yield dbrefs with Mappings
+    
     SequenceI dna1 = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
     dna1.addDBRef(new DBRefEntry("UNIPROT", "ENA:0", "Q9ZTS2"));
     dna1.addDBRef(new DBRefEntry("UNIPROT", "ENA:0", "P30419"));
     dna1.addDBRef(new DBRefEntry("UNIPROT", "ENA:0", "P00314"));
     final SequenceI pep1 = new Sequence("Q9ZTS2", "MYQLIRSSW");
-    pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+    pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2",null,true));
 
     final SequenceI pep2 = new Sequence("P00314", "MRKLLAASG");
-    pep2.addDBRef(new DBRefEntry("UNIPROT", "0", "P00314"));
+    pep2.addDBRef(new DBRefEntry("UNIPROT", "0", "P00314",null,true));
 
     /*
      * argument false suppresses adding DAS sources
index 1faf3f2..cc35976 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNull;
@@ -182,7 +184,7 @@ public class RnaTest
         char second = bases.charAt(j);
         boolean result = Rna.isCanonicalOrWobblePair(first, second);
         String pair = new String(new char[] { first, second })
-                .toUpperCase();
+                .toUpperCase(Locale.ROOT);
         if (pair.equals("AT") || pair.equals("TA") || pair.equals("AU")
                 || pair.equals("UA") || pair.equals("GC")
                 || pair.equals("CG") || pair.equals("GT")
@@ -211,7 +213,7 @@ public class RnaTest
         char second = bases.charAt(j);
         boolean result = Rna.isCanonicalPair(first, second);
         String pair = new String(new char[] { first, second })
-                .toUpperCase();
+                .toUpperCase(Locale.ROOT);
         if (pair.equals("AT") || pair.equals("TA") || pair.equals("AU")
                 || pair.equals("UA") || pair.equals("GC")
                 || pair.equals("CG"))
index 59fc79d..ee03e77 100644 (file)
@@ -54,7 +54,7 @@ public class CommandLineOperations
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
-  private static final int TEST_TIMEOUT = 9000; // Note longer timeout needed
+  private static final int TEST_TIMEOUT = 12500; // Note longer timeout needed
                                                 // on
                                                 // full test run than on
                                                 // individual tests
@@ -226,7 +226,7 @@ public class CommandLineOperations
   public void setUpForHeadlessCommandLineInputOperations()
           throws IOException
   {
-    String cmds = "nodisplay -open examples/uniref50.fa -sortbytree -props test/jalview/io/testProps.jvprops -colour zappo "
+    String cmds = "nodisplay -open examples/uniref50.fa -sortbytree -props test/jalview/bin/testProps.jvprops -colour zappo "
             + "-jabaws http://www.compbio.dundee.ac.uk/jabaws -nosortbytree "
             + "-features examples/testdata/plantfdx.features -annotations examples/testdata/plantfdx.annotations -tree examples/testdata/uniref50_test_tree";
     Worker worker = getJalviewDesktopRunner(true, cmds, SETUP_TIMEOUT);
@@ -246,18 +246,53 @@ public class CommandLineOperations
   public void setUpForCommandLineInputOperations() throws IOException
   {
     String cmds = "-open examples/uniref50.fa -noquestionnaire -nousagestats";
-    Worker worker = getJalviewDesktopRunner(false, cmds, SETUP_TIMEOUT);
-    String ln = null;
-    int count = 0;
-    while ((ln = worker.getErrorReader().readLine()) != null)
+    final Worker worker = getJalviewDesktopRunner(false, cmds,
+            SETUP_TIMEOUT);
+    
+    
+    // number of lines expected on STDERR when Jalview starts up normally
+    // may need to adjust this if Jalview is excessively noisy ?
+    final int STDERR_SETUPLINES=30;
+    
+    // thread monitors stderr - bails after SETUP_TIMEOUT or when
+    // STDERR_SETUPLINES have been read
+    Thread runner = new Thread(new Runnable()
     {
-      System.out.println(ln);
-      successfulCMDs.add(ln);
-      if (++count > 25)
+      public void run()
+      {
+        String ln = null;
+        int count = 0;
+        try
+        {
+          while ((ln = worker.getErrorReader().readLine()) != null)
+          {
+            System.out.println(ln);
+            successfulCMDs.add(ln);
+            if (++count > STDERR_SETUPLINES)
+            {
+              break;
+            }
+          }
+        } catch (Exception e)
+        {
+          System.err.println(
+                  "Unexpected Exception reading stderr from the Jalview process");
+          e.printStackTrace();
+        }
+      }
+    });
+    long t = System.currentTimeMillis() + SETUP_TIMEOUT;
+    runner.start();
+    while (!runner.isInterrupted() && System.currentTimeMillis() < t)
+    {
+      try
+      {
+        Thread.sleep(500);
+      } catch (InterruptedException e)
       {
-        break;
       }
     }
+    runner.interrupt();
     if (worker != null && worker.exit == null)
     {
       worker.interrupt();
@@ -275,7 +310,7 @@ public class CommandLineOperations
 
   @Test(
     groups =
-    { "Functional", "testben" },
+    { "Functional" },
     dataProvider = "headlessModeOutputOperationsData")
   public void testHeadlessModeOutputOperations(String harg, String type,
           String fileName, boolean withAWT, int expectedMinFileSize,
@@ -310,7 +345,7 @@ public class CommandLineOperations
         // headless mode input operations
         { "CMD [-color zappo] executed successfully!",
             "Failed command : -color zappo" },
-        { "CMD [-props test/jalview/io/testProps.jvprops] executed successfully!",
+        { "CMD [-props test/jalview/bin/testProps.jvprops] executed successfully!",
             "Failed command : -props File" },
         { "CMD [-sortbytree] executed successfully!",
             "Failed command : -sortbytree" },
index 71d13d0..470ec35 100644 (file)
@@ -162,7 +162,7 @@ public class HiDPISettingTest2
   @Test(groups = { "Functional" }, dataProvider = "hidpiScaleArguments")
   public void testHiDPISettings(int scale)
   {
-    if (Platform.isLinux())
+    if (!Platform.isLinux())
     {
       throw new SkipException(
               "Not linux platform, not testing actual scaling with "
index a1ab82a..7018dc4 100644 (file)
@@ -1,2 +1,3 @@
 VERSION_CHECK=true
 LATEST_VERSION=test
+logs.Jalview.level=INFO
index 348d871..91f844e 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.commands;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
@@ -286,7 +288,7 @@ public class EditCommandTest
     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
     assertEquals("fghjZ-xYopq", seqs[1].getSequenceAsString());
     // Dataset Sequence should always be uppercase
-    assertEquals("fghjZxYopq".toUpperCase(),
+    assertEquals("fghjZxYopq".toUpperCase(Locale.ROOT),
             seqs[1].getDatasetSequence().getSequenceAsString());
     assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
     assertEquals("1234567890", seqs[3].getSequenceAsString());
@@ -317,7 +319,7 @@ public class EditCommandTest
     assertEquals(1, seq.getStart());
     assertEquals(8, seq.getEnd());
     // Dataset sequence always uppercase
-    assertEquals("ABxyZDEF".toUpperCase(),
+    assertEquals("ABxyZDEF".toUpperCase(Locale.ROOT),
             seq.getDatasetSequence().getSequenceAsString());
     assertEquals(8, seq.getDatasetSequence().getEnd());
 
@@ -343,7 +345,7 @@ public class EditCommandTest
     assertEquals(1, seq.getStart());
     assertEquals(8, seq.getEnd());
     // dataset sequence should be Uppercase
-    assertEquals("ABxyZDEF".toUpperCase(),
+    assertEquals("ABxyZDEF".toUpperCase(Locale.ROOT),
             seq.getDatasetSequence().getSequenceAsString());
     assertEquals(8, seq.getDatasetSequence().getEnd());
 
@@ -367,7 +369,7 @@ public class EditCommandTest
     // and ds is preserved
     assertTrue(dsseq == seqs[1].getDatasetSequence());
     // and it is unchanged and UPPERCASE !
-    assertEquals("fghjklmnopq".toUpperCase(), dsseq.getSequenceAsString());
+    assertEquals("fghjklmnopq".toUpperCase(Locale.ROOT), dsseq.getSequenceAsString());
     // and that alignment sequence start has been adjusted
     assertEquals(5, seqs[1].getStart());
     assertEquals(11, seqs[1].getEnd());
@@ -394,7 +396,7 @@ public class EditCommandTest
     // and ds is preserved
     assertTrue(dsseq == seqs[1].getDatasetSequence());
     // and it is unchanged AND UPPERCASE !
-    assertEquals("fghjklmnopq".toUpperCase(), dsseq.getSequenceAsString());
+    assertEquals("fghjklmnopq".toUpperCase(Locale.ROOT), dsseq.getSequenceAsString());
     // and that alignment sequence start has been adjusted
     assertEquals(5, seqs[1].getStart());
     assertEquals(11, seqs[1].getEnd());
index fb4073a..337ac1a 100644 (file)
@@ -22,20 +22,22 @@ package jalview.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 
-import jalview.gui.JvOptionPane;
-import jalview.util.MapList;
-
 import java.util.Arrays;
 import java.util.List;
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
+import jalview.gui.JvOptionPane;
+import jalview.util.MapList;
+
 public class AlignedCodonFrameTest
 {
 
@@ -98,52 +100,67 @@ public class AlignedCodonFrameTest
   public void testGetMappedRegion()
   {
     // introns lower case, exons upper case
-    final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
-    seq1.createDatasetSequence();
-    final Sequence seq2 = new Sequence("Seq2", "-TA-gG-Gg-CG-a");
-    seq2.createDatasetSequence();
+    final Sequence dna1 = new Sequence("Seq1/10-18", "c-G-TA-gC-gT-T");
+    dna1.createDatasetSequence();
+    final Sequence dna2 = new Sequence("Seq2/20-28", "-TA-gG-Gg-CG-a");
+    dna2.createDatasetSequence();
 
-    final Sequence aseq1 = new Sequence("Seq1", "-P-R");
-    aseq1.createDatasetSequence();
-    final Sequence aseq2 = new Sequence("Seq2", "-LY-Q");
-    aseq2.createDatasetSequence();
+    final Sequence pep1 = new Sequence("Seq1/3-4", "-P-R");
+    pep1.createDatasetSequence();
+    final Sequence pep2 = new Sequence("Seq2/7-9", "-LY-Q");
+    pep2.createDatasetSequence();
 
     /*
      * First with no mappings
      */
     AlignedCodonFrame acf = new AlignedCodonFrame();
 
-    assertNull(acf.getMappedRegion(seq1, aseq1, 1));
+    assertNull(acf.getMappedRegion(dna1, pep1, 3));
 
     /*
      * Set up the mappings for the exons (upper-case bases)
      * Note residue Q is unmapped
      */
-    MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
-        1, 2 }, 3, 1);
-    acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
-    map = new MapList(new int[] { 1, 2, 4, 5, 7, 8 }, new int[] { 1, 2 },
+    MapList map1 = new MapList(new int[] { 11, 13, 15, 15, 17, 18 }, new int[] {
+        3, 4 }, 3, 1);
+    acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map1);
+    MapList map2 = new MapList(new int[] { 20, 21, 23, 24, 26, 27 }, new int[] { 7, 9 },
             3, 1);
-    acf.addMap(seq2.getDatasetSequence(), aseq2.getDatasetSequence(), map);
+    acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map2);
 
-    assertArrayEquals(new int[] { 2, 4 },
-            acf.getMappedRegion(seq1, aseq1, 1));
-    assertArrayEquals(new int[] { 6, 6, 8, 9 },
-            acf.getMappedRegion(seq1, aseq1, 2));
-    assertArrayEquals(new int[] { 1, 2, 4, 4 },
-            acf.getMappedRegion(seq2, aseq2, 1));
-    assertArrayEquals(new int[] { 5, 5, 7, 8 },
-            acf.getMappedRegion(seq2, aseq2, 2));
+    /*
+     * get codon positions for peptide position
+     */
+    assertArrayEquals(new int[] { 11, 13 },
+            acf.getMappedRegion(dna1, pep1, 3));
+    assertArrayEquals(new int[] { 15, 15, 17, 18 },
+            acf.getMappedRegion(dna1, pep1, 4));
+    assertArrayEquals(new int[] { 20, 21, 23, 23 },
+            acf.getMappedRegion(dna2, pep2, 7));
+    assertArrayEquals(new int[] { 24, 24, 26, 27 },
+            acf.getMappedRegion(dna2, pep2, 8));
 
     /*
-     * No mapping from seq2 to Q
+     * No mapping from dna2 to Q
      */
-    assertNull(acf.getMappedRegion(seq2, aseq2, 3));
+    assertNull(acf.getMappedRegion(dna2, pep2, 9));
 
     /*
-     * No mapping from sequence 1 to sequence 2
+     * No mapping from dna1 to pep2
      */
-    assertNull(acf.getMappedRegion(seq1, aseq2, 1));
+    assertNull(acf.getMappedRegion(dna1, pep2, 7));
+    
+    /*
+     * get peptide position for codon position
+     */
+    assertArrayEquals(new int[] { 3, 3 },
+            acf.getMappedRegion(pep1, dna1, 11));
+    assertArrayEquals(new int[] { 3, 3 },
+            acf.getMappedRegion(pep1, dna1, 12));
+    assertArrayEquals(new int[] { 3, 3 },
+            acf.getMappedRegion(pep1, dna1, 13));
+    assertNull(acf.getMappedRegion(pep1, dna1, 14)); // intron base, not mapped
+
   }
 
   @Test(groups = { "Functional" })
@@ -486,4 +503,212 @@ public class AlignedCodonFrameTest
     assertEquals(1, acf.getMappingsFromSequence(seq1).size());
     assertSame(before, acf.getMappingsFromSequence(seq1).get(0));
   }
+  
+  @Test(groups = { "Functional" })
+  public void testGetCoveringMapping()
+  {
+    SequenceI dna = new Sequence("dna", "acttcaATGGCGGACtaattt");
+    SequenceI cds = new Sequence("cds/7-15", "ATGGCGGAC");
+    cds.setDatasetSequence(dna);
+    SequenceI pep = new Sequence("pep", "MAD");
+    
+    /*
+     * with null argument or no mappings
+     */
+    AlignedCodonFrame acf = new AlignedCodonFrame();
+    assertNull(acf.getCoveringMapping(null,  null));
+    assertNull(acf.getCoveringMapping(dna,  null));
+    assertNull(acf.getCoveringMapping(null,  pep));
+    assertNull(acf.getCoveringMapping(dna,  pep));
+
+    /*
+     * with a non-covering mapping e.g. overlapping exon
+     */
+    MapList map = new MapList(new int[] { 7, 9 }, new int[] {
+        1, 1 }, 3, 1);
+    acf.addMap(dna, pep, map);
+    assertNull(acf.getCoveringMapping(dna,  pep));
+    
+    acf = new AlignedCodonFrame();
+    MapList map2 = new MapList(new int[] { 13, 18 }, new int[] {
+        2, 2 }, 3, 1);
+    acf.addMap(dna, pep, map2);
+    assertNull(acf.getCoveringMapping(dna,  pep));
+    
+    /*
+     * with a covering mapping from CDS (dataset) to protein
+     */
+    acf = new AlignedCodonFrame();
+    MapList map3 = new MapList(new int[] { 7, 15 }, new int[] {
+        1, 3 }, 3, 1);
+    acf.addMap(dna, pep, map3);
+    assertNull(acf.getCoveringMapping(dna,  pep));
+    SequenceToSequenceMapping mapping = acf.getCoveringMapping(cds,  pep);
+    assertNotNull(mapping);
+    
+    /*
+     * with a mapping that extends to stop codon
+     */
+    acf = new AlignedCodonFrame();
+    MapList map4 = new MapList(new int[] { 7, 18 }, new int[] {
+        1, 3 }, 3, 1);
+    acf.addMap(dna, pep, map4);
+    assertNull(acf.getCoveringMapping(dna,  pep));
+    assertNull(acf.getCoveringMapping(cds,  pep));
+    SequenceI cds2 = new Sequence("cds/7-18", "ATGGCGGACtaa");
+    cds2.setDatasetSequence(dna);
+    mapping = acf.getCoveringMapping(cds2,  pep);
+    assertNotNull(mapping);
+  }
+
+  /**
+   * Test the method that adds mapped positions to SearchResults
+   */
+  @Test(groups = { "Functional" })
+  public void testMarkMappedRegion()
+  {
+    // introns lower case, exons upper case
+    final Sequence dna1 = new Sequence("Seq1/10-18", "c-G-TA-gC-gT-T");
+    dna1.createDatasetSequence();
+    final Sequence dna2 = new Sequence("Seq2/20-28", "-TA-gG-Gg-CG-a");
+    dna2.createDatasetSequence();
+  
+    final Sequence pep1 = new Sequence("Seq1/3-4", "-P-R");
+    pep1.createDatasetSequence();
+    final Sequence pep2 = new Sequence("Seq2/7-9", "-LY-Q");
+    pep2.createDatasetSequence();
+  
+    /*
+     * First with no mappings
+     */
+    AlignedCodonFrame acf = new AlignedCodonFrame();
+    SearchResults sr = new SearchResults();
+    acf.markMappedRegion(dna1, 12, sr);
+    assertTrue(sr.isEmpty());
+  
+    /*
+     * Set up the mappings for the exons (upper-case bases)
+     * Note residue Q is unmapped
+     */
+    MapList map1 = new MapList(new int[] { 11, 13, 15, 15, 17, 18 }, new int[] {
+        3, 4 }, 3, 1);
+    acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map1);
+    MapList map2 = new MapList(new int[] { 20, 21, 23, 24, 26, 27 }, new int[] { 7, 8 },
+            3, 1);
+    acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map2);
+    
+    /*
+     * intron bases are not mapped
+     */
+    acf.markMappedRegion(dna1, 10, sr);
+    assertTrue(sr.isEmpty());
+  
+    /*
+     * Q is not mapped
+     */
+    acf.markMappedRegion(pep2, 9, sr);
+    assertTrue(sr.isEmpty());
+
+    /*
+     * mark peptide position for exon position (of aligned sequence)
+     */
+    acf.markMappedRegion(dna1, 11, sr);
+    SearchResults expected = new SearchResults();
+    expected.addResult(pep1.getDatasetSequence(),  3, 3);
+    assertEquals(sr, expected);
+
+    /*
+     * mark peptide position for exon position of dataset sequence - same result
+     */
+    sr = new SearchResults();
+    acf.markMappedRegion(dna1.getDatasetSequence(), 11, sr);
+    assertEquals(sr, expected);
+    
+    /*
+     * marking the same position a second time should not create a duplicate match
+     */
+    acf.markMappedRegion(dna1.getDatasetSequence(), 12, sr);
+    assertEquals(sr, expected);
+    
+    /*
+     * mark exon positions for peptide position (of aligned sequence)
+     */
+    sr = new SearchResults();
+    acf.markMappedRegion(pep2, 7, sr); // codon positions 20, 21, 23
+    expected = new SearchResults();
+    expected.addResult(dna2.getDatasetSequence(),  20, 21);
+    expected.addResult(dna2.getDatasetSequence(),  23, 23);
+    assertEquals(sr, expected);
+    
+    /*
+     * add another codon to the same SearchResults
+     */
+    acf.markMappedRegion(pep1.getDatasetSequence(), 4, sr); // codon positions 15, 17, 18
+    expected.addResult(dna1.getDatasetSequence(),  15, 15);
+    expected.addResult(dna1.getDatasetSequence(),  17, 18);
+    assertEquals(sr, expected);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetCoveringCodonMapping()
+  {
+    SequenceI dna = new Sequence("dna/10-30", "acttcaATGGCGGACtaattt");
+    // CDS sequence with its own dataset sequence (JAL-3763)
+    SequenceI cds = new Sequence("cds/1-9", "-A--TGGC-GGAC");
+    cds.createDatasetSequence();
+    SequenceI pep = new Sequence("pep/1-3", "MAD");
+    
+    /*
+     * with null argument or no mappings
+     */
+    AlignedCodonFrame acf = new AlignedCodonFrame();
+    assertNull(acf.getCoveringCodonMapping(null));
+    assertNull(acf.getCoveringCodonMapping(dna));
+    assertNull(acf.getCoveringCodonMapping(pep));
+  
+    /*
+     * with a non-covering mapping e.g. overlapping exon
+     */
+    MapList map = new MapList(new int[] { 16, 18 }, new int[] {
+        1, 1 }, 3, 1);
+    acf.addMap(dna, pep, map);
+    assertNull(acf.getCoveringCodonMapping(dna));
+    assertNull(acf.getCoveringCodonMapping(pep));
+    
+    acf = new AlignedCodonFrame();
+    MapList map2 = new MapList(new int[] { 13, 18 }, new int[] {
+        2, 2 }, 3, 1);
+    acf.addMap(dna, pep, map2);
+    assertNull(acf.getCoveringCodonMapping(dna));
+    assertNull(acf.getCoveringCodonMapping(pep));
+    
+    /*
+     * with a covering mapping from CDS (dataset) to protein
+     */
+    acf = new AlignedCodonFrame();
+    MapList map3 = new MapList(new int[] { 1, 9 }, new int[] {
+        1, 3 }, 3, 1);
+    acf.addMap(cds.getDatasetSequence(), pep, map3);
+    assertNull(acf.getCoveringCodonMapping(dna));
+    SequenceToSequenceMapping mapping = acf.getCoveringCodonMapping(pep);
+    assertNotNull(mapping);
+    SequenceToSequenceMapping mapping2 = acf.getCoveringCodonMapping(cds.getDatasetSequence());
+    assertSame(mapping, mapping2);
+    
+    /*
+     * with a mapping that extends to stop codon
+     * (EMBL CDS location often includes the stop codon)
+     * - getCoveringCodonMapping is lenient (doesn't require exact length match)
+     */
+    SequenceI cds2 = new Sequence("cds/1-12", "-A--TGGC-GGACTAA");
+    cds2.createDatasetSequence();
+    acf = new AlignedCodonFrame();
+    MapList map4 = new MapList(new int[] { 1, 12 }, new int[] {
+        1, 3 }, 3, 1);
+    acf.addMap(cds2, pep, map4);
+    mapping = acf.getCoveringCodonMapping(cds2.getDatasetSequence());
+    assertNotNull(mapping);
+    mapping2 = acf.getCoveringCodonMapping(pep);
+    assertSame(mapping, mapping2);
+  }
 }
index c8f998b..e95a8b5 100644 (file)
@@ -134,6 +134,21 @@ public class DBRefEntryTest
     assertEquals("3", ref1.getVersion());
 
     /*
+     * canonical == false superseded by canonical == true
+     */
+    ref1.setCanonical(false);
+    ref2.setCanonical(true);
+    assertTrue(ref1.updateFrom(ref2));
+    assertTrue(ref1.isCanonical());
+
+    /*
+     * canonical == true NOT superseded by canonical == false
+     */
+    ref1.setCanonical(true);
+    ref2.setCanonical(false);
+    assertFalse(ref1.updateFrom(ref2));
+
+    /*
      * version "source:n" with n>0 is not superseded
      */
     ref1.setVersion("UNIPROT:1");
index cf4294e..80b7376 100644 (file)
@@ -90,7 +90,7 @@ public class PDBEntryTest
     PDBEntry case9 = new PDBEntry("1xyz", "A", null, "x/y/z/File");
     // different file only
     PDBEntry case10 = new PDBEntry("1xyz", "A", null, "a/b/c/File");
-
+    
     /*
      * assertEquals will invoke PDBEntry.equals()
      */
@@ -208,7 +208,7 @@ public class PDBEntryTest
     assertTrue(pdb1.updateFrom(pdb2));
     assertEquals(pdb1.getFile(), "filePath");
     assertEquals(pdb1.getType(), Type.FILE.toString());
-
+    assertEquals(pdb1.getChainCode(),"B");
     /*
      * change of file is not allowed
      */
@@ -269,6 +269,21 @@ public class PDBEntryTest
     pdb2.setProperty("hello", "moon");
     assertTrue(pdb1.updateFrom(pdb2));
     assertEquals(pdb1.getProperty("hello"), "moon");
+    
+    /*
+    * different id but authoritative
+    */
+    pdb1 = new PDBEntry("af:1xyz", "A", null, "a/b/c/File");
+    pdb2 = new PDBEntry("af-1xyz", "A", null, "a/b/c/File");
+    pdb1.setAuthoritative(true);
+
+    assertTrue(pdb1.isAuthoritative());
+    assertFalse(pdb2.isAuthoritative());
+    // can update pdb1 (authoritative) from pdb2 (non-authoritative)
+    assertTrue(pdb1.updateFrom(pdb2));
+    // but the ID must remain the same
+    assertEquals(pdb1.getId(),"af:1xyz");
+    
   }
 
   @Test(groups = { "Functional" })
index e90e1a9..a6e7429 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import java.util.Locale;
+
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
@@ -181,7 +183,7 @@ public class ResidueCountTest
     ResidueCount rc = new ResidueCount(false);
     // expected characters (upper or lower case):
     String aas = "ACDEFGHIKLMNPQRSTVWXY";
-    String lower = aas.toLowerCase();
+    String lower = aas.toLowerCase(Locale.ROOT);
     for (int i = 0; i < aas.length(); i++)
     {
       rc.put(aas.charAt(i), i);
@@ -206,7 +208,7 @@ public class ResidueCountTest
     ResidueCount rc = new ResidueCount(true);
     // expected characters (upper or lower case):
     String nucs = "ACGTUN";
-    String lower = nucs.toLowerCase();
+    String lower = nucs.toLowerCase(Locale.ROOT);
     for (int i = 0; i < nucs.length(); i++)
     {
       rc.put(nucs.charAt(i), i);
index f8479a3..bd5e9ac 100644 (file)
@@ -48,8 +48,8 @@ public class SequenceFeatureTest
   @Test(groups = { "Functional" })
   public void testCopyConstructors()
   {
-    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf1.setValue("STRAND", "+");
     sf1.setValue("Note", "Testing");
     Integer count = Integer.valueOf(7);
@@ -83,8 +83,8 @@ public class SequenceFeatureTest
     /*
      * copy constructor modifying type/begin/end/group/score
      */
-    SequenceFeature sf4 = new SequenceFeature(sf1, "Disulfide bond", 12,
-            15, "group3", -9.1f);
+    SequenceFeature sf4 = new SequenceFeature(sf1, "Disulfide bond", 12, 15,
+            "group3", -9.1f);
     assertEquals("Disulfide bond", sf4.getType());
     assertTrue(sf4.isContactFeature());
     assertEquals("desc", sf4.getDescription());
@@ -104,8 +104,8 @@ public class SequenceFeatureTest
   @Test(groups = { "Functional" })
   public void testGetValue()
   {
-    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf1.setValue("STRAND", "+");
     assertEquals("+", sf1.getValue("STRAND"));
     assertNull(sf1.getValue("strand")); // case-sensitive
@@ -137,15 +137,15 @@ public class SequenceFeatureTest
   @Test(groups = { "Functional" })
   public void testEqualsAndHashCode()
   {
-    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf1 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf1.setValue("ID", "id");
     sf1.setValue("Name", "name");
     sf1.setValue("Parent", "parent");
     sf1.setStrand("+");
     sf1.setPhase("1");
-    SequenceFeature sf2 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf2 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
     sf2.setValue("ID", "id");
     sf2.setValue("Name", "name");
     sf2.setValue("Parent", "parent");
@@ -158,10 +158,10 @@ public class SequenceFeatureTest
     assertEquals(sf1.hashCode(), sf2.hashCode());
 
     // changing type breaks equals:
-    SequenceFeature sf3 = new SequenceFeature("type", "desc", 22, 33,
-            12.5f, "group");
-    SequenceFeature sf4 = new SequenceFeature("Type", "desc", 22, 33,
-            12.5f, "group");
+    SequenceFeature sf3 = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
+    SequenceFeature sf4 = new SequenceFeature("Type", "desc", 22, 33, 12.5f,
+            "group");
     assertFalse(sf3.equals(sf4));
 
     // changing description breaks equals:
@@ -195,7 +195,8 @@ public class SequenceFeatureTest
 
     // changing start position breaks equals:
     int restorei = sf2.getBegin();
-    sf2 = new SequenceFeature(sf2, 21, sf2.getEnd(), sf2.getFeatureGroup(), sf2.getScore());
+    sf2 = new SequenceFeature(sf2, 21, sf2.getEnd(), sf2.getFeatureGroup(),
+            sf2.getScore());
     assertFalse(sf1.equals(sf2));
     sf2 = new SequenceFeature(sf2, restorei, sf2.getEnd(),
             sf2.getFeatureGroup(), sf2.getScore());
@@ -210,9 +211,11 @@ public class SequenceFeatureTest
 
     // changing feature group breaks equals:
     restores = sf2.getFeatureGroup();
-    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), "Group", sf2.getScore());
+    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), "Group",
+            sf2.getScore());
     assertFalse(sf1.equals(sf2));
-    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), restores, sf2.getScore());
+    sf2 = new SequenceFeature(sf2, sf2.getBegin(), sf2.getEnd(), restores,
+            sf2.getScore());
 
     // changing ID breaks equals:
     restores = (String) sf2.getValue("ID");
@@ -285,7 +288,8 @@ public class SequenceFeatureTest
     String seqName = seq.getName();
 
     // single locus, no group, no score
-    SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22, null);
+    SequenceFeature sf = new SequenceFeature("variant", "G,C", 22, 22,
+            null);
     String expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22</td></tr>"
             + "<tr><td>Type</td><td>variant</td><td></td></tr>"
             + "<tr><td>Description</td><td>G,C</td><td></td></tr></table>";
@@ -299,8 +303,7 @@ public class SequenceFeatureTest
             + "<tr><td>Description</td><td>a description</td><td></td></tr></table>";
     assertEquals(expected, sf.getDetailsReport(seqName, null));
 
-    sf = new SequenceFeature("variant", "G,C", 22, 33,
-            12.5f, "group");
+    sf = new SequenceFeature("variant", "G,C", 22, 33, 12.5f, "group");
     sf.setValue("Parent", "ENSG001");
     sf.setValue("Child", "ENSP002");
     expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22-33</td></tr>"
@@ -351,9 +354,23 @@ public class SequenceFeatureTest
             + "<tr><td>Type</td><td>variant</td><td></td></tr>"
             + "<tr><td>Description</td><td>G,C</td><td></td></tr>"
             + "<tr><td>Consequence</td><td><i>Translated by Jalview</i></td><td>p.Leu9Phe</td></tr>"
-            + "<tr><td>alleles</td><td></td><td>G,C</td></tr>"
+            + "<tr><td>alleles</td><td></td><td>G,C</td></tr>" 
             + "</table>";
 
     assertEquals(expected, sf.getDetailsReport(seq.getName(), mf));
+    
+
+    /*
+     * exon feature extending beyond mapped range; mapped location should be
+     * restricted to peptide mapped range limit i.e. 10-13
+     */
+    SequenceFeature sf2 = new SequenceFeature("exon", "exon 1", 109, 230, null);
+    features.add(sf2);
+    expected = "<br><table><tr><td>Location</td><td>Cds</td><td>109-230</td></tr>"
+            + "<tr><td>Peptide Location</td><td>TestSeq</td><td>10-13</td></tr>"
+            + "<tr><td>Type</td><td>exon</td><td></td></tr>"
+            + "<tr><td>Description</td><td>exon 1</td><td></td></tr>"
+            + "</table>";
+    assertEquals(expected, sf2.getDetailsReport(seq.getName(), mf));
   }
 }
index 129d7b3..2b44261 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.datamodel;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNotNull;
@@ -110,6 +112,23 @@ public class SequenceTest
     assertTrue(sq.isProtein());
   }
 
+  @Test(groups = ("Functional"))
+  public void testIsProteinWithXorNAmbiguityCodes()
+  {
+    // test Protein with N - poly asparagine 
+    assertTrue(new Sequence("prot", "ASDFASDFASDFNNNNNNNNN").isProtein());
+    assertTrue(new Sequence("prot", "NNNNNNNNNNNNNNNNNNNNN").isProtein());
+    // test Protein with X
+    assertTrue(new Sequence("prot", "ASDFASDFASDFXXXXXXXXX").isProtein());
+    // test DNA with X
+    assertFalse(new Sequence("prot", "ACGTACGTACGTXXXXXXXX").isProtein());
+    // test DNA with N
+    assertFalse(new Sequence("prot", "ACGTACGTACGTNNNNNNNN").isProtein());
+    // test RNA with X
+    assertFalse(new Sequence("prot", "ACGUACGUACGUXXXXXXXXX").isProtein());
+    assertFalse(new Sequence("prot", "ACGUACGUACGUNNNNNNNNN").isProtein());
+  }
+
   @Test(groups = { "Functional" })
   public void testGetAnnotation()
   {
@@ -175,6 +194,35 @@ public class SequenceTest
     assertTrue(seq.getAlignmentAnnotations(null, null).isEmpty());
   }
 
+
+  @Test(groups = { "Functional" })
+  public void testGetAlignmentAnnotations_forCalcIdLabelAndDescription()
+  {
+    addAnnotation("label1", "desc1", "calcId1", 1f);
+    AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
+            1f);
+    addAnnotation("label2", "desc3", "calcId3", 1f);
+    AlignmentAnnotation ann4 = addAnnotation("label2", "desc3", "calcId2",
+            1f);
+    addAnnotation("label5", "desc3", null, 1f);
+    addAnnotation(null, "desc3", "calcId3", 1f);
+
+    List<AlignmentAnnotation> anns = seq.getAlignmentAnnotations("calcId2",
+            "label2", "desc3");
+    assertEquals(1, anns.size());
+    assertSame(ann4, anns.get(0));
+    /**
+     * null matching should fail
+     */
+    assertTrue(seq.getAlignmentAnnotations("calcId3", "label2",null).isEmpty());
+    
+    assertTrue(seq.getAlignmentAnnotations("calcId2", "label3",null).isEmpty());
+    assertTrue(seq.getAlignmentAnnotations("calcId3", "label5",null).isEmpty());
+    assertTrue(seq.getAlignmentAnnotations("calcId2", null,null).isEmpty());
+    assertTrue(seq.getAlignmentAnnotations(null, "label3",null).isEmpty());
+    assertTrue(seq.getAlignmentAnnotations(null, null,null).isEmpty());
+  }
+
   /**
    * Tests for addAlignmentAnnotation. Note this method has the side-effect of
    * setting the sequenceRef on the annotation. Adding the same annotation twice
@@ -766,7 +814,7 @@ public class SequenceTest
     } catch (IllegalArgumentException e)
     {
       // TODO Jalview error/exception class for raising implementation errors
-      assertTrue(e.getMessage().toLowerCase()
+      assertTrue(e.getMessage().toLowerCase(Locale.ROOT)
               .contains("implementation error"));
     }
     assertTrue(sq.getSequenceFeatures().isEmpty());
@@ -1414,6 +1462,21 @@ public class SequenceTest
     seq.addPDBId(pdbe5);
     assertEquals(4, seq.getAllPDBEntries().size());
     assertSame(pdbe5, seq.getAllPDBEntries().get(3));
+    
+    // add with a fake pdbid 
+    // (models don't have an embedded ID)
+    String realId = "RealIDQ";
+    PDBEntry pdbe6 = new PDBEntry(realId,null,Type.PDB,"real/localpath");
+    PDBEntry pdbe7 = new PDBEntry("RealID/real/localpath","C",Type.MMCIF,"real/localpath");
+    pdbe7.setFakedPDBId(true);
+    seq.addPDBId(pdbe6);
+    assertEquals(5,seq.getAllPDBEntries().size());
+    seq.addPDBId(pdbe7);
+    assertEquals(5,seq.getAllPDBEntries().size());
+    assertFalse(pdbe6.fakedPDBId());
+    assertSame(pdbe6,seq.getAllPDBEntries().get(4));
+    assertEquals("C",pdbe6.getChainCode());
+    assertEquals(realId, pdbe6.getId());
   }
 
   @Test(
@@ -2175,4 +2238,25 @@ public class SequenceTest
     assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator()));
 
   }
+  @Test(groups= {"Functional"})
+  public void testTransferAnnotation() {
+    Sequence origSeq = new Sequence("MYSEQ","THISISASEQ");
+    Sequence toSeq = new Sequence("MYSEQ","THISISASEQ");
+    origSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "Q12345", null, true));
+    toSeq.transferAnnotation(origSeq, null);
+    assertTrue(toSeq.getDBRefs().size()==1);
+    
+    assertTrue(toSeq.getDBRefs().get(0).isCanonical());
+    
+    // check for promotion of non-canonical 
+    // to canonical (e.g. fetch-db-refs on a jalview project pre 2.11.2)
+    toSeq.setDBRefs(null);
+    toSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "Q12345", null, false));
+    toSeq.transferAnnotation(origSeq, null);
+    assertTrue(toSeq.getDBRefs().size()==1);
+    
+    assertTrue("Promotion of non-canonical DBRefEntry failed",toSeq.getDBRefs().get(0).isCanonical());
+    
+    
+  }
 }
index 9e9d9a4..c927f04 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ext.ensembl;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNull;
@@ -230,7 +232,7 @@ public class EnsemblCdnaTest
     assertTrue(testee.retainFeature(sf, accId));
 
     // test is not case-sensitive
-    assertTrue(testee.retainFeature(sf, accId.toLowerCase()));
+    assertTrue(testee.retainFeature(sf, accId.toLowerCase(Locale.ROOT)));
 
     // feature with wrong parent is not retained
     sf.setValue("Parent", "XYZ");
index 8b1e840..e16197a 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ext.ensembl;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
@@ -161,7 +163,7 @@ public class EnsemblGeneTest
     SequenceFeature sf3 = new SequenceFeature("NMD_transcript_variant", "",
             22000, 22500, 0f, null);
     // id matching should not be case-sensitive
-    sf3.setValue("Parent", geneId.toLowerCase());
+    sf3.setValue("Parent", geneId.toLowerCase(Locale.ROOT));
     sf3.setValue("id", "transcript3");
     genomic.addSequenceFeature(sf3);
 
@@ -271,18 +273,24 @@ public class EnsemblGeneTest
 
   /**
    * Check behaviour of feature colour scheme for EnsemblGene sequences.
-   * Currently coded to display exon and sequence_variant (or sub-types) only,
-   * with sequence_variant in red above exon coloured by label.
+   * Currently coded to hide all except exon and sequence_variant (or sub-types)
+   * only, with sequence_variant in red above exon coloured by label.
    */
   @Test(groups = "Functional")
   public void testGetFeatureColourScheme()
   {
     FeatureSettingsModelI fc = new EnsemblGene().getFeatureColourScheme();
-    assertTrue(fc.isFeatureDisplayed("exon"));
-    assertTrue(fc.isFeatureDisplayed("coding_exon")); // subtype of exon
-    assertTrue(fc.isFeatureDisplayed("sequence_variant"));
-    assertTrue(fc.isFeatureDisplayed("feature_variant")); // subtype
-    assertFalse(fc.isFeatureDisplayed("transcript"));
+    assertFalse(fc.isFeatureDisplayed("exon"));
+    assertFalse(fc.isFeatureHidden("exon"));
+    assertFalse(fc.isFeatureDisplayed("coding_exon")); // subtype of exon
+    assertFalse(fc.isFeatureHidden("coding_exon")); // subtype of exon
+    assertFalse(fc.isFeatureDisplayed("sequence_variant"));
+    assertFalse(fc.isFeatureHidden("sequence_variant"));
+    assertFalse(fc.isFeatureDisplayed("feature_variant")); // subtype
+    assertFalse(fc.isFeatureHidden("feature_variant")); // subtype
+    assertTrue(fc.isFeatureHidden("transcript"));
+    assertTrue(fc.isFeatureHidden("CDS"));
+
     assertEquals(Color.RED, fc.getFeatureColour("sequence_variant")
             .getColour());
     assertEquals(Color.RED, fc.getFeatureColour("feature_variant")
index 21f7e19..6265c05 100644 (file)
@@ -42,6 +42,7 @@ import jalview.gui.SequenceRenderer;
 import jalview.schemes.JalviewColourScheme;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommandI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
 
@@ -130,34 +131,34 @@ public class JmolCommandsTest
   public void testGetAtomSpec()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, false), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, false), "2-4:A/1.1");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "2-4:A/1.1");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, false), "2-4:A/1.1|8:A/1.1");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "2-4:A/1.1|8:A/1.1");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-4:A/1.1|8:A/1.1|5-7:B/1.1");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-7:B/1.1");
     model.addRange("2", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-7:B/1.1|1-4:B/2.1");
     model.addRange("2", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-7:B/1.1|1-4:B/2.1|5-9:C/2.1");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|5-9:C/2.1");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|5-9:C/2.1");
     model.addRange("2", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|3-10:C/2.1");
     model.addRange("5", 25, 35, " ");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|3-10:C/2.1|25-35:/5.1");
 
   }
@@ -199,7 +200,7 @@ public class JmolCommandsTest
     toAlign.addRange("2", 20, 21, "B");
     toAlign.addRange("2", 22, 22, "C");
     List<StructureCommandI> command = testee.superposeStructures(ref,
-            toAlign);
+            toAlign, AtomSpecType.ALPHA); // doesn't matter for Jmol whether nuc or protein
     assertEquals(command.size(), 1);
     String refSpec = "12-14:A/1.1|18:B/1.1|22-23:B/1.1";
     String toAlignSpec = "15-17:B/2.1|20-21:B/2.1|22:C/2.1";
index 2832135..10882d3 100644 (file)
@@ -277,6 +277,10 @@ public class JmolParserTest
     assertEquals(structureData.getId(), "localstruct");
     assertNotNull(structureData.getSeqs());
     /*
+     * local structures have a fake ID
+     */
+    assertTrue(structureData.getSeqs().get(0).getAllPDBEntries().get(0).fakedPDBId());
+    /*
      * the ID is also the group for features derived from structure data 
      */
     String featureGroup = structureData.getSeqs().get(0)
index 7d0916b..80fffff 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.ext.paradise;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.datamodel.AlignmentI;
@@ -151,11 +153,11 @@ public class TestAnnotate3D
         {
           {
             SequenceI struseq = null;
-            String sq_ = sq.getSequenceAsString().toLowerCase();
+            String sq_ = sq.getSequenceAsString().toLowerCase(Locale.ROOT);
             for (SequenceI _struseq : pdbf.getSeqsAsArray())
             {
               final String lowerCase = _struseq.getSequenceAsString()
-                      .toLowerCase();
+                      .toLowerCase(Locale.ROOT);
               if (lowerCase.equals(sq_))
               {
                 struseq = _struseq;
index f6bad92..7759724 100644 (file)
@@ -36,6 +36,7 @@ import jalview.ext.rbvi.chimera.ChimeraCommands;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 
 public class PymolCommandsTest
 {
@@ -80,32 +81,32 @@ public class PymolCommandsTest
   public void testGetAtomSpec()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, false), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, false), "1//A/2-4/");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "1//A/2-4/");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, false), "1//A/2-4+8/");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "1//A/2-4+8/");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, false), "1//A/2-4+8/ 1//B/5-7/");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "1//A/2-4+8/ 1//B/5-7/");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, false), "1//A/2-5+8/ 1//B/5-7/");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "1//A/2-5+8/ 1//B/5-7/");
     model.addRange("0", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "0//B/1-4/ 1//A/2-5+8/ 1//B/5-7/");
     model.addRange("0", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "0//B/1-4/ 0//C/5-9/ 1//A/2-5+8/ 1//B/5-7/");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "0//B/1-4/ 0//C/5-9/ 1//A/2-5+8/ 1//B/5-10/");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "0//B/1-4/ 0//C/5-9/ 1//A/2-5+8/ 1//B/5-10/");
     model.addRange("0", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "0//B/1-4/ 0//C/3-10/ 1//A/2-5+8/ 1//B/5-10/");
     model.addRange("5", 25, 35, " ");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "0//B/1-4/ 0//C/3-10/ 1//A/2-5+8/ 1//B/5-10/ 5///25-35/");
 
   }
@@ -122,16 +123,16 @@ public class PymolCommandsTest
     toAlign.addRange("2", 20, 21, "B");
     toAlign.addRange("2", 22, 22, "C");
     List<StructureCommandI> commands = testee.superposeStructures(ref,
-            toAlign);
+            toAlign, AtomSpecType.ALPHA);
     assertEquals(commands.size(), 2);
-    String refSpecCA = "1//A/12-14/CA 1//B/18+22-23/CA";
-    String toAlignSpecCA = "2//B/15-17+20-21/CA 2//C/22/CA";
+    String refSpecCA = "(1//A/12-14/CA 1//B/18+22-23/CA";
+    String toAlignSpecCA = "(2//B/15-17+20-21/CA 2//C/22/CA";
     String refSpec = "1//A/12-14/ 1//B/18+22-23/";
     String toAlignSpec = "2//B/15-17+20-21/ 2//C/22/";
-
+    String altLoc =  " and (altloc '' or altloc 'a'))";
     // super command: separate arguments for regions to align
     assertEquals(commands.get(0),
-            new StructureCommand("super", refSpecCA, toAlignSpecCA));
+            new StructureCommand("pair_fit", toAlignSpecCA+altLoc, refSpecCA+altLoc));
     // show aligned regions: one argument for combined atom specs
     assertEquals(commands.get(1), new StructureCommand("show", "cartoon",
             refSpec + " " + toAlignSpec));
@@ -141,34 +142,34 @@ public class PymolCommandsTest
   public void testGetAtomSpec_alphaOnly()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, true), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, true), "1//A/2-4/CA");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "1//A/2-4/CA");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, true), "1//A/2-4+8/CA");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "1//A/2-4+8/CA");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "1//A/2-4+8/CA 1//B/5-7/CA");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "1//A/2-5+8/CA 1//B/5-7/CA");
     model.addRange("0", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "0//B/1-4/CA 1//A/2-5+8/CA 1//B/5-7/CA");
     model.addRange("0", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "0//B/1-4/CA 0//C/5-9/CA 1//A/2-5+8/CA 1//B/5-7/CA");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "0//B/1-4/CA 0//C/5-9/CA 1//A/2-5+8/CA 1//B/5-10/CA");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "0//B/1-4/CA 0//C/5-9/CA 1//A/2-5+8/CA 1//B/5-10/CA");
     model.addRange("0", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "0//B/1-4/CA 0//C/3-10/CA 1//A/2-5+8/CA 1//B/5-10/CA");
     model.addRange("5", 25, 35, " ");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "0//B/1-4/CA 0//C/3-10/CA 1//A/2-5+8/CA 1//B/5-10/CA 5///25-35/CA");
   }
 
index 6880985..23e42ca 100644 (file)
@@ -35,6 +35,7 @@ import org.testng.annotations.Test;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 
 public class ChimeraCommandsTest
 {
@@ -161,32 +162,32 @@ public class ChimeraCommandsTest
   public void testGetAtomSpec()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, false), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, false), "#1:2-4.A");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1:2-4.A");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, false), "#1:2-4.A,8.A");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1:2-4.A,8.A");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, false), "#1:2-4.A,8.A,5-7.B");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1:2-4.A,8.A,5-7.B");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, false), "#1:2-5.A,8.A,5-7.B");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1:2-5.A,8.A,5-7.B");
     model.addRange("0", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
     model.addRange("0", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
     model.addRange("0", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
     model.addRange("5", 25, 35, " ");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
 
   }
@@ -203,7 +204,7 @@ public class ChimeraCommandsTest
     toAlign.addRange("2", 20, 21, "B");
     toAlign.addRange("2", 22, 22, "C");
     List<StructureCommandI> command = testee.superposeStructures(ref,
-            toAlign);
+            toAlign, AtomSpecType.ALPHA);
     // qualifier to restrict match to CA and no altlocs
     String carbonAlphas = "@CA&~@.B-Z&~@.2-9";
     String refSpec = "#1:12-14.A,18.B,22-23.B";
@@ -218,36 +219,36 @@ public class ChimeraCommandsTest
   public void testGetAtomSpec_alphaOnly()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, true), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#1:2-4.A@CA&~@.B-Z&~@.2-9");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#1:2-4.A,8.A@CA&~@.B-Z&~@.2-9");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#1:2-4.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#1:2-5.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9");
     model.addRange("0", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0:1-4.B@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9");
     model.addRange("0", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0:1-4.B,5-9.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-7.B@CA&~@.B-Z&~@.2-9");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0:1-4.B,5-9.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0:1-4.B,5-9.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9");
     model.addRange("0", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0:1-4.B,3-10.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9");
     model.addRange("5", 25, 35, " "); // empty chain code
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0:1-4.B,3-10.C@CA&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA&~@.B-Z&~@.2-9|#5:25-35.@CA&~@.B-Z&~@.2-9");
 
   }
index 439401a..143a5d8 100644 (file)
@@ -35,6 +35,7 @@ import org.testng.annotations.Test;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 
 public class ChimeraXCommandsTest
 {
@@ -187,7 +188,7 @@ public class ChimeraXCommandsTest
     toAlign.addRange("2", 20, 21, "B");
     toAlign.addRange("2", 22, 22, "C");
     List<StructureCommandI> command = testee.superposeStructures(ref,
-            toAlign);
+            toAlign,AtomSpecType.ALPHA);
     assertEquals(command.size(), 1);
     String cmd = command.get(0).getCommand();
     String refSpec = "#1/A:12-14/B:18,22-23";
@@ -207,32 +208,33 @@ public class ChimeraXCommandsTest
   public void testGetAtomSpec()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, false), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY
+            ), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, false), "#1/A:2-4");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1/A:2-4");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, false), "#1/A:2-4,8");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1/A:2-4,8");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, false), "#1/A:2-4,8/B:5-7");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1/A:2-4,8/B:5-7");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, false), "#1/A:2-5,8/B:5-7");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY), "#1/A:2-5,8/B:5-7");
     model.addRange("0", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0/B:1-4|#1/A:2-5,8/B:5-7");
     model.addRange("0", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0/B:1-4/C:5-9|#1/A:2-5,8/B:5-7");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0/B:1-4/C:5-9|#1/A:2-5,8/B:5-10");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0/B:1-4/C:5-9|#1/A:2-5,8/B:5-10");
     model.addRange("0", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0/B:1-4/C:3-10|#1/A:2-5,8/B:5-10");
     model.addRange("5", 25, 35, " ");
-    assertEquals(testee.getAtomSpec(model, false),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.RESIDUE_ONLY),
             "#0/B:1-4/C:3-10|#1/A:2-5,8/B:5-10|#5/:25-35");
   }
 
@@ -240,32 +242,32 @@ public class ChimeraXCommandsTest
   public void testGetAtomSpec_alphaOnly()
   {
     AtomSpecModel model = new AtomSpecModel();
-    assertEquals(testee.getAtomSpec(model, true), "");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "");
     model.addRange("1", 2, 4, "A");
-    assertEquals(testee.getAtomSpec(model, true), "#1/A:2-4@CA");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "#1/A:2-4@CA");
     model.addRange("1", 8, 8, "A");
-    assertEquals(testee.getAtomSpec(model, true), "#1/A:2-4,8@CA");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "#1/A:2-4,8@CA");
     model.addRange("1", 5, 7, "B");
-    assertEquals(testee.getAtomSpec(model, true), "#1/A:2-4,8/B:5-7@CA");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "#1/A:2-4,8/B:5-7@CA");
     model.addRange("1", 3, 5, "A");
-    assertEquals(testee.getAtomSpec(model, true), "#1/A:2-5,8/B:5-7@CA");
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA), "#1/A:2-5,8/B:5-7@CA");
     model.addRange("0", 1, 4, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0/B:1-4@CA|#1/A:2-5,8/B:5-7@CA");
     model.addRange("0", 5, 9, "C");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0/B:1-4/C:5-9@CA|#1/A:2-5,8/B:5-7@CA");
     model.addRange("1", 8, 10, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0/B:1-4/C:5-9@CA|#1/A:2-5,8/B:5-10@CA");
     model.addRange("1", 8, 9, "B");
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0/B:1-4/C:5-9@CA|#1/A:2-5,8/B:5-10@CA");
     model.addRange("0", 3, 10, "C"); // subsumes 5-9
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0/B:1-4/C:3-10@CA|#1/A:2-5,8/B:5-10@CA");
     model.addRange("5", 25, 35, " "); // empty chain code
-    assertEquals(testee.getAtomSpec(model, true),
+    assertEquals(testee.getAtomSpec(model, AtomSpecType.ALPHA),
             "#0/B:1-4/C:3-10@CA|#1/A:2-5,8/B:5-10@CA|#5/:25-35@CA");
   }
 
index d397a6b..e8b5bea 100644 (file)
@@ -39,8 +39,10 @@ import jalview.api.FeatureRenderer;
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -118,6 +120,7 @@ public class JalviewChimeraView
   @Test(groups = { "External" })
   public void testSingleSeqViewChimera()
   {
+
     String inFile = "examples/1gaq.txt";
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
             DataSourceType.FILE);
@@ -139,7 +142,7 @@ public class JalviewChimeraView
     /*
      * Wait for viewer load thread to complete
      */
-    while (!binding.isFinishedInit())
+    do
     {
       try
       {
@@ -147,11 +150,36 @@ public class JalviewChimeraView
       } catch (InterruptedException e)
       {
       }
-    }
+    } while (!binding.isFinishedInit()  ||  !chimeraViewer.isVisible());
 
     assertTrue(binding.isViewerRunning(), "Failed to start Chimera");
 
     assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
+    assertTrue(chimeraViewer.hasViewerActionsMenu());
+
+    // now add another sequence and bind to view
+    // 
+    AlignmentI al = af.getViewport().getAlignment();
+    PDBEntry xpdb = al.getSequenceAt(0).getPDBEntry("1GAQ");
+    sq = new Sequence("1GAQ", al.getSequenceAt(0).getSequence(25, 95).toString());
+    al.addSequence(sq);
+    structureViewer.viewStructures(new PDBEntry[] { xpdb }, new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+
+    /*
+     * Wait for viewer load thread to complete
+     */
+    do 
+    {
+      try {
+        Thread.sleep(1500);
+      } catch (InterruptedException q) {};
+    } while (!binding.isLoadingFinished());
+    
+    // still just one PDB structure shown
+    assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
+    // and the viewer action menu should still be visible
+    assertTrue(chimeraViewer.hasViewerActionsMenu());
+
     chimeraViewer.closeViewer(true);
     chimeraViewer = null;
     return;
index 224a712..0b4dd92 100644 (file)
@@ -69,7 +69,7 @@ public class PDBFTSPanelTest
     String expectedString = "1xyz OR text:2xyz OR text:3xyz";
     String outcome = PDBFTSPanel.decodeSearchTerm("1xyz:A;2xyz;3xyz",
             "text");
-    // System.out.println("1 >>>>>>>>>>> " + outcome);
+    System.out.println("1 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
 
     expectedString = "1xyz";
@@ -124,5 +124,13 @@ public class PDBFTSPanelTest
     assertTrue(!mainFrame.getTitle().equalsIgnoreCase(
             "PDB Sequence Fetcher"));
   }
+  
+  @Test
+  public void getFTSframeTitleTest() {
+    PDBFTSPanel searchPanel = new PDBFTSPanel(null);
+    String outcome = searchPanel.getFTSFrameTitle();
+    //System.out.println("FTS Frame title :" + outcome);
+    assertEquals(outcome, "PDB Sequence Fetcher");
+  }
 
 }
index bbd45aa..73956e3 100644 (file)
@@ -24,6 +24,7 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.core.FTSRestClient;
 import jalview.fts.core.FTSRestRequest;
 import jalview.fts.core.FTSRestResponse;
 import jalview.gui.JvOptionPane;
@@ -93,6 +94,8 @@ public class PDBFTSRestClientTest
     {
       e1.printStackTrace();
     }
+    System.out.println("wantedFields >>" + wantedFields);
+
 
     FTSRestRequest request = new FTSRestRequest();
     request.setAllowEmptySeq(false);
@@ -193,9 +196,10 @@ public class PDBFTSRestClientTest
     assertEquals(expectedErrorMsg, parsedErrorResponse);
   }
 
-  @Test(groups = { "External" }, expectedExceptions = Exception.class)
+  @Test(groups = { "External" }, enabled = false, expectedExceptions = Exception.class)
   public void testForExpectedRuntimeException() throws Exception
   {
+    // FIXME JBPNote: looks like this test fails for no good reason - what exception was supposed to be raised ?
     List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
     wantedFields.add(PDBFTSRestClient.getInstance()
             .getDataColumnByNameOrCode("pdb_id"));
@@ -208,6 +212,7 @@ public class PDBFTSRestClientTest
   }
 
   // JBP: Is this actually external ? Looks like it is mocked
+  // JBP looks like the mock is not up to date for this test
   @Test(groups = { "External" })
   public void parsePDBJsonResponseTest()
   {
@@ -246,6 +251,7 @@ public class PDBFTSRestClientTest
     assertTrue(response.getSearchSummary() != null);
     assertTrue(response.getNumberOfItemsFound() == 931);
     assertTrue(response.getSearchSummary().size() == 14);
+    System.out.println("Search summary : " + response.getSearchSummary());
   }
 
   @Test(groups = { "Functional" })
@@ -351,7 +357,13 @@ public class PDBFTSRestClientTest
     }
   }
 
-  public String readJsonStringFromFile(String filePath) throws IOException
+  /**
+   * reads any string from filePath
+   * @param filePath
+   * @return
+   * @throws IOException
+   */
+  public static String readJsonStringFromFile(String filePath) throws IOException
   {
     String fileContent;
     BufferedReader br = new BufferedReader(new FileReader(filePath));
@@ -374,4 +386,350 @@ public class PDBFTSRestClientTest
     return fileContent;
   }
 
+  public static void setMock()
+  {
+    String[][] mocks = new String[2][];
+    mocks[0] = new String[] {"https://www.ebi.ac.uk/pdbe/search/pdb/select?wt=json&fl=pdb_id,title,experimental_method,resolution&rows=500&start=0&q=(4igk+OR+7lyb+OR+3k0h+OR+3k0k+OR+1t15+OR+3pxc+OR+3pxd+OR+3pxe+OR+1jm7+OR+7jzv+OR+3pxa+OR+3pxb+OR+1y98+OR+1n5o+OR+4ifi+OR+4y2g+OR+3k15+OR+3k16+OR+4jlu+OR+2ing+OR+4ofb+OR+6g2i+OR+3coj+OR+1jnx+OR+4y18+OR+4u4a+OR+1oqa+OR+1t29+OR+1t2u+OR+1t2v)+AND+molecule_sequence:%5B''+TO+*%5D+AND+status:REL&sort=",
+        "{\n"
+        + "  \"responseHeader\":{\n"
+        + "    \"status\":0,\n"
+        + "    \"QTime\":0,\n"
+        + "    \"params\":{\n"
+        + "      \"q\":\"(4igk OR 7lyb OR 3k0h OR 3k0k OR 1t15 OR 3pxc OR 3pxd OR 3pxe OR 1jm7 OR 7jzv OR 3pxa OR 3pxb OR 1y98 OR 1n5o OR 4ifi OR 4y2g OR 3k15 OR 3k16 OR 4jlu OR 2ing OR 4ofb OR 6g2i OR 3coj OR 1jnx OR 4y18 OR 4u4a OR 1oqa OR 1t29 OR 1t2u OR 1t2v) AND molecule_sequence:['' TO *] AND status:REL\",\n"
+        + "      \"fl\":\"pdb_id,title,experimental_method,resolution\",\n"
+        + "      \"start\":\"0\",\n"
+        + "      \"sort\":\"\",\n"
+        + "      \"rows\":\"500\",\n"
+        + "      \"wt\":\"json\"}},\n"
+        + "  \"response\":{\"numFound\":64,\"start\":0,\"docs\":[\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4ofb\",\n"
+        + "        \"resolution\":3.05,\n"
+        + "        \"title\":\"Crystal structure of human BRCA1 BRCT in complex with nonphosphopeptide inhibitor\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3pxe\",\n"
+        + "        \"resolution\":2.85,\n"
+        + "        \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: E1836K\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4jlu\",\n"
+        + "        \"resolution\":3.5,\n"
+        + "        \"title\":\"Crystal structure of BRCA1 BRCT with doubly phosphorylated Abraxas\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4y2g\",\n"
+        + "        \"resolution\":2.5,\n"
+        + "        \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas single phosphorylated peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Solution NMR\"],\n"
+        + "        \"pdb_id\":\"1oqa\",\n"
+        + "        \"title\":\"Solution structure of the BRCT-c domain from human BRCA1\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4u4a\",\n"
+        + "        \"resolution\":3.51,\n"
+        + "        \"title\":\"Complex Structure of BRCA1 BRCT with singly phospho Abraxas\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k16\",\n"
+        + "        \"resolution\":3.0,\n"
+        + "        \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t15\",\n"
+        + "        \"resolution\":1.85,\n"
+        + "        \"title\":\"Crystal Structure of the Brca1 BRCT Domains in Complex with the Phosphorylated Interacting Region from Bach1 Helicase\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k15\",\n"
+        + "        \"resolution\":2.8,\n"
+        + "        \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t2v\",\n"
+        + "        \"resolution\":3.3,\n"
+        + "        \"title\":\"Structural basis of phospho-peptide recognition by the BRCT domain of BRCA1, structure with phosphopeptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1y98\",\n"
+        + "        \"resolution\":2.5,\n"
+        + "        \"title\":\"Structure of the BRCT repeats of BRCA1 bound to a CtIP phosphopeptide.\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t29\",\n"
+        + "        \"resolution\":2.3,\n"
+        + "        \"title\":\"Crystal structure of the BRCA1 BRCT repeats bound to a phosphorylated BACH1 peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k0k\",\n"
+        + "        \"resolution\":2.7,\n"
+        + "        \"title\":\"Crystal Structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus.\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k0h\",\n"
+        + "        \"resolution\":2.7,\n"
+        + "        \"title\":\"The crystal structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4ifi\",\n"
+        + "        \"resolution\":2.2,\n"
+        + "        \"title\":\"Structure of human BRCA1 BRCT in complex with BAAT peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3pxd\",\n"
+        + "        \"resolution\":2.8,\n"
+        + "        \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: R1835P\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3pxc\",\n"
+        + "        \"resolution\":2.8,\n"
+        + "        \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: R1699Q\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1jnx\",\n"
+        + "        \"resolution\":2.5,\n"
+        + "        \"title\":\"Crystal structure of the BRCT repeat region from the breast cancer associated protein, BRCA1\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3pxa\",\n"
+        + "        \"resolution\":2.55,\n"
+        + "        \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: G1656D\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Solution NMR\"],\n"
+        + "        \"pdb_id\":\"1jm7\",\n"
+        + "        \"title\":\"Solution structure of the BRCA1/BARD1 RING-domain heterodimer\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4igk\",\n"
+        + "        \"resolution\":1.75,\n"
+        + "        \"title\":\"Structure of human BRCA1 BRCT in complex with ATRIP peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t2u\",\n"
+        + "        \"resolution\":2.8,\n"
+        + "        \"title\":\"Structural basis of phosphopeptide recognition by the BRCT domain of BRCA1: structure of BRCA1 missense variant V1809F\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3pxb\",\n"
+        + "        \"resolution\":2.5,\n"
+        + "        \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: T1700A\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1n5o\",\n"
+        + "        \"resolution\":2.8,\n"
+        + "        \"title\":\"Structural consequences of a cancer-causing BRCA1-BRCT missense mutation\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3coj\",\n"
+        + "        \"resolution\":3.21,\n"
+        + "        \"title\":\"Crystal Structure of the BRCT Domains of Human BRCA1 in Complex with a Phosphorylated Peptide from Human Acetyl-CoA Carboxylase 1\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"6g2i\",\n"
+        + "        \"resolution\":5.9,\n"
+        + "        \"title\":\"Filament of acetyl-CoA carboxylase and BRCT domains of BRCA1 (ACC-BRCT) at 5.9 A resolution\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4jlu\",\n"
+        + "        \"resolution\":3.5,\n"
+        + "        \"title\":\"Crystal structure of BRCA1 BRCT with doubly phosphorylated Abraxas\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4ofb\",\n"
+        + "        \"resolution\":3.05,\n"
+        + "        \"title\":\"Crystal structure of human BRCA1 BRCT in complex with nonphosphopeptide inhibitor\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3pxe\",\n"
+        + "        \"resolution\":2.85,\n"
+        + "        \"title\":\"Impact of BRCA1 BRCT domain missense substitutions on phospho-peptide recognition: E1836K\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4u4a\",\n"
+        + "        \"resolution\":3.51,\n"
+        + "        \"title\":\"Complex Structure of BRCA1 BRCT with singly phospho Abraxas\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4y2g\",\n"
+        + "        \"resolution\":2.5,\n"
+        + "        \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas single phosphorylated peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4y18\",\n"
+        + "        \"resolution\":3.5,\n"
+        + "        \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas double phosphorylated peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"2ing\",\n"
+        + "        \"resolution\":3.6,\n"
+        + "        \"title\":\"X-ray Structure of the BRCA1 BRCT mutant M1775K\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t15\",\n"
+        + "        \"resolution\":1.85,\n"
+        + "        \"title\":\"Crystal Structure of the Brca1 BRCT Domains in Complex with the Phosphorylated Interacting Region from Bach1 Helicase\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t29\",\n"
+        + "        \"resolution\":2.3,\n"
+        + "        \"title\":\"Crystal structure of the BRCA1 BRCT repeats bound to a phosphorylated BACH1 peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Solution NMR\"],\n"
+        + "        \"pdb_id\":\"1jm7\",\n"
+        + "        \"title\":\"Solution structure of the BRCA1/BARD1 RING-domain heterodimer\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1t2v\",\n"
+        + "        \"resolution\":3.3,\n"
+        + "        \"title\":\"Structural basis of phospho-peptide recognition by the BRCT domain of BRCA1, structure with phosphopeptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4ifi\",\n"
+        + "        \"resolution\":2.2,\n"
+        + "        \"title\":\"Structure of human BRCA1 BRCT in complex with BAAT peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4igk\",\n"
+        + "        \"resolution\":1.75,\n"
+        + "        \"title\":\"Structure of human BRCA1 BRCT in complex with ATRIP peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k0k\",\n"
+        + "        \"resolution\":2.7,\n"
+        + "        \"title\":\"Crystal Structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus.\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k16\",\n"
+        + "        \"resolution\":3.0,\n"
+        + "        \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with a free carboxy C-terminus\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k15\",\n"
+        + "        \"resolution\":2.8,\n"
+        + "        \"title\":\"Crystal Structure of BRCA1 BRCT D1840T in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3k0h\",\n"
+        + "        \"resolution\":2.7,\n"
+        + "        \"title\":\"The crystal structure of BRCA1 BRCT in complex with a minimal recognition tetrapeptide with an amidated C-terminus\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"1y98\",\n"
+        + "        \"resolution\":2.5,\n"
+        + "        \"title\":\"Structure of the BRCT repeats of BRCA1 bound to a CtIP phosphopeptide.\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"3coj\",\n"
+        + "        \"resolution\":3.21,\n"
+        + "        \"title\":\"Crystal Structure of the BRCT Domains of Human BRCA1 in Complex with a Phosphorylated Peptide from Human Acetyl-CoA Carboxylase 1\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"X-ray diffraction\"],\n"
+        + "        \"pdb_id\":\"4y18\",\n"
+        + "        \"resolution\":3.5,\n"
+        + "        \"title\":\"Structure of BRCA1 BRCT domains in complex with Abraxas double phosphorylated peptide\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"6g2i\",\n"
+        + "        \"resolution\":5.9,\n"
+        + "        \"title\":\"Filament of acetyl-CoA carboxylase and BRCT domains of BRCA1 (ACC-BRCT) at 5.9 A resolution\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7lyb\",\n"
+        + "        \"resolution\":3.28,\n"
+        + "        \"title\":\"Cryo-EM structure of the human nucleosome core particle in complex with BRCA1-BARD1-UbcH5c\"},\n"
+        + "      {\n"
+        + "        \"experimental_method\":[\"Electron Microscopy\"],\n"
+        + "        \"pdb_id\":\"7jzv\",\n"
+        + "        \"resolution\":3.9,\n"
+        + "        \"title\":\"Cryo-EM structure of the BRCA1-UbcH5c/BARD1 E3-E2 module bound to a nucleosome\"}]\n"
+        + "  }}" };
+    
+    mocks[1] = new String[2];
+    try {
+    mocks[1][0] = readJsonStringFromFile("test/jalview/fts/threedbeacons/p01308_pdbfts_query.txt").trim();
+    mocks[1][1] = readJsonStringFromFile("test/jalview/fts/threedbeacons/p01308_pdbfts_resp.txt").trim();
+    } catch (Throwable e)
+    {
+      Assert.fail("Couldn't read mock data.",e);
+    }
+    
+    FTSRestClient.createMockFTSRestClient((FTSRestClient) PDBFTSRestClient.getInstance(), mocks);
+  }
 }
diff --git a/test/jalview/fts/threedbeacons/.gitignore b/test/jalview/fts/threedbeacons/.gitignore
new file mode 100644 (file)
index 0000000..084aa65
--- /dev/null
@@ -0,0 +1,2 @@
+/tdbJson.java
+/tdbresttest2.java
diff --git a/test/jalview/fts/threedbeacons/TDBeaconsFTSRestClientTest.java b/test/jalview/fts/threedbeacons/TDBeaconsFTSRestClientTest.java
new file mode 100644 (file)
index 0000000..f72ad89
--- /dev/null
@@ -0,0 +1,453 @@
+package jalview.fts.threedbeacons;
+
+import static org.testng.Assert.assertNull;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClientTest;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
+import jalview.gui.JvOptionPane;
+
+public class TDBeaconsFTSRestClientTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  private FTSRestClient ftsRestClient;
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception
+  {
+    ftsRestClient = new FTSRestClient()
+    {
+
+      @Override
+      public String getColumnDataConfigFileName()
+      {
+        return "/fts/tdbeacons_data_columns.txt";
+      }
+
+      @Override
+      public FTSRestResponse executeRequest(FTSRestRequest ftsRequest)
+              throws Exception
+      {
+        return null;
+      }
+    };
+  }
+
+  @AfterMethod(alwaysRun = true)
+  public void tearDown() throws Exception
+  {
+  }
+
+  @Test
+  public void getAllDefaulDisplayedDataColumns()
+  {
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    Assert.assertNotNull(
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns());
+    System.out
+            .println(ftsRestClient.getAllDefaultDisplayedFTSDataColumns());
+    Assert.assertTrue(!ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
+            .isEmpty());
+    Assert.assertEquals(
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns().size(),
+            15);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getPrimaryKeyColumIndexTest()
+  {
+    Collection<FTSDataColumnI> wantedFields = ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns();
+    int foundIndex = -1;
+    try
+    {
+      Assert.assertEquals(foundIndex, -1);
+      foundIndex = ftsRestClient.getPrimaryKeyColumIndex(wantedFields,
+              false);
+      Assert.assertEquals(foundIndex, 12);
+      foundIndex = ftsRestClient.getPrimaryKeyColumIndex(wantedFields,
+              true);
+      // 1+primary key index
+      Assert.assertEquals(foundIndex, 13);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDataColumnsFieldsAsCommaDelimitedString()
+  {
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    Collection<FTSDataColumnI> wantedFields = ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns();
+    String actual = ftsRestClient
+            .getDataColumnsFieldsAsCommaDelimitedString(wantedFields);
+    Assert.assertEquals(actual,
+            "uniprot_start,uniprot_end,provider,model_identifier,model_category,model_title,resolution,confidence_avg_local_score,confidence_type,confidence_version,coverage,created,model_url,model_format,model_page_url");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getAllFTSDataColumns()
+  {
+    Collection<FTSDataColumnI> allFields = ftsRestClient
+            .getAllFTSDataColumns();
+    Assert.assertNotNull(allFields);
+    // System.out.println(allFields.size());
+    Assert.assertEquals(allFields.size(), 20);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getSearchableDataColumns()
+  {
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    Collection<FTSDataColumnI> searchableFields = ftsRestClient
+            .getSearchableDataColumns();
+    Assert.assertNotNull(searchableFields);
+    // System.out.println(searchableFields.size());
+    Assert.assertEquals(searchableFields.size(), 1); // only 1: uniprot
+                                                     // accession
+  }
+
+  @Test(groups = { "Functional" })
+  public void getPrimaryKeyColumn()
+  {
+    // to change when resources.tdbeacons_data_columns.txt is changed
+    FTSDataColumnI expectedPKColumn;
+    try
+    {
+      expectedPKColumn = ftsRestClient.getDataColumnByNameOrCode("Url");
+      Assert.assertNotNull(ftsRestClient.getPrimaryKeyColumn());
+      Assert.assertEquals(ftsRestClient.getPrimaryKeyColumn(),
+              expectedPKColumn);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDataColumnByNameOrCode()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("uniprot_accession");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getName(), "UniProt Accession");
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDataColumnGroupById()
+  {
+    FTSDataColumnGroupI foundDataColGroup;
+    try
+    {
+      foundDataColGroup = ftsRestClient.getDataColumnGroupById("g2");
+      Assert.assertNotNull(foundDataColGroup);
+      Assert.assertEquals(foundDataColGroup.getName(), "Quality");
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDefaultResponsePageSize()
+  {
+    int defaultResSize = ftsRestClient.getDefaultResponsePageSize();
+    Assert.assertEquals(defaultResSize, 100); // why 100 or 500 ? pdb is 100,
+                                              // uniprot 500
+  }
+
+  @Test(groups = { "Functional" })
+  public void getColumnMinWidthTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("uniprot_accession");
+      Assert.assertNotNull(foundDataCol);
+      int actualColMinWidth = foundDataCol.getMinWidth();
+      Assert.assertEquals(actualColMinWidth, 50);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+  // could add test for MaxWidth & PreferedWith
+
+  @Test(groups = { "Functional" })
+  public void getColumnClassTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("uniprot_accession");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              String.class);
+      foundDataCol = ftsRestClient.getDataColumnByNameOrCode("id");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              String.class);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void coverageForEqualsAndHashFunction()
+  {
+    Set<FTSDataColumnI> uniqueSet = new HashSet<FTSDataColumnI>();
+    Collection<FTSDataColumnI> searchableCols = ftsRestClient
+            .getSearchableDataColumns();
+    System.out.println(searchableCols);
+    for (FTSDataColumnI foundCol : searchableCols)
+    {
+      System.out.println(foundCol.toString());
+      uniqueSet.add(foundCol);
+      uniqueSet.add(foundCol);
+    }
+    Assert.assertTrue(!uniqueSet.isEmpty());
+    // Assert.assertEquals(uniqueSet.size(), 22); -> 1 or 2 currently for 3DB
+  }
+
+  @Test(groups = { "Functional" })
+  public void getTDBIdColumIndexTest()
+  {
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("Model id"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_accession"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("Title"));
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    try
+    {
+      assertEquals(4, TDBeaconsFTSRestClient.getInstance()
+              .getPrimaryKeyColumIndex(wantedFields, true));
+      // assertEquals(3, TDBeaconsFTSRestClient.getInstance()
+      // .getPrimaryKeyColumIndex(wantedFields, true));
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  private static String[][] mocks = { { "P38398.json",
+      "{\"uniprot_entry\":{\"sequence_length\":1863,\"ac\":\"P38398\",\"id\":\"BRCA1_HUMAN\"},\"structures\":[{\"model_identifier\":\"4igk\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2012-12-17\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":1.75,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4igk_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4igk\"},{\"model_identifier\":\"1t15\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2004-04-15\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":1.85,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1t15_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1t15\"},{\"model_identifier\":\"4ifi\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2012-12-14\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.2,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4ifi_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4ifi\"},{\"model_identifier\":\"1t29\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2004-04-20\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.3,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1t29_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1t29\"},{\"model_identifier\":\"3pxb\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2010-12-09\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.5,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3pxb_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3pxb\"},{\"model_identifier\":\"4y2g\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2015-02-09\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.5,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4y2g_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4y2g\"},{\"model_identifier\":\"1y98\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2004-12-14\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.5,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1y98_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1y98\"},{\"model_identifier\":\"1jnx\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2001-07-26\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.5,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1jnx_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1jnx\"},{\"model_identifier\":\"3pxa\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2010-12-09\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.55,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3pxa_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3pxa\"},{\"model_identifier\":\"3k0h\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2009-09-24\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.7,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3k0h_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3k0h\"},{\"model_identifier\":\"3k0k\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2009-09-24\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.7,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3k0k_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3k0k\"},{\"model_identifier\":\"1n5o\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2002-11-06\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.8,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1n5o_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1n5o\"},{\"model_identifier\":\"3pxc\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2010-12-09\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.8,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3pxc_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3pxc\"},{\"model_identifier\":\"3pxd\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2010-12-09\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.8,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3pxd_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3pxd\"},{\"model_identifier\":\"1t2u\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2004-04-22\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.8,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1t2u_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1t2u\"},{\"model_identifier\":\"3k15\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2009-09-25\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.8,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3k15_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3k15\"},{\"model_identifier\":\"3pxe\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2010-12-09\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":2.85,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3pxe_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3pxe\"},{\"model_identifier\":\"3k16\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2009-09-25\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":3.0,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3k16_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3k16\"},{\"model_identifier\":\"4ofb\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2014-01-14\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":3.05,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4ofb_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4ofb\"},{\"model_identifier\":\"3coj\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2008-03-28\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":3.21,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/3coj_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/3coj\"},{\"model_identifier\":\"7lyb\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2021-03-06\",\"sequence_identity\":100.0,\"uniprot_start\":1,\"uniprot_end\":100,\"resolution\":3.28,\"coverage\":5.37,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/7lyb_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"ELECTRON MICROSCOPY\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/7lyb\"},{\"model_identifier\":\"1t2v\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2004-04-22\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":3.3,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1t2v_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1t2v\"},{\"model_identifier\":\"4y18\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2015-02-06\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":3.5,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4y18_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4y18\"},{\"model_identifier\":\"4jlu\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2013-03-13\",\"sequence_identity\":100.0,\"uniprot_start\":1649,\"uniprot_end\":1859,\"resolution\":3.5,\"coverage\":11.33,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4jlu_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4jlu\"},{\"model_identifier\":\"4u4a\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2014-07-23\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":3.51,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/4u4a_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/4u4a\"},{\"model_identifier\":\"2ing\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2006-10-07\",\"sequence_identity\":100.0,\"uniprot_start\":1649,\"uniprot_end\":1859,\"resolution\":3.6,\"coverage\":11.33,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/2ing_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"X-RAY DIFFRACTION\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/2ing\"},{\"model_identifier\":\"7jzv\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2020-09-02\",\"sequence_identity\":99.0,\"uniprot_start\":2,\"uniprot_end\":104,\"resolution\":3.9,\"coverage\":5.53,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/7jzv_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"ELECTRON MICROSCOPY\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/7jzv\"},{\"model_identifier\":\"6g2i\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2018-03-23\",\"sequence_identity\":100.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"resolution\":5.9,\"coverage\":11.49,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/6g2i_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"ELECTRON MICROSCOPY\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/6g2i\"},{\"model_identifier\":\"1jm7\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2001-07-17\",\"sequence_identity\":100.0,\"uniprot_start\":1,\"uniprot_end\":110,\"resolution\":null,\"coverage\":5.9,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1jm7_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"SOLUTION NMR\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1jm7\"},{\"model_identifier\":\"1oqa\",\"model_category\":\"EXPERIMENTALLY DETERMINED\",\"provider\":\"PDBe\",\"created\":\"2003-03-07\",\"sequence_identity\":100.0,\"uniprot_start\":1755,\"uniprot_end\":1863,\"resolution\":null,\"coverage\":5.85,\"model_url\":\"https://www.ebi.ac.uk/pdbe/static/entry/1oqa_updated.cif\",\"model_format\":\"MMCIF\",\"experimental_method\":\"SOLUTION NMR\",\"model_page_url\":\"https://www.ebi.ac.uk/pdbe/entry/pdb/1oqa\"},{\"model_identifier\":\"P38398_1646-1859:6g2i.1.K\",\"model_category\":\"TEMPLATE-BASED\",\"provider\":\"SWISS-MODEL\",\"created\":\"2021-11-05\",\"sequence_identity\":1.0,\"uniprot_start\":1646,\"uniprot_end\":1859,\"coverage\":0.115,\"confidence_version\":\"4.2.0\",\"confidence_avg_local_score\":0.776,\"model_url\":\"https://swissmodel.expasy.org/3d-beacons/uniprot/P38398.pdb?range=1646-1859&template=6g2i.1.K&provider=swissmodel\",\"model_format\":\"PDB\",\"model_page_url\":\"https://swissmodel.expasy.org/repository/uniprot/P38398?range=1646-1859&template=6g2i.1.K\",\"confidence_type\":\"QMEANDisCo\"},{\"model_identifier\":\"P38398_1-103:1jm7.1.A\",\"model_category\":\"TEMPLATE-BASED\",\"provider\":\"SWISS-MODEL\",\"created\":\"2021-11-05\",\"sequence_identity\":1.0,\"uniprot_start\":1,\"uniprot_end\":103,\"coverage\":0.055,\"confidence_version\":\"4.2.0\",\"confidence_avg_local_score\":0.655,\"model_url\":\"https://swissmodel.expasy.org/3d-beacons/uniprot/P38398.pdb?range=1-103&template=1jm7.1.A&provider=swissmodel\",\"model_format\":\"PDB\",\"model_page_url\":\"https://swissmodel.expasy.org/repository/uniprot/P38398?range=1-103&template=1jm7.1.A\",\"confidence_type\":\"QMEANDisCo\"},{\"model_identifier\":\"AF-P38398-F1\",\"model_category\":\"DEEP-LEARNING\",\"provider\":\"AlphaFold DB\",\"created\":\"2021-07-01\",\"sequence_identity\":1.0,\"uniprot_start\":1,\"uniprot_end\":1863,\"coverage\":100.0,\"model_url\":\"https://alphafold.ebi.ac.uk/files/AF-P38398-F1-model_v1.cif\",\"model_format\":\"MMCIF\",\"model_page_url\":\"https://alphafold.ebi.ac.uk/entry/P38398\"}]}" },
+      { "P01308.json",null}};
+
+  private static void setMockData()
+  {
+    try
+    {
+      mocks[1][1]= PDBFTSRestClientTest.readJsonStringFromFile("test/jalview/fts/threedbeacons/p01308_tdb_resp.txt");
+    } catch (IOException e)
+    {
+      Assert.fail("Couldn't read mock response data",e);
+    }
+  }
+  
+  public static void setMock()
+  {
+    setMockData();
+    FTSRestClient.createMockFTSRestClient(
+            (FTSRestClient) TDBeaconsFTSRestClient.getInstance(),
+            mocks);
+  }
+
+  private static String dev_url = "https://wwwdev.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
+  private static String prod_url = "https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/";
+
+  /**
+   * check that the mock request and response are the same as the response from
+   * a live 3D-beacons endpoint
+   * 
+   * Note - servers often have rapidly changing ids / URIs so this might fail, but the overall structure will remain. 
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Network", "Integration" })
+  public void verifyMockTDBRequest() throws Exception
+  {
+    setMockData();
+    for (String[] otherMock:mocks)
+    {
+    verifyMockTDBRequest(otherMock[0],otherMock[1]);
+    }
+  }
+  private void verifyMockTDBRequest(String mockRequest, String _mockResponse) throws Exception
+  {
+    URL tdb_req = new URL(prod_url + mockRequest);
+    byte[] resp = tdb_req.openStream().readAllBytes();
+    String tresp = new String(resp, StandardCharsets.UTF_8);
+    assertEquals(_mockResponse.trim(), tresp.trim());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testMockTDBRequest()
+  {
+
+    setMock();
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("Model Id"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("model_url"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("provider"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("model_category"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("qmean_avg_local_score"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_start"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_end"));
+    } catch (Exception e1)
+    {
+      e1.printStackTrace();
+    }
+    System.out.println("wantedFields >>" + wantedFields);
+
+    FTSRestRequest request = new FTSRestRequest();
+    FTSRestResponse response;
+
+    request.setResponseSize(100);
+    request.setFieldToSearchBy("");
+    request.setWantedFields(wantedFields);
+    // check 404 behaviour
+    request.setSearchTerm("P00000.json");
+
+    try
+    {
+      response = TDBeaconsFTSRestClient.getInstance()
+              .executeRequest(request);
+
+      assertNull(response);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Unexpected failure during mock 3DBeacons 404 test");
+    }
+
+    // check 200 behaviour
+    request.setSearchTerm("P38398.json");
+    System.out.println("request : " + request.getFieldToSearchBy());
+    // System.out.println(request.toString());
+
+    try
+    {
+      response = TDBeaconsFTSRestClient.getInstance()
+              .executeRequest(request);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Couldn't execute webservice call!");
+      return;
+    }
+    assertTrue(response.getSearchSummary() != null);
+    assertTrue(response.getNumberOfItemsFound() > 3); // 4 atm
+    System.out.println("Search summary : \n" + response.getSearchSummary());
+
+    // System.out.println(response.getSearchSummary().size());
+  }
+
+  @Test(groups = { "External", "Network" })
+  public void executeRequestTest()
+  {
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("Model Id"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("model_url"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("provider"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("model_category"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("confidence_avg_local_score"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_start"));
+      wantedFields.add(TDBeaconsFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("uniprot_end"));
+    } catch (Exception e1)
+    {
+      e1.printStackTrace();
+    }
+    System.out.println("wantedFields >>" + wantedFields);
+
+    FTSRestRequest request = new FTSRestRequest();
+    request.setResponseSize(100);
+    request.setFieldToSearchBy("");
+    request.setSearchTerm("P01318.json");
+    request.setWantedFields(wantedFields);
+    System.out.println("request : " + request.getFieldToSearchBy());
+    // System.out.println(request.toString());
+
+    FTSRestResponse response;
+    try
+    {
+      response = TDBeaconsFTSRestClient.getInstance()
+              .executeRequest(request);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Couldn't execute webservice call!");
+      return;
+    }
+    assertTrue(response.getSearchSummary() != null);
+    assertTrue(response.getNumberOfItemsFound() > 3); // 4 atm
+    System.out.println("Search summary : \n" + response.getSearchSummary());
+    // System.out.println(response.getSearchSummary().size());
+  }
+}
diff --git a/test/jalview/fts/threedbeacons/TDBeaconsPanelTest.java b/test/jalview/fts/threedbeacons/TDBeaconsPanelTest.java
new file mode 100644 (file)
index 0000000..dec33e3
--- /dev/null
@@ -0,0 +1,68 @@
+package jalview.fts.threedbeacons;
+
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.fts.service.pdb.PDBFTSPanel;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSPanel;
+import jalview.gui.JvOptionPane;
+
+import javax.swing.JComboBox;
+import javax.swing.JInternalFrame;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import junit.extensions.PA;
+
+
+public class TDBeaconsPanelTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception
+  {
+  }
+
+  @AfterMethod(alwaysRun = true)
+  public void tearDown() throws Exception
+  {
+  }
+
+  @Test(groups = { "Functional" })
+  public void populateCmbSearchTargetOptionsTest()
+  {
+    TDBeaconsFTSPanel searchPanel = new TDBeaconsFTSPanel(null);
+    assertTrue(searchPanel.getCmbSearchTarget().getItemCount() > 0);
+    searchPanel.populateCmbSearchTargetOptions();
+  }
+  
+  @Test
+  public void getFTSframeTitleTest() {
+    TDBeaconsFTSPanel searchPanel = new TDBeaconsFTSPanel(null);
+    System.out.println(searchPanel.getFTSFrameTitle());
+  }
+  
+  @Test
+  public void testgetUNIPROTid() {
+    String outcome = TDBeaconsFTSPanel.decodeSearchTerm("P01308");
+    System.out.println(outcome);
+  }
+//  
+//  @Test
+//  public void queryTest() {
+//    int outcome = TDBeaconsFTSPanel.executeParse("P01308");
+//    //System.out.println("query outcome :" + outcome);
+//    int expected_length = 110;
+//    assertEquals(outcome, expected_length);
+//  }
+}
diff --git a/test/jalview/fts/threedbeacons/p01308_pdbfts_query.txt b/test/jalview/fts/threedbeacons/p01308_pdbfts_query.txt
new file mode 100644 (file)
index 0000000..47a59ab
--- /dev/null
@@ -0,0 +1 @@
+https://www.ebi.ac.uk/pdbe/search/pdb/select?wt=json&fl=pdb_id,title,experimental_method,resolution&rows=500&start=0&q=(5hpu+OR+2jmn+OR+4iuz+OR+6s34+OR+1efe+OR+6ce7+OR+1w8p+OR+1evr+OR+1hls+OR+5hpr+OR+7jp3+OR+3v19+OR+5bts+OR+3q6e+OR+2m1d+OR+2m1e+OR+2n2v+OR+2n2w+OR+2n2x+OR+1t1p+OR+1t1q+OR+2rn5+OR+2m2o+OR+4une+OR+3v1g+OR+2m2p+OR+4unh+OR+5t7r+OR+4ung+OR+4gbi+OR+4rxw+OR+4gbl+OR+4gbk+OR+4gbn+OR+3aiy+OR+1ioh+OR+1iog+OR+5wob+OR+4gbc+OR+2m2m+OR+2m2n+OR+5hqi+OR+2hiu+OR+6ce9+OR+4z76+OR+4z78+OR+4z77+OR+2kqp+OR+2kqq+OR+5en9+OR+6k59+OR+1mhj+OR+1mhi+OR+5hrq+OR+6ceb+OR+1jca+OR+4p65+OR+1k3m+OR+3kq6+OR+6s4i+OR+4f0o+OR+6s4j+OR+4f0n+OR+6gnq+OR+5ems+OR+2mvc+OR+2mvd+OR+1sf1+OR+3hyd+OR+2l1y+OR+1uz9+OR+2l1z+OR+7nhu+OR+3w80+OR+4aiy+OR+3utq+OR+3ilg+OR+5cjo+OR+4ak0+OR+6b3q+OR+4f1g+OR+4wdi+OR+1jco+OR+1vkt+OR+6tyh+OR+4iyd+OR+5ena+OR+4f1b+OR+4f1a+OR+4iyf+OR+4f1d+OR+4f1c+OR+4f1f+OR+4ajx+OR+4ajz+OR+1ben+OR+1tyl+OR+1tym+OR+2vk0+OR+6bfc+OR+2om0+OR+2om1+OR+3uts+OR+3utt+OR+3tt8+OR+2omh+OR+2omi+OR+3u4n+OR+6o17+OR+4fg3+OR+2vjz+OR+4oga+OR+2lgb+OR+6ck2+OR+2omg+OR+5uoz+OR+2oly+OR+1zeg+OR+2olz+OR+3inc+OR+1zeh+OR+4akj+OR+4f51+OR+3w7y+OR+3rov+OR+3w7z+OR+6b70+OR+5co9+OR+1j73+OR+5aiy+OR+5co2+OR+1os4+OR+5uqa+OR+1os3+OR+4f4t+OR+2jv1+OR+5co6+OR+4f4v+OR+7bw7+OR+5wdm+OR+7bw8+OR+1rwe+OR+2ceu+OR+2omq+OR+2r34+OR+2r35+OR+7s4y+OR+2r36+OR+5cny+OR+2juu+OR+2juv+OR+5mt9+OR+2jum+OR+3exx+OR+3ir0+OR+1htv+OR+5mt3+OR+7bwa+OR+3zqr+OR+6h3m+OR+1lkq+OR+5mam+OR+3zs2+OR+2mli+OR+1ai0+OR+5usp+OR+5uu2+OR+5uu4+OR+5uu3+OR+3e7y+OR+3e7z+OR+4ex0+OR+3jsd+OR+6gv0+OR+4ex1+OR+2kxk+OR+1sjt+OR+1q4v+OR+1sju+OR+5uru+OR+5urt+OR+6jk8+OR+1xda+OR+6z7y+OR+1hui+OR+5hyj+OR+6z7w+OR+4ey9+OR+4eww+OR+1a7f+OR+2k91+OR+4nib+OR+1b9e+OR+4ewx+OR+4ewz+OR+4ey1+OR+1jk8+OR+5uss+OR+5usv+OR+3zu1+OR+6p4z+OR+4efx+OR+6x4x+OR+1xw7+OR+2kjj+OR+1kmf+OR+4eyd+OR+1fu2+OR+4exx+OR+2wc0+OR+2ws6+OR+1qj0+OR+2ws7+OR+2c8q+OR+2c8r+OR+5udp+OR+5boq+OR+4f8f+OR+2ws0+OR+2ws1+OR+1guj+OR+2ws4+OR+1lph+OR+2wby+OR+1qiz+OR+1qiy+OR+3i40+OR+2k9r+OR+6sof+OR+2wru+OR+4fka+OR+4eyp+OR+2wrv+OR+2wrw+OR+2wrx+OR+1xgl+OR+5bpo+OR+1aiy+OR+5c0d+OR+2kju+OR+4eyn+OR+3fq9+OR+3i3z+OR+3p33+OR+1hiq+OR+2mpg+OR+5mwq+OR+2mpi+OR+1mso+OR+2h67+OR+6vep+OR+5bqq+OR+6ves+OR+4y19+OR+6vet+OR+1fub+OR+6ver+OR+6tc2+OR+1t0c+OR+1ev6+OR+1ev3+OR+2aiy+OR+3zi3+OR+5viz+OR+2g54+OR+4y1a+OR+6nwv+OR+5mhd+OR+2g56+OR+3bxq+OR+4cy7+OR+1hit+OR+1his+OR+2hh4+OR+6u46+OR+3w11+OR+2w44+OR+3w12+OR+3w13+OR+6hn5+OR+2hho+OR+5e7w+OR+1t1k+OR+4xc4+OR+6jr3+OR+1trz+OR+2qiu+OR+1g7b+OR+1g7a+OR+4cxl+OR+3p2x+OR+4cxn+OR+1znj)+AND+molecule_sequence:%5B''+TO+*%5D+AND+status:REL&sort=
diff --git a/test/jalview/fts/threedbeacons/p01308_pdbfts_resp.txt b/test/jalview/fts/threedbeacons/p01308_pdbfts_resp.txt
new file mode 100644 (file)
index 0000000..5d8a286
--- /dev/null
@@ -0,0 +1,2377 @@
+{
+  "responseHeader":{
+    "status":0,
+    "QTime":4,
+    "params":{
+      "q":"(5hpu OR 2jmn OR 4iuz OR 6s34 OR 1efe OR 6ce7 OR 1w8p OR 1evr OR 1hls OR 5hpr OR 7jp3 OR 3v19 OR 5bts OR 3q6e OR 2m1d OR 2m1e OR 2n2v OR 2n2w OR 2n2x OR 1t1p OR 1t1q OR 2rn5 OR 2m2o OR 4une OR 3v1g OR 2m2p OR 4unh OR 5t7r OR 4ung OR 4gbi OR 4rxw OR 4gbl OR 4gbk OR 4gbn OR 3aiy OR 1ioh OR 1iog OR 5wob OR 4gbc OR 2m2m OR 2m2n OR 5hqi OR 2hiu OR 6ce9 OR 4z76 OR 4z78 OR 4z77 OR 2kqp OR 2kqq OR 5en9 OR 6k59 OR 1mhj OR 1mhi OR 5hrq OR 6ceb OR 1jca OR 4p65 OR 1k3m OR 3kq6 OR 6s4i OR 4f0o OR 6s4j OR 4f0n OR 6gnq OR 5ems OR 2mvc OR 2mvd OR 1sf1 OR 3hyd OR 2l1y OR 1uz9 OR 2l1z OR 7nhu OR 3w80 OR 4aiy OR 3utq OR 3ilg OR 5cjo OR 4ak0 OR 6b3q OR 4f1g OR 4wdi OR 1jco OR 1vkt OR 6tyh OR 4iyd OR 5ena OR 4f1b OR 4f1a OR 4iyf OR 4f1d OR 4f1c OR 4f1f OR 4ajx OR 4ajz OR 1ben OR 1tyl OR 1tym OR 2vk0 OR 6bfc OR 2om0 OR 2om1 OR 3uts OR 3utt OR 3tt8 OR 2omh OR 2omi OR 3u4n OR 6o17 OR 4fg3 OR 2vjz OR 4oga OR 2lgb OR 6ck2 OR 2omg OR 5uoz OR 2oly OR 1zeg OR 2olz OR 3inc OR 1zeh OR 4akj OR 4f51 OR 3w7y OR 3rov OR 3w7z OR 6b70 OR 5co9 OR 1j73 OR 5aiy OR 5co2 OR 1os4 OR 5uqa OR 1os3 OR 4f4t OR 2jv1 OR 5co6 OR 4f4v OR 7bw7 OR 5wdm OR 7bw8 OR 1rwe OR 2ceu OR 2omq OR 2r34 OR 2r35 OR 7s4y OR 2r36 OR 5cny OR 2juu OR 2juv OR 5mt9 OR 2jum OR 3exx OR 3ir0 OR 1htv OR 5mt3 OR 7bwa OR 3zqr OR 6h3m OR 1lkq OR 5mam OR 3zs2 OR 2mli OR 1ai0 OR 5usp OR 5uu2 OR 5uu4 OR 5uu3 OR 3e7y OR 3e7z OR 4ex0 OR 3jsd OR 6gv0 OR 4ex1 OR 2kxk OR 1sjt OR 1q4v OR 1sju OR 5uru OR 5urt OR 6jk8 OR 1xda OR 6z7y OR 1hui OR 5hyj OR 6z7w OR 4ey9 OR 4eww OR 1a7f OR 2k91 OR 4nib OR 1b9e OR 4ewx OR 4ewz OR 4ey1 OR 1jk8 OR 5uss OR 5usv OR 3zu1 OR 6p4z OR 4efx OR 6x4x OR 1xw7 OR 2kjj OR 1kmf OR 4eyd OR 1fu2 OR 4exx OR 2wc0 OR 2ws6 OR 1qj0 OR 2ws7 OR 2c8q OR 2c8r OR 5udp OR 5boq OR 4f8f OR 2ws0 OR 2ws1 OR 1guj OR 2ws4 OR 1lph OR 2wby OR 1qiz OR 1qiy OR 3i40 OR 2k9r OR 6sof OR 2wru OR 4fka OR 4eyp OR 2wrv OR 2wrw OR 2wrx OR 1xgl OR 5bpo OR 1aiy OR 5c0d OR 2kju OR 4eyn OR 3fq9 OR 3i3z OR 3p33 OR 1hiq OR 2mpg OR 5mwq OR 2mpi OR 1mso OR 2h67 OR 6vep OR 5bqq OR 6ves OR 4y19 OR 6vet OR 1fub OR 6ver OR 6tc2 OR 1t0c OR 1ev6 OR 1ev3 OR 2aiy OR 3zi3 OR 5viz OR 2g54 OR 4y1a OR 6nwv OR 5mhd OR 2g56 OR 3bxq OR 4cy7 OR 1hit OR 1his OR 2hh4 OR 6u46 OR 3w11 OR 2w44 OR 3w12 OR 3w13 OR 6hn5 OR 2hho OR 5e7w OR 1t1k OR 4xc4 OR 6jr3 OR 1trz OR 2qiu OR 1g7b OR 1g7a OR 4cxl OR 3p2x OR 4cxn OR 1znj) AND molecule_sequence:['' TO *] AND status:REL",
+      "fl":"pdb_id,title,experimental_method,resolution",
+      "start":"0",
+      "sort":"",
+      "rows":"500",
+      "wt":"json"}},
+  "response":{"numFound":641,"start":0,"docs":[
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3hyd",
+        "resolution":1.0,
+        "title":"LVEALYL peptide derived from human insulin chain B, residues 11-17"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t0c",
+        "title":"Solution Structure of Human Proinsulin C-Peptide"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"6u46",
+        "title":"Solution Structure of a Heat-Resistant Long-Acting Insulin Analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omq",
+        "resolution":2.0,
+        "title":"VEALYL peptide derived from human insulin chain B, residues 12-17"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1sju",
+        "title":"MINI-PROINSULIN, SINGLE CHAIN INSULIN ANALOG MUTANT: DES B30, HIS(B 10)ASP, PRO(B 28)ASP AND PEPTIDE BOND BETWEEN LYS B 29 AND GLY A 1, NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1efe",
+        "title":"AN ACTIVE MINI-PROINSULIN, M2PI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5wdm",
+        "resolution":2.803,
+        "title":"An ultra-stable single-chain insulin analog resists thermal inactivation and exhibits biological signaling duration equivalent to the native protein"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1his",
+        "title":"Structure and dynamics of des-pentapeptide-insulin in solution: the molten-globule hypothesis."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1his",
+        "title":"Structure and dynamics of des-pentapeptide-insulin in solution: the molten-globule hypothesis."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"6k59",
+        "title":"Structure of Glargine insulin in 20% acetic acid-d4 (pH 1.9)"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"6k59",
+        "title":"Structure of Glargine insulin in 20% acetic acid-d4 (pH 1.9)"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hit",
+        "title":"Receptor binding redefined by a structural switch in a mutant Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hit",
+        "title":"Receptor binding redefined by a structural switch in a mutant Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1vkt",
+        "title":"HUMAN INSULIN TWO DISULFIDE MODEL, NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m1e",
+        "title":"Biosynthetic engineered B28K-B29P human insulin monomer structure in in water solutions."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2o",
+        "title":"Structure of [D-HisB24] insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2p",
+        "title":"Structure of [D-HisB24] insulin analogue at pH 8.0"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m1d",
+        "title":"Biosynthetic engineered B28K-B29P human insulin monomer structure in in water/acetonitrile solutions."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2c8q",
+        "resolution":1.95,
+        "title":"insuline(1sec) and UV laser excited fluorescence"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2c8q",
+        "resolution":1.95,
+        "title":"insuline(1sec) and UV laser excited fluorescence"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2c8r",
+        "resolution":1.5,
+        "title":"insuline(60sec) and UV laser excited fluorescence"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2c8r",
+        "resolution":1.5,
+        "title":"insuline(60sec) and UV laser excited fluorescence"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hiq",
+        "title":"PARADOXICAL STRUCTURE AND FUNCTION IN A MUTANT HUMAN INSULIN ASSOCIATED WITH DIABETES MELLITUS"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hiq",
+        "title":"PARADOXICAL STRUCTURE AND FUNCTION IN A MUTANT HUMAN INSULIN ASSOCIATED WITH DIABETES MELLITUS"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"7nhu",
+        "resolution":1.4,
+        "title":"Crystal structure of desB30 insulin produced by cell free protein synthesis"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"7nhu",
+        "resolution":1.4,
+        "title":"Crystal structure of desB30 insulin produced by cell free protein synthesis"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6o17",
+        "resolution":1.58,
+        "title":"Recombinant Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6o17",
+        "resolution":1.58,
+        "title":"Recombinant Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mvc",
+        "title":"Solution structure of human insulin at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mvd",
+        "title":"Solution structure of [GlnB22]-insulin mutant at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mvd",
+        "title":"Solution structure of [GlnB22]-insulin mutant at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2n",
+        "title":"Structure of [L-HisB24] insulin analogue at pH 8.0"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2n",
+        "title":"Structure of [L-HisB24] insulin analogue at pH 8.0"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1vkt",
+        "title":"HUMAN INSULIN TWO DISULFIDE MODEL, NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws4",
+        "resolution":1.9,
+        "title":"Semi-synthetic analogue of human insulin ProB26-DTI in monomer form"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m1e",
+        "title":"Biosynthetic engineered B28K-B29P human insulin monomer structure in in water solutions."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2o",
+        "title":"Structure of [D-HisB24] insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2p",
+        "title":"Structure of [D-HisB24] insulin analogue at pH 8.0"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m1d",
+        "title":"Biosynthetic engineered B28K-B29P human insulin monomer structure in in water/acetonitrile solutions."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1k3m",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT ILE-A2-ALA, HIS-B10-ASP, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1k3m",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT ILE-A2-ALA, HIS-B10-ASP, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1lkq",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT ILE-A2-GLY, VAL-A3-GLY, HIS-B10-ASP, PRO-B28-LYS, LYS-B29-PRO, 20 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1sjt",
+        "title":"MINI-PROINSULIN, TWO CHAIN INSULIN ANALOG MUTANT: DES B30, HIS(B 10)ASP, PRO(B 28)ASP, NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1sjt",
+        "title":"MINI-PROINSULIN, TWO CHAIN INSULIN ANALOG MUTANT: DES B30, HIS(B 10)ASP, PRO(B 28)ASP, NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1lkq",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT ILE-A2-GLY, VAL-A3-GLY, HIS-B10-ASP, PRO-B28-LYS, LYS-B29-PRO, 20 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3ilg",
+        "resolution":1.9,
+        "title":"Crystal structure of humnan insulin Sr+2 complex"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"5mwq",
+        "title":"Biosynthetic engineered A21K-B31K-B32R human insulin monomer structure in water/acetonitrile solution"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mvc",
+        "title":"Solution structure of human insulin at pH 1.9"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5ena",
+        "resolution":1.35,
+        "title":"Xray crystal structure of isotope-labeled human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5viz",
+        "resolution":1.7,
+        "title":"X-Ray structure of Insulin Glargine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5viz",
+        "resolution":1.7,
+        "title":"X-Ray structure of Insulin Glargine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5en9",
+        "resolution":1.5,
+        "title":"High resolution x-ray crystal structure of isotope-labeled ester-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3i40",
+        "resolution":1.85,
+        "title":"Human insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kjj",
+        "title":"Dynamics of insulin probed by 1H-NMR amide proton exchange anomalous flexibility of the receptor-binding surface"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kjj",
+        "title":"Dynamics of insulin probed by 1H-NMR amide proton exchange anomalous flexibility of the receptor-binding surface"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2juu",
+        "title":"allo-ThrA3 DKP-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2jum",
+        "title":"ThrA3-DKP-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2jum",
+        "title":"ThrA3-DKP-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2jv1",
+        "title":"NMR structure of human insulin monomer in 35% CD3CN zinc free, 50 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1iog",
+        "title":"INSULIN MUTANT A3 GLY,(B1, B10, B16, B27)GLU, DES-B30, NMR, 19 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1jco",
+        "title":"Solution structure of the monomeric [Thr(B27)->Pro,Pro(B28)->Thr] insulin mutant (PT insulin)"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1xgl",
+        "title":"HUMAN INSULIN DISULFIDE ISOMER, NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1xgl",
+        "title":"HUMAN INSULIN DISULFIDE ISOMER, NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2r35",
+        "resolution":2.08,
+        "title":"Crystal structure of RB human arg-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2qiu",
+        "resolution":2.0,
+        "title":"Structure of Human Arg-Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws4",
+        "resolution":1.9,
+        "title":"Semi-synthetic analogue of human insulin ProB26-DTI in monomer form"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wrw",
+        "resolution":2.41,
+        "title":"Semi-synthetic highly active analogue of human insulin D-ProB26-DTI- NH2"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wrw",
+        "resolution":2.41,
+        "title":"Semi-synthetic highly active analogue of human insulin D-ProB26-DTI- NH2"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2l1z",
+        "title":"NMR Structure of human insulin mutant GLY-B20-D-ALA, GLY-B23-D-ALA PRO-B28-LYS, LYS-B29-PRO, 20 Structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2l1z",
+        "title":"NMR Structure of human insulin mutant GLY-B20-D-ALA, GLY-B23-D-ALA PRO-B28-LYS, LYS-B29-PRO, 20 Structures"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2r34",
+        "resolution":2.25,
+        "title":"Crystal structure of MN human arg-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1kmf",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT ILE-A2-ALLO-ILE, HIS-B10-ASP, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1kmf",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT ILE-A2-ALLO-ILE, HIS-B10-ASP, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1ioh",
+        "title":"INSULIN MUTANT A8 HIS,(B1, B10, B16, B27)GLU, DES-B30, NMR, 26 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hui",
+        "title":"INSULIN MUTANT (B1, B10, B16, B27)GLU, DES-B30, NMR, 25 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hui",
+        "title":"INSULIN MUTANT (B1, B10, B16, B27)GLU, DES-B30, NMR, 25 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1os4",
+        "resolution":2.25,
+        "title":"Dehydrated T6 human insulin at 295 K"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1a7f",
+        "title":"INSULIN MUTANT B16 GLU, B24 GLY, DES-B30, NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kju",
+        "title":"NMR structure of human insulin mutant glu-b21-d-glu, his-b10 asp pro-b28-lys, lys-b29-pro, 20 structures"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3ilg",
+        "resolution":1.9,
+        "title":"Crystal structure of humnan insulin Sr+2 complex"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t1k",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT HIS-B10-ASP, VAL-B12-ALA, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t1k",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT HIS-B10-ASP, VAL-B12-ALA, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5t7r",
+        "resolution":1.55,
+        "title":"A6-A11 trans-dicarba human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5t7r",
+        "resolution":1.55,
+        "title":"A6-A11 trans-dicarba human insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"5mwq",
+        "title":"Biosynthetic engineered A21K-B31K-B32R human insulin monomer structure in water/acetonitrile solution"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6jr3",
+        "resolution":14.5,
+        "title":"Crystal structure of insulin hexamer fitted into cryo EM density map where each dimer was kept as rigid body"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6jr3",
+        "resolution":14.5,
+        "title":"Crystal structure of insulin hexamer fitted into cryo EM density map where each dimer was kept as rigid body"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"6x4x",
+        "title":"B24Y DKP insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"6x4x",
+        "title":"B24Y DKP insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5ena",
+        "resolution":1.35,
+        "title":"Xray crystal structure of isotope-labeled human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3u4n",
+        "resolution":1.98,
+        "title":"A novel covalently linked insulin dimer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3u4n",
+        "resolution":1.98,
+        "title":"A novel covalently linked insulin dimer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zi3",
+        "resolution":1.7,
+        "title":"Crystal structure of the B24His-insulin - human analogue"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zi3",
+        "resolution":1.7,
+        "title":"Crystal structure of the B24His-insulin - human analogue"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5en9",
+        "resolution":1.5,
+        "title":"High resolution x-ray crystal structure of isotope-labeled ester-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"7jp3",
+        "resolution":1.95,
+        "title":"Des-B29,B30-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3i40",
+        "resolution":1.85,
+        "title":"Human insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2hho",
+        "title":"NMR structure of human insulin mutant GLY-B8-SER, HIS-B10-ASP PRO-B28-LYS, LYS-B29-PRO, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2juu",
+        "title":"allo-ThrA3 DKP-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2h67",
+        "title":"NMR structure of human insulin mutant HIS-B5-ALA, HIS-B10-ASP PRO-B28-LYS, LYS-B29-PRO, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2h67",
+        "title":"NMR structure of human insulin mutant HIS-B5-ALA, HIS-B10-ASP PRO-B28-LYS, LYS-B29-PRO, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2jv1",
+        "title":"NMR structure of human insulin monomer in 35% CD3CN zinc free, 50 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2juv",
+        "title":"AbaA3-DKP-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2juv",
+        "title":"AbaA3-DKP-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws0",
+        "resolution":2.1,
+        "title":"Semi-synthetic analogue of human insulin NMeAlaB26-insulin at pH 7.5"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1iog",
+        "title":"INSULIN MUTANT A3 GLY,(B1, B10, B16, B27)GLU, DES-B30, NMR, 19 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1jco",
+        "title":"Solution structure of the monomeric [Thr(B27)->Pro,Pro(B28)->Thr] insulin mutant (PT insulin)"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t1p",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT HIS-B10-ASP, VAL-B12-THR, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t1p",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT HIS-B10-ASP, VAL-B12-THR, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t1q",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT HIS-B10-ASP, VAL-B12-ABA, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1t1q",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN MUTANT HIS-B10-ASP, VAL-B12-ABA, PRO-B28-LYS, LYS-B29-PRO, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1sf1",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN under Amyloidogenic Condition, 15 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1sf1",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN under Amyloidogenic Condition, 15 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2r35",
+        "resolution":2.08,
+        "title":"Crystal structure of RB human arg-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2qiu",
+        "resolution":2.0,
+        "title":"Structure of Human Arg-Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2rn5",
+        "title":"Humal Insulin Mutant B31Lys-B32Arg"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2rn5",
+        "title":"Humal Insulin Mutant B31Lys-B32Arg"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2lgb",
+        "title":"Modified A22Gly-B31Arg Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2lgb",
+        "title":"Modified A22Gly-B31Arg Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1ioh",
+        "title":"INSULIN MUTANT A8 HIS,(B1, B10, B16, B27)GLU, DES-B30, NMR, 26 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1a7f",
+        "title":"INSULIN MUTANT B16 GLU, B24 GLY, DES-B30, NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1mso",
+        "resolution":1.0,
+        "title":"T6 Human Insulin at 1.0 A Resolution"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1os4",
+        "resolution":2.25,
+        "title":"Dehydrated T6 human insulin at 295 K"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hls",
+        "title":"NMR STRUCTURE OF THE HUMAN INSULIN-HIS(B16)"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1hls",
+        "title":"NMR STRUCTURE OF THE HUMAN INSULIN-HIS(B16)"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3i3z",
+        "resolution":1.6,
+        "title":"Human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3i3z",
+        "resolution":1.6,
+        "title":"Human insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kju",
+        "title":"NMR structure of human insulin mutant glu-b21-d-glu, his-b10 asp pro-b28-lys, lys-b29-pro, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6ves",
+        "resolution":1.85,
+        "title":"Human insulin analog: [GluB10,HisA8,ArgA9]-DOI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6ves",
+        "resolution":1.85,
+        "title":"Human insulin analog: [GluB10,HisA8,ArgA9]-DOI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6s34",
+        "resolution":1.35,
+        "title":"Zinc free, dimeric human insulin determined to 1.35 Angstrom resolution"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6s34",
+        "resolution":1.35,
+        "title":"Zinc free, dimeric human insulin determined to 1.35 Angstrom resolution"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ung",
+        "resolution":1.81,
+        "title":"Human insulin B26Asn mutant crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4unh",
+        "resolution":2.75,
+        "title":"Human insulin B26Gly mutant crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4unh",
+        "resolution":2.75,
+        "title":"Human insulin B26Gly mutant crystal structure"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mpg",
+        "title":"Solution structure of the [AibB8,LysB28,ProB29]-insulin analogue"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4iyd",
+        "resolution":1.66,
+        "title":"Insulin glargine crystal structure 1"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4iyd",
+        "resolution":1.66,
+        "title":"Insulin glargine crystal structure 1"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3w7z",
+        "resolution":1.15,
+        "title":"1.15A structure of human 2Zn insulin at 293K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3w7z",
+        "resolution":1.15,
+        "title":"1.15A structure of human 2Zn insulin at 293K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3w7y",
+        "resolution":0.92,
+        "title":"0.92A structure of 2Zn human insulin at 100K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3w7y",
+        "resolution":0.92,
+        "title":"0.92A structure of 2Zn human insulin at 100K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ak0",
+        "resolution":2.28,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ak0",
+        "resolution":2.28,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uoz",
+        "resolution":1.1746387,
+        "title":"Insulin with proline analog FyP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uoz",
+        "resolution":1.1746387,
+        "title":"Insulin with proline analog FyP at position B28 in the T2 state"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2hiu",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN IN 20% ACETIC ACID, ZINC-FREE, 10 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2hiu",
+        "title":"NMR STRUCTURE OF HUMAN INSULIN IN 20% ACETIC ACID, ZINC-FREE, 10 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2m",
+        "title":"Structure of [L-HisB24] insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2m2m",
+        "title":"Structure of [L-HisB24] insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2hho",
+        "title":"NMR structure of human insulin mutant GLY-B8-SER, HIS-B10-ASP PRO-B28-LYS, LYS-B29-PRO, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2k91",
+        "title":"Enhancing the activity of insulin by stereospecific unfolding"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2k91",
+        "title":"Enhancing the activity of insulin by stereospecific unfolding"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2hh4",
+        "title":"NMR structure of human insulin mutant GLY-B8-D-SER, HIS-B10-ASP PRO-B28-LYS, LYS-B29-PRO, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2hh4",
+        "title":"NMR structure of human insulin mutant GLY-B8-D-SER, HIS-B10-ASP PRO-B28-LYS, LYS-B29-PRO, 20 structures"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws0",
+        "resolution":2.1,
+        "title":"Semi-synthetic analogue of human insulin NMeAlaB26-insulin at pH 7.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1os3",
+        "resolution":1.95,
+        "title":"Dehydrated T6 human insulin at 100 K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1os3",
+        "resolution":1.95,
+        "title":"Dehydrated T6 human insulin at 100 K"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"3aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, REFINED AVERAGE STRUCTURE"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"3aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, REFINED AVERAGE STRUCTURE"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3inc",
+        "resolution":1.85,
+        "title":"Crystal structure of human insulin with Ni+2 complex"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3inc",
+        "resolution":1.85,
+        "title":"Crystal structure of human insulin with Ni+2 complex"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kxk",
+        "title":"Human Insulin Mutant A22Gly-B31Lys-B32Arg"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4cxn",
+        "resolution":1.7,
+        "title":"Crystal structure of human insulin analogue (NMe-AlaB8)-insulin crystal form I"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4cxn",
+        "resolution":1.7,
+        "title":"Crystal structure of human insulin analogue (NMe-AlaB8)-insulin crystal form I"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2r34",
+        "resolution":2.25,
+        "title":"Crystal structure of MN human arg-insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kxk",
+        "title":"Human Insulin Mutant A22Gly-B31Lys-B32Arg"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wrx",
+        "resolution":1.5,
+        "title":"Semi-synthetic analogue of human insulin NMeAlaB26-insulin at pH 3.0"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wrx",
+        "resolution":1.5,
+        "title":"Semi-synthetic analogue of human insulin NMeAlaB26-insulin at pH 3.0"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1mhi",
+        "title":"THREE-DIMENSIONAL SOLUTION STRUCTURE OF AN INSULIN DIMER. A STUDY OF THE B9(ASP) MUTANT OF HUMAN INSULIN USING NUCLEAR MAGNETIC RESONANCE DISTANCE GEOMETRY AND RESTRAINED MOLECULAR DYNAMICS"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1mhi",
+        "title":"THREE-DIMENSIONAL SOLUTION STRUCTURE OF AN INSULIN DIMER. A STUDY OF THE B9(ASP) MUTANT OF HUMAN INSULIN USING NUCLEAR MAGNETIC RESONANCE DISTANCE GEOMETRY AND RESTRAINED MOLECULAR DYNAMICS"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1mhj",
+        "title":"SOLUTION STRUCTURE OF THE SUPERACTIVE MONOMERIC DES-[PHE(B25)] HUMAN INSULIN MUTANT. ELUCIDATION OF THE STRUCTURAL BASIS FOR THE MONOMERIZATION OF THE DES-[PHE(B25)] INSULIN AND THE DIMERIZATION OF NATIVE INSULIN"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1mhj",
+        "title":"SOLUTION STRUCTURE OF THE SUPERACTIVE MONOMERIC DES-[PHE(B25)] HUMAN INSULIN MUTANT. ELUCIDATION OF THE STRUCTURAL BASIS FOR THE MONOMERIZATION OF THE DES-[PHE(B25)] INSULIN AND THE DIMERIZATION OF NATIVE INSULIN"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1mso",
+        "resolution":1.0,
+        "title":"T6 Human Insulin at 1.0 A Resolution"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2g56",
+        "resolution":2.2,
+        "title":"crystal structure of human insulin-degrading enzyme in complex with insulin B chain"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 20 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kqq",
+        "title":"NMR structure of human insulin mutant gly-b8-d-ala, his-b10-asp, pro-b28-lys, lys-b29-pro, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2l1y",
+        "title":"NMR Structure of human insulin mutant GLY-B20-D-ALA, GLY-B23-D-ALA PRO-B28-LYS, LYS-B29-PRO, 20 Structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2n2v",
+        "title":"Solution structure of [B26-B29 triazole cross-linked]-insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2n2w",
+        "title":"Solution structure of [B26-B29 triazole cross-linked]-insulin analogue at pH 8.0"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4une",
+        "resolution":1.59,
+        "title":"Human insulin B26Phe mutant crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4une",
+        "resolution":1.59,
+        "title":"Human insulin B26Phe mutant crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ung",
+        "resolution":1.81,
+        "title":"Human insulin B26Asn mutant crystal structure"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mpi",
+        "title":"Solution structure of B24G insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mpi",
+        "title":"Solution structure of B24G insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mpg",
+        "title":"Solution structure of the [AibB8,LysB28,ProB29]-insulin analogue"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mli",
+        "title":"NMR structure of B25-(alpha, beta)-dehydro-phenylalanine insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3w80",
+        "resolution":1.4,
+        "title":"Crystal structure of dodecamer human insulin with double C-axis length of the hexamer 2 Zn insulin cell"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3w80",
+        "resolution":1.4,
+        "title":"Crystal structure of dodecamer human insulin with double C-axis length of the hexamer 2 Zn insulin cell"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"4aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 'GREEN' SUBSTATE, AVERAGE STRUCTURE"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"4aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 'GREEN' SUBSTATE, AVERAGE STRUCTURE"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ewx",
+        "resolution":2.201,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3tt8",
+        "resolution":1.12,
+        "title":"Crystal Structure Analysis of Cu Human Insulin Derivative"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3tt8",
+        "resolution":1.12,
+        "title":"Crystal Structure Analysis of Cu Human Insulin Derivative"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4iyf",
+        "resolution":1.8,
+        "title":"Insulin glargine crystal structure 2"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4iyf",
+        "resolution":1.8,
+        "title":"Insulin glargine crystal structure 2"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"5aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 'RED' SUBSTATE, AVERAGE STRUCTURE"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"5aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 'RED' SUBSTATE, AVERAGE STRUCTURE"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"5mhd",
+        "title":"Biosynthetic engineered A22S-B3K-B31R human insulin monomer structure in water/acetonitrile solutions."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"5mhd",
+        "title":"Biosynthetic engineered A22S-B3K-B31R human insulin monomer structure in water/acetonitrile solutions."},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2n2x",
+        "title":"Solution structure of [GlyB24,B27-B29 triazole cross-linked]-insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hqi",
+        "resolution":0.97,
+        "title":"Insulin with proline analog HzP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hqi",
+        "resolution":0.97,
+        "title":"Insulin with proline analog HzP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eww",
+        "resolution":2.3,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wru",
+        "resolution":1.57,
+        "title":"Semi-synthetic highly active analogue of human insulin NMeAlaB26-DTI- NH2"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wru",
+        "resolution":1.57,
+        "title":"Semi-synthetic highly active analogue of human insulin NMeAlaB26-DTI- NH2"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1a",
+        "resolution":1.8,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1a",
+        "resolution":1.8,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f51",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f4t",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f0o",
+        "resolution":1.672,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws1",
+        "resolution":1.6,
+        "title":"Semi-synthetic analogue of human insulin NMeTyrB26-insulin in monomer form"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws1",
+        "resolution":1.6,
+        "title":"Semi-synthetic analogue of human insulin NMeTyrB26-insulin in monomer form"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4fka",
+        "resolution":1.08,
+        "title":"High resolution structure of the manganese derivative of insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1g",
+        "resolution":1.637,
+        "title":"Human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f8f",
+        "resolution":1.676,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1d",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f0n",
+        "resolution":1.679,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f0n",
+        "resolution":1.679,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1b",
+        "resolution":1.591,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1c",
+        "resolution":1.7,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1f",
+        "resolution":1.684,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f4v",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1aiy",
+        "title":"R6 HUMAN INSULIN HEXAMER (SYMMETRIC), NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1htv",
+        "resolution":1.9,
+        "title":"CRYSTAL STRUCTURE OF DESTRIPEPTIDE (B28-B30) INSULIN"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1htv",
+        "resolution":1.9,
+        "title":"CRYSTAL STRUCTURE OF DESTRIPEPTIDE (B28-B30) INSULIN"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1ai0",
+        "title":"R6 HUMAN INSULIN HEXAMER (NON-SYMMETRIC), NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"1ai0",
+        "title":"R6 HUMAN INSULIN HEXAMER (NON-SYMMETRIC), NMR, 10 STRUCTURES"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3bxq",
+        "resolution":1.3,
+        "title":"The structure of a mutant insulin uncouples receptor binding from protein allostery. An electrostatic block to the TR transition"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1jca",
+        "resolution":2.5,
+        "title":"Non-standard Design of Unstable Insulin Analogues with Enhanced Activity"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2kqq",
+        "title":"NMR structure of human insulin mutant gly-b8-d-ala, his-b10-asp, pro-b28-lys, lys-b29-pro, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2l1y",
+        "title":"NMR Structure of human insulin mutant GLY-B20-D-ALA, GLY-B23-D-ALA PRO-B28-LYS, LYS-B29-PRO, 20 Structures"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6ver",
+        "resolution":1.047,
+        "title":"Human insulin analog: [GluB10,TyrB20]-DOI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6ver",
+        "resolution":1.047,
+        "title":"Human insulin analog: [GluB10,TyrB20]-DOI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5bts",
+        "resolution":1.77,
+        "title":"Structural and biophysical characterization of a covalent insulin dimer formed during storage of neutral formulation of human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5bts",
+        "resolution":1.77,
+        "title":"Structural and biophysical characterization of a covalent insulin dimer formed during storage of neutral formulation of human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5bpo",
+        "resolution":1.9,
+        "title":"Human insulin with intra-chain chemical crosslink between modified B27 and B29"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5urt",
+        "resolution":1.18,
+        "title":"Insulin with proline analog DhP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5usp",
+        "resolution":1.174,
+        "title":"Insulin with proline analog Pip at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5usp",
+        "resolution":1.174,
+        "title":"Insulin with proline analog Pip at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6h3m",
+        "resolution":1.821,
+        "title":"The crystal structure of a human seleno-insulin analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6h3m",
+        "resolution":1.821,
+        "title":"The crystal structure of a human seleno-insulin analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4rxw",
+        "resolution":1.73,
+        "title":"Crystal Structure of the cobalt human insulin derivative"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4rxw",
+        "resolution":1.73,
+        "title":"Crystal Structure of the cobalt human insulin derivative"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2n2v",
+        "title":"Solution structure of [B26-B29 triazole cross-linked]-insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2n2w",
+        "title":"Solution structure of [B26-B29 triazole cross-linked]-insulin analogue at pH 8.0"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eyd",
+        "resolution":1.471,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eyd",
+        "resolution":1.471,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eyn",
+        "resolution":1.532,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eyn",
+        "resolution":1.532,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ey1",
+        "resolution":1.471,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ewx",
+        "resolution":2.201,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eyp",
+        "resolution":1.591,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4exx",
+        "resolution":1.55,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4exx",
+        "resolution":1.55,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5usv",
+        "resolution":1.3,
+        "title":"Insulin with proline analog AzeP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5usv",
+        "resolution":1.3,
+        "title":"Insulin with proline analog AzeP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uu2",
+        "resolution":1.223,
+        "title":"Insulin with proline analog ThioP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ex1",
+        "resolution":1.657,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2n2x",
+        "title":"Solution structure of [GlyB24,B27-B29 triazole cross-linked]-insulin analogue at pH 1.9"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ey9",
+        "resolution":1.471,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ey9",
+        "resolution":1.471,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3q6e",
+        "resolution":2.05,
+        "title":"Human insulin in complex with cucurbit[7]uril"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3q6e",
+        "resolution":2.05,
+        "title":"Human insulin in complex with cucurbit[7]uril"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ex0",
+        "resolution":1.86,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ex0",
+        "resolution":1.86,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eww",
+        "resolution":2.3,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ewz",
+        "resolution":1.791,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ewz",
+        "resolution":1.791,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5c0d",
+        "resolution":1.68,
+        "title":"HLA-A02 carrying AQWGPDPAAA"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3ir0",
+        "resolution":2.2,
+        "title":"Crystal Structure of Human Insulin complexed with Cu+2 metal ion"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3ir0",
+        "resolution":2.2,
+        "title":"Crystal Structure of Human Insulin complexed with Cu+2 metal ion"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3exx",
+        "resolution":1.35,
+        "title":"Structure of the T6 human insulin derivative with nickel at 1.35 A resolution"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3exx",
+        "resolution":1.35,
+        "title":"Structure of the T6 human insulin derivative with nickel at 1.35 A resolution"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wrv",
+        "resolution":2.15,
+        "title":"Semi-synthetic highly active analogue of human insulin NMeHisB26-DTI- NH2"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wrv",
+        "resolution":2.15,
+        "title":"Semi-synthetic highly active analogue of human insulin NMeHisB26-DTI- NH2"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2vk0",
+        "resolution":2.2,
+        "title":"Crystal structure form ultalente insulin microcrystals"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1b9e",
+        "resolution":2.5,
+        "title":"HUMAN INSULIN MUTANT SERB9GLU"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1b9e",
+        "resolution":2.5,
+        "title":"HUMAN INSULIN MUTANT SERB9GLU"},
+      {
+        "experimental_method":["X-ray powder diffraction"],
+        "pdb_id":"1fub",
+        "title":"FIRST PROTEIN STRUCTURE DETERMINED FROM X-RAY POWDER DIFFRACTION DATA"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f51",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f4t",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f0o",
+        "resolution":1.672,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2vjz",
+        "resolution":1.8,
+        "title":"Crystal structure form ultalente insulin microcrystals"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4fka",
+        "resolution":1.08,
+        "title":"High resolution structure of the manganese derivative of insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1g",
+        "resolution":1.637,
+        "title":"Human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2r36",
+        "resolution":2.0,
+        "title":"Crystal structure of ni human ARG-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbi",
+        "resolution":2.502,
+        "title":"Crystal structure of aspart insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f8f",
+        "resolution":1.676,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1d",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbc",
+        "resolution":1.778,
+        "title":"Crystal structure of aspart insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbn",
+        "resolution":1.872,
+        "title":"Crystal structure of aspart insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4cxl",
+        "resolution":1.5,
+        "title":"Human insulin analogue (D-ProB8)-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4cxl",
+        "resolution":1.5,
+        "title":"Human insulin analogue (D-ProB8)-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1b",
+        "resolution":1.591,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1c",
+        "resolution":1.7,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f1f",
+        "resolution":1.684,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4f4v",
+        "resolution":1.637,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ceu",
+        "resolution":1.8,
+        "title":"Despentapeptide insulin in acetic acid (pH 2)"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ceu",
+        "resolution":1.8,
+        "title":"Despentapeptide insulin in acetic acid (pH 2)"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3bxq",
+        "resolution":1.3,
+        "title":"The structure of a mutant insulin uncouples receptor binding from protein allostery. An electrostatic block to the TR transition"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1jca",
+        "resolution":2.5,
+        "title":"Non-standard Design of Unstable Insulin Analogues with Enhanced Activity"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5cny",
+        "resolution":1.7,
+        "title":"Crystal Structure of human zinc insulin at pH 5.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5bpo",
+        "resolution":1.9,
+        "title":"Human insulin with intra-chain chemical crosslink between modified B27 and B29"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5urt",
+        "resolution":1.18,
+        "title":"Insulin with proline analog DhP at position B28 in the T2 state"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2mli",
+        "title":"NMR structure of B25-(alpha, beta)-dehydro-phenylalanine insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4iuz",
+        "resolution":1.6,
+        "title":"High resolution crystal structure of racemic ester insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ey1",
+        "resolution":1.471,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4eyp",
+        "resolution":1.591,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uu2",
+        "resolution":1.223,
+        "title":"Insulin with proline analog ThioP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ex1",
+        "resolution":1.657,
+        "title":"Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omi",
+        "resolution":2.24,
+        "title":"Structure of human insulin cocrystallized with protamine"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2k9r",
+        "title":"Enhancing the activity of insulin by stereospecific unfolding"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2k9r",
+        "title":"Enhancing the activity of insulin by stereospecific unfolding"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2g54",
+        "resolution":2.25,
+        "title":"Crystal structure of Zn-bound human insulin-degrading enzyme in complex with insulin B chain"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2vk0",
+        "resolution":2.2,
+        "title":"Crystal structure form ultalente insulin microcrystals"},
+      {
+        "experimental_method":["X-ray powder diffraction"],
+        "pdb_id":"1fub",
+        "title":"FIRST PROTEIN STRUCTURE DETERMINED FROM X-RAY POWDER DIFFRACTION DATA"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2vjz",
+        "resolution":1.8,
+        "title":"Crystal structure form ultalente insulin microcrystals"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2r36",
+        "resolution":2.0,
+        "title":"Crystal structure of ni human ARG-insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbk",
+        "resolution":2.4,
+        "title":"Crystal structure of aspart insulin at pH 8.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbk",
+        "resolution":2.4,
+        "title":"Crystal structure of aspart insulin at pH 8.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbi",
+        "resolution":2.502,
+        "title":"Crystal structure of aspart insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbc",
+        "resolution":1.778,
+        "title":"Crystal structure of aspart insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4cy7",
+        "resolution":1.4,
+        "title":"Crystal structure of human insulin analogue (NMe-AlaB8)-insulin crystal form II"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbn",
+        "resolution":1.872,
+        "title":"Crystal structure of aspart insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbl",
+        "resolution":2.5,
+        "title":"Crystal structure of aspart insulin at pH 8.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4gbl",
+        "resolution":2.5,
+        "title":"Crystal structure of aspart insulin at pH 8.5"},
+      {
+        "experimental_method":["X-ray powder diffraction"],
+        "pdb_id":"1fu2",
+        "title":"FIRST PROTEIN STRUCTURE DETERMINED FROM X-RAY POWDER DIFFRACTION DATA"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1ev3",
+        "resolution":1.78,
+        "title":"Structure of the rhombohedral form of the M-cresol/insulin R6 hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1j73",
+        "resolution":2.0,
+        "title":"Crystal structure of an unstable insulin analog with native activity."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1j73",
+        "resolution":2.0,
+        "title":"Crystal structure of an unstable insulin analog with native activity."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6s4i",
+        "resolution":1.511,
+        "title":"Crystal structure of zinc free A14E, B25H, B29K(N(eps)-[2-(2-[2-(2-[2-(Octadecandioyl-gamma-Glu)amino]ethoxy)ethoxy]acetylamino)ethoxy]ethoxy)acetyl]), desB30 human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6s4i",
+        "resolution":1.511,
+        "title":"Crystal structure of zinc free A14E, B25H, B29K(N(eps)-[2-(2-[2-(2-[2-(Octadecandioyl-gamma-Glu)amino]ethoxy)ethoxy]acetylamino)ethoxy]ethoxy)acetyl]), desB30 human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6p4z",
+        "resolution":1.8,
+        "title":"Structure of gadolinium-caged cobalt (III) insulin hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5co9",
+        "resolution":1.92,
+        "title":"Crystal structure of human zinc insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5cny",
+        "resolution":1.7,
+        "title":"Crystal Structure of human zinc insulin at pH 5.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5co2",
+        "resolution":1.7,
+        "title":"Crystalization of human zinc insulin at pH 5.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5co2",
+        "resolution":1.7,
+        "title":"Crystalization of human zinc insulin at pH 5.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5boq",
+        "resolution":1.7,
+        "title":"Human insulin with intra-chain chemical crosslink between modified B24 and B29"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5boq",
+        "resolution":1.7,
+        "title":"Human insulin with intra-chain chemical crosslink between modified B24 and B29"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6vet",
+        "resolution":1.46,
+        "title":"Human insulin analog: [GluB10,HisA8,ArgA9,TyrB20]-DOI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6vet",
+        "resolution":1.46,
+        "title":"Human insulin analog: [GluB10,HisA8,ArgA9,TyrB20]-DOI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6gv0",
+        "resolution":1.26,
+        "title":"Insulin glulisine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4iuz",
+        "resolution":1.6,
+        "title":"High resolution crystal structure of racemic ester insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4efx",
+        "resolution":1.98,
+        "title":"Highly biologically active insulin with additional disulfide bond"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4efx",
+        "resolution":1.98,
+        "title":"Highly biologically active insulin with additional disulfide bond"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6ce7",
+        "resolution":7.4,
+        "title":"Insulin Receptor ectodomain in complex with one insulin molecule"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2jmn",
+        "title":"NMR structure of human insulin mutant His-B10-Asp, Pro-B28-Lys, Lys-B29-Pro, 20 structures"},
+      {
+        "experimental_method":["Solution NMR"],
+        "pdb_id":"2jmn",
+        "title":"NMR structure of human insulin mutant His-B10-Asp, Pro-B28-Lys, Lys-B29-Pro, 20 structures"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3utq",
+        "resolution":1.67,
+        "title":"Human HLA-A*0201-ALWGPDPAAA"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omi",
+        "resolution":2.24,
+        "title":"Structure of human insulin cocrystallized with protamine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3e7y",
+        "resolution":1.6,
+        "title":"Structure of human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3e7y",
+        "resolution":1.6,
+        "title":"Structure of human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1ev6",
+        "resolution":1.9,
+        "title":"Structure of the monoclinic form of the M-cresol/insulin R6 hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1trz",
+        "resolution":1.6,
+        "title":"CRYSTALLOGRAPHIC EVIDENCE FOR DUAL COORDINATION AROUND ZINC IN THE T3R3 HUMAN INSULIN HEXAMER"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1trz",
+        "resolution":1.6,
+        "title":"CRYSTALLOGRAPHIC EVIDENCE FOR DUAL COORDINATION AROUND ZINC IN THE T3R3 HUMAN INSULIN HEXAMER"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws7",
+        "resolution":2.59,
+        "title":"Semi-synthetic analogue of human insulin ProB26-DTI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4nib",
+        "resolution":1.4,
+        "title":"Crystal structure of human insulin mutant B20 D-ala, B23 D-ala"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4nib",
+        "resolution":1.4,
+        "title":"Crystal structure of human insulin mutant B20 D-ala, B23 D-ala"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4cy7",
+        "resolution":1.4,
+        "title":"Crystal structure of human insulin analogue (NMe-AlaB8)-insulin crystal form II"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1qj0",
+        "resolution":2.4,
+        "title":"HUMAN INSULIN HEXAMERS WITH CHAIN B HIS MUTATED TO TYR"},
+      {
+        "experimental_method":["X-ray powder diffraction"],
+        "pdb_id":"1fu2",
+        "title":"FIRST PROTEIN STRUCTURE DETERMINED FROM X-RAY POWDER DIFFRACTION DATA"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1evr",
+        "resolution":1.9,
+        "title":"The structure of the resorcinol/insulin R6 hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1ev6",
+        "resolution":1.9,
+        "title":"Structure of the monoclinic form of the M-cresol/insulin R6 hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1guj",
+        "resolution":1.62,
+        "title":"Insulin at pH 2: structural analysis of the conditions promoting insulin fibre formation."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1guj",
+        "resolution":1.62,
+        "title":"Insulin at pH 2: structural analysis of the conditions promoting insulin fibre formation."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1ev3",
+        "resolution":1.78,
+        "title":"Structure of the rhombohedral form of the M-cresol/insulin R6 hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2w44",
+        "resolution":2.0,
+        "title":"Structure DeltaA1-A4 insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1uz9",
+        "resolution":1.6,
+        "title":"Crystallographic and solution studies of N-lithocholyl insulin: a new generation of prolonged-acting insulins."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1uz9",
+        "resolution":1.6,
+        "title":"Crystallographic and solution studies of N-lithocholyl insulin: a new generation of prolonged-acting insulins."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3e7z",
+        "resolution":1.7,
+        "title":"Structure of human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3e7z",
+        "resolution":1.7,
+        "title":"Structure of human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6gnq",
+        "resolution":2.2,
+        "title":"Monoclinic crystalline form of human insulin, complexed with meta-cresol"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"7s4y",
+        "resolution":1.71,
+        "title":"Serial Macromolecular Crystallography at ALBA Synchrotron Light Source - Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"7s4y",
+        "resolution":1.71,
+        "title":"Serial Macromolecular Crystallography at ALBA Synchrotron Light Source - Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5co6",
+        "resolution":1.8,
+        "title":"Crystal structure of human zinc insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5co6",
+        "resolution":1.8,
+        "title":"Crystal structure of human zinc insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6p4z",
+        "resolution":1.8,
+        "title":"Structure of gadolinium-caged cobalt (III) insulin hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5co9",
+        "resolution":1.92,
+        "title":"Crystal structure of human zinc insulin at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6s4j",
+        "resolution":1.5,
+        "title":"Crystal structure of zinc free A14E, B25H, B29K(N(eps)-[2-(2-[2-(2-[2-(Octadecandioyl-gamma-Glu)amino]ethoxy)ethoxy]acetylamino)ethoxy]ethoxy)acetyl]), desB27, desB30 human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6s4j",
+        "resolution":1.5,
+        "title":"Crystal structure of zinc free A14E, B25H, B29K(N(eps)-[2-(2-[2-(2-[2-(Octadecandioyl-gamma-Glu)amino]ethoxy)ethoxy]acetylamino)ethoxy]ethoxy)acetyl]), desB27, desB30 human insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6gv0",
+        "resolution":1.26,
+        "title":"Insulin glulisine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zu1",
+        "resolution":1.6,
+        "title":"Structure of LysB29(Nepsilon omega-carboxyheptadecanoyl) des(B30) Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zu1",
+        "resolution":1.6,
+        "title":"Structure of LysB29(Nepsilon omega-carboxyheptadecanoyl) des(B30) Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5ems",
+        "resolution":2.3,
+        "title":"Crystal Structure of an iodinated insulin analog"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6ce7",
+        "resolution":7.4,
+        "title":"Insulin Receptor ectodomain in complex with one insulin molecule"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1jk8",
+        "resolution":2.4,
+        "title":"Crystal structure of a human insulin peptide-HLA-DQ8 complex"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wby",
+        "resolution":2.6,
+        "title":"Crystal structure of human insulin-degrading enzyme in complex with insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wby",
+        "resolution":2.6,
+        "title":"Crystal structure of human insulin-degrading enzyme in complex with insulin"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6hn5",
+        "resolution":3.2,
+        "title":"Leucine-zippered human insulin receptor ectodomain with single bound insulin - \"upper\" membrane-distal part"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2om1",
+        "resolution":1.97,
+        "title":"Structure of human insulin in presence of thiocyanate at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2om0",
+        "resolution":2.05,
+        "title":"Structure of human insulin in presence of urea at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2om0",
+        "resolution":2.05,
+        "title":"Structure of human insulin in presence of urea at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3p33",
+        "resolution":2.3,
+        "title":"Insulin fibrillation is the Janus face of induced fit. A chiral clamp stabilizes the native state at the expense of activity"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omg",
+        "resolution":1.52,
+        "title":"Structure of human insulin cocrystallized with protamine and urea"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2olz",
+        "resolution":1.7,
+        "title":"Structure of human insulin in presence of thiocyanate at pH 7.0"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2olz",
+        "resolution":1.7,
+        "title":"Structure of human insulin in presence of thiocyanate at pH 7.0"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1ben",
+        "resolution":1.4,
+        "title":"INSULIN COMPLEXED WITH 4-HYDROXYBENZAMIDE"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1g7a",
+        "resolution":1.2,
+        "title":"1.2 A structure of T3R3 human insulin at 100 K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1g7a",
+        "resolution":1.2,
+        "title":"1.2 A structure of T3R3 human insulin at 100 K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1w8p",
+        "resolution":2.08,
+        "title":"Structural properties of the B25Tyr-NMe-B26Phe insulin mutant."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1w8p",
+        "resolution":2.08,
+        "title":"Structural properties of the B25Tyr-NMe-B26Phe insulin mutant."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1rwe",
+        "resolution":1.8,
+        "title":"Enhancing the activity of insulin at receptor edge: crystal structure and photo-cross-linking of A8 analogues"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1rwe",
+        "resolution":1.8,
+        "title":"Enhancing the activity of insulin at receptor edge: crystal structure and photo-cross-linking of A8 analogues"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1znj",
+        "resolution":2.0,
+        "title":"INSULIN, MONOCLINIC CRYSTAL FORM"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1znj",
+        "resolution":2.0,
+        "title":"INSULIN, MONOCLINIC CRYSTAL FORM"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1xw7",
+        "resolution":2.3,
+        "title":"Diabetes-Associated Mutations in Human Insulin: Crystal Structure and Photo-Cross-Linking Studies of A-Chain Variant Insulin Wakayama"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1xw7",
+        "resolution":2.3,
+        "title":"Diabetes-Associated Mutations in Human Insulin: Crystal Structure and Photo-Cross-Linking Studies of A-Chain Variant Insulin Wakayama"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4fg3",
+        "resolution":2.001,
+        "title":"Crystal Structure Analysis of the Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4fg3",
+        "resolution":2.001,
+        "title":"Crystal Structure Analysis of the Human Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2ws7",
+        "resolution":2.59,
+        "title":"Semi-synthetic analogue of human insulin ProB26-DTI"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1lph",
+        "resolution":2.3,
+        "title":"LYS(B28)PRO(B29)-HUMAN INSULIN"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1qj0",
+        "resolution":2.4,
+        "title":"HUMAN INSULIN HEXAMERS WITH CHAIN B HIS MUTATED TO TYR"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1g7b",
+        "resolution":1.3,
+        "title":"1.3 A STRUCTURE OF T3R3 HUMAN INSULIN AT 100 K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1g7b",
+        "resolution":1.3,
+        "title":"1.3 A STRUCTURE OF T3R3 HUMAN INSULIN AT 100 K"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1evr",
+        "resolution":1.9,
+        "title":"The structure of the resorcinol/insulin R6 hexamer"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2w44",
+        "resolution":2.0,
+        "title":"Structure DeltaA1-A4 insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6gnq",
+        "resolution":2.2,
+        "title":"Monoclinic crystalline form of human insulin, complexed with meta-cresol"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uru",
+        "resolution":2.41,
+        "title":"Insulin with proline analog DhP at position B28 in the R6 state"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"7bw7",
+        "resolution":4.1,
+        "title":"Cryo-EM Structure for the Ectodomain of the Full-length Human Insulin Receptor in Complex with 1 Insulin."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6ck2",
+        "resolution":2.25,
+        "title":"Insulin analog containing a YB26W mutation"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6nwv",
+        "resolution":1.601,
+        "title":"Insulin Lispro Analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hrq",
+        "resolution":1.28,
+        "title":"Insulin with proline analog HzP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zqr",
+        "resolution":1.9,
+        "title":"NMePheB25 insulin analogue crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zqr",
+        "resolution":1.9,
+        "title":"NMePheB25 insulin analogue crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ajx",
+        "resolution":1.2,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ajx",
+        "resolution":1.2,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4akj",
+        "resolution":2.01,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ajz",
+        "resolution":1.8,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3v19",
+        "resolution":2.0,
+        "title":"Forestalling insulin fibrillation by insertion of a chiral clamp mechanism-based application of protein engineering to global health"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3v19",
+        "resolution":2.0,
+        "title":"Forestalling insulin fibrillation by insertion of a chiral clamp mechanism-based application of protein engineering to global health"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zs2",
+        "resolution":1.97,
+        "title":"TyrB25,NMePheB26,LysB28,ProB29-insulin analogue crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3zs2",
+        "resolution":1.97,
+        "title":"TyrB25,NMePheB26,LysB28,ProB29-insulin analogue crystal structure"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3v1g",
+        "resolution":2.2,
+        "title":"Forestalling insulin fibrillation by insertion of a chiral clamp mechanism-based application of protein engineering to global health"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3v1g",
+        "resolution":2.2,
+        "title":"Forestalling insulin fibrillation by insertion of a chiral clamp mechanism-based application of protein engineering to global health"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uu3",
+        "resolution":2.25,
+        "title":"Insulin with proline analog DfP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uss",
+        "resolution":2.061,
+        "title":"Insulin with proline analog PiP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uss",
+        "resolution":2.061,
+        "title":"Insulin with proline analog PiP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5udp",
+        "resolution":1.348,
+        "title":"High resolution x-ray crystal structure of synthetic insulin lispro"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5udp",
+        "resolution":1.348,
+        "title":"High resolution x-ray crystal structure of synthetic insulin lispro"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5mt9",
+        "resolution":1.88,
+        "title":"Human insulin in complex with serotonin and arginine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5ems",
+        "resolution":2.3,
+        "title":"Crystal Structure of an iodinated insulin analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hpr",
+        "resolution":1.33,
+        "title":"Insulin with proline analog HyP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hpr",
+        "resolution":1.33,
+        "title":"Insulin with proline analog HyP at position B28 in the T2 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3kq6",
+        "resolution":1.9,
+        "title":"Enhancing the Therapeutic Properties of a Protein by a Designed Zinc-Binding Site, Structural principles of a novel long-acting insulin analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3kq6",
+        "resolution":1.9,
+        "title":"Enhancing the Therapeutic Properties of a Protein by a Designed Zinc-Binding Site, Structural principles of a novel long-acting insulin analog"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5mt3",
+        "resolution":2.02,
+        "title":"Human insulin in complex with serotonin and arginine"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6hn5",
+        "resolution":3.2,
+        "title":"Leucine-zippered human insulin receptor ectodomain with single bound insulin - \"upper\" membrane-distal part"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4wdi",
+        "resolution":2.313,
+        "title":"Weak TCR binding to an unstable insulin epitope drives type 1 diabetes"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wc0",
+        "resolution":2.8,
+        "title":"crystal structure of human insulin degrading enzyme in complex with iodinated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2wc0",
+        "resolution":2.8,
+        "title":"crystal structure of human insulin degrading enzyme in complex with iodinated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6z7y",
+        "resolution":2.2,
+        "title":"Human insulin in complex with the analytical antibody OXI-005 Fab"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6z7y",
+        "resolution":2.2,
+        "title":"Human insulin in complex with the analytical antibody OXI-005 Fab"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6sof",
+        "resolution":4.3,
+        "title":"human insulin receptor ectodomain bound by 4 insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3p2x",
+        "resolution":2.0,
+        "title":"Insulin fibrillation is the Janus face of induced fit. A chiaral clamp stabilizes the native state at the expense of activity"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3p2x",
+        "resolution":2.0,
+        "title":"Insulin fibrillation is the Janus face of induced fit. A chiaral clamp stabilizes the native state at the expense of activity"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3jsd",
+        "resolution":2.5,
+        "title":"Insulin's biosynthesis and activity have opposing structural requirements: a new factor in neonatal diabetes mellitus"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3jsd",
+        "resolution":2.5,
+        "title":"Insulin's biosynthesis and activity have opposing structural requirements: a new factor in neonatal diabetes mellitus"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2om1",
+        "resolution":1.97,
+        "title":"Structure of human insulin in presence of thiocyanate at pH 6.5"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omh",
+        "resolution":1.36,
+        "title":"Structure of human insulin cocrystallized with ARG-12 peptide in presence of urea"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omh",
+        "resolution":1.36,
+        "title":"Structure of human insulin cocrystallized with ARG-12 peptide in presence of urea"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3fq9",
+        "resolution":1.35,
+        "title":"Design of an insulin analog with enhanced receptor-binding selectivity. Rationale, structure, and therapeutic implications"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3fq9",
+        "resolution":1.35,
+        "title":"Design of an insulin analog with enhanced receptor-binding selectivity. Rationale, structure, and therapeutic implications"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"3p33",
+        "resolution":2.3,
+        "title":"Insulin fibrillation is the Janus face of induced fit. A chiral clamp stabilizes the native state at the expense of activity"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2omg",
+        "resolution":1.52,
+        "title":"Structure of human insulin cocrystallized with protamine and urea"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1ben",
+        "resolution":1.4,
+        "title":"INSULIN COMPLEXED WITH 4-HYDROXYBENZAMIDE"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1qiz",
+        "resolution":2.0,
+        "title":"HUMAN INSULIN HEXAMERS WITH CHAIN B HIS MUTATED TO TYR COMPLEXED WITH RESORCINOL"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1qiz",
+        "resolution":2.0,
+        "title":"HUMAN INSULIN HEXAMERS WITH CHAIN B HIS MUTATED TO TYR COMPLEXED WITH RESORCINOL"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4p65",
+        "resolution":1.5,
+        "title":"Crystal structure of an cyclohexylalanine substituted insulin analog."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4p65",
+        "resolution":1.5,
+        "title":"Crystal structure of an cyclohexylalanine substituted insulin analog."},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1lph",
+        "resolution":2.3,
+        "title":"LYS(B28)PRO(B29)-HUMAN INSULIN"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"2oly",
+        "resolution":1.7,
+        "title":"Structure of human insulin in presence of urea at pH 7.0"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6tyh",
+        "resolution":1.600019,
+        "title":"Four-Disulfide Insulin Analog A22/B22"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6tyh",
+        "resolution":1.600019,
+        "title":"Four-Disulfide Insulin Analog A22/B22"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uru",
+        "resolution":2.41,
+        "title":"Insulin with proline analog DhP at position B28 in the R6 state"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"7bw8",
+        "resolution":3.8,
+        "title":"Cryo-EM Structure for the Insulin Binding Region in the Ectodomain of the Full-length Human Insulin Receptor in Complex with 1 Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6ck2",
+        "resolution":2.25,
+        "title":"Insulin analog containing a YB26W mutation"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6bfc",
+        "resolution":3.7,
+        "title":"Cryo-EM structure of human insulin degrading enzyme in complex with insulin"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"6b3q",
+        "resolution":3.7,
+        "title":"Cryo-EM structure of human insulin degrading enzyme in complex with insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6nwv",
+        "resolution":1.601,
+        "title":"Insulin Lispro Analog"},
+      {
+        "experimental_method":["Electron Microscopy"],
+        "pdb_id":"7bwa",
+        "resolution":4.9,
+        "title":"Cryo-EM Structure for the Ectodomain of the Full-length Human Insulin Receptor in Complex with 2 Insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hpu",
+        "resolution":2.2,
+        "title":"Insulin with proline analog HyP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hpu",
+        "resolution":2.2,
+        "title":"Insulin with proline analog HyP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5hrq",
+        "resolution":1.28,
+        "title":"Insulin with proline analog HzP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4akj",
+        "resolution":2.01,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4ajz",
+        "resolution":1.8,
+        "title":"Ligand controlled assembly of hexamers, dihexamers, and linear multihexamer structures by an engineered acylated insulin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uu3",
+        "resolution":2.25,
+        "title":"Insulin with proline analog DfP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uu4",
+        "resolution":1.973,
+        "title":"Insulin with proline analog ThioP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5uu4",
+        "resolution":1.973,
+        "title":"Insulin with proline analog ThioP at position B28 in the R6 state"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5mam",
+        "resolution":2.2,
+        "title":"Human insulin in complex with serotonin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5mam",
+        "resolution":2.2,
+        "title":"Human insulin in complex with serotonin"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5mt3",
+        "resolution":2.02,
+        "title":"Human insulin in complex with serotonin and arginine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5mt9",
+        "resolution":1.88,
+        "title":"Human insulin in complex with serotonin and arginine"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"5bqq",
+        "resolution":1.54,
+        "title":"Human insulin with intra-chain chemical crosslink between modified B27 and B30"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"1q4v",
+        "resolution":2.0,
+        "title":"CRYSTAL STRUCTURE OF ALLO-ILEA2-INSULIN, AN INACTIVE CHIRAL ANALOGUE: IMPLICATIONS FOR THE MECHANISM OF RECEPTOR"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4xc4",
+        "resolution":1.499,
+        "title":"Insulin co-crystallizes in the presence of it beta-cell chaperone sulfatide"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"4xc4",
+        "resolution":1.499,
+        "title":"Insulin co-crystallizes in the presence of it beta-cell chaperone sulfatide"},
+      {
+        "experimental_method":["X-ray diffraction"],
+        "pdb_id":"6z7y",
+        "resolution":2.2,
+        "title":"Human insulin in complex with the analytical antibody OXI-005 Fab"}]
+  }}
diff --git a/test/jalview/fts/threedbeacons/p01308_tdb_resp.txt b/test/jalview/fts/threedbeacons/p01308_tdb_resp.txt
new file mode 100644 (file)
index 0000000..14a5d43
--- /dev/null
@@ -0,0 +1 @@
+{"uniprot_entry":{"sequence_length":110,"ac":"P01308","id":"INS_HUMAN"},"structures":[{"model_identifier":"3w7y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-03-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":0.92,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w7y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w7y"},{"model_identifier":"3w7y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-03-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":0.92,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w7y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w7y"},{"model_identifier":"5e7w","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-10-13","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":0.9519,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5e7w_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5e7w"},{"model_identifier":"5e7w","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-10-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":0.9519,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5e7w_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5e7w"},{"model_identifier":"5hqi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":0.97,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hqi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hqi"},{"model_identifier":"5hqi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":0.97,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hqi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hqi"},{"model_identifier":"1mso","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2002-09-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1mso_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1mso"},{"model_identifier":"1mso","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2002-09-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1mso_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1mso"},{"model_identifier":"3hyd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-06-22","sequence_identity":100.0,"uniprot_start":35,"uniprot_end":41,"resolution":1.0,"coverage":8.14,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3hyd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3hyd"},{"model_identifier":"6ver","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":91.0,"uniprot_start":25,"uniprot_end":46,"resolution":1.047,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ver_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ver"},{"model_identifier":"6ver","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.047,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ver_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ver"},{"model_identifier":"4fka","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-06-13","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.08,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4fka_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4fka"},{"model_identifier":"4fka","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-06-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.08,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4fka_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4fka"},{"model_identifier":"3tt8","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-09-14","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.12,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3tt8_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3tt8"},{"model_identifier":"3tt8","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-09-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.12,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3tt8_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3tt8"},{"model_identifier":"3w7z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-03-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.15,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w7z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w7z"},{"model_identifier":"3w7z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-03-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.15,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w7z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w7z"},{"model_identifier":"5usp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-13","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.174,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5usp_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5usp"},{"model_identifier":"5usp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.174,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5usp_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5usp"},{"model_identifier":"5uoz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.17463871031,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uoz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uoz"},{"model_identifier":"5uoz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.17463871031,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uoz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uoz"},{"model_identifier":"5urt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-12","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.18,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5urt_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5urt"},{"model_identifier":"5urt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-12","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.18,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5urt_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5urt"},{"model_identifier":"1g7a","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-11-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1g7a_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1g7a"},{"model_identifier":"4ajx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.2,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ajx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ajx"},{"model_identifier":"1g7a","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-11-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1g7a_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1g7a"},{"model_identifier":"4ajx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ajx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ajx"},{"model_identifier":"5uu2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-15","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.223,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uu2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uu2"},{"model_identifier":"5uu2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-15","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.223,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uu2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uu2"},{"model_identifier":"6gv0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-06-20","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.26,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6gv0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6gv0"},{"model_identifier":"6gv0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-06-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.26,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6gv0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6gv0"},{"model_identifier":"5hrq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-24","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.28,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hrq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hrq"},{"model_identifier":"5hrq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-24","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.28,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hrq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hrq"},{"model_identifier":"1g7b","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-11-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1g7b_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1g7b"},{"model_identifier":"5usv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-14","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5usv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5usv"},{"model_identifier":"3bxq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-01-14","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3bxq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3bxq"},{"model_identifier":"1g7b","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-11-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1g7b_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1g7b"},{"model_identifier":"5usv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5usv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5usv"},{"model_identifier":"3bxq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-01-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3bxq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3bxq"},{"model_identifier":"5uqa","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-07","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.31000248093,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uqa_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uqa"},{"model_identifier":"5uqa","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.31000248093,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uqa_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uqa"},{"model_identifier":"5hpr","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.33,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hpr_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hpr"},{"model_identifier":"5hpr","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.33,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hpr_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hpr"},{"model_identifier":"5udp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-12-28","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.348,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5udp_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5udp"},{"model_identifier":"5udp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-12-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.348,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5udp_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5udp"},{"model_identifier":"3fq9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-01-07","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.35,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3fq9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3fq9"},{"model_identifier":"5ena","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-11-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.35,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5ena_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5ena"},{"model_identifier":"3exx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-10-17","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.35,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3exx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3exx"},{"model_identifier":"6s34","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-06-24","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.35,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6s34_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6s34"},{"model_identifier":"5ena","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-11-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.35,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5ena_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5ena"},{"model_identifier":"3exx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-10-17","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.35,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3exx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3exx"},{"model_identifier":"6s34","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-06-24","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.35,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6s34_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6s34"},{"model_identifier":"3fq9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-01-07","sequence_identity":95.0,"uniprot_start":91,"uniprot_end":110,"resolution":1.35,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3fq9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3fq9"},{"model_identifier":"6tc2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-11-04","sequence_identity":100.0,"uniprot_start":1,"uniprot_end":110,"resolution":1.36,"coverage":100.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6tc2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6tc2"},{"model_identifier":"2omh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.36,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omh"},{"model_identifier":"2omh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.36,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omh"},{"model_identifier":"4nib","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-11-05","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.4,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4nib_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4nib"},{"model_identifier":"4cy7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-04-10","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.4,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4cy7_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4cy7"},{"model_identifier":"3w80","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-03-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.4,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w80_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w80"},{"model_identifier":"1ben","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-02-15","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.4,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ben_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ben"},{"model_identifier":"7nhu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2021-02-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.4,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7nhu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7nhu"},{"model_identifier":"4nib","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-11-05","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4nib_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4nib"},{"model_identifier":"4cy7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-04-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4cy7_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4cy7"},{"model_identifier":"7nhu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2021-02-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7nhu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7nhu"},{"model_identifier":"3w80","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-03-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w80_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w80"},{"model_identifier":"1ben","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-02-15","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ben_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ben"},{"model_identifier":"6vet","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":91.0,"uniprot_start":25,"uniprot_end":46,"resolution":1.46,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6vet_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6vet"},{"model_identifier":"6vet","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.46,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6vet_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6vet"},{"model_identifier":"4ey1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.471,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ey1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ey1"},{"model_identifier":"4ey9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.471,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ey9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ey9"},{"model_identifier":"4eyd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.471,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eyd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eyd"},{"model_identifier":"4ey1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.471,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ey1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ey1"},{"model_identifier":"4ey9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.471,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ey9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ey9"},{"model_identifier":"4eyd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.471,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eyd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eyd"},{"model_identifier":"4xc4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-12-17","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.499,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4xc4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4xc4"},{"model_identifier":"4xc4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-12-17","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.499,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4xc4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4xc4"},{"model_identifier":"1zeh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-05-01","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1zeh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1zeh"},{"model_identifier":"2wrx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wrx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wrx"},{"model_identifier":"2ws6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws6"},{"model_identifier":"2ws6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws6"},{"model_identifier":"4cxl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-04-07","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4cxl_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4cxl"},{"model_identifier":"5en9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-11-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5en9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5en9"},{"model_identifier":"4p65","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-03-21","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4p65_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4p65"},{"model_identifier":"2c8r","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2005-12-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.5,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2c8r_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2c8r"},{"model_identifier":"6s4j","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-06-28","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.5,"coverage":32.56,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6s4j_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6s4j"},{"model_identifier":"1zeh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1zeh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1zeh"},{"model_identifier":"2wrx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wrx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wrx"},{"model_identifier":"2ws6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws6"},{"model_identifier":"2c8r","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2005-12-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2c8r_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2c8r"},{"model_identifier":"4cxl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-04-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4cxl_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4cxl"},{"model_identifier":"5en9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-11-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5en9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5en9"},{"model_identifier":"4p65","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-03-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4p65_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4p65"},{"model_identifier":"6s4j","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-06-28","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6s4j_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6s4j"},{"model_identifier":"6s4i","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-06-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.511,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6s4i_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6s4i"},{"model_identifier":"6s4i","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-06-28","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.511,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6s4i_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6s4i"},{"model_identifier":"2omg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.52,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omg_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omg"},{"model_identifier":"2omg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.52,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omg_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omg"},{"model_identifier":"4eyn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.532,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eyn_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eyn"},{"model_identifier":"4eyn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.532,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eyn_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eyn"},{"model_identifier":"5bqq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-29","sequence_identity":96.0,"uniprot_start":25,"uniprot_end":52,"resolution":1.54,"coverage":32.56,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5bqq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5bqq"},{"model_identifier":"5bqq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.54,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5bqq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5bqq"},{"model_identifier":"4exx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.55,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4exx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4exx"},{"model_identifier":"5t7r","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-09-05","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.55,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5t7r_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5t7r"},{"model_identifier":"4exx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.55,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4exx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4exx"},{"model_identifier":"5t7r","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-09-05","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.55,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5t7r_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5t7r"},{"model_identifier":"2wru","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":1.57,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wru_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wru"},{"model_identifier":"2wru","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.57,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wru_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wru"},{"model_identifier":"6o17","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-02-18","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.58,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6o17_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6o17"},{"model_identifier":"6o17","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-02-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.58,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6o17_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6o17"},{"model_identifier":"4une","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.59,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4une_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4une"},{"model_identifier":"4une","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.59,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4une_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4une"},{"model_identifier":"4eyp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.591,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eyp_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eyp"},{"model_identifier":"4f1b","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.591,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1b_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1b"},{"model_identifier":"4eyp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.591,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eyp_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eyp"},{"model_identifier":"4f1b","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.591,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1b_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1b"},{"model_identifier":"1zeg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-05-01","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.6,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1zeg_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1zeg"},{"model_identifier":"2ws1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.6,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws1"},{"model_identifier":"3zu1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-07-13","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.6,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zu1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zu1"},{"model_identifier":"1trz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1993-11-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.6,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1trz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1trz"},{"model_identifier":"4iuz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-22","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.6,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4iuz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4iuz"},{"model_identifier":"3i3z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-07-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.6,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3i3z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3i3z"},{"model_identifier":"1uz9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-03-08","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.6,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1uz9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1uz9"},{"model_identifier":"3e7y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-08-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.6,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3e7y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3e7y"},{"model_identifier":"3i3z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-07-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3i3z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3i3z"},{"model_identifier":"1zeg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-05-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1zeg_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1zeg"},{"model_identifier":"2ws1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws1"},{"model_identifier":"1uz9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-03-08","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1uz9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1uz9"},{"model_identifier":"3zu1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-07-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zu1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zu1"},{"model_identifier":"3e7y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-08-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3e7y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3e7y"},{"model_identifier":"1trz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1993-11-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1trz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1trz"},{"model_identifier":"4iuz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-22","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.6,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4iuz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4iuz"},{"model_identifier":"6tyh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-08-08","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.60001899481,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6tyh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6tyh"},{"model_identifier":"6tyh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-08-08","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.60001899481,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6tyh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6tyh"},{"model_identifier":"6nwv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-02-07","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.601,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6nwv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6nwv"},{"model_identifier":"6nwv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-02-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.601,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6nwv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6nwv"},{"model_identifier":"1guj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2002-01-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.62,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1guj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1guj"},{"model_identifier":"1guj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2002-01-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.62,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1guj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1guj"},{"model_identifier":"4f1d","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.637,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1d_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1d"},{"model_identifier":"4f1g","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.637,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1g_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1g"},{"model_identifier":"4f4t","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.637,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f4t_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f4t"},{"model_identifier":"4f4v","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.637,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f4v_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f4v"},{"model_identifier":"4f51","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.637,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f51_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f51"},{"model_identifier":"4f1d","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.637,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1d_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1d"},{"model_identifier":"4f1g","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.637,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1g_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1g"},{"model_identifier":"4f4t","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.637,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f4t_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f4t"},{"model_identifier":"4f4v","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.637,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f4v_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f4v"},{"model_identifier":"4f51","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.637,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f51_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f51"},{"model_identifier":"4ex1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.657,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ex1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ex1"},{"model_identifier":"4ex1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.657,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ex1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ex1"},{"model_identifier":"4iyd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.66,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4iyd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4iyd"},{"model_identifier":"4iyd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":1.66,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4iyd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4iyd"},{"model_identifier":"3utq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-11-26","sequence_identity":100.0,"uniprot_start":15,"uniprot_end":24,"resolution":1.67,"coverage":0.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3utq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3utq"},{"model_identifier":"4f0o","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-04","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.672,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f0o_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f0o"},{"model_identifier":"4f0o","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-04","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.672,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f0o_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f0o"},{"model_identifier":"4f8f","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-17","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.676,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f8f_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f8f"},{"model_identifier":"4f8f","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-17","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.676,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f8f_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f8f"},{"model_identifier":"4f0n","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-04","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.679,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f0n_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f0n"},{"model_identifier":"4f0n","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-04","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.679,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f0n_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f0n"},{"model_identifier":"5c0d","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-06-12","sequence_identity":90.0,"uniprot_start":15,"uniprot_end":24,"resolution":1.68,"coverage":0.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5c0d_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5c0d"},{"model_identifier":"4f1f","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.684,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1f_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1f"},{"model_identifier":"4f1f","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.684,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1f_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1f"},{"model_identifier":"3zi3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-02","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zi3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zi3"},{"model_identifier":"4f1c","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1c_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1c"},{"model_identifier":"4cxn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-04-07","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4cxn_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4cxn"},{"model_identifier":"5cny","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-18","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5cny_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5cny"},{"model_identifier":"5co2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5co2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5co2"},{"model_identifier":"2oly","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2oly_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2oly"},{"model_identifier":"2olz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2olz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2olz"},{"model_identifier":"5boq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-27","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.7,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5boq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5boq"},{"model_identifier":"5viz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-04-17","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.7,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5viz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5viz"},{"model_identifier":"3e7z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-08-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.7,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3e7z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3e7z"},{"model_identifier":"3zi3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zi3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zi3"},{"model_identifier":"4f1c","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1c_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1c"},{"model_identifier":"4cxn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-04-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4cxn_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4cxn"},{"model_identifier":"5cny","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5cny_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5cny"},{"model_identifier":"3e7z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-08-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3e7z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3e7z"},{"model_identifier":"5co2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5co2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5co2"},{"model_identifier":"2oly","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2oly_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2oly"},{"model_identifier":"2olz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2olz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2olz"},{"model_identifier":"5boq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5boq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5boq"},{"model_identifier":"5viz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-04-17","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":1.7,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5viz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5viz"},{"model_identifier":"7s4y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2021-09-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.71,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7s4y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7s4y"},{"model_identifier":"7s4y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2021-09-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.71,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7s4y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7s4y"},{"model_identifier":"4rxw","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-12-12","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.73,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4rxw_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4rxw"},{"model_identifier":"4rxw","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-12-12","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.73,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4rxw_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4rxw"},{"model_identifier":"5bts","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-06-03","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.77,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5bts_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5bts"},{"model_identifier":"5bts","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-06-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.77,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5bts_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5bts"},{"model_identifier":"4gbc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.778,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbc_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbc"},{"model_identifier":"4gbc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.778,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbc_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbc"},{"model_identifier":"1ev3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-04-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.78,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ev3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ev3"},{"model_identifier":"1ev3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-04-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.78,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ev3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ev3"},{"model_identifier":"4ewz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.791,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ewz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ewz"},{"model_identifier":"4ewz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.791,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ewz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ewz"},{"model_identifier":"4f1a","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.8,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1a_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1a"},{"model_identifier":"2vjz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-12-14","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.8,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2vjz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2vjz"},{"model_identifier":"1rwe","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-12-16","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.8,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1rwe_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1rwe"},{"model_identifier":"5co6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.8,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5co6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5co6"},{"model_identifier":"6p4z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-05-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.8,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6p4z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6p4z"},{"model_identifier":"1xda","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-12-18","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.8,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1xda_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1xda"},{"model_identifier":"4ajz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.8,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ajz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ajz"},{"model_identifier":"4iyf","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.8,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4iyf_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4iyf"},{"model_identifier":"2ceu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-02-10","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":1.8,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ceu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ceu"},{"model_identifier":"4f1a","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-05-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4f1a_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4f1a"},{"model_identifier":"2ceu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-02-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ceu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ceu"},{"model_identifier":"2vjz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-12-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2vjz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2vjz"},{"model_identifier":"1rwe","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-12-16","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1rwe_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1rwe"},{"model_identifier":"1xda","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-12-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1xda_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1xda"},{"model_identifier":"5co6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5co6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5co6"},{"model_identifier":"4ajz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ajz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ajz"},{"model_identifier":"6p4z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-05-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6p4z_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6p4z"},{"model_identifier":"4iyf","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2013-01-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":1.8,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4iyf_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4iyf"},{"model_identifier":"4ung","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.81,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ung_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ung"},{"model_identifier":"4ung","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.81,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ung_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ung"},{"model_identifier":"6h3m","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-07-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.821,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6h3m_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6h3m"},{"model_identifier":"6h3m","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-07-19","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.821,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6h3m_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6h3m"},{"model_identifier":"3inc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-08-12","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.85,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3inc_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3inc"},{"model_identifier":"3i40","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-07-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.85,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3i40_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3i40"},{"model_identifier":"6ves","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":95.0,"uniprot_start":25,"uniprot_end":46,"resolution":1.85,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ves_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ves"},{"model_identifier":"3i40","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-07-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.85,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3i40_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3i40"},{"model_identifier":"6ves","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.85,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ves_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ves"},{"model_identifier":"3inc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-08-12","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.85,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3inc_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3inc"},{"model_identifier":"4z77","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-04-06","sequence_identity":89.0,"uniprot_start":39,"uniprot_end":47,"resolution":1.85,"coverage":10.47,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4z77_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4z77"},{"model_identifier":"4ex0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.86,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ex0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ex0"},{"model_identifier":"4ex0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.86,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ex0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ex0"},{"model_identifier":"4gbn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.872,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbn_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbn"},{"model_identifier":"4gbn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.872,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbn_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbn"},{"model_identifier":"5mt9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-01-07","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.88,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mt9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mt9"},{"model_identifier":"5mt9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-01-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.88,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mt9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mt9"},{"model_identifier":"4z76","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-04-06","sequence_identity":89.0,"uniprot_start":39,"uniprot_end":47,"resolution":1.88,"coverage":10.47,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4z76_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4z76"},{"model_identifier":"3ilg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-08-07","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3ilg_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3ilg"},{"model_identifier":"3zqr","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-06-10","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zqr_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zqr"},{"model_identifier":"3kq6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-11-17","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3kq6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3kq6"},{"model_identifier":"1ev6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-04-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ev6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ev6"},{"model_identifier":"1evr","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-04-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1evr_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1evr"},{"model_identifier":"1tyl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-06-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1tyl_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1tyl"},{"model_identifier":"1tym","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-06-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1tym_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1tym"},{"model_identifier":"5bpo","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-28","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5bpo_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5bpo"},{"model_identifier":"1htv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-01-01","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":51,"resolution":1.9,"coverage":31.4,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1htv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1htv"},{"model_identifier":"2ws4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":1.9,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws4"},{"model_identifier":"1htv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-01-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1htv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1htv"},{"model_identifier":"2ws4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws4"},{"model_identifier":"3ilg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-08-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3ilg_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3ilg"},{"model_identifier":"3zqr","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-06-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zqr_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zqr"},{"model_identifier":"3kq6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-11-17","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3kq6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3kq6"},{"model_identifier":"1ev6","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-04-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ev6_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ev6"},{"model_identifier":"1evr","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-04-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1evr_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1evr"},{"model_identifier":"1tyl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-06-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1tyl_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1tyl"},{"model_identifier":"1tym","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-06-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1tym_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1tym"},{"model_identifier":"5bpo","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5bpo_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5bpo"},{"model_identifier":"5co9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.92,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5co9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5co9"},{"model_identifier":"5co9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.92,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5co9_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5co9"},{"model_identifier":"7jp3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-08-07","sequence_identity":56.0,"uniprot_start":25,"uniprot_end":110,"resolution":1.95,"coverage":56.98,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7jp3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7jp3"},{"model_identifier":"1os3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-03-18","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.95,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1os3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1os3"},{"model_identifier":"2c8q","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2005-12-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.95,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2c8q_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2c8q"},{"model_identifier":"2c8q","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2005-12-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.95,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2c8q_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2c8q"},{"model_identifier":"1os3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-03-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.95,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1os3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1os3"},{"model_identifier":"2om1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.97,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2om1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2om1"},{"model_identifier":"3zs2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-06-21","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.97,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zs2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zs2"},{"model_identifier":"2om1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.97,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2om1_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2om1"},{"model_identifier":"3zs2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-06-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.97,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3zs2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3zs2"},{"model_identifier":"5uu4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-16","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":1.973,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uu4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uu4"},{"model_identifier":"5uu4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-16","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.973,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uu4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uu4"},{"model_identifier":"3u4n","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-10-10","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":53,"resolution":1.98,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3u4n_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3u4n"},{"model_identifier":"4efx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-03-30","sequence_identity":96.0,"uniprot_start":25,"uniprot_end":52,"resolution":1.98,"coverage":32.56,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4efx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4efx"},{"model_identifier":"3u4n","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-10-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.98,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3u4n_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3u4n"},{"model_identifier":"4efx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-03-30","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":1.98,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4efx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4efx"},{"model_identifier":"1q4v","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-08-04","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1q4v_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1q4v"},{"model_identifier":"3p2x","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-10-04","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3p2x_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3p2x"},{"model_identifier":"2qiu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-07-05","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2qiu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2qiu"},{"model_identifier":"3v19","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-12-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3v19_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3v19"},{"model_identifier":"1j73","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-05-15","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1j73_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1j73"},{"model_identifier":"1qiz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1999-06-18","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1qiz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1qiz"},{"model_identifier":"1znj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-09-23","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1znj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1znj"},{"model_identifier":"2r36","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.0,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2r36_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2r36"},{"model_identifier":"2w44","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-11-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":2.0,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2w44_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2w44"},{"model_identifier":"2qiu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-07-05","sequence_identity":100.0,"uniprot_start":89,"uniprot_end":110,"resolution":2.0,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2qiu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2qiu"},{"model_identifier":"2r36","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-29","sequence_identity":100.0,"uniprot_start":89,"uniprot_end":110,"resolution":2.0,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2r36_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2r36"},{"model_identifier":"1q4v","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-08-04","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1q4v_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1q4v"},{"model_identifier":"3p2x","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-10-04","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3p2x_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3p2x"},{"model_identifier":"3v19","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-12-09","sequence_identity":86.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3v19_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3v19"},{"model_identifier":"1j73","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-05-15","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1j73_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1j73"},{"model_identifier":"1qiz","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1999-06-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1qiz_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1qiz"},{"model_identifier":"1znj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-09-23","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.0,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1znj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1znj"},{"model_identifier":"2w44","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-11-21","sequence_identity":100.0,"uniprot_start":94,"uniprot_end":110,"resolution":2.0,"coverage":19.77,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2w44_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2w44"},{"model_identifier":"2omq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":36,"uniprot_end":41,"resolution":2.0,"coverage":6.98,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omq"},{"model_identifier":"4fg3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-06-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.001,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4fg3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4fg3"},{"model_identifier":"4fg3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-06-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.001,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4fg3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4fg3"},{"model_identifier":"4akj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-23","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":2.01,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4akj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4akj"},{"model_identifier":"4akj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-23","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.01,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4akj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4akj"},{"model_identifier":"5mt3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-01-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.02,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mt3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mt3"},{"model_identifier":"5mt3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-01-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.02,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mt3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mt3"},{"model_identifier":"2om0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.05,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2om0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2om0"},{"model_identifier":"3q6e","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-12-31","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.05,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3q6e_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3q6e"},{"model_identifier":"2om0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-20","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.05,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2om0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2om0"},{"model_identifier":"3q6e","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-12-31","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.05,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3q6e_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3q6e"},{"model_identifier":"5uss","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-13","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.061,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uss_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uss"},{"model_identifier":"5uss","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.061,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uss_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uss"},{"model_identifier":"1w8p","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-09-24","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.08,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1w8p_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1w8p"},{"model_identifier":"2r35","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.08,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2r35_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2r35"},{"model_identifier":"2r35","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-29","sequence_identity":100.0,"uniprot_start":89,"uniprot_end":110,"resolution":2.08,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2r35_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2r35"},{"model_identifier":"1w8p","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-09-24","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.08,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1w8p_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1w8p"},{"model_identifier":"2ws0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.1,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws0"},{"model_identifier":"2ws0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.1,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws0"},{"model_identifier":"2wrv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":2.15,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wrv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wrv"},{"model_identifier":"2wrv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.15,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wrv_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wrv"},{"model_identifier":"6z7y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-06-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6z7y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6z7y"},{"model_identifier":"5mam","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-11-03","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mam_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mam"},{"model_identifier":"3v1g","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-12-09","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3v1g_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3v1g"},{"model_identifier":"2vk0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-12-14","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2vk0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2vk0"},{"model_identifier":"3ir0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-08-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3ir0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3ir0"},{"model_identifier":"5hpu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hpu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hpu"},{"model_identifier":"2g56","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-02-22","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2g56_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2g56"},{"model_identifier":"6gnq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-05-31","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6gnq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6gnq"},{"model_identifier":"6z7y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-06-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6z7y_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6z7y"},{"model_identifier":"5mam","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-11-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mam_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mam"},{"model_identifier":"3v1g","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-12-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3v1g_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3v1g"},{"model_identifier":"2vk0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-12-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2vk0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2vk0"},{"model_identifier":"3ir0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-08-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3ir0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3ir0"},{"model_identifier":"5hpu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-01-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hpu_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hpu"},{"model_identifier":"6gnq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-05-31","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6gnq_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6gnq"},{"model_identifier":"4ewx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.201,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ewx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ewx"},{"model_identifier":"4ewx","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.201,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ewx_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ewx"},{"model_identifier":"2omi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.24,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omi"},{"model_identifier":"2omi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-01-22","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.24,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2omi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2omi"},{"model_identifier":"5uu3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-16","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.25,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uu3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uu3"},{"model_identifier":"1os4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-03-18","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.25,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1os4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1os4"},{"model_identifier":"2g54","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-02-22","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.25,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2g54_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2g54"},{"model_identifier":"6ck2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-02-27","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.25,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ck2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ck2"},{"model_identifier":"2r34","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.25,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2r34_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2r34"},{"model_identifier":"2r34","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-29","sequence_identity":100.0,"uniprot_start":89,"uniprot_end":110,"resolution":2.25,"coverage":25.58,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2r34_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2r34"},{"model_identifier":"5uu3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-16","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.25,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uu3_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uu3"},{"model_identifier":"1os4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2003-03-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.25,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1os4_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1os4"},{"model_identifier":"6ck2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-02-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.25,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ck2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ck2"},{"model_identifier":"4ak0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-21","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":53,"resolution":2.28,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ak0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ak0"},{"model_identifier":"4ak0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-02-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.28,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4ak0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4ak0"},{"model_identifier":"3p33","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-10-04","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3p33_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3p33"},{"model_identifier":"5ems","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-11-06","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5ems_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5ems"},{"model_identifier":"1qiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1999-06-18","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1qiy_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1qiy"},{"model_identifier":"1lph","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1995-04-19","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1lph_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1lph"},{"model_identifier":"3rov","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-04-26","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3rov_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3rov"},{"model_identifier":"4eww","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eww_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eww"},{"model_identifier":"1xw7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-10-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1xw7_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1xw7"},{"model_identifier":"3p33","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-10-04","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3p33_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3p33"},{"model_identifier":"5ems","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-11-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5ems_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5ems"},{"model_identifier":"1qiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1999-06-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1qiy_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1qiy"},{"model_identifier":"1lph","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1995-04-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1lph_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1lph"},{"model_identifier":"3rov","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-04-26","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3rov_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3rov"},{"model_identifier":"4eww","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-04-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4eww_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4eww"},{"model_identifier":"1xw7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-10-29","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1xw7_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1xw7"},{"model_identifier":"4z78","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-04-06","sequence_identity":100.0,"uniprot_start":39,"uniprot_end":48,"resolution":2.304,"coverage":11.63,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4z78_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4z78"},{"model_identifier":"4wdi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-09-08","sequence_identity":100.0,"uniprot_start":39,"uniprot_end":47,"resolution":2.313,"coverage":10.47,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4wdi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4wdi"},{"model_identifier":"1qj0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1999-06-18","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.4,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1qj0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1qj0"},{"model_identifier":"4gbk","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.4,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbk_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbk"},{"model_identifier":"1qj0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1999-06-18","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1qj0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1qj0"},{"model_identifier":"4gbk","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbk_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbk"},{"model_identifier":"1jk8","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-07-11","sequence_identity":100.0,"uniprot_start":35,"uniprot_end":47,"resolution":2.4,"coverage":15.12,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1jk8_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1jk8"},{"model_identifier":"5uru","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-13","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.41,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uru_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uru"},{"model_identifier":"2wrw","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":2.41,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wrw_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wrw"},{"model_identifier":"2wrw","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.41,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wrw_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wrw"},{"model_identifier":"5uru","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-02-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.41,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5uru_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5uru"},{"model_identifier":"6z7w","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-06-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.42,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6z7w_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6z7w"},{"model_identifier":"6z7w","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-06-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.42,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6z7w_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6z7w"},{"model_identifier":"1jca","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-06-08","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1jca_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1jca"},{"model_identifier":"3jsd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-10","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3jsd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3jsd"},{"model_identifier":"1b9e","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-11-12","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1b9e_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1b9e"},{"model_identifier":"4gbl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbl_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbl"},{"model_identifier":"1jca","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-06-08","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1jca_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1jca"},{"model_identifier":"3jsd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3jsd_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3jsd"},{"model_identifier":"1b9e","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-11-12","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1b9e_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1b9e"},{"model_identifier":"4gbl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbl_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbl"},{"model_identifier":"4y19","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-02-07","sequence_identity":100.0,"uniprot_start":75,"uniprot_end":90,"resolution":2.5,"coverage":18.6,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4y19_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4y19"},{"model_identifier":"4gbi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.502,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbi"},{"model_identifier":"4gbi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-07-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.502,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4gbi_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4gbi"},{"model_identifier":"2ws7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":96.0,"uniprot_start":25,"uniprot_end":50,"resolution":2.59,"coverage":30.23,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws7_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws7"},{"model_identifier":"2ws7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-09-03","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.59,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2ws7_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2ws7"},{"model_identifier":"2wby","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-03-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":2.6,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wby_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wby"},{"model_identifier":"2wby","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-03-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":43,"resolution":2.6,"coverage":22.09,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wby_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wby"},{"model_identifier":"3utt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-11-26","sequence_identity":100.0,"uniprot_start":15,"uniprot_end":24,"resolution":2.6,"coverage":0.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3utt_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3utt"},{"model_identifier":"3uts","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-11-26","sequence_identity":100.0,"uniprot_start":15,"uniprot_end":24,"resolution":2.712,"coverage":0.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3uts_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3uts"},{"model_identifier":"4unh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.75,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4unh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4unh"},{"model_identifier":"4unh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.75,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4unh_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4unh"},{"model_identifier":"2wc0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-03-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.8,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wc0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wc0"},{"model_identifier":"2wc0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-03-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.8,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2wc0_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2wc0"},{"model_identifier":"5wdm","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-07-05","sequence_identity":57.0,"uniprot_start":25,"uniprot_end":110,"resolution":2.803,"coverage":66.28,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5wdm_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5wdm"},{"model_identifier":"6vep","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":2.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6vep_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6vep"},{"model_identifier":"6vep","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-01-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":2.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6vep_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6vep"},{"model_identifier":"5hyj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-02-01","sequence_identity":90.0,"uniprot_start":15,"uniprot_end":24,"resolution":3.06,"coverage":0.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5hyj_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5hyj"},{"model_identifier":"6hn5","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-09-14","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":3.2,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6hn5_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6hn5"},{"model_identifier":"6hn5","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-09-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":3.2,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6hn5_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6hn5"},{"model_identifier":"5cjo","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-07-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":3.287,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5cjo_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5cjo"},{"model_identifier":"4oga","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-01-15","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":3.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4oga_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4oga"},{"model_identifier":"4oga","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-01-15","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":3.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4oga_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4oga"},{"model_identifier":"6b70","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-10-03","sequence_identity":100.0,"uniprot_start":1,"uniprot_end":110,"resolution":3.7,"coverage":100.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6b70_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6b70"},{"model_identifier":"6b3q","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-09-22","sequence_identity":100.0,"uniprot_start":1,"uniprot_end":110,"resolution":3.7,"coverage":100.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6b3q_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6b3q"},{"model_identifier":"6bfc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-10-26","sequence_identity":100.0,"uniprot_start":1,"uniprot_end":110,"resolution":3.7,"coverage":100.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6bfc_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6bfc"},{"model_identifier":"7bw8","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-04-14","sequence_identity":86.0,"uniprot_start":25,"uniprot_end":110,"resolution":3.8,"coverage":86.05,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7bw8_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7bw8"},{"model_identifier":"3w11","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":3.9,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w11_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w11"},{"model_identifier":"3w11","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":3.9,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w11_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w11"},{"model_identifier":"5wob","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-08-01","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":3.95,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5wob_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5wob"},{"model_identifier":"4y1a","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-02-07","sequence_identity":100.0,"uniprot_start":75,"uniprot_end":90,"resolution":4.0,"coverage":18.6,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4y1a_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4y1a"},{"model_identifier":"7bw7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-04-13","sequence_identity":86.0,"uniprot_start":25,"uniprot_end":110,"resolution":4.1,"coverage":86.05,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7bw7_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7bw7"},{"model_identifier":"6sof","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-08-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":4.3,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6sof_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6sof"},{"model_identifier":"6ce9","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-02-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":4.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ce9_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ce9"},{"model_identifier":"6sof","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-08-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":4.3,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6sof_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6sof"},{"model_identifier":"3w12","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":4.301,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w12_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w12"},{"model_identifier":"3w12","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":4.301,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w12_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w12"},{"model_identifier":"3w13","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":4.303,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w13_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w13"},{"model_identifier":"3w13","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":4.303,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3w13_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3w13"},{"model_identifier":"6jk8","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-02-27","sequence_identity":100.0,"uniprot_start":1,"uniprot_end":110,"resolution":4.7,"coverage":100.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6jk8_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6jk8"},{"model_identifier":"6ceb","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-02-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":4.7,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ceb_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ceb"},{"model_identifier":"7bwa","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-04-14","sequence_identity":86.0,"uniprot_start":25,"uniprot_end":110,"resolution":4.9,"coverage":86.05,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/7bwa_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/7bwa"},{"model_identifier":"6ce7","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2018-02-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":7.4,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6ce7_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6ce7"},{"model_identifier":"6jr3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-04-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":14.5,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6jr3_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6jr3"},{"model_identifier":"6jr3","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-04-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":14.5,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6jr3_updated.cif","model_format":"MMCIF","experimental_method":"ELECTRON MICROSCOPY","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6jr3"},{"model_identifier":"2kqp","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-11-12","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":110,"resolution":null,"coverage":100.0,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kqp_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kqp"},{"model_identifier":"1efe","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-02-08","sequence_identity":65.0,"uniprot_start":25,"uniprot_end":110,"resolution":null,"coverage":69.77,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1efe_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1efe"},{"model_identifier":"6u46","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-08-23","sequence_identity":61.0,"uniprot_start":25,"uniprot_end":109,"resolution":null,"coverage":67.44,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6u46_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6u46"},{"model_identifier":"1sju","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-10-09","sequence_identity":56.0,"uniprot_start":25,"uniprot_end":110,"resolution":null,"coverage":58.14,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1sju_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1sju"},{"model_identifier":"5mwq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-01-19","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":56,"resolution":null,"coverage":37.21,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mwq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mwq"},{"model_identifier":"6k59","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-05-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":56,"resolution":null,"coverage":37.21,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6k59_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6k59"},{"model_identifier":"1t0c","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-08","sequence_identity":100.0,"uniprot_start":57,"uniprot_end":87,"resolution":null,"coverage":36.05,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t0c_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t0c"},{"model_identifier":"5mhd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-11-24","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":55,"resolution":null,"coverage":36.05,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mhd_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mhd"},{"model_identifier":"2lgb","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-07-25","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":55,"resolution":null,"coverage":36.05,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2lgb_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2lgb"},{"model_identifier":"2mvd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-10-02","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mvd_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mvd"},{"model_identifier":"2mvc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-10-02","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mvc_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mvc"},{"model_identifier":"1k3m","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-10-03","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1k3m_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1k3m"},{"model_identifier":"2juu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-09-03","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2juu_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2juu"},{"model_identifier":"1hiq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1993-03-05","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hiq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hiq"},{"model_identifier":"2juv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-09-05","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2juv_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2juv"},{"model_identifier":"2rn5","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-12-06","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2rn5_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2rn5"},{"model_identifier":"2kxk","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-05-07","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kxk_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kxk"},{"model_identifier":"2hiu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-10-08","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2hiu_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2hiu"},{"model_identifier":"2l1y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-08-09","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2l1y_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2l1y"},{"model_identifier":"2l1z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-08-09","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2l1z_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2l1z"},{"model_identifier":"2kju","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-06-10","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kju_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kju"},{"model_identifier":"1xgl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-10-10","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1xgl_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1xgl"},{"model_identifier":"1jco","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-06-11","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1jco_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1jco"},{"model_identifier":"2jv1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-09-11","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2jv1_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2jv1"},{"model_identifier":"2kqq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-11-13","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kqq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kqq"},{"model_identifier":"1fu2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-09-13","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1fu2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY POWDER DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1fu2"},{"model_identifier":"1kmf","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-12-14","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1kmf_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1kmf"},{"model_identifier":"1vkt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-10-14","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1vkt_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1vkt"},{"model_identifier":"1fub","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-09-14","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1fub_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY POWDER DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1fub"},{"model_identifier":"2n2x","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-15","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2n2x_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2n2x"},{"model_identifier":"2n2v","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-15","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2n2v_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2n2v"},{"model_identifier":"2n2w","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-15","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2n2w_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2n2w"},{"model_identifier":"1t1k","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-16","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t1k_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t1k"},{"model_identifier":"1t1p","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-16","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t1p_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t1p"},{"model_identifier":"1t1q","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-16","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t1q_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t1q"},{"model_identifier":"2mpg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-17","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mpg_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mpg"},{"model_identifier":"1sf1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-02-19","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1sf1_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1sf1"},{"model_identifier":"2mpi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-19","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mpi_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mpi"},{"model_identifier":"2jmn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-11-21","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2jmn_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2jmn"},{"model_identifier":"2k9r","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-10-23","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2k9r_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2k9r"},{"model_identifier":"6x4x","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-05-24","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6x4x_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6x4x"},{"model_identifier":"1lkq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2002-04-25","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1lkq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1lkq"},{"model_identifier":"2m1d","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-26","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m1d_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m1d"},{"model_identifier":"2m1e","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-26","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m1e_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m1e"},{"model_identifier":"2mli","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-02-27","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mli_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mli"},{"model_identifier":"2hh4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-06-27","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2hh4_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2hh4"},{"model_identifier":"2m2m","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2m_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2m"},{"model_identifier":"2aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2aiy"},{"model_identifier":"1hit","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1992-02-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hit_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hit"},{"model_identifier":"2hho","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-06-28","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2hho_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2hho"},{"model_identifier":"1hls","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1995-06-28","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hls_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hls"},{"model_identifier":"2m2n","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-29","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2n_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2n"},{"model_identifier":"2m2o","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-29","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2o_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2o"},{"model_identifier":"2m2p","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-29","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2p_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2p"},{"model_identifier":"3aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3aiy"},{"model_identifier":"4aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4aiy"},{"model_identifier":"5aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-29","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5aiy"},{"model_identifier":"2kjj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-05-29","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kjj_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kjj"},{"model_identifier":"2k91","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-09-29","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2k91_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2k91"},{"model_identifier":"1ai0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-04-30","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ai0_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ai0"},{"model_identifier":"1aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-04-30","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1aiy"},{"model_identifier":"2h67","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-05-30","sequence_identity":87.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2h67_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2h67"},{"model_identifier":"1mhi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-11-30","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1mhi_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1mhi"},{"model_identifier":"2jum","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-31","sequence_identity":90.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":34.88,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2jum_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2jum"},{"model_identifier":"1sjt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-10-09","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":53,"resolution":null,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1sjt_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1sjt"},{"model_identifier":"1a7f","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-03-12","sequence_identity":93.0,"uniprot_start":25,"uniprot_end":53,"resolution":null,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1a7f_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1a7f"},{"model_identifier":"1iog","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-08-13","sequence_identity":86.0,"uniprot_start":25,"uniprot_end":53,"resolution":null,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1iog_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1iog"},{"model_identifier":"1ioh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-08-13","sequence_identity":86.0,"uniprot_start":25,"uniprot_end":53,"resolution":null,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ioh_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ioh"},{"model_identifier":"1mhj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-11-30","sequence_identity":97.0,"uniprot_start":25,"uniprot_end":54,"resolution":null,"coverage":33.72,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1mhj_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1mhj"},{"model_identifier":"1hui","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-03-29","sequence_identity":89.0,"uniprot_start":26,"uniprot_end":53,"resolution":null,"coverage":32.56,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hui_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hui"},{"model_identifier":"1his","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1992-02-28","sequence_identity":100.0,"uniprot_start":25,"uniprot_end":49,"resolution":null,"coverage":29.07,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1his_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1his"},{"model_identifier":"2mvc","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-10-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mvc_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mvc"},{"model_identifier":"2mvd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-10-02","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mvd_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mvd"},{"model_identifier":"1k3m","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-10-03","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1k3m_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1k3m"},{"model_identifier":"2juu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-09-03","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2juu_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2juu"},{"model_identifier":"1hiq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1993-03-05","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hiq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hiq"},{"model_identifier":"2juv","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-09-05","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2juv_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2juv"},{"model_identifier":"2rn5","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-12-06","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2rn5_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2rn5"},{"model_identifier":"2kxk","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-05-07","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kxk_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kxk"},{"model_identifier":"2hiu","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-10-08","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2hiu_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2hiu"},{"model_identifier":"2l1z","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-08-09","sequence_identity":86.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2l1z_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2l1z"},{"model_identifier":"2l1y","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2010-08-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2l1y_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2l1y"},{"model_identifier":"1sjt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-10-09","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1sjt_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1sjt"},{"model_identifier":"2kju","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-06-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kju_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kju"},{"model_identifier":"1xgl","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-10-10","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1xgl_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1xgl"},{"model_identifier":"1jco","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-06-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1jco_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1jco"},{"model_identifier":"2jv1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-09-11","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2jv1_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2jv1"},{"model_identifier":"1a7f","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-03-12","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1a7f_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1a7f"},{"model_identifier":"1iog","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-08-13","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1iog_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1iog"},{"model_identifier":"1ioh","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-08-13","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ioh_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ioh"},{"model_identifier":"2kqq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-11-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kqq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kqq"},{"model_identifier":"1fu2","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-09-13","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1fu2_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY POWDER DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1fu2"},{"model_identifier":"1kmf","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2001-12-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1kmf_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1kmf"},{"model_identifier":"1vkt","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-10-14","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1vkt_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1vkt"},{"model_identifier":"1fub","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2000-09-14","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1fub_updated.cif","model_format":"MMCIF","experimental_method":"X-RAY POWDER DIFFRACTION","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1fub"},{"model_identifier":"2n2v","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-15","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2n2v_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2n2v"},{"model_identifier":"2n2w","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-15","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2n2w_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2n2w"},{"model_identifier":"2n2x","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2015-05-15","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2n2x_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2n2x"},{"model_identifier":"1t1k","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-16","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t1k_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t1k"},{"model_identifier":"1t1p","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-16","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t1p_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t1p"},{"model_identifier":"1t1q","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-04-16","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1t1q_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1t1q"},{"model_identifier":"2mpg","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-17","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mpg_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mpg"},{"model_identifier":"1sf1","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2004-02-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1sf1_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1sf1"},{"model_identifier":"5mwq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2017-01-19","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mwq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mwq"},{"model_identifier":"2mpi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-05-19","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mpi_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mpi"},{"model_identifier":"2jmn","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-11-21","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2jmn_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2jmn"},{"model_identifier":"2k9r","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-10-23","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2k9r_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2k9r"},{"model_identifier":"6x4x","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2020-05-24","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6x4x_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6x4x"},{"model_identifier":"5mhd","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2016-11-24","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5mhd_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5mhd"},{"model_identifier":"1lkq","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2002-04-25","sequence_identity":90.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1lkq_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1lkq"},{"model_identifier":"2lgb","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2011-07-25","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2lgb_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2lgb"},{"model_identifier":"2m1d","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-26","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m1d_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m1d"},{"model_identifier":"2m1e","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-11-26","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m1e_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m1e"},{"model_identifier":"2mli","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2014-02-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2mli_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2mli"},{"model_identifier":"2hh4","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-06-27","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2hh4_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2hh4"},{"model_identifier":"2m2m","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2m_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2m"},{"model_identifier":"2aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2aiy"},{"model_identifier":"1his","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1992-02-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1his_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1his"},{"model_identifier":"1hit","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1992-02-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hit_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hit"},{"model_identifier":"2hho","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-06-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2hho_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2hho"},{"model_identifier":"1hls","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1995-06-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hls_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hls"},{"model_identifier":"2m2n","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2n_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2n"},{"model_identifier":"2m2o","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2o_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2o"},{"model_identifier":"2m2p","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2012-12-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2m2p_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2m2p"},{"model_identifier":"3aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/3aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/3aiy"},{"model_identifier":"4aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/4aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/4aiy"},{"model_identifier":"5aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1998-12-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/5aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/5aiy"},{"model_identifier":"1hui","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1996-03-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1hui_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1hui"},{"model_identifier":"2kjj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2009-05-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2kjj_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2kjj"},{"model_identifier":"2k91","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2008-09-29","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2k91_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2k91"},{"model_identifier":"1ai0","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-04-30","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1ai0_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1ai0"},{"model_identifier":"1aiy","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1997-04-30","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1aiy_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1aiy"},{"model_identifier":"2h67","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2006-05-30","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2h67_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2h67"},{"model_identifier":"1mhi","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-11-30","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1mhi_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1mhi"},{"model_identifier":"1mhj","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"1994-11-30","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/1mhj_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/1mhj"},{"model_identifier":"2jum","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2007-08-31","sequence_identity":95.0,"uniprot_start":90,"uniprot_end":110,"resolution":null,"coverage":24.42,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/2jum_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/2jum"},{"model_identifier":"6k59","model_category":"EXPERIMENTALLY DETERMINED","provider":"PDBe","created":"2019-05-28","sequence_identity":100.0,"uniprot_start":90,"uniprot_end":109,"resolution":null,"coverage":23.26,"model_url":"https://www.ebi.ac.uk/pdbe/static/entry/6k59_updated.cif","model_format":"MMCIF","experimental_method":"SOLUTION NMR","model_page_url":"https://www.ebi.ac.uk/pdbe/entry/pdb/6k59"},{"model_identifier":"PED00093e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00093e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00093","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00093e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00093e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00093e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00093","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00093e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00094e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00094e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00094","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00094e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00094e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00094e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00094","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00094e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00095e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00095e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00095","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00095e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00095e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00095e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00095","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00095e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00096e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00096e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00096","number_of_conformers":35,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00096e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00096e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00096e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00096","number_of_conformers":35,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00096e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00101e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":26,"uniprot_end":53,"model_url":"https://proteinensemble.org/api/ensemble/PED00101e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00101","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00101e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00101e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00101e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00101","number_of_conformers":25,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00101e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00102e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00102e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00102","number_of_conformers":40,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00102e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00102e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00102e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00102","number_of_conformers":40,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00102e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00103e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00103e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00103","number_of_conformers":30,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00103e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00103e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00103e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00103","number_of_conformers":30,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00103e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00104e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":90,"uniprot_end":110,"model_url":"https://proteinensemble.org/api/ensemble/PED00104e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00104","number_of_conformers":50,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00104e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"PED00104e000","model_category":"CONFORMATIONAL ENSEMBLE","provider":"PED","created":"2020-10-01","uniprot_start":25,"uniprot_end":54,"model_url":"https://proteinensemble.org/api/ensemble/PED00104e000","model_format":"PDB","model_page_url":"https://proteinensemble.org/PED00104","number_of_conformers":50,"ensemble_sample_url":"https://proteinensemble.org/api/ensemble_sample/PED00104e000","ensemble_sample_format":"MMCIF"},{"model_identifier":"P01308_25-110:2lwz.1.A","model_category":"TEMPLATE-BASED","provider":"SWISS-MODEL","created":"2021-11-05","sequence_identity":1.0,"uniprot_start":25,"uniprot_end":110,"coverage":0.782,"confidence_version":"4.2.0","confidence_avg_local_score":0.524,"model_url":"https://swissmodel.expasy.org/3d-beacons/uniprot/P01308.pdb?range=25-110&template=2lwz.1.A&provider=swissmodel","model_format":"PDB","model_page_url":"https://swissmodel.expasy.org/repository/uniprot/P01308?range=25-110&template=2lwz.1.A","confidence_type":"QMEANDisCo"},{"model_identifier":"AF-P01308-F1","model_category":"DEEP-LEARNING","provider":"AlphaFold DB","created":"2021-07-01","sequence_identity":1.0,"uniprot_start":1,"uniprot_end":110,"coverage":100.0,"model_url":"https://alphafold.ebi.ac.uk/files/AF-P01308-F1-model_v1.cif","model_format":"MMCIF","model_page_url":"https://alphafold.ebi.ac.uk/entry/P01308"},{"model_identifier":"2400","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2018-11-11","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDE25_fit1_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDE25"},{"model_identifier":"2396","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2018-11-11","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDE25_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDE25"},{"model_identifier":"2452","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEV5_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEV5"},{"model_identifier":"2453","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEV5_fit3_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEV5"},{"model_identifier":"2456","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEW5_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEW5"},{"model_identifier":"2457","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEW5_fit3_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEW5"},{"model_identifier":"2459","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEX5_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEX5"},{"model_identifier":"2460","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEX5_fit3_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEX5"},{"model_identifier":"2462","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":609,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEY5_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEY5"},{"model_identifier":"2463","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":609,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEY5_fit3_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEY5"},{"model_identifier":"2465","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":609,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEZ5_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEZ5"},{"model_identifier":"2467","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":609,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDEZ5_fit3_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDEZ5"},{"model_identifier":"2469","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":609,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDE26_fit2_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDE26"},{"model_identifier":"2470","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2019-04-07","uniprot_start":25,"uniprot_end":609,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDE26_fit3_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDE26"},{"model_identifier":"4420","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2020-12-18","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDJY3_fit1_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDJY3"},{"model_identifier":"4421","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2020-12-18","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDJY3_fit1_model2.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDJY3"},{"model_identifier":"4422","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2020-12-18","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDJZ3_fit1_model1.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDJZ3"},{"model_identifier":"4423","model_category":"EXPERIMENTALLY DETERMINED","provider":"SASBDB","created":"2020-12-18","uniprot_start":25,"uniprot_end":110,"model_url":"https://www.sasbdb.org/media/pdb_file/SASDJZ3_fit1_model2.pdb","model_format":"PDB","model_page_url":"https://www.sasbdb.org/data/SASDJZ3"}]}
\ No newline at end of file
index bcd5784..25dcac1 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.gui;
 
-import jalview.bin.Cache;
-
 import java.awt.Dimension;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -35,6 +33,8 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import jalview.bin.Console;
+
 public class JAL1353bugdemo
 {
 
@@ -60,7 +60,7 @@ public class JAL1353bugdemo
   @Test(groups = { "Functional" }, enabled = false)
   public void test()
   {
-    Cache.initLogger();
+    Console.initLogger();
     // final Desktop foo = new Desktop();
     final JFrame cfoo = new JFrame("Crash Java");
     final JDesktopPane foo = new JDesktopPane();
index cc13fb9..b2d5b0a 100644 (file)
@@ -46,6 +46,7 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -94,7 +95,7 @@ public class PopupMenuTest
   public void setUp() throws IOException
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.initLogger();
+    Console.initLogger();
 
     String inMenuString = ("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
             + SEQUENCE_ID
index 073bde8..f183e5c 100644 (file)
  */
 package jalview.gui;
 
-import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.Assert.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceI;
-import jalview.fts.api.FTSData;
-import jalview.jbgui.GStructureChooser.FilterOption;
-import jalview.ws.params.InvalidArgumentException;
-
 import java.util.Collection;
 import java.util.Vector;
 
+import org.junit.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.fts.service.pdb.PDBFTSRestClientTest;
+import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
+import jalview.fts.threedbeacons.TDBeaconsFTSRestClientTest;
+import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
+import jalview.jbgui.FilterOption;
 import junit.extensions.PA;
 
+@Test(singleThreaded = true)
 public class StructureChooserTest
 {
 
@@ -53,7 +58,7 @@ public class StructureChooserTest
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
-  Sequence seq;
+  Sequence seq,upSeq,upSeq_nocanonical;
 
   @BeforeMethod(alwaysRun = true)
   public void setUp() throws Exception
@@ -75,60 +80,80 @@ public class StructureChooserTest
     pdbIds.add(dbRef);
 
     seq.setPDBId(pdbIds);
+    
+    // Uniprot sequence for 3D-Beacons mocks
+    upSeq = new Sequence("P38398", 
+            "MDLSALRVEEVQNVINAMQKILECPICLELIKEPVSTKCDHIFCKFCMLKLLNQKKGPSQCPLCKNDITKRS\n"
+            + "LQESTRFSQLVEELLKIICAFQLDTGLEYANSYNFAKKENNSPEHLKDEVSIIQSMGYRNRAKRLLQSEPEN\n"
+            + "PSLQETSLSVQLSNLGTVRTLRTKQRIQPQKTSVYIELGSDSSEDTVNKATYCSVGDQELLQITPQGTRDEI\n"
+            + "SLDSAKKAACEFSETDVTNTEHHQPSNNDLNTTEKRAAERHPEKYQGSSVSNLHVEPCGTNTHASSLQHENS\n"
+            + "SLLLTKDRMNVEKAEFCNKSKQPGLARSQHNRWAGSKETCNDRRTPSTEKKVDLNADPLCERKEWNKQKLPC\n"
+            + "SENPRDTEDVPWITLNSSIQKVNEWFSRSDELLGSDDSHDGESESNAKVADVLDVLNEVDEYSGSSEKIDLL\n"
+            + "ASDPHEALICKSERVHSKSVESNIEDKIFGKTYRKKASLPNLSHVTENLIIGAFVTEPQIIQERPLTNKLKR\n"
+            + "KRRPTSGLHPEDFIKKADLAVQKTPEMINQGTNQTEQNGQVMNITNSGHENKTKGDSIQNEKNPNPIESLEK\n"
+            + "ESAFKTKAEPISSSISNMELELNIHNSKAPKKNRLRRKSSTRHIHALELVVSRNLSPPNCTELQIDSCSSSE\n"
+            + "EIKKKKYNQMPVRHSRNLQLMEGKEPATGAKKSNKPNEQTSKRHDSDTFPELKLTNAPGSFTKCSNTSELKE\n"
+            + "FVNPSLPREEKEEKLETVKVSNNAEDPKDLMLSGERVLQTERSVESSSISLVPGTDYGTQESISLLEVSTLG\n"
+            + "KAKTEPNKCVSQCAAFENPKGLIHGCSKDNRNDTEGFKYPLGHEVNHSRETSIEMEESELDAQYLQNTFKVS\n"
+            + "KRQSFAPFSNPGNAEEECATFSAHSGSLKKQSPKVTFECEQKEENQGKNESNIKPVQTVNITAGFPVVGQKD\n"
+            + "KPVDNAKCSIKGGSRFCLSSQFRGNETGLITPNKHGLLQNPYRIPPLFPIKSFVKTKCKKNLLEENFEEHSM\n"
+            + "SPEREMGNENIPSTVSTISRNNIRENVFKEASSSNINEVGSSTNEVGSSINEIGSSDENIQAELGRNRGPKL\n"
+            + "NAMLRLGVLQPEVYKQSLPGSNCKHPEIKKQEYEEVVQTVNTDFSPYLISDNLEQPMGSSHASQVCSETPDD\n"
+            + "LLDDGEIKEDTSFAENDIKESSAVFSKSVQKGELSRSPSPFTHTHLAQGYRRGAKKLESSEENLSSEDEELP\n"
+            + "CFQHLLFGKVNNIPSQSTRHSTVATECLSKNTEENLLSLKNSLNDCSNQVILAKASQEHHLSEETKCSASLF\n"
+            + "SSQCSELEDLTANTNTQDPFLIGSSKQMRHQSESQGVGLSDKELVSDDEERGTGLEENNQEEQSMDSNLGEA\n"
+            + "ASGCESETSVSEDCSGLSSQSDILTTQQRDTMQHNLIKLQQEMAELEAVLEQHGSQPSNSYPSIISDSSALE\n"
+            + "DLRNPEQSTSEKAVLTSQKSSEYPISQNPEGLSADKFEVSADSSTSKNKEPGVERSSPSKCPSLDDRWYMHS\n"
+            + "CSGSLQNRNYPSQEELIKVVDVEEQQLEESGPHDLTETSYLPRQDLEGTPYLESGISLFSDDPESDPSEDRA\n"
+            + "PESARVGNIPSSTSALKVPQLKVAESAQSPAAAHTTDTAGYNAMEESVSREKPELTASTERVNKRMSMVVSG\n"
+            + "LTPEEFMLVYKFARKHHITLTNLITEETTHVVMKTDAEFVCERTLKYFLGIAGGKWVVSYFWVTQSIKERKM\n"
+            + "LNEHDFEVRGDVVNGRNHQGPKRARESQDRKIFRGLEICCYGPFTNMPTDQLEWMVQLCGASVVKELSSFTL\n"
+            + "GTGVHPIVVVQPDAWTEDNGFHAIGQMCEAPVVTREWVLDSVALYQCQELDTYLIPQIPHSHY\n"
+            + "", 1,
+1863);
+    upSeq.setDescription("Breast cancer type 1 susceptibility protein");
+    upSeq_nocanonical = new Sequence(upSeq);
+    upSeq.createDatasetSequence();
+    upSeq.addDBRef(new DBRefEntry("UNIPROT","0","P38398",null,true));
+    
+    upSeq_nocanonical.createDatasetSequence();
+    // not a canonical reference
+    upSeq_nocanonical.addDBRef(new DBRefEntry("UNIPROT","0","P38398",null,false));
+
   }
 
   @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
     seq = null;
-  }
-
-  @Test(groups = { "Functional" })
-  public void buildQueryTest()
-  {
-    String query = StructureChooser.buildQuery(seq);
-    assertEquals("pdb_id:1tim", query);
-    System.out.println("seq >>>> " + seq);
-    seq.getAllPDBEntries().clear();
-    query = StructureChooser.buildQuery(seq);
-    assertEquals(
-            "text:XYZ_1 OR text:XYZ_2 OR text:XYZ_3 OR text:XYZ_4 OR text:4kqy",
-            query);
-       seq.setDBRefs(null);
-    query = StructureChooser.buildQuery(seq);
-    assertEquals("text:4kqy", query);
-
-    DBRefEntry uniprotDBRef = new DBRefEntry();
-    uniprotDBRef.setAccessionId("P12345");
-    uniprotDBRef.setSource(DBRefSource.UNIPROT);
-    seq.addDBRef(uniprotDBRef);
-
-    DBRefEntry pdbDBRef = new DBRefEntry();
-    pdbDBRef.setAccessionId("1XYZ");
-    pdbDBRef.setSource(DBRefSource.PDB);
-    seq.addDBRef(pdbDBRef);
-
-    for (int x = 1; x < 5; x++)
-    {
-      DBRefEntry dbRef = new DBRefEntry();
-      dbRef.setAccessionId("XYZ_" + x);
-      seq.addDBRef(dbRef);
-    }
-    query = StructureChooser.buildQuery(seq);
-    assertEquals(
-            "uniprot_accession:P12345 OR uniprot_id:P12345 OR pdb_id:1xyz",
-            query);
+    upSeq=null;
+    upSeq_nocanonical=null;
   }
 
   @Test(groups = { "Functional" })
   public void populateFilterComboBoxTest() throws InterruptedException
   {
+    TDBeaconsFTSRestClientTest.setMock();
+    PDBFTSRestClientTest.setMock();
+
     SequenceI[] selectedSeqs = new SequenceI[] { seq };
     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
+    ThreadwaitFor(200, sc);
+    
+    // if structures are not discovered then don't
+    // populate filter options
     sc.populateFilterComboBox(false, false);
     int optionsSize = sc.getCmbFilterOption().getItemCount();
-    assertEquals(2, optionsSize); // if structures are not discovered then don't
-                                  // populate filter options
+    System.out.println("Items (no data, no cache): ");
+    StringBuilder items = new StringBuilder();
+    for (int p=0;p<optionsSize;p++)
+    {
+      items.append
+      ("- ").append(sc.getCmbFilterOption().getItemAt(p).getName()).append("\n");
+
+    }
+    // report items when this fails - seems to be a race condition
+    Assert.assertEquals(items.toString(),optionsSize,2); 
 
     sc.populateFilterComboBox(true, false);
     optionsSize = sc.getCmbFilterOption().getItemCount();
@@ -140,36 +165,89 @@ public class StructureChooserTest
     FilterOption filterOpt = (FilterOption) sc.getCmbFilterOption()
             .getSelectedItem();
     assertEquals("Cached Structures", filterOpt.getName());
+    FTSRestClient.unMock((FTSRestClient) TDBeaconsFTSRestClient.getInstance());
+    FTSRestClient.unMock((FTSRestClient) PDBFTSRestClient.getInstance());
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void displayTDBQueryTest() throws InterruptedException
+  {
+    TDBeaconsFTSRestClientTest.setMock();
+    PDBFTSRestClientTest.setMock();
+
+    SequenceI[] selectedSeqs = new SequenceI[] { upSeq_nocanonical };
+    StructureChooser sc = new StructureChooser(selectedSeqs, upSeq_nocanonical, null);
+    // mock so should be quick. Exceptions from mocked PDBFTS are expected too
+    ThreadwaitFor(500, sc);
+    
+    assertTrue(sc.isCanQueryTDB() && sc.isNotQueriedTDBYet());
   }
 
   @Test(groups = { "Network" })
   public void fetchStructuresInfoTest()
   {
+    FTSRestClient.unMock((FTSRestClient) TDBeaconsFTSRestClient.getInstance());
+    PDBFTSRestClient.unMock((FTSRestClient) PDBFTSRestClient.getInstance());
     SequenceI[] selectedSeqs = new SequenceI[] { seq };
     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
+    // not mocked, wait for 2s 
+    ThreadwaitFor(2000, sc);
+    
     sc.fetchStructuresMetaData();
     Collection<FTSData> ss = (Collection<FTSData>) PA.getValue(sc,
             "discoveredStructuresSet");
     assertNotNull(ss);
     assertTrue(ss.size() > 0);
+  }
 
+  @Test(groups = { "Functional" })
+  public void fetchStructuresInfoMockedTest()
+  {
+    TDBeaconsFTSRestClientTest.setMock();
+    PDBFTSRestClientTest.setMock();
+    SequenceI[] selectedSeqs = new SequenceI[] { upSeq };
+    StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
+    ThreadwaitFor(500, sc);
+    
+    sc.fetchStructuresMetaData();
+    Collection<FTSData> ss = (Collection<FTSData>) PA.getValue(sc,
+            "discoveredStructuresSet");
+    assertNotNull(ss);
+    assertTrue(ss.size() > 0);
   }
 
+  private void ThreadwaitFor(int i, StructureChooser sc)
+  {
+    long timeout = i+System.currentTimeMillis();
+    while (!sc.isDialogVisible() && timeout > System.currentTimeMillis())
+    {
+      try {
+        Thread.sleep(50);
+      } catch (InterruptedException x)
+      {
+        
+      }
+    }
+    
+  }
+
+
   @Test(groups = { "Functional" })
   public void sanitizeSeqNameTest()
   {
     String name = "ab_cdEF|fwxyz012349";
-    assertEquals(name, StructureChooser.sanitizeSeqName(name));
+    assertEquals(name, PDBStructureChooserQuerySource.sanitizeSeqName(name));
 
     // remove a [nn] substring
     name = "abcde12[345]fg";
-    assertEquals("abcde12fg", StructureChooser.sanitizeSeqName(name));
+    assertEquals("abcde12fg", PDBStructureChooserQuerySource.sanitizeSeqName(name));
 
     // remove characters other than a-zA-Z0-9 | or _
     name = "ab[cd],.\t£$*!- \\\"@:e";
-    assertEquals("abcde", StructureChooser.sanitizeSeqName(name));
+    assertEquals("abcde", PDBStructureChooserQuerySource.sanitizeSeqName(name));
 
     name = "abcde12[345a]fg";
-    assertEquals("abcde12345afg", StructureChooser.sanitizeSeqName(name));
+    assertEquals("abcde12345afg", PDBStructureChooserQuerySource.sanitizeSeqName(name));
   }
 }
diff --git a/test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java b/test/jalview/gui/structurechooser/StructureChooserQuerySourceTest.java
new file mode 100644 (file)
index 0000000..1912f14
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ */
+package jalview.gui.structurechooser;
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Vector;
+
+import org.junit.Assert;
+import org.testng.AssertJUnit;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.fts.service.pdb.PDBFTSRestClientTest;
+import jalview.fts.threedbeacons.TDBeaconsFTSRestClientTest;
+import jalview.gui.JvOptionPane;
+import jalview.gui.StructureChooser;
+import jalview.jbgui.FilterOption;
+
+public class StructureChooserQuerySourceTest
+{
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  Sequence seq,upSeq,upSeq_insulin;
+
+  // same set up as for structurechooser test
+  
+@BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception
+  {
+    seq = new Sequence("PDB|4kqy|4KQY|A", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1,
+            26);
+    seq.createDatasetSequence();
+    for (int x = 1; x < 5; x++)
+    {
+      DBRefEntry dbRef = new DBRefEntry();
+      dbRef.setAccessionId("XYZ_" + x);
+      seq.addDBRef(dbRef);
+    }
+
+    PDBEntry dbRef = new PDBEntry();
+    dbRef.setId("1tim");
+
+    Vector<PDBEntry> pdbIds = new Vector<>();
+    pdbIds.add(dbRef);
+
+    seq.setPDBId(pdbIds);
+    
+    // Uniprot sequence for 3D-Beacons mocks
+    upSeq = new Sequence("P38398", 
+            "MDLSALRVEEVQNVINAMQKILECPICLELIKEPVSTKCDHIFCKFCMLKLLNQKKGPSQCPLCKNDITKRS\n"
+            + "LQESTRFSQLVEELLKIICAFQLDTGLEYANSYNFAKKENNSPEHLKDEVSIIQSMGYRNRAKRLLQSEPEN\n"
+            + "PSLQETSLSVQLSNLGTVRTLRTKQRIQPQKTSVYIELGSDSSEDTVNKATYCSVGDQELLQITPQGTRDEI\n"
+            + "SLDSAKKAACEFSETDVTNTEHHQPSNNDLNTTEKRAAERHPEKYQGSSVSNLHVEPCGTNTHASSLQHENS\n"
+            + "SLLLTKDRMNVEKAEFCNKSKQPGLARSQHNRWAGSKETCNDRRTPSTEKKVDLNADPLCERKEWNKQKLPC\n"
+            + "SENPRDTEDVPWITLNSSIQKVNEWFSRSDELLGSDDSHDGESESNAKVADVLDVLNEVDEYSGSSEKIDLL\n"
+            + "ASDPHEALICKSERVHSKSVESNIEDKIFGKTYRKKASLPNLSHVTENLIIGAFVTEPQIIQERPLTNKLKR\n"
+            + "KRRPTSGLHPEDFIKKADLAVQKTPEMINQGTNQTEQNGQVMNITNSGHENKTKGDSIQNEKNPNPIESLEK\n"
+            + "ESAFKTKAEPISSSISNMELELNIHNSKAPKKNRLRRKSSTRHIHALELVVSRNLSPPNCTELQIDSCSSSE\n"
+            + "EIKKKKYNQMPVRHSRNLQLMEGKEPATGAKKSNKPNEQTSKRHDSDTFPELKLTNAPGSFTKCSNTSELKE\n"
+            + "FVNPSLPREEKEEKLETVKVSNNAEDPKDLMLSGERVLQTERSVESSSISLVPGTDYGTQESISLLEVSTLG\n"
+            + "KAKTEPNKCVSQCAAFENPKGLIHGCSKDNRNDTEGFKYPLGHEVNHSRETSIEMEESELDAQYLQNTFKVS\n"
+            + "KRQSFAPFSNPGNAEEECATFSAHSGSLKKQSPKVTFECEQKEENQGKNESNIKPVQTVNITAGFPVVGQKD\n"
+            + "KPVDNAKCSIKGGSRFCLSSQFRGNETGLITPNKHGLLQNPYRIPPLFPIKSFVKTKCKKNLLEENFEEHSM\n"
+            + "SPEREMGNENIPSTVSTISRNNIRENVFKEASSSNINEVGSSTNEVGSSINEIGSSDENIQAELGRNRGPKL\n"
+            + "NAMLRLGVLQPEVYKQSLPGSNCKHPEIKKQEYEEVVQTVNTDFSPYLISDNLEQPMGSSHASQVCSETPDD\n"
+            + "LLDDGEIKEDTSFAENDIKESSAVFSKSVQKGELSRSPSPFTHTHLAQGYRRGAKKLESSEENLSSEDEELP\n"
+            + "CFQHLLFGKVNNIPSQSTRHSTVATECLSKNTEENLLSLKNSLNDCSNQVILAKASQEHHLSEETKCSASLF\n"
+            + "SSQCSELEDLTANTNTQDPFLIGSSKQMRHQSESQGVGLSDKELVSDDEERGTGLEENNQEEQSMDSNLGEA\n"
+            + "ASGCESETSVSEDCSGLSSQSDILTTQQRDTMQHNLIKLQQEMAELEAVLEQHGSQPSNSYPSIISDSSALE\n"
+            + "DLRNPEQSTSEKAVLTSQKSSEYPISQNPEGLSADKFEVSADSSTSKNKEPGVERSSPSKCPSLDDRWYMHS\n"
+            + "CSGSLQNRNYPSQEELIKVVDVEEQQLEESGPHDLTETSYLPRQDLEGTPYLESGISLFSDDPESDPSEDRA\n"
+            + "PESARVGNIPSSTSALKVPQLKVAESAQSPAAAHTTDTAGYNAMEESVSREKPELTASTERVNKRMSMVVSG\n"
+            + "LTPEEFMLVYKFARKHHITLTNLITEETTHVVMKTDAEFVCERTLKYFLGIAGGKWVVSYFWVTQSIKERKM\n"
+            + "LNEHDFEVRGDVVNGRNHQGPKRARESQDRKIFRGLEICCYGPFTNMPTDQLEWMVQLCGASVVKELSSFTL\n"
+            + "GTGVHPIVVVQPDAWTEDNGFHAIGQMCEAPVVTREWVLDSVALYQCQELDTYLIPQIPHSHY\n"
+            + "", 1,
+1863);
+    upSeq.createDatasetSequence();
+    upSeq.setDescription("Breast cancer type 1 susceptibility protein");
+    upSeq.addDBRef(new DBRefEntry("UNIPROT","0","P38398",null,true));
+    
+    upSeq_insulin=new Sequence("INS_HUMAN",
+            "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGP"
+            + "GAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN");
+    upSeq_insulin.createDatasetSequence();
+    upSeq_insulin.setDescription("Insulin");
+    upSeq_insulin.addDBRef(new DBRefEntry("UNIPROT","0","P01308",null,true));
+  }
+
+@AfterMethod(alwaysRun = true)
+  public void tearDown() throws Exception
+  {
+    seq = null;
+    upSeq=null;
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test(groups = { "Functional" })
+  public void buildPDBQueryTest()
+  {
+    System.out.println("seq >>>> " + seq);
+    
+    StructureChooserQuerySource scquery = StructureChooserQuerySource.getQuerySourceFor(new SequenceI[] { seq});
+    AssertJUnit.assertTrue(scquery instanceof PDBStructureChooserQuerySource);
+    String query = scquery.buildQuery(seq);
+    AssertJUnit.assertEquals("pdb_id:1tim", query);
+    seq.getAllPDBEntries().clear();
+    query = scquery.buildQuery(seq);
+    AssertJUnit.assertEquals(
+            "text:XYZ_1 OR text:XYZ_2 OR text:XYZ_3 OR text:XYZ_4 OR text:4kqy",
+            query);
+    seq.setDBRefs(null);
+    query = scquery.buildQuery(seq);
+    System.out.println(query);
+    AssertJUnit.assertEquals("text:4kqy", query);
+
+    DBRefEntry uniprotDBRef = new DBRefEntry();
+    uniprotDBRef.setAccessionId("P12345");
+    uniprotDBRef.setSource(DBRefSource.UNIPROT);
+    seq.addDBRef(uniprotDBRef);
+
+    DBRefEntry pdbDBRef = new DBRefEntry();
+    pdbDBRef.setAccessionId("1XYZ");
+    pdbDBRef.setSource(DBRefSource.PDB);
+    seq.addDBRef(pdbDBRef);
+
+    for (int x = 1; x < 5; x++)
+    {
+      DBRefEntry dbRef = new DBRefEntry();
+      dbRef.setAccessionId("XYZ_" + x);
+      seq.addDBRef(dbRef);
+    }
+    System.out.println("");
+    System.out.println(seq.getDBRefs());
+    System.out.println(query);
+    query = scquery.buildQuery(seq);
+    AssertJUnit.assertEquals(
+            "uniprot_accession:P12345 OR uniprot_id:P12345 OR pdb_id:1xyz",
+            query);
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test(groups = { "Functional" })
+  public void buildThreeDBQueryTest()
+  {
+    System.out.println("seq >>>> " + upSeq);
+    TDBeaconsFTSRestClientTest.setMock();
+    PDBFTSRestClientTest.setMock();
+    StructureChooserQuerySource scquery = StructureChooserQuerySource.getQuerySourceFor(new SequenceI[] { upSeq});
+    // gets the lightweight proxy rather than the ThreeDBStructureChooserQuerySource
+    AssertJUnit.assertTrue(scquery instanceof ThreeDBStructureChooserQuerySource);
+    String query = scquery.buildQuery(upSeq);
+    AssertJUnit.assertEquals("P38398", query);
+    
+    // query shouldn't change regardless of additional entries
+    // because 3DBeacons requires canonical entries.
+    upSeq.getAllPDBEntries().clear();
+    query = scquery.buildQuery(upSeq);
+    AssertJUnit.assertEquals("P38398", query);
+    upSeq.setDBRefs(null);
+    query = scquery.buildQuery(upSeq);
+    /*
+     * legacy projects/datasets will not have canonical flags set for uniprot dbrefs
+     * graceful behaviour would be to
+     *  - pick one ? not possible
+     *  - iterate through all until a 200 is obtained ?
+     *  ---> ideal but could be costly
+     *  ---> better to do a direct retrieval from uniprot to work out which is the canonical identifier..
+     *  ----> need a test to check that accessions can be promoted to canonical!
+     */
+    //FIXME - need to be able to use ID to query here ?
+    AssertJUnit.assertEquals(null, query);
+
+    
+    
+    // TODO: 
+    /**
+     * set of sequences:
+     * - no protein -> TDB not applicable, query PDBe only (consider RNA or DNA - specific query adapter ?)
+     * - protein but no uniprot -> first consider trying to get uniprot refs (need a mark to say none are available)
+     * - protein and uniprot - no canonicals -> resolve to uniprot automatically to get canonicals
+     * - query uniprot against 3DBeacons
+     * --> decorate experimental structures with additional data from PDBe
+     * - query remaining against PDBe
+     * Ranking
+     * - 3D Beacons
+     *  --> in memory ranking - no need to query twice
+     *  Rank by
+     *  - experimental > AlphaFold -> Model
+     *  - start > end
+     *  -> filters for 
+     *  -> experimental only
+     *  -> experimental plus best models for other regions
+     *  -> "best cover" 
+     *  -> need to be able to select correct reference (the longest one that covers all) for superposition
+     */
+//    
+//    DBRefEntry uniprotDBRef = new DBRefEntry();
+//    uniprotDBRef.setAccessionId("P12345");
+//    uniprotDBRef.setSource(DBRefSource.UNIPROT);
+//    upSeq.addDBRef(uniprotDBRef);
+//
+//    DBRefEntry pdbDBRef = new DBRefEntry();
+//    pdbDBRef.setAccessionId("1XYZ");
+//    pdbDBRef.setSource(DBRefSource.PDB);
+//    upSeq.addDBRef(pdbDBRef);
+//
+//    for (int x = 1; x < 5; x++)
+//    {
+//      DBRefEntry dbRef = new DBRefEntry();
+//      dbRef.setAccessionId("XYZ_" + x);
+//      seq.addDBRef(dbRef);
+//    }
+//    System.out.println("");
+//    System.out.println(seq.getDBRefs());
+//    System.out.println(query);
+//    query = scquery.buildQuery(seq);
+//    assertEquals(
+//            "uniprot_accession:P12345 OR uniprot_id:P12345 OR pdb_id:1xyz",
+//            query);
+  }
+  @Test(groups= {"Functional"},dataProvider = "testUpSeqs")
+  public void cascadingThreeDBandPDBQuerys(SequenceI testUpSeq)
+  {
+    TDBeaconsFTSRestClientTest.setMock();
+    PDBFTSRestClientTest.setMock();
+    ThreeDBStructureChooserQuerySource tdbquery = new ThreeDBStructureChooserQuerySource();
+    PDBStructureChooserQuerySource pdbquery  = new PDBStructureChooserQuerySource();
+            
+
+    
+    FTSRestResponse upResponse = null;
+    FTSRestResponse pdbResponse = null;
+    // TODO test available options
+    // Best coverage
+    // Best Alphafold Model
+    // Best model (by confidence score)
+    // Will also need to develop a more sophisticated filtering system
+    List<FilterOption> opts = tdbquery.getAvailableFilterOptions(StructureChooser.VIEWS_FILTER);
+    FilterOption opt_singlebest = opts.get(0);
+    FilterOption opt_manybest = opts.get(1);
+    assertEquals(opt_singlebest.getValue(), ThreeDBStructureChooserQuerySource.FILTER_FIRST_BEST_COVERAGE);
+    assertEquals(opt_manybest.getValue(), ThreeDBStructureChooserQuerySource.FILTER_TDBEACONS_COVERAGE);
+    
+    try {
+      upResponse = tdbquery.fetchStructuresMetaData(testUpSeq, tdbquery.getDocFieldPrefs().getStructureSummaryFields(),  opt_singlebest, false);
+      tdbquery.updateAvailableFilterOptions(StructureChooser.VIEWS_FILTER,opts,upResponse.getSearchSummary());
+      // test ranking without additional PDBe data
+      FTSRestResponse firstRanked = tdbquery.selectFirstRankedQuery(testUpSeq, upResponse.getSearchSummary(), tdbquery.getDocFieldPrefs().getStructureSummaryFields(), opt_singlebest.getValue(), false);
+      assertEquals(firstRanked.getNumberOfItemsFound(),1);
+      // many best response
+      upResponse = tdbquery.fetchStructuresMetaData(testUpSeq, tdbquery.getDocFieldPrefs().getStructureSummaryFields(),  opt_manybest, false);
+      assertTrue(firstRanked.getSearchSummary().size()<upResponse.getSearchSummary().size());
+      // NB Could have race condition here 
+      String pdb_Query = tdbquery.buildPDBFTSQueryFor(upResponse);
+      assertTrue(pdb_Query.trim().length()>0);
+      pdbResponse = tdbquery.fetchStructuresMetaDataFor(pdbquery, upResponse);
+      assertTrue(pdbResponse.getNumberOfItemsFound()>0);
+      FTSRestResponse joinedResp = tdbquery.joinResponses(upResponse, pdbResponse);
+      assertEquals(upResponse.getNumberOfItemsFound(),joinedResp.getNumberOfItemsFound());
+      
+      
+    } catch (Exception x)
+    {
+      x.printStackTrace();
+      Assert.fail("Unexpected Exception");
+    }
+    StructureChooserQuerySource scquery = StructureChooserQuerySource.getQuerySourceFor(new SequenceI[] { testUpSeq});
+
+  }
+  
+  @DataProvider(name = "testUpSeqs")
+  public Object[][] testUpSeqs() throws Exception
+  {
+    setUp();
+    return new Object[][] { {upSeq},{upSeq_insulin}};
+  }
+  
+  @Test(groups = { "Functional" })
+  public void sanitizeSeqNameTest()
+  {
+    String name = "ab_cdEF|fwxyz012349";
+    AssertJUnit.assertEquals(name, PDBStructureChooserQuerySource.sanitizeSeqName(name));
+
+    // remove a [nn] substring
+    name = "abcde12[345]fg";
+    AssertJUnit.assertEquals("abcde12fg", PDBStructureChooserQuerySource.sanitizeSeqName(name));
+
+    // remove characters other than a-zA-Z0-9 | or _
+    name = "ab[cd],.\t£$*!- \\\"@:e";
+    AssertJUnit.assertEquals("abcde", PDBStructureChooserQuerySource.sanitizeSeqName(name));
+
+    name = "abcde12[345a]fg";
+    AssertJUnit.assertEquals("abcde12345afg", PDBStructureChooserQuerySource.sanitizeSeqName(name));
+  }
+}
index 05ce22d..9c4be2d 100644 (file)
  */
 package jalview.io;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.HiddenColumns;
-import jalview.gui.JvOptionPane;
-import jalview.io.AnnotationFile.ViewDef;
-
+import java.awt.Color;
 import java.io.File;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.SequenceGroup;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.io.AnnotationFile.ViewDef;
+
 public class AnnotationFileIOTest
 {
 
@@ -165,4 +170,45 @@ public class AnnotationFileIOTest
             + "\nCouldn't complete Annotation file roundtrip input/output/input test for '"
             + annotFile + "'.");
   }
+  
+  @Test(groups="Functional")
+  public void testAnnotateAlignmentView()
+  {
+    long t1 = System.currentTimeMillis();
+    /*
+     * JAL-3779 test multiple groups of the same name get annotated
+     */
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            ">Seq1\nQRSIL\n>Seq2\nFTHND\n>Seq3\nRPVSL\n",
+            DataSourceType.PASTE);
+    long t2 = System.currentTimeMillis();
+    System.err.println("t0: " + (t2 - t1));
+    // seq1 and seq3 are in distinct groups both named Group1
+    String annotationFile = "JALVIEW_ANNOTATION\nSEQUENCE_GROUP\tGroup1\t*\t*\t1\n"
+            + "SEQUENCE_GROUP\tGroup2\t*\t*\t2\n"
+            + "SEQUENCE_GROUP\tGroup1\t*\t*\t3\n"
+            + "PROPERTIES\tGroup1\toutlineColour=blue\tidColour=red\n";
+    new AnnotationFile().annotateAlignmentView(af.getViewport(), annotationFile, DataSourceType.PASTE);
+    
+    AlignmentI al = af.getViewport().getAlignment();
+    List<SequenceGroup> groups = al.getGroups();
+    assertEquals(3, groups.size());
+    SequenceGroup sg = groups.get(0);
+    assertEquals("Group1", sg.getName());
+    assertTrue(sg.contains(al.getSequenceAt(0)));
+    assertEquals(Color.BLUE, sg.getOutlineColour());
+    assertEquals(Color.RED, sg.getIdColour());
+    sg = groups.get(1);
+    assertEquals("Group2", sg.getName());
+    assertTrue(sg.contains(al.getSequenceAt(1)));
+    
+    /*
+     * the bug fix: a second group of the same name is also given properties
+     */
+    sg = groups.get(2);
+    assertEquals("Group1", sg.getName());
+    assertTrue(sg.contains(al.getSequenceAt(2)));
+    assertEquals(Color.BLUE, sg.getOutlineColour());
+    assertEquals(Color.RED, sg.getIdColour());
+  }
 }
index e735ef6..8542f8f 100644 (file)
@@ -312,7 +312,8 @@ public class BackupFilesTest
     cleanupTmpFiles(newFile, suffix, digits);
   }
 
-  private void cleanupTmpFiles(String file, String mysuffix, int mydigits)
+  protected static void cleanupTmpFiles(String file, String mysuffix,
+          int mydigits)
   {
     File newfile = new File(file);
     if (newfile.exists())
diff --git a/test/jalview/io/EmblFlatFileTest.java b/test/jalview/io/EmblFlatFileTest.java
new file mode 100644 (file)
index 0000000..f36e935
--- /dev/null
@@ -0,0 +1,363 @@
+package jalview.io;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jalview.bin.Console;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence.DBModList;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeatures;
+import jalview.util.MapList;
+
+public class EmblFlatFileTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    Console.initLogger();
+  }
+
+  /**
+   * A fairly tough test, using J03321 (circular DNA), which has 8 CDS features,
+   * one of them reverse strand
+   * 
+   * @throws MalformedURLException
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testParse() throws MalformedURLException, IOException
+  {
+    File dataFile = new File("test/jalview/io/J03321.embl.txt");
+    FileParse fp = new FileParse(dataFile, DataSourceType.FILE);
+    EmblFlatFile parser = new EmblFlatFile(fp, "EmblTest");
+    List<SequenceI> seqs = parser.getSeqs();
+
+    assertEquals(seqs.size(), 1);
+    SequenceI seq = seqs.get(0);
+    assertEquals(seq.getName(), "EmblTest|J03321");
+    assertEquals(seq.getLength(), 7502);
+    assertEquals(seq.getDescription(),
+            "Chlamydia trachomatis plasmid pCHL1, complete sequence");
+
+    /*
+     * should be 9 CDS features (one is a 'join' of two exons)
+     */
+    Set<String> featureTypes = seq.getFeatures().getFeatureTypes();
+    assertEquals(featureTypes.size(), 1);
+    assertTrue(featureTypes.contains("CDS"));
+
+    /*
+     * inspect some features (sorted just for convenience of test assertions)
+     */
+    List<SequenceFeature> features = seq.getFeatures()
+            .getAllFeatures("CDS");
+    SequenceFeatures.sortFeatures(features, true);
+    assertEquals(features.size(), 9);
+
+    SequenceFeature sf = features.get(0);
+    assertEquals(sf.getBegin(), 1);
+    assertEquals(sf.getEnd(), 437);
+    assertEquals(sf.getDescription(),
+            "Exon 2 for protein EMBLCDS:AAA91567.1");
+    assertEquals(sf.getFeatureGroup(), "EmblTest");
+    assertEquals(sf.getEnaLocation(), "join(7022..7502,1..437)");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), 1);
+    assertEquals(sf.getValue("note"), "pGP7-D");
+    // this is the second exon of circular CDS!
+    assertEquals(sf.getValue("exon number"), 2);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+    assertEquals(sf.getValue("transl_table"), "11");
+
+    sf = features.get(1);
+    assertEquals(sf.getBegin(), 488);
+    assertEquals(sf.getEnd(), 1480);
+    assertEquals(sf.getDescription(),
+            "Exon 1 for protein EMBLCDS:AAA91568.1");
+    assertEquals(sf.getFeatureGroup(), "EmblTest");
+    assertEquals(sf.getEnaLocation(), "complement(488..1480)");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), -1); // reverse strand!
+    assertEquals(sf.getValue("note"), "pGP8-D");
+    assertEquals(sf.getValue("exon number"), 1);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+
+    sf = features.get(7);
+    assertEquals(sf.getBegin(), 6045);
+    assertEquals(sf.getEnd(), 6788);
+    assertEquals(sf.getDescription(),
+            "Exon 1 for protein EMBLCDS:AAA91574.1");
+    assertEquals(sf.getFeatureGroup(), "EmblTest");
+    assertEquals(sf.getEnaLocation(), "6045..6788");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), 1);
+    assertEquals(sf.getValue("note"), "pGP6-D (gtg start codon)");
+    assertEquals(sf.getValue("exon number"), 1);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+
+    /*
+     * CDS at 7022-7502 is the first exon of the circular CDS
+     */
+    sf = features.get(8);
+    assertEquals(sf.getBegin(), 7022);
+    assertEquals(sf.getEnd(), 7502);
+    assertEquals(sf.getDescription(),
+            "Exon 1 for protein EMBLCDS:AAA91567.1");
+    assertEquals(sf.getFeatureGroup(), "EmblTest");
+    assertEquals(sf.getEnaLocation(), "join(7022..7502,1..437)");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), 1);
+    assertEquals(sf.getValue("note"), "pGP7-D");
+    assertEquals(sf.getValue("exon number"), 1);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+
+    /*
+     * Verify DBRefs, whether declared in the file or added by Jalview.
+     * There are 4 'direct' (DR) dbrefs, and numerous CDS /db_xref entries 
+     * (some e.g. INTERPRO are duplicates). Jalview adds a dbref to 'self'.
+     * Sample a few here. Note DBRefEntry constructor capitalises source.
+     */
+    List<DBRefEntry> dbrefs = seq.getDBRefs();
+    assertEquals(dbrefs.size(), 32);
+    // xref to 'self':
+    DBRefEntry selfRef = new DBRefEntry("EMBLTEST", "1", "J03321");
+    int[] range = new int[] { 1, seq.getLength() };
+    selfRef.setMap(new Mapping(null, range, range, 1, 1));
+    assertTrue(dbrefs.contains(selfRef));
+
+    // 1st DR line; note trailing period is removed
+    assertTrue(dbrefs.contains(new DBRefEntry("MD5", "0",
+            "d4c4942a634e3df4995fd5ac75c26a61")));
+    // the 4th DR line:
+    assertTrue(
+            dbrefs.contains(new DBRefEntry("EUROPEPMC", "0", "PMC87941")));
+    // from the first CDS feature
+    assertTrue(dbrefs.contains(new DBRefEntry("GOA", "0", "P0CE19")));
+    // from the last CDS feature
+    assertTrue(
+            dbrefs.contains(new DBRefEntry("INTERPRO", "0", "IPR005350")));
+
+    /*
+     * verify mappings to, and sequences for, UNIPROT proteins
+     */
+    int uniprotCount = 0;
+    List<int[]> ranges;
+    for (DBRefEntry dbref : dbrefs)
+    {
+      if ("UNIPROT".equals(dbref.getSource()))
+      {
+        uniprotCount++;
+        Mapping mapping = dbref.getMap();
+        assertNotNull(mapping);
+        MapList map = mapping.getMap();
+        String mappedToName = mapping.getTo().getName();
+        if ("UNIPROT|P0CE16".equals(mappedToName))
+        {
+          assertEquals((ranges = map.getFromRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1579);
+          assertEquals(ranges.get(0)[1], 2931);  // excludes stop 2934 
+          assertEquals((ranges = map.getToRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1);
+          assertEquals(ranges.get(0)[1], 451);
+          // CDS /product carries over as protein product description
+          assertEquals(mapping.getTo().getDescription(),
+                  "hypothetical protein");
+        }
+        else if ("UNIPROT|P0CE17".equals(mappedToName))
+        {
+          assertEquals((ranges = map.getFromRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 2928);
+          assertEquals(ranges.get(0)[1], 3989);  // excludes stop 3992
+          assertEquals((ranges = map.getToRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1);
+          assertEquals(ranges.get(0)[1], 354);
+        }
+        else if ("UNIPROT|P0CE18".equals(mappedToName))
+        {
+          assertEquals((ranges = map.getFromRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 4054);
+          assertEquals(ranges.get(0)[1], 4845); // excludes stop 4848
+          assertEquals((ranges = map.getToRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1);
+          assertEquals(ranges.get(0)[1], 264);
+        }
+        else if ("UNIPROT|P0CE19".equals(mappedToName))
+        {
+          // join(7022..7502,1..437)
+          assertEquals((ranges = map.getFromRanges()).size(), 2);
+          assertEquals(ranges.get(0)[0], 7022);
+          assertEquals(ranges.get(0)[1], 7502);
+          assertEquals(ranges.get(1)[0], 1);
+          assertEquals(ranges.get(1)[1], 434); // excludes stop at 437
+          assertEquals((ranges = map.getToRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1);
+          assertEquals(ranges.get(0)[1], 305);
+        }
+        else if ("UNIPROT|P0CE20".equals(mappedToName))
+        {
+          // complement(488..1480)
+          assertEquals((ranges = map.getFromRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1480);
+          assertEquals(ranges.get(0)[1], 491); // // excludes stop at 488
+          assertEquals((ranges = map.getToRanges()).size(), 1);
+          assertEquals(ranges.get(0)[0], 1);
+          assertEquals(ranges.get(0)[1], 330);
+        }
+        else if (!"UNIPROT|P0CE23".equals(mappedToName)
+                && !"UNIPROT|P10559".equals(mappedToName)
+                && !"UNIPROT|P10560".equals(mappedToName))
+        {
+          fail("Unexpected UNIPROT dbref to " + mappedToName);
+        }
+      }
+    }
+    assertEquals(uniprotCount, 8);
+  }
+  /**
+   * A fairly tough test, using J03321 (circular DNA), which has 8 CDS features,
+   * one of them reverse strand
+   * 
+   * @throws MalformedURLException
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testParseToRNA() throws MalformedURLException, IOException
+  {
+    File dataFile = new File("test/jalview/io/J03321_rna.embl.txt");
+    FileParse fp = new FileParse(dataFile, DataSourceType.FILE);
+    EmblFlatFile parser = new EmblFlatFile(fp, "EmblTest");
+    List<SequenceI> seqs = parser.getSeqs();
+    assertTrue(seqs.get(0).getSequenceAsString().indexOf("u")>-1);
+  }
+
+  @Test(groups = "Functional")
+  public void testParse_codonStartNot1()
+  {
+    // TODO verify CDS-to-protein mapping for CDS with /codon_start=2
+    // example: https://www.ebi.ac.uk/ena/browser/api/embl/EU498516
+  }
+
+  /**
+   * Test for the case that the EMBL CDS has no UNIPROT xref. In this case
+   * Jalview should synthesize an xref to EMBLCDSPROTEIN in the hope this will
+   * allow Get Cross-References.
+   * 
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testParse_noUniprotXref() throws IOException
+  {
+    // MN908947 cut down to 40BP, one CDS, length 5 peptide for test purposes
+    // plus an additional (invented) test case:
+    // - multi-line /product qualifier including escaped quotes
+    String data = "ID   MN908947; SV 3; linear; genomic RNA; STD; VRL; 20 BP.\n"
+            + "DE   Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1,\n"
+            + "FT   CDS             3..17\n"
+            + "FT                   /protein_id=\"QHD43415.1\"\n"
+            + "FT                   /product=\"orf1ab polyprotein\n"
+            + "FT                   \"\"foobar\"\" \"\n"
+            + "FT                   /translation=\"MRKLD\n"
+            + "SQ   Sequence 7496 BP; 2450 A; 1290 C; 1434 G; 2322 T; 0 other;\n"
+            + "     ggatGcgtaa gttagacgaa attttgtctt tgcgcacaga        40\n";
+    FileParse fp = new FileParse(data, DataSourceType.PASTE);
+    EmblFlatFile parser = new EmblFlatFile(fp, "EmblTest");
+    List<SequenceI> seqs = parser.getSeqs();
+    assertEquals(seqs.size(), 1);
+    SequenceI seq = seqs.get(0);
+    DBModList<DBRefEntry> dbrefs = seq.getDBRefs();
+
+    /*
+     * dna should have dbref to itself, and to inferred EMBLCDSPROTEIN:QHD43415.1
+     */
+    assertEquals(dbrefs.size(), 2);
+    
+    // dbref to self
+    DBRefEntry dbref = dbrefs.get(0);
+    assertEquals(dbref.getSource(), "EMBLTEST");
+    assertEquals(dbref.getAccessionId(), "MN908947");
+    Mapping mapping = dbref.getMap();
+    assertNull(mapping.getTo());
+    MapList map = mapping.getMap();
+    assertEquals(map.getFromLowest(), 1);
+    assertEquals(map.getFromHighest(), 40);
+    assertEquals(map.getToLowest(), 1);
+    assertEquals(map.getToHighest(), 40);
+    assertEquals(map.getFromRatio(), 1);
+    assertEquals(map.getToRatio(), 1);
+    
+    // dbref to inferred EMBLCDSPROTEIN:
+    dbref = dbrefs.get(1);
+    assertEquals(dbref.getSource(), "EMBLCDSPROTEIN");
+    assertEquals(dbref.getAccessionId(), "QHD43415.1");
+    mapping = dbref.getMap();
+    SequenceI mapTo = mapping.getTo();
+    assertEquals(mapTo.getName(), "QHD43415.1");
+    // the /product qualifier transfers to protein product description
+    assertEquals(mapTo.getDescription(), "orf1ab polyprotein \"foobar\"");
+    assertEquals(mapTo.getSequenceAsString(), "MRKLD");
+    map = mapping.getMap();
+    assertEquals(map.getFromLowest(), 3);
+    assertEquals(map.getFromHighest(), 17);
+    assertEquals(map.getToLowest(), 1);
+    assertEquals(map.getToHighest(), 5);
+    assertEquals(map.getFromRatio(), 3);
+    assertEquals(map.getToRatio(), 1);
+  }
+
+  @Test(groups = "Functional")
+  public void testAdjustForProteinLength()
+  {
+    int[] exons = new int[] { 11, 15, 21, 25, 31, 38 }; // 18 bp
+
+    // exact length match:
+    assertSame(exons, EmblFlatFile.adjustForProteinLength(6, exons));
+
+    // patch from JAL-3725 in EmblXmlSource propagated to Flatfile
+    // match if we assume exons include stop codon not in protein: 
+    int[] truncated = EmblFlatFile.adjustForProteinLength(5, exons);
+    assertEquals(Arrays.toString(truncated), "[11, 15, 21, 25, 31, 35]");
+    
+    // truncate last exon by 6bp
+    truncated = EmblFlatFile.adjustForProteinLength(4, exons);
+    assertEquals(Arrays.toString(truncated),"[11, 15, 21, 25, 31, 32]");
+
+    // remove last exon and truncate preceding by 1bp (so 3bp in total)
+    truncated = EmblFlatFile.adjustForProteinLength(3, exons);
+    assertEquals(Arrays.toString(truncated),"[11, 15, 21, 24]");
+
+    // exact removal of exon case:
+    exons = new int[] { 11, 15, 21, 27, 33, 38 }; // 18 bp
+    truncated = EmblFlatFile.adjustForProteinLength(4, exons);
+    assertEquals(Arrays.toString(truncated), "[11, 15, 21, 27]");
+
+    // what if exons are too short for protein?
+    truncated = EmblFlatFile.adjustForProteinLength(7, exons);
+    assertSame(exons, truncated);
+  }
+
+  @Test(groups = "Functional")
+  public void testRemoveQuotes()
+  {
+    assertNull(EmblFlatFile.removeQuotes(null));
+    assertEquals(EmblFlatFile.removeQuotes("No quotes here"), "No quotes here");
+    assertEquals(EmblFlatFile.removeQuotes("\"Enclosing quotes\""), "Enclosing quotes");
+    assertEquals(EmblFlatFile.removeQuotes("\"Escaped \"\"quotes\"\" example\""), "Escaped \"quotes\" example");
+  }
+}
index 53f18bf..3d25bf1 100644 (file)
@@ -1,5 +1,7 @@
 package jalview.io;
 
+import java.util.Locale;
+
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotEquals;
@@ -31,14 +33,15 @@ public class FileFormatsTest
   public void testIsIdentifiable()
   {
     FileFormats formats = FileFormats.getInstance();
-    assertTrue(formats.isIdentifiable(formats.forName(FileFormat.Fasta
-            .getName())));
-    assertTrue(formats.isIdentifiable(formats.forName(FileFormat.MMCif
-            .getName())));
-    assertTrue(formats.isIdentifiable(formats.forName(FileFormat.Jnet
-            .getName())));
-    assertTrue(formats.isIdentifiable(formats.forName(FileFormat.Jalview
-            .getName())));
+    assertTrue(formats
+            .isIdentifiable(formats.forName(FileFormat.Fasta.getName())));
+    assertTrue(formats
+            .isIdentifiable(formats.forName(FileFormat.MMCif.getName())));
+    assertTrue(formats
+            .isIdentifiable(formats.forName(FileFormat.Jnet.getName())));
+    assertTrue(formats
+            .isIdentifiable(formats.forName(FileFormat.Jalview.getName())));
+    // GenBank/ENA
     assertFalse(formats.isIdentifiable(null));
 
     /*
@@ -55,7 +58,7 @@ public class FileFormatsTest
   @Test(groups = "Functional")
   public void testGetReadableFormats()
   {
-    String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview]";
+    String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GenBank Flatfile, ENA Flatfile, GFF or Jalview features, PDB, mmCIF, Jalview]";
     FileFormats formats = FileFormats.getInstance();
     assertEquals(formats.getReadableFormats().toString(), expected);
   }
@@ -74,14 +77,14 @@ public class FileFormatsTest
   public void testDeregisterFileFormat()
   {
     String writable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]";
-    String readable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview]";
+    String readable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GenBank Flatfile, ENA Flatfile, GFF or Jalview features, PDB, mmCIF, Jalview]";
     FileFormats formats = FileFormats.getInstance();
     assertEquals(formats.getWritableFormats(true).toString(), writable);
     assertEquals(formats.getReadableFormats().toString(), readable);
 
     formats.deregisterFileFormat(FileFormat.Fasta.getName());
     writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]";
-    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview]";
+    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GenBank Flatfile, ENA Flatfile, GFF or Jalview features, PDB, mmCIF, Jalview]";
     assertEquals(formats.getWritableFormats(true).toString(), writable);
     assertEquals(formats.getReadableFormats().toString(), readable);
 
@@ -90,7 +93,7 @@ public class FileFormatsTest
      */
     formats.registerFileFormat(FileFormat.Fasta);
     writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Fasta]";
-    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, Fasta]";
+    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GenBank Flatfile, ENA Flatfile, GFF or Jalview features, PDB, mmCIF, Jalview, Fasta]";
     assertEquals(formats.getWritableFormats(true).toString(), writable);
     assertEquals(formats.getReadableFormats().toString(), readable);
   }
@@ -102,8 +105,8 @@ public class FileFormatsTest
     for (FileFormatI ff : FileFormat.values())
     {
       assertSame(ff, formats.forName(ff.getName()));
-      assertSame(ff, formats.forName(ff.getName().toUpperCase()));
-      assertSame(ff, formats.forName(ff.getName().toLowerCase()));
+      assertSame(ff, formats.forName(ff.getName().toUpperCase(Locale.ROOT)));
+      assertSame(ff, formats.forName(ff.getName().toLowerCase(Locale.ROOT)));
     }
     assertNull(formats.forName(null));
     assertNull(formats.forName("rubbish"));
@@ -144,8 +147,7 @@ public class FileFormatsTest
      * verify the list of file formats registered matches the enum values
      */
     FileFormats instance = FileFormats.getInstance();
-    Iterator<FileFormatI> formats = instance.getFormats()
-            .iterator();
+    Iterator<FileFormatI> formats = instance.getFormats().iterator();
     FileFormatI[] builtIn = FileFormat.values();
 
     for (FileFormatI ff : builtIn)
index e37ae3f..b693d51 100644 (file)
@@ -36,7 +36,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.JvOptionPane;
 
 /**
@@ -59,7 +59,7 @@ public class FileIOTester
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-    Cache.initLogger();
+    Console.initLogger();
   }
 
   /**
diff --git a/test/jalview/io/GenBankFileTest.java b/test/jalview/io/GenBankFileTest.java
new file mode 100644 (file)
index 0000000..83d630f
--- /dev/null
@@ -0,0 +1,202 @@
+package jalview.io;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.AssertJUnit.assertNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jalview.bin.Console;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.SequenceFeatures;
+import jalview.util.MapList;
+
+public class GenBankFileTest
+{
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    Console.initLogger();
+  }
+
+  /**
+   * A fairly tough test, using J03321 (circular DNA), which has 8 CDS features,
+   * one of them reverse strand
+   * 
+   * @throws MalformedURLException
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testParse() throws MalformedURLException, IOException
+  {
+    File dataFile = new File("test/jalview/io/J03321.gb");
+    FileParse fp = new FileParse(dataFile.getAbsolutePath(),
+            DataSourceType.FILE);
+    EMBLLikeFlatFile parser = new GenBankFile(fp, "GenBankTest");
+    List<SequenceI> seqs = parser.getSeqs();
+
+    assertEquals(seqs.size(), 1);
+    SequenceI seq = seqs.get(0);
+    assertEquals(seq.getName(), "GenBankTest|J03321");
+    assertEquals(seq.getLength(), 7502);
+    assertEquals(seq.getDescription(),
+            "Chlamydia trachomatis plasmid pCHL1, complete sequence");
+
+    /*
+     * should be 9 CDS features (one is a 'join' of two exons)
+     */
+    Set<String> featureTypes = seq.getFeatures().getFeatureTypes();
+    assertEquals(featureTypes.size(), 1);
+    assertTrue(featureTypes.contains("CDS"));
+
+    /*
+     * inspect some features (sorted just for convenience of test assertions)
+     */
+    List<SequenceFeature> features = seq.getFeatures()
+            .getAllFeatures("CDS");
+    SequenceFeatures.sortFeatures(features, true);
+    assertEquals(features.size(), 9);
+
+    SequenceFeature sf = features.get(0);
+    assertEquals(sf.getBegin(), 1);
+    assertEquals(sf.getEnd(), 437);
+    assertEquals(sf.getDescription(),
+            "Exon 2 for protein EMBLCDS:AAA91567.1");
+    assertEquals(sf.getFeatureGroup(), "GenBankTest");
+    assertEquals(sf.getEnaLocation(), "join(7022..7502,1..437)");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), 1);
+    assertEquals(sf.getValue("note"), "pGP7-D");
+    // this is the second exon of circular CDS!
+    assertEquals(sf.getValue("exon number"), 2);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+    assertEquals(sf.getValue("transl_table"), "11");
+
+    sf = features.get(1);
+    assertEquals(sf.getBegin(), 488);
+    assertEquals(sf.getEnd(), 1480);
+    assertEquals(sf.getDescription(),
+            "Exon 1 for protein EMBLCDS:AAA91568.1");
+    assertEquals(sf.getFeatureGroup(), "GenBankTest");
+    assertEquals(sf.getEnaLocation(), "complement(488..1480)");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), -1); // reverse strand!
+    assertEquals(sf.getValue("note"), "pGP8-D");
+    assertEquals(sf.getValue("exon number"), 1);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+
+    sf = features.get(7);
+    assertEquals(sf.getBegin(), 6045);
+    assertEquals(sf.getEnd(), 6788);
+    assertEquals(sf.getDescription(),
+            "Exon 1 for protein EMBLCDS:AAA91574.1");
+    assertEquals(sf.getFeatureGroup(), "GenBankTest");
+    assertEquals(sf.getEnaLocation(), "6045..6788");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), 1);
+    assertEquals(sf.getValue("note"), "pGP6-D (gtg start codon)");
+    assertEquals(sf.getValue("exon number"), 1);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+
+    /*
+     * CDS at 7022-7502 is the first exon of the circular CDS
+     */
+    sf = features.get(8);
+    assertEquals(sf.getBegin(), 7022);
+    assertEquals(sf.getEnd(), 7502);
+    assertEquals(sf.getDescription(),
+            "Exon 1 for protein EMBLCDS:AAA91567.1");
+    assertEquals(sf.getFeatureGroup(), "GenBankTest");
+    assertEquals(sf.getEnaLocation(), "join(7022..7502,1..437)");
+    assertEquals(sf.getPhase(), "0");
+    assertEquals(sf.getStrand(), 1);
+    assertEquals(sf.getValue("note"), "pGP7-D");
+    assertEquals(sf.getValue("exon number"), 1);
+    assertEquals(sf.getValue("product"), "hypothetical protein");
+
+    /*
+     * GenBank doesn't declare accession or CDS xrefs;
+     * dbrefs are added by Jalview for 
+     * xref to self : 1
+     * protein products: 8
+     */
+    List<DBRefEntry> dbrefs = seq.getDBRefs();
+
+    assertEquals(dbrefs.size(), 9);
+    // xref to 'self':
+    DBRefEntry selfRef = new DBRefEntry("GENBANKTEST", "1", "J03321");
+    int[] range = new int[] { 1, seq.getLength() };
+    selfRef.setMap(new Mapping(null, range, range, 1, 1));
+    assertTrue(dbrefs.contains(selfRef));
+
+    /*
+     * dna should have dbref to itself, and to EMBLCDSPROTEIN
+     * for each /protein_id (synthesized as no UNIPROT xref)
+     */
+    // TODO check if we should synthesize EMBLCDSPROTEIN dbrefs
+    DBRefEntry dbref = dbrefs.get(0);
+    assertEquals(dbref.getSource(), "GENBANKTEST");
+    assertEquals(dbref.getAccessionId(), "J03321");
+    Mapping mapping = dbref.getMap();
+    assertNull(mapping.getTo());
+    MapList map = mapping.getMap();
+    assertEquals(map.getFromLowest(), 1);
+    assertEquals(map.getFromHighest(), 7502);
+    assertEquals(map.getToLowest(), 1);
+    assertEquals(map.getToHighest(), 7502);
+    assertEquals(map.getFromRatio(), 1);
+    assertEquals(map.getToRatio(), 1);
+
+    // dbref to inferred EMBLCDSPROTEIN for first CDS
+    dbref = dbrefs.get(1);
+    assertEquals(dbref.getSource(), "EMBLCDSPROTEIN");
+    assertEquals(dbref.getAccessionId(), "AAA91567.1");
+    mapping = dbref.getMap();
+    SequenceI mapTo = mapping.getTo();
+    assertEquals(mapTo.getName(), "AAA91567.1");
+    // the /product qualifier transfers to protein product description
+    assertEquals(mapTo.getDescription(), "hypothetical protein");
+    String seqString = mapTo.getSequenceAsString();
+    assertEquals(seqString.length(), 305);
+    assertTrue(seqString.startsWith("MGSMAF"));
+    assertTrue(seqString.endsWith("QTPTIL"));
+    map = mapping.getMap();
+    assertEquals(map.getFromLowest(), 1);
+    assertEquals(map.getFromHighest(), 7502);
+    assertEquals(map.getToLowest(), 1);
+    assertEquals(map.getToHighest(), 305);
+    assertEquals(map.getFromRatio(), 3);
+    assertEquals(map.getToRatio(), 1);
+
+    // dbref to inferred EMBLCDSPROTEIN for last CDS
+    dbref = dbrefs.get(8);
+    assertEquals(dbref.getSource(), "EMBLCDSPROTEIN");
+    assertEquals(dbref.getAccessionId(), "AAA91574.1");
+    mapping = dbref.getMap();
+    mapTo = mapping.getTo();
+    assertEquals(mapTo.getName(), "AAA91574.1");
+    // the /product qualifier transfers to protein product description
+    assertEquals(mapTo.getDescription(), "hypothetical protein");
+    seqString = mapTo.getSequenceAsString();
+    assertEquals(seqString.length(), 247);
+    assertTrue(seqString.startsWith("MNKLK"));
+    assertTrue(seqString.endsWith("FKQKS"));
+    map = mapping.getMap();
+    assertEquals(map.getFromLowest(), 6045);
+    assertEquals(map.getFromHighest(), 6785); // excludes stop at 6788
+    assertEquals(map.getToLowest(), 1);
+    assertEquals(map.getToHighest(), 247);
+    assertEquals(map.getFromRatio(), 3);
+    assertEquals(map.getToRatio(), 1);
+  }
+}
index cf7f58f..68c099e 100644 (file)
@@ -24,13 +24,13 @@ import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.gui.JvOptionPane;
-
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import jalview.gui.JvOptionPane;
+
 public class IdentifyFileTest
 {
 
@@ -102,6 +102,8 @@ public class IdentifyFileTest
         { "examples/testdata/test.html", FileFormat.Html },
         { "examples/testdata/test.pileup", FileFormat.Pileup },
         { "examples/testdata/test.blc", FileFormat.BLC },
+        { "test/jalview/io/J03321.embl.txt", FileFormat.Embl },
+        { "test/jalview/io/J03321.gb", FileFormat.GenBank },
         { "examples/exampleFeatures.txt", FileFormat.Features },
         { "examples/testdata/simpleGff3.gff", FileFormat.Features },
         { "examples/testdata/test.jvp", FileFormat.Jalview },
diff --git a/test/jalview/io/J03321.embl.txt b/test/jalview/io/J03321.embl.txt
new file mode 100644 (file)
index 0000000..555c2b5
--- /dev/null
@@ -0,0 +1,306 @@
+ID   J03321; SV 1; circular; genomic DNA; STD; PRO; 7502 BP.
+XX
+AC   J03321;
+XX
+DT   27-JUL-1990 (Rel. 24, Created)
+DT   10-APR-2020 (Rel. 144, Last updated, Version 9)
+XX
+DE   Chlamydia trachomatis plasmid pCHL1, complete sequence.
+XX
+KW   .
+XX
+OS   Chlamydia trachomatis
+OC   Bacteria; Chlamydiae; Chlamydiales; Chlamydiaceae;
+OC   Chlamydia/Chlamydophila group; Chlamydia.
+OG   Plasmid pCHL1
+XX
+RN   [1]
+RP   1-7502
+RX   DOI; 10.1016/0147-619X(90)90034-A.
+RX   PUBMED; 2194229.
+RA   Comanducci M., Ricci S., Cevenini R., Ratti G.;
+RT   "Diversity of the Chlamydia trachomatis common plasmid in biovars with
+RT   different pathogenicity";
+RL   Plasmid 23(2):149-154(1990).
+XX
+RN   [2]
+RP   1-7502
+RA   Comanducci M., Ricci S., Cevenini R., Ratti G.;
+RT   ;
+RL   Submitted (23-JUN-2010) to the INSDC.
+RL   Sclavo Research Centre, Siena, Italy
+XX
+DR   MD5; d4c4942a634e3df4995fd5ac75c26a61.
+DR   BioSample; SAMN14225621.
+DR   EuropePMC; PMC4450983; 26031715.
+DR   EuropePMC; PMC87941; 11283058.
+XX
+CC   Draft entry and computer-readable sequence kindly submitted by
+CC   G.Ratti, 28-MAR-1990.
+XX
+FH   Key             Location/Qualifiers
+FH
+FT   source          1..7502
+FT                   /organism="Chlamydia trachomatis"
+FT                   /plasmid="pCHL1"
+FT                   /isolate="G0/86"
+FT                   /serotype="D"
+FT                   /mol_type="genomic DNA"
+FT                   /isolation_source="trachoma"
+FT                   /db_xref="taxon:813"
+XX   next line artificially split for test purposes!
+FT   CDS             join(7022..7502,
+FT                   1..437)
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP7-D"
+FT                   /db_xref="GOA:P0CE19"
+FT                   /db_xref="InterPro:IPR002104"
+FT                   /db_xref="InterPro:IPR011010"
+FT                   /db_xref="InterPro:IPR013762"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE19"
+FT                   /protein_id="AAA91567.1"
+FT                   /translation="MGSMAFHKSRLFLTFGDASEIWLSTLSYLTRKNYASGINFLVSLE
+FT                   ILDLSETLIKAISLDHSESLFKIKSLDVFNGKVVSEASKQARAACYISFTKFLYRLTKG
+FT                   YIKPAIPLKDFGNTTFFKIRDKIKTESISKQEWTVFFEALRIVNYRDYLIGKLIVQGIR
+FT                   KLDEILSLRTDDLFFASNQISFRIKKRQNKETKILITFPISLMEELQKYTCGRNGRVFV
+FT                   SKIGIPVTTSQVAHNFRLAEFHSAMKIKITPRVLRASALIHLKQIGLKDEEIMRISCLS
+FT                   SRQSVCSYCSGEEVIPLVQTPTIL"
+FT   CDS             complement(488..1480)
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP8-D"
+FT                   /db_xref="GOA:P0CE20"
+FT                   /db_xref="InterPro:IPR002104"
+FT                   /db_xref="InterPro:IPR011010"
+FT                   /db_xref="InterPro:IPR013762"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE20"
+FT                   /protein_id="AAA91568.1"
+FT                   /translation="MGKGILSLQQEMSLEYSEKSYQEVLKIRQESYWKRMKSFSLFEVI
+FT                   MHWTASLNKHTCRSYRGSFLSLEKIGLLSLDMNLQEFSLLNHNLILDAIKKVSSAKTSW
+FT                   TEGTKQVRAASYISLTRFLNRMTQGIVAIAQPSKQENSRTFFKTREIVKTDAMNSLQTA
+FT                   SFLKELKKINARDWLIAQTMLQGGKRSSEVLSLEISQICFQQATISFSQLKNRQTEKRI
+FT                   IITYPQKFMHFLQEYIGQRRGFVFVTRSGKMVGLRQIARTFSQAGLQAAIPFKITPHVL
+FT                   RATAVTEYKRLGCSDSDIMKVTGHATAKMIFAYDKSSREDNASKKMALI"
+FT   CDS             1579..2934
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP1-D"
+FT                   /db_xref="GOA:P0CE16"
+FT                   /db_xref="InterPro:IPR003593"
+FT                   /db_xref="InterPro:IPR007693"
+FT                   /db_xref="InterPro:IPR007694"
+FT                   /db_xref="InterPro:IPR027417"
+FT                   /db_xref="InterPro:IPR036185"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE16"
+FT                   /protein_id="AAA91569.1"
+FT                   /translation="MKTRSEIENRMQDIEYALLGKALIFEDSTEYILRQLANYEFKCSH
+FT                   HKNIFIVFKHLKDNGLPITVDSAWEELLRRRIKDMDKSYLGLMLHDALSNDKLRSVSHT
+FT                   VFLDDLSVCSAEENLSNFIFRSFNEYNENPLRRSPFLLLERIKGRLDSAIAKTFSIRSA
+FT                   RGRSIYDIFSQSEIGVLARIKKRRVAFSENQNSFFDGFPTGYKDIDDKGVILAKGNFVI
+FT                   IAARPSIGKTALAIDMAINLAVTQQRRVGFLSLEMSAGQIVERIIANLTGISGEKLQRG
+FT                   DLSKEELFRVEEAGETVRESHFYICSDSQYKLNLIANQIRLLRKEDRVDVIFIDYLQLI
+FT                   NSSVGENRQNEIADISRTLRGLASELNIPIVCLSQLSRKVEDRANKVPMLSDLRDSGQI
+FT                   EQDADVILFINRKESSSNCEITVGKNRHGSVFSSVLHFDPKISKFSAIKKVW"
+FT   CDS             2928..3992
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP2-D"
+FT                   /db_xref="InterPro:IPR040719"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE17"
+FT                   /protein_id="AAA91570.1"
+FT                   /translation="MVNYSNCHFIKSPIHLENQKFGRRPGQSIKISPKLAQNGMVEVIG
+FT                   LDFLSSHYHALAAIQRLLTATNYKGNTKGVVLSRESNSFQFEGWIPRIRFTKTEFLEAY
+FT                   GVKRYKTSRNKYEFSGKEAETALEALYHLGHQPFLIVATRTRWTNGTQIVDRYQTLSPI
+FT                   IRIYEGWEGLTDEENIDIDLTPFNSPPTRKHKGFVVEPCPILVDQIESYFVIKPANVYQ
+FT                   EIKMRFPNASKYAYTFIDWVITAAAKKRRKLTKDNSWPENLLLNVNVKSLAYILRMNRY
+FT                   ICTRNWKKIELAIDKCIEIAIQLGWLSRRKRIEFLDSSKLSKKEILYLNKERFEEITKK
+FT                   SKEQMEQLEQESIN"
+FT   CDS             4054..4848
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP3-D"
+FT                   /db_xref="InterPro:IPR008444"
+FT                   /db_xref="InterPro:IPR033758"
+FT                   /db_xref="InterPro:IPR038264"
+FT                   /db_xref="PDB:6GJT"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE18"
+FT                   /protein_id="AAA91571.1"
+FT                   /translation="MGNSGFYLYNTENCVFADNIKVGQMTEPLKDQQIILGTTSTPVAA
+FT                   KMTASDGISLTVSNNSSTNASITIGLDAEKAYQLILEKLGDQILDGIADTIVDSTVQDI
+FT                   LDKIKTDPSLGLLKAFNNFPITNKIQCNGLFTPSNIETLLGGTEIGKFTVTPKSSGSMF
+FT                   LVSADIIASRMEGGVVLALVREGDSKPCAISYGYSSGIPNLCSLRTSITNTGLTPTTYS
+FT                   LRVGGLESGVVWVNALSNGNDILGITNTSNVSFLEVIPQTNA"
+FT   CDS             4918..5226
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP4-D"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE23"
+FT                   /protein_id="AAA91572.1"
+FT                   /translation="MQNKRKVRDDFIKIVKDVKKDFPELDLKIRVNKEKVTFLNSPLEL
+FT                   YHKSVSLILGLLQQIENSLGLFPDSPVLEKLEDNSLKLKKALIMLILSRKDMFSKAE"
+FT   CDS             5317..6048
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP5-D (gtg start codon)"
+FT                   /db_xref="GOA:P10559"
+FT                   /db_xref="InterPro:IPR025669"
+FT                   /db_xref="InterPro:IPR027417"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P10559"
+FT                   /protein_id="AAA91573.1"
+FT                   /translation="MGCNLAQFLGKKVLLADLDPQSNLSSGLGASVRSDQKGLHDIVYT
+FT                   SNDLKSIICETKKDSVDLIPASFSSEQFRELDIHRGPSNNLKLFLNEYCAPFYDICIID
+FT                   TPPSLGGLTKEAFVAGDKLIACLTPEPFSILGLQKIREFLSSVGKPEEEHILGIALSFW
+FT                   DDRNSTNQMYIDIIESIYKNKLFSTKIRRDISLSRSLLKEDSVANVYPNSRAAEDILKL
+FT                   THEIANILHIEYERDYSQRTT"
+FT   CDS             6045..6788
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP6-D (gtg start codon)"
+FT                   /db_xref="InterPro:IPR005350"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P10560"
+FT                   /protein_id="AAA91574.1"
+FT                   /translation="MNKLKKEADVFFKKNQTAASLDFKKTLPSIELFSATLNSEESQSL
+FT                   DRLFLSESQNYSDEEFYQEDILAVKLLTGQIKSIQKQHVLLLGEKIYNARKILSKDHFS
+FT                   STTFSSWIELVFRTKSSAYNALAYYELFINLPNQTLQKEFQSIPYKSAYILAARKGDLK
+FT                   TKVDVIGKVCGMSNSSAIRVLDQFLPSSRNKDVRETIDKSDSEKNRQLSDFLIEILRIM
+FT                   CSGVSLSSYNENLLQQLFELFKQKS"
+FT   repeat_region   6857..6945
+FT                   /note="four tandem 22bp repeats"
+XX
+SQ   Sequence 7502 BP; 2460 A; 1285 C; 1433 G; 2324 T; 0 other;
+     ggatccgtaa gttagacgaa attttgtctt tgcgcacaga cgatctattt tttgcatcca        60
+     atcagatttc ctttcgcatt aaaaaaagac agaataaaga aaccaaaatt ctaatcacat       120
+     ttcctatcag cttaatggaa gagttgcaaa aatacacttg tgggagaaat gggagagtat       180
+     ttgtttctaa aatagggatt cctgtaacaa caagtcaggt tgcgcataat tttaggcttg       240
+     cagagttcca tagtgctatg aaaataaaaa ttactcccag agtacttcgt gcaagcgctt       300
+     tgattcattt aaagcaaata ggattaaaag atgaggaaat catgcgtatt tcctgtcttt       360
+     catcgagaca aagtgtgtgt tcttattgtt ctggggaaga ggtaattcct ctagtacaaa       420
+     cacccacaat attgtgatat aattaaaatt atattcatat tctgttgcca gaaaaaacac       480
+     ctttaggcta tattagagcc atcttctttg aagcgttgtc ttctcgagaa gatttatcgt       540
+     acgcaaatat catctttgcg gttgcgtgtc ctgtgacctt cattatgtcg gagtctgagc       600
+     accctaggcg tttgtactcc gtcacagcgg ttgctcgaag cacgtgcggg gttattttaa       660
+     aagggattgc agcttgtagt cctgcttgag agaacgtgcg ggcgatttgc cttaacccca       720
+     ccatttttcc ggagcgagtt acgaagacaa aacctcttcg ttgaccgatg tactcttgta       780
+     gaaagtgcat aaacttctga ggataagtta taataatcct cttttctgtc tgacggttct       840
+     taagctggga gaaagaaatg gtagcttgtt ggaaacaaat ctgactaatc tccaagctta       900
+     agacttcaga ggagcgttta cctccttgga gcattgtctg ggcgatcaac caatcccggg       960
+     cattgatttt ttttagctct tttaggaagg atgctgtttg caaactgttc atcgcatccg      1020
+     tttttactat ttccctggtt ttaaaaaatg ttcgactatt ttcttgttta gaaggttgcg      1080
+     ctatagcgac tattccttga gtcatcctgt ttaggaatct tgttaaggaa atatagcttg      1140
+     ctgctcgaac ttgtttagta ccttcggtcc aagaagtctt ggcagaggaa acttttttaa      1200
+     tcgcatctag gattagatta tgatttaaaa gggaaaactc ttgcagattc atatccaagg      1260
+     acaatagacc aatcttttct aaagacaaaa aagatcctcg atatgatcta caagtatgtt      1320
+     tgttgagtga tgcggtccaa tgcataataa cttcgaataa ggagaagctt ttcatgcgtt      1380
+     tccaatagga ttcttggcga atttttaaaa cttcctgata agacttttca ctatattcta      1440
+     acgacatttc ttgctgcaaa gataaaatcc ctttacccat gaaatccctc gtgatataac      1500
+     ctatccgtaa aatgtcctga ttagtgaaat aatcaggttg ttaacaggat agcacgctcg      1560
+     gtattttttt atataaacat gaaaactcgt tccgaaatag aaaatcgcat gcaagatatc      1620
+     gagtatgcgt tgttaggtaa agctctgata tttgaagact ctactgagta tattctgagg      1680
+     cagcttgcta attatgagtt taagtgttct catcataaaa acatattcat agtatttaaa      1740
+     cacttaaaag acaatggatt acctataact gtagactcgg cttgggaaga gcttttgcgg      1800
+     cgtcgtatca aagatatgga caaatcgtat ctcgggttaa tgttgcatga tgctttatca      1860
+     aatgacaagc ttagatccgt ttctcatacg gttttcctcg atgatttgag cgtgtgtagc      1920
+     gctgaagaaa atttgagtaa tttcattttc cgctcgttta atgagtacaa tgaaaatcca      1980
+     ttgcgtagat ctccgtttct attgcttgag cgtataaagg gaaggcttga tagtgctata      2040
+     gcaaagactt tttctattcg cagcgctaga ggccggtcta tttatgatat attctcacag      2100
+     tcagaaattg gagtgctggc tcgtataaaa aaaagacgag tagcgttctc tgagaatcaa      2160
+     aattctttct ttgatggctt cccaacagga tacaaggata ttgatgataa aggagttatc      2220
+     ttagctaaag gtaatttcgt gattatagca gctagaccat ctatagggaa aacagcttta      2280
+     gctatagaca tggcgataaa tcttgcggtt actcaacagc gtagagttgg tttcctatct      2340
+     ctagaaatga gcgcaggtca aattgttgag cggattattg ctaatttaac aggaatatct      2400
+     ggtgaaaaat tacaaagagg ggatctctct aaagaagaat tattccgagt agaagaagct      2460
+     ggagaaacgg ttagagaatc acatttttat atctgcagtg atagtcagta taagcttaac      2520
+     ttaatcgcga atcagatccg gttgctgaga aaagaagatc gagtagacgt aatatttatc      2580
+     gattacttgc agttgatcaa ctcatcggtt ggagaaaatc gtcaaaatga aatagcagat      2640
+     atatctagaa ccttaagagg tttagcctca gagctaaaca ttcctatagt ttgtttatcc      2700
+     caactatcta gaaaagttga ggatagagca aataaagttc ccatgctttc agatttgcga      2760
+     gacagcggtc aaatagagca agacgcagat gtgattttgt ttatcaatag gaaggaatcg      2820
+     tcttctaatt gtgagataac tgttgggaaa aatagacatg gatcggtttt ctcttcggta      2880
+     ttacatttcg atccaaaaat tagtaaattc tccgctatta aaaaagtatg gtaaattata      2940
+     gtaactgcca cttcatcaaa agtcctatcc accttgaaaa tcagaagttt ggaagaagac      3000
+     ctggtcaatc tattaagata tctcccaaat tggctcaaaa tgggatggta gaagttatag      3060
+     gtcttgattt tctttcatct cattaccatg cattagcagc tatccaaaga ttactgaccg      3120
+     caacgaatta caaggggaac acaaaagggg ttgttttatc cagagaatca aatagttttc      3180
+     aatttgaagg atggatacca agaatccgtt ttacaaaaac tgaattctta gaggcttatg      3240
+     gagttaagcg gtataaaaca tccagaaata agtatgagtt tagtggaaaa gaagctgaaa      3300
+     ctgctttaga agccttatac catttaggac atcaaccgtt tttaatagtg gcaactagaa      3360
+     ctcgatggac taatggaaca caaatagtag accgttacca aactctttct ccgatcatta      3420
+     ggatttacga aggatgggaa ggtttaactg acgaagaaaa tatagatata gacttaacac      3480
+     cttttaattc accacctaca cggaaacata aagggttcgt tgtagagcca tgtcctatct      3540
+     tggtagatca aatagaatcc tactttgtaa tcaagcctgc aaatgtatac caagaaataa      3600
+     aaatgcgttt cccaaatgca tcaaagtatg cttacacatt tatcgactgg gtgattacag      3660
+     cagctgcgaa aaagagacga aaattaacta aggataattc ttggccagaa aacttgttat      3720
+     taaacgttaa cgttaaaagt cttgcatata ttttaaggat gaatcggtac atctgtacaa      3780
+     ggaactggaa aaaaatcgag ttagctatcg ataaatgtat agaaatcgcc attcagcttg      3840
+     gctggttatc tagaagaaaa cgcattgaat ttctggattc ttctaaactc tctaaaaaag      3900
+     aaattctata tctaaataaa gagcgctttg aagaaataac taagaaatct aaagaacaaa      3960
+     tggaacaatt agaacaagaa tctattaatt aatagcaagc ttgaaactaa aaacctaatt      4020
+     tatttaaagc tcaaaataaa aaagagtttt aaaatgggaa attctggttt ttatttgtat      4080
+     aacactgaaa actgcgtctt tgctgataat atcaaagttg ggcaaatgac agagccgctc      4140
+     aaggaccagc aaataatcct tgggacaaca tcaacacctg tcgcagccaa aatgacagct      4200
+     tctgatggaa tatctttaac agtctccaat aattcatcaa ccaatgcttc tattacaatt      4260
+     ggtttggatg cggaaaaagc ttaccagctt attctagaaa agttgggaga tcaaattctt      4320
+     gatggaattg ctgatactat tgttgatagt acagtccaag atattttaga caaaatcaaa      4380
+     acagaccctt ctctaggttt gttgaaagct tttaacaact ttccaatcac taataaaatt      4440
+     caatgcaacg ggttattcac tcccagtaac attgaaactt tattaggagg aactgaaata      4500
+     ggaaaattca cagtcacacc caaaagctct gggagcatgt tcttagtctc agcagatatt      4560
+     attgcatcaa gaatggaagg cggcgttgtt ctagctttgg tacgagaagg tgattctaag      4620
+     ccctgcgcga ttagttatgg atactcatca ggcattccta atttatgtag tctaagaacc      4680
+     agtattacta atacaggatt gactccgaca acgtattcat tacgtgtagg cggtttagaa      4740
+     agcggtgtgg tatgggttaa tgccctttct aatggcaatg atattttagg aataacaaat      4800
+     acttctaatg tatctttttt agaggtaata cctcaaacaa acgcttaaac aatttttatt      4860
+     ggatttttct tataggtttt atatttagag aaaacagttc gaattacggg gtttgttatg      4920
+     caaaataaaa gaaaagtgag ggacgatttt attaaaattg ttaaagatgt gaaaaaagat      4980
+     ttccccgaat tagacctaaa aatacgagta aacaaggaaa aagtaacttt cttaaattct      5040
+     cccttagaac tctaccataa aagtgtctca ctaattctag gactgcttca acaaatagaa      5100
+     aactctttag gattattccc agactctcct gttcttgaaa aattagagga taacagttta      5160
+     aagctaaaaa aggctttgat tatgcttatc ttgtctagaa aagacatgtt ttccaaggct      5220
+     gaatagacaa cttactctaa cgttggagtt gatttgcaca ccttagtttt ttgctctttt      5280
+     aagggaggaa ctggaaaaac aacactttct ctaaacgtgg gatgcaactt ggcccaattt      5340
+     ttagggaaaa aagtgttact tgctgaccta gacccgcaat ccaatttatc ttctggattg      5400
+     ggggctagtg tcagaagtga ccaaaaaggc ttgcacgaca tagtatacac atcaaacgat      5460
+     ttaaaatcaa tcatttgcga aacaaaaaaa gatagtgtgg acctaattcc tgcatcattt      5520
+     tcatccgaac agtttagaga attggatatt catagaggac ctagtaacaa cttaaagtta      5580
+     tttctgaatg agtactgcgc tcctttttat gacatctgca taatagacac tccacctagc      5640
+     ctaggagggt taacgaaaga agcttttgtt gcaggagaca aattaattgc ttgtttaact      5700
+     ccagaacctt tttctattct agggttacaa aagatacgtg aattcttaag ttcggtcgga      5760
+     aaacctgaag aagaacacat tcttggaata gctttgtctt tttgggatga tcgtaactcg      5820
+     actaaccaaa tgtatataga cattatcgag tctatttaca aaaacaagct tttttcaaca      5880
+     aaaattcgtc gagatatttc tctcagccgt tctcttctta aagaagattc tgtagctaat      5940
+     gtctatccaa attctagggc cgcagaagat attctgaagt taacgcatga aatagcaaat      6000
+     attttgcata tcgaatatga acgagattac tctcagagga caacgtgaac aaactaaaaa      6060
+     aagaagcgga tgtctttttt aaaaaaaatc aaactgccgc ttctctagat tttaagaaga      6120
+     cgcttccctc cattgaacta ttctcagcaa ctttgaattc tgaggaaagt cagagtttgg      6180
+     atcgattatt tttatcagag tcccaaaact attcggatga agaattttat caagaagaca      6240
+     tcctagcggt aaaactgctt actggtcaga taaaatccat acagaagcaa cacgtacttc      6300
+     ttttaggaga aaaaatctat aatgctagaa aaatcctgag taaggatcac ttctcctcaa      6360
+     caactttttc atcttggata gagttagttt ttagaactaa gtcttctgct tacaatgctc      6420
+     ttgcatatta cgagcttttt ataaacctcc ccaaccaaac tctacaaaaa gagtttcaat      6480
+     cgatccccta taaatccgca tatattttgg ccgctagaaa aggcgattta aaaaccaagg      6540
+     tcgatgtgat agggaaagta tgtggaatgt cgaactcatc ggcgataagg gtgttggatc      6600
+     aatttcttcc ttcatctaga aacaaagacg ttagagaaac gatagataag tctgattcag      6660
+     agaagaatcg ccaattatct gatttcttaa tagagatact tcgcatcatg tgttccggag      6720
+     tttctttgtc ctcctataac gaaaatcttc tacaacagct ttttgaactt tttaagcaaa      6780
+     agagctgatc ctccgtcagc tcatatatat atatctatta tatatatata tttagggatt      6840
+     tgatttcacg agagagattt gcaactcttg gtggtagact ttgcaactct tggtggtaga      6900
+     ctttgcaact cttggtggta gactttgcaa ctcttggtgg tagacttggt cataatggac      6960
+     ttttgttaaa aaatttatta aaatcttaga gctccgattt tgaatagctt tggttaagaa      7020
+     aatgggctcg atggctttcc ataaaagtag attgttttta acttttgggg acgcgtcgga      7080
+     aatttggtta tctactttat cttatctaac tagaaaaaat tatgcgtctg ggattaactt      7140
+     tcttgtttct ttagagattc tggatttatc ggaaaccttg ataaaggcta tttctcttga      7200
+     ccacagcgaa tctttgttta aaatcaagtc tctagatgtt tttaatggaa aagttgtttc      7260
+     agaggcatct aaacaggcta gagcggcatg ctacatatct ttcacaaagt ttttgtatag      7320
+     attgaccaag ggatatatta aacccgctat tccattgaaa gattttggaa acactacatt      7380
+     ttttaaaatc cgagacaaaa tcaaaacaga atcgatttct aagcaggaat ggacagtttt      7440
+     ttttgaagcg ctccggatag tgaattatag agactattta atcggtaaat tgattgtaca      7500
+     ag                                                                     7502
+//
diff --git a/test/jalview/io/J03321.gb b/test/jalview/io/J03321.gb
new file mode 100644 (file)
index 0000000..99729e4
--- /dev/null
@@ -0,0 +1,258 @@
+LOCUS       CH1L1CG                 7502 bp    DNA     circular BCT 06-APR-2020
+DEFINITION  Chlamydia trachomatis plasmid pCHL1, complete sequence.
+ACCESSION   J03321
+VERSION     J03321.1
+DBLINK      BioSample: SAMN14225621
+KEYWORDS    .
+SOURCE      Chlamydia trachomatis
+  ORGANISM  Chlamydia trachomatis
+            Bacteria; Chlamydiae; Chlamydiales; Chlamydiaceae;
+            Chlamydia/Chlamydophila group; Chlamydia.
+REFERENCE   1  (bases 1 to 7502)
+  AUTHORS   Comanducci,M., Ricci,S., Cevenini,R. and Ratti,G.
+  TITLE     Diversity of the Chlamydia trachomatis common plasmid in biovars
+            with different pathogenicity
+  JOURNAL   Plasmid 23 (2), 149-154 (1990)
+   PUBMED   2194229
+REFERENCE   2  (bases 1 to 7502)
+  AUTHORS   Comanducci,M., Ricci,S., Cevenini,R. and Ratti,G.
+  TITLE     Direct Submission
+  JOURNAL   Submitted (23-JUN-2010) Sclavo Research Centre, Siena, Italy
+COMMENT     Draft entry and computer-readable sequence kindly submitted by
+            G.Ratti, 28-MAR-1990.
+            ! CDS location split below (and this line added), for Jalview test purposes !
+FEATURES             Location/Qualifiers
+     source          1..7502
+                     /organism="Chlamydia trachomatis"
+                     /mol_type="genomic DNA"
+                     /serotype="D"
+                     /isolate="G0/86"
+                     /isolation_source="trachoma"
+                     /db_xref="taxon:813"
+                     /plasmid="pCHL1"
+     CDS             join(7022..7502,
+                     1..437)
+                     /note="pGP7-D"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91567.1"
+                     /translation="MGSMAFHKSRLFLTFGDASEIWLSTLSYLTRKNYASGINFLVSL
+                     EILDLSETLIKAISLDHSESLFKIKSLDVFNGKVVSEASKQARAACYISFTKFLYRLT
+                     KGYIKPAIPLKDFGNTTFFKIRDKIKTESISKQEWTVFFEALRIVNYRDYLIGKLIVQ
+                     GIRKLDEILSLRTDDLFFASNQISFRIKKRQNKETKILITFPISLMEELQKYTCGRNG
+                     RVFVSKIGIPVTTSQVAHNFRLAEFHSAMKIKITPRVLRASALIHLKQIGLKDEEIMR
+                     ISCLSSRQSVCSYCSGEEVIPLVQTPTIL"
+     CDS             complement(488..1480)
+                     /note="pGP8-D"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91568.1"
+                     /translation="MGKGILSLQQEMSLEYSEKSYQEVLKIRQESYWKRMKSFSLFEV
+                     IMHWTASLNKHTCRSYRGSFLSLEKIGLLSLDMNLQEFSLLNHNLILDAIKKVSSAKT
+                     SWTEGTKQVRAASYISLTRFLNRMTQGIVAIAQPSKQENSRTFFKTREIVKTDAMNSL
+                     QTASFLKELKKINARDWLIAQTMLQGGKRSSEVLSLEISQICFQQATISFSQLKNRQT
+                     EKRIIITYPQKFMHFLQEYIGQRRGFVFVTRSGKMVGLRQIARTFSQAGLQAAIPFKI
+                     TPHVLRATAVTEYKRLGCSDSDIMKVTGHATAKMIFAYDKSSREDNASKKMALI"
+     CDS             1579..2934
+                     /note="pGP1-D"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91569.1"
+                     /translation="MKTRSEIENRMQDIEYALLGKALIFEDSTEYILRQLANYEFKCS
+                     HHKNIFIVFKHLKDNGLPITVDSAWEELLRRRIKDMDKSYLGLMLHDALSNDKLRSVS
+                     HTVFLDDLSVCSAEENLSNFIFRSFNEYNENPLRRSPFLLLERIKGRLDSAIAKTFSI
+                     RSARGRSIYDIFSQSEIGVLARIKKRRVAFSENQNSFFDGFPTGYKDIDDKGVILAKG
+                     NFVIIAARPSIGKTALAIDMAINLAVTQQRRVGFLSLEMSAGQIVERIIANLTGISGE
+                     KLQRGDLSKEELFRVEEAGETVRESHFYICSDSQYKLNLIANQIRLLRKEDRVDVIFI
+                     DYLQLINSSVGENRQNEIADISRTLRGLASELNIPIVCLSQLSRKVEDRANKVPMLSD
+                     LRDSGQIEQDADVILFINRKESSSNCEITVGKNRHGSVFSSVLHFDPKISKFSAIKKV
+                     W"
+     CDS             2928..3992
+                     /note="pGP2-D"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91570.1"
+                     /translation="MVNYSNCHFIKSPIHLENQKFGRRPGQSIKISPKLAQNGMVEVI
+                     GLDFLSSHYHALAAIQRLLTATNYKGNTKGVVLSRESNSFQFEGWIPRIRFTKTEFLE
+                     AYGVKRYKTSRNKYEFSGKEAETALEALYHLGHQPFLIVATRTRWTNGTQIVDRYQTL
+                     SPIIRIYEGWEGLTDEENIDIDLTPFNSPPTRKHKGFVVEPCPILVDQIESYFVIKPA
+                     NVYQEIKMRFPNASKYAYTFIDWVITAAAKKRRKLTKDNSWPENLLLNVNVKSLAYIL
+                     RMNRYICTRNWKKIELAIDKCIEIAIQLGWLSRRKRIEFLDSSKLSKKEILYLNKERF
+                     EEITKKSKEQMEQLEQESIN"
+     CDS             4054..4848
+                     /note="pGP3-D"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91571.1"
+                     /translation="MGNSGFYLYNTENCVFADNIKVGQMTEPLKDQQIILGTTSTPVA
+                     AKMTASDGISLTVSNNSSTNASITIGLDAEKAYQLILEKLGDQILDGIADTIVDSTVQ
+                     DILDKIKTDPSLGLLKAFNNFPITNKIQCNGLFTPSNIETLLGGTEIGKFTVTPKSSG
+                     SMFLVSADIIASRMEGGVVLALVREGDSKPCAISYGYSSGIPNLCSLRTSITNTGLTP
+                     TTYSLRVGGLESGVVWVNALSNGNDILGITNTSNVSFLEVIPQTNA"
+     CDS             4918..5226
+                     /note="pGP4-D"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91572.1"
+                     /translation="MQNKRKVRDDFIKIVKDVKKDFPELDLKIRVNKEKVTFLNSPLE
+                     LYHKSVSLILGLLQQIENSLGLFPDSPVLEKLEDNSLKLKKALIMLILSRKDMFSKAE
+                     "
+     CDS             5317..6048
+                     /note="pGP5-D (gtg start codon)"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91573.1"
+                     /translation="MGCNLAQFLGKKVLLADLDPQSNLSSGLGASVRSDQKGLHDIVY
+                     TSNDLKSIICETKKDSVDLIPASFSSEQFRELDIHRGPSNNLKLFLNEYCAPFYDICI
+                     IDTPPSLGGLTKEAFVAGDKLIACLTPEPFSILGLQKIREFLSSVGKPEEEHILGIAL
+                     SFWDDRNSTNQMYIDIIESIYKNKLFSTKIRRDISLSRSLLKEDSVANVYPNSRAAED
+                     ILKLTHEIANILHIEYERDYSQRTT"
+     CDS             6045..6788
+                     /note="pGP6-D (gtg start codon)"
+                     /codon_start=1
+                     /transl_table=11
+                     /product="hypothetical protein"
+                     /protein_id="AAA91574.1"
+                     /translation="MNKLKKEADVFFKKNQTAASLDFKKTLPSIELFSATLNSEESQS
+                     LDRLFLSESQNYSDEEFYQEDILAVKLLTGQIKSIQKQHVLLLGEKIYNARKILSKDH
+                     FSSTTFSSWIELVFRTKSSAYNALAYYELFINLPNQTLQKEFQSIPYKSAYILAARKG
+                     DLKTKVDVIGKVCGMSNSSAIRVLDQFLPSSRNKDVRETIDKSDSEKNRQLSDFLIEI
+                     LRIMCSGVSLSSYNENLLQQLFELFKQKS"
+     repeat_region   6857..6945
+                     /note="four tandem 22bp repeats"
+ORIGIN      
+        1 ggatccgtaa gttagacgaa attttgtctt tgcgcacaga cgatctattt tttgcatcca
+       61 atcagatttc ctttcgcatt aaaaaaagac agaataaaga aaccaaaatt ctaatcacat
+      121 ttcctatcag cttaatggaa gagttgcaaa aatacacttg tgggagaaat gggagagtat
+      181 ttgtttctaa aatagggatt cctgtaacaa caagtcaggt tgcgcataat tttaggcttg
+      241 cagagttcca tagtgctatg aaaataaaaa ttactcccag agtacttcgt gcaagcgctt
+      301 tgattcattt aaagcaaata ggattaaaag atgaggaaat catgcgtatt tcctgtcttt
+      361 catcgagaca aagtgtgtgt tcttattgtt ctggggaaga ggtaattcct ctagtacaaa
+      421 cacccacaat attgtgatat aattaaaatt atattcatat tctgttgcca gaaaaaacac
+      481 ctttaggcta tattagagcc atcttctttg aagcgttgtc ttctcgagaa gatttatcgt
+      541 acgcaaatat catctttgcg gttgcgtgtc ctgtgacctt cattatgtcg gagtctgagc
+      601 accctaggcg tttgtactcc gtcacagcgg ttgctcgaag cacgtgcggg gttattttaa
+      661 aagggattgc agcttgtagt cctgcttgag agaacgtgcg ggcgatttgc cttaacccca
+      721 ccatttttcc ggagcgagtt acgaagacaa aacctcttcg ttgaccgatg tactcttgta
+      781 gaaagtgcat aaacttctga ggataagtta taataatcct cttttctgtc tgacggttct
+      841 taagctggga gaaagaaatg gtagcttgtt ggaaacaaat ctgactaatc tccaagctta
+      901 agacttcaga ggagcgttta cctccttgga gcattgtctg ggcgatcaac caatcccggg
+      961 cattgatttt ttttagctct tttaggaagg atgctgtttg caaactgttc atcgcatccg
+     1021 tttttactat ttccctggtt ttaaaaaatg ttcgactatt ttcttgttta gaaggttgcg
+     1081 ctatagcgac tattccttga gtcatcctgt ttaggaatct tgttaaggaa atatagcttg
+     1141 ctgctcgaac ttgtttagta ccttcggtcc aagaagtctt ggcagaggaa acttttttaa
+     1201 tcgcatctag gattagatta tgatttaaaa gggaaaactc ttgcagattc atatccaagg
+     1261 acaatagacc aatcttttct aaagacaaaa aagatcctcg atatgatcta caagtatgtt
+     1321 tgttgagtga tgcggtccaa tgcataataa cttcgaataa ggagaagctt ttcatgcgtt
+     1381 tccaatagga ttcttggcga atttttaaaa cttcctgata agacttttca ctatattcta
+     1441 acgacatttc ttgctgcaaa gataaaatcc ctttacccat gaaatccctc gtgatataac
+     1501 ctatccgtaa aatgtcctga ttagtgaaat aatcaggttg ttaacaggat agcacgctcg
+     1561 gtattttttt atataaacat gaaaactcgt tccgaaatag aaaatcgcat gcaagatatc
+     1621 gagtatgcgt tgttaggtaa agctctgata tttgaagact ctactgagta tattctgagg
+     1681 cagcttgcta attatgagtt taagtgttct catcataaaa acatattcat agtatttaaa
+     1741 cacttaaaag acaatggatt acctataact gtagactcgg cttgggaaga gcttttgcgg
+     1801 cgtcgtatca aagatatgga caaatcgtat ctcgggttaa tgttgcatga tgctttatca
+     1861 aatgacaagc ttagatccgt ttctcatacg gttttcctcg atgatttgag cgtgtgtagc
+     1921 gctgaagaaa atttgagtaa tttcattttc cgctcgttta atgagtacaa tgaaaatcca
+     1981 ttgcgtagat ctccgtttct attgcttgag cgtataaagg gaaggcttga tagtgctata
+     2041 gcaaagactt tttctattcg cagcgctaga ggccggtcta tttatgatat attctcacag
+     2101 tcagaaattg gagtgctggc tcgtataaaa aaaagacgag tagcgttctc tgagaatcaa
+     2161 aattctttct ttgatggctt cccaacagga tacaaggata ttgatgataa aggagttatc
+     2221 ttagctaaag gtaatttcgt gattatagca gctagaccat ctatagggaa aacagcttta
+     2281 gctatagaca tggcgataaa tcttgcggtt actcaacagc gtagagttgg tttcctatct
+     2341 ctagaaatga gcgcaggtca aattgttgag cggattattg ctaatttaac aggaatatct
+     2401 ggtgaaaaat tacaaagagg ggatctctct aaagaagaat tattccgagt agaagaagct
+     2461 ggagaaacgg ttagagaatc acatttttat atctgcagtg atagtcagta taagcttaac
+     2521 ttaatcgcga atcagatccg gttgctgaga aaagaagatc gagtagacgt aatatttatc
+     2581 gattacttgc agttgatcaa ctcatcggtt ggagaaaatc gtcaaaatga aatagcagat
+     2641 atatctagaa ccttaagagg tttagcctca gagctaaaca ttcctatagt ttgtttatcc
+     2701 caactatcta gaaaagttga ggatagagca aataaagttc ccatgctttc agatttgcga
+     2761 gacagcggtc aaatagagca agacgcagat gtgattttgt ttatcaatag gaaggaatcg
+     2821 tcttctaatt gtgagataac tgttgggaaa aatagacatg gatcggtttt ctcttcggta
+     2881 ttacatttcg atccaaaaat tagtaaattc tccgctatta aaaaagtatg gtaaattata
+     2941 gtaactgcca cttcatcaaa agtcctatcc accttgaaaa tcagaagttt ggaagaagac
+     3001 ctggtcaatc tattaagata tctcccaaat tggctcaaaa tgggatggta gaagttatag
+     3061 gtcttgattt tctttcatct cattaccatg cattagcagc tatccaaaga ttactgaccg
+     3121 caacgaatta caaggggaac acaaaagggg ttgttttatc cagagaatca aatagttttc
+     3181 aatttgaagg atggatacca agaatccgtt ttacaaaaac tgaattctta gaggcttatg
+     3241 gagttaagcg gtataaaaca tccagaaata agtatgagtt tagtggaaaa gaagctgaaa
+     3301 ctgctttaga agccttatac catttaggac atcaaccgtt tttaatagtg gcaactagaa
+     3361 ctcgatggac taatggaaca caaatagtag accgttacca aactctttct ccgatcatta
+     3421 ggatttacga aggatgggaa ggtttaactg acgaagaaaa tatagatata gacttaacac
+     3481 cttttaattc accacctaca cggaaacata aagggttcgt tgtagagcca tgtcctatct
+     3541 tggtagatca aatagaatcc tactttgtaa tcaagcctgc aaatgtatac caagaaataa
+     3601 aaatgcgttt cccaaatgca tcaaagtatg cttacacatt tatcgactgg gtgattacag
+     3661 cagctgcgaa aaagagacga aaattaacta aggataattc ttggccagaa aacttgttat
+     3721 taaacgttaa cgttaaaagt cttgcatata ttttaaggat gaatcggtac atctgtacaa
+     3781 ggaactggaa aaaaatcgag ttagctatcg ataaatgtat agaaatcgcc attcagcttg
+     3841 gctggttatc tagaagaaaa cgcattgaat ttctggattc ttctaaactc tctaaaaaag
+     3901 aaattctata tctaaataaa gagcgctttg aagaaataac taagaaatct aaagaacaaa
+     3961 tggaacaatt agaacaagaa tctattaatt aatagcaagc ttgaaactaa aaacctaatt
+     4021 tatttaaagc tcaaaataaa aaagagtttt aaaatgggaa attctggttt ttatttgtat
+     4081 aacactgaaa actgcgtctt tgctgataat atcaaagttg ggcaaatgac agagccgctc
+     4141 aaggaccagc aaataatcct tgggacaaca tcaacacctg tcgcagccaa aatgacagct
+     4201 tctgatggaa tatctttaac agtctccaat aattcatcaa ccaatgcttc tattacaatt
+     4261 ggtttggatg cggaaaaagc ttaccagctt attctagaaa agttgggaga tcaaattctt
+     4321 gatggaattg ctgatactat tgttgatagt acagtccaag atattttaga caaaatcaaa
+     4381 acagaccctt ctctaggttt gttgaaagct tttaacaact ttccaatcac taataaaatt
+     4441 caatgcaacg ggttattcac tcccagtaac attgaaactt tattaggagg aactgaaata
+     4501 ggaaaattca cagtcacacc caaaagctct gggagcatgt tcttagtctc agcagatatt
+     4561 attgcatcaa gaatggaagg cggcgttgtt ctagctttgg tacgagaagg tgattctaag
+     4621 ccctgcgcga ttagttatgg atactcatca ggcattccta atttatgtag tctaagaacc
+     4681 agtattacta atacaggatt gactccgaca acgtattcat tacgtgtagg cggtttagaa
+     4741 agcggtgtgg tatgggttaa tgccctttct aatggcaatg atattttagg aataacaaat
+     4801 acttctaatg tatctttttt agaggtaata cctcaaacaa acgcttaaac aatttttatt
+     4861 ggatttttct tataggtttt atatttagag aaaacagttc gaattacggg gtttgttatg
+     4921 caaaataaaa gaaaagtgag ggacgatttt attaaaattg ttaaagatgt gaaaaaagat
+     4981 ttccccgaat tagacctaaa aatacgagta aacaaggaaa aagtaacttt cttaaattct
+     5041 cccttagaac tctaccataa aagtgtctca ctaattctag gactgcttca acaaatagaa
+     5101 aactctttag gattattccc agactctcct gttcttgaaa aattagagga taacagttta
+     5161 aagctaaaaa aggctttgat tatgcttatc ttgtctagaa aagacatgtt ttccaaggct
+     5221 gaatagacaa cttactctaa cgttggagtt gatttgcaca ccttagtttt ttgctctttt
+     5281 aagggaggaa ctggaaaaac aacactttct ctaaacgtgg gatgcaactt ggcccaattt
+     5341 ttagggaaaa aagtgttact tgctgaccta gacccgcaat ccaatttatc ttctggattg
+     5401 ggggctagtg tcagaagtga ccaaaaaggc ttgcacgaca tagtatacac atcaaacgat
+     5461 ttaaaatcaa tcatttgcga aacaaaaaaa gatagtgtgg acctaattcc tgcatcattt
+     5521 tcatccgaac agtttagaga attggatatt catagaggac ctagtaacaa cttaaagtta
+     5581 tttctgaatg agtactgcgc tcctttttat gacatctgca taatagacac tccacctagc
+     5641 ctaggagggt taacgaaaga agcttttgtt gcaggagaca aattaattgc ttgtttaact
+     5701 ccagaacctt tttctattct agggttacaa aagatacgtg aattcttaag ttcggtcgga
+     5761 aaacctgaag aagaacacat tcttggaata gctttgtctt tttgggatga tcgtaactcg
+     5821 actaaccaaa tgtatataga cattatcgag tctatttaca aaaacaagct tttttcaaca
+     5881 aaaattcgtc gagatatttc tctcagccgt tctcttctta aagaagattc tgtagctaat
+     5941 gtctatccaa attctagggc cgcagaagat attctgaagt taacgcatga aatagcaaat
+     6001 attttgcata tcgaatatga acgagattac tctcagagga caacgtgaac aaactaaaaa
+     6061 aagaagcgga tgtctttttt aaaaaaaatc aaactgccgc ttctctagat tttaagaaga
+     6121 cgcttccctc cattgaacta ttctcagcaa ctttgaattc tgaggaaagt cagagtttgg
+     6181 atcgattatt tttatcagag tcccaaaact attcggatga agaattttat caagaagaca
+     6241 tcctagcggt aaaactgctt actggtcaga taaaatccat acagaagcaa cacgtacttc
+     6301 ttttaggaga aaaaatctat aatgctagaa aaatcctgag taaggatcac ttctcctcaa
+     6361 caactttttc atcttggata gagttagttt ttagaactaa gtcttctgct tacaatgctc
+     6421 ttgcatatta cgagcttttt ataaacctcc ccaaccaaac tctacaaaaa gagtttcaat
+     6481 cgatccccta taaatccgca tatattttgg ccgctagaaa aggcgattta aaaaccaagg
+     6541 tcgatgtgat agggaaagta tgtggaatgt cgaactcatc ggcgataagg gtgttggatc
+     6601 aatttcttcc ttcatctaga aacaaagacg ttagagaaac gatagataag tctgattcag
+     6661 agaagaatcg ccaattatct gatttcttaa tagagatact tcgcatcatg tgttccggag
+     6721 tttctttgtc ctcctataac gaaaatcttc tacaacagct ttttgaactt tttaagcaaa
+     6781 agagctgatc ctccgtcagc tcatatatat atatctatta tatatatata tttagggatt
+     6841 tgatttcacg agagagattt gcaactcttg gtggtagact ttgcaactct tggtggtaga
+     6901 ctttgcaact cttggtggta gactttgcaa ctcttggtgg tagacttggt cataatggac
+     6961 ttttgttaaa aaatttatta aaatcttaga gctccgattt tgaatagctt tggttaagaa
+     7021 aatgggctcg atggctttcc ataaaagtag attgttttta acttttgggg acgcgtcgga
+     7081 aatttggtta tctactttat cttatctaac tagaaaaaat tatgcgtctg ggattaactt
+     7141 tcttgtttct ttagagattc tggatttatc ggaaaccttg ataaaggcta tttctcttga
+     7201 ccacagcgaa tctttgttta aaatcaagtc tctagatgtt tttaatggaa aagttgtttc
+     7261 agaggcatct aaacaggcta gagcggcatg ctacatatct ttcacaaagt ttttgtatag
+     7321 attgaccaag ggatatatta aacccgctat tccattgaaa gattttggaa acactacatt
+     7381 ttttaaaatc cgagacaaaa tcaaaacaga atcgatttct aagcaggaat ggacagtttt
+     7441 ttttgaagcg ctccggatag tgaattatag agactattta atcggtaaat tgattgtaca
+     7501 ag
+//
+
diff --git a/test/jalview/io/J03321_rna.embl.txt b/test/jalview/io/J03321_rna.embl.txt
new file mode 100644 (file)
index 0000000..84b9b69
--- /dev/null
@@ -0,0 +1,306 @@
+ID   J03321; SV 1; circular; genomic DNA; STD; PRO; 7502 BP.
+XX
+AC   J03321;
+XX
+DT   27-JUL-1990 (Rel. 24, Created)
+DT   10-APR-2020 (Rel. 144, Last updated, Version 9)
+XX
+DE   Chlamydia trachomatis plasmid pCHL1, complete sequence.
+XX
+KW   .
+XX
+OS   Chlamydia trachomatis
+OC   Bacteria; Chlamydiae; Chlamydiales; Chlamydiaceae;
+OC   Chlamydia/Chlamydophila group; Chlamydia.
+OG   Plasmid pCHL1
+XX
+RN   [1]
+RP   1-7502
+RX   DOI; 10.1016/0147-619X(90)90034-A.
+RX   PUBMED; 2194229.
+RA   Comanducci M., Ricci S., Cevenini R., Ratti G.;
+RT   "Diversity of the Chlamydia trachomatis common plasmid in biovars with
+RT   different pathogenicity";
+RL   Plasmid 23(2):149-154(1990).
+XX
+RN   [2]
+RP   1-7502
+RA   Comanducci M., Ricci S., Cevenini R., Ratti G.;
+RT   ;
+RL   Submitted (23-JUN-2010) to the INSDC.
+RL   Sclavo Research Centre, Siena, Italy
+XX
+DR   MD5; d4c4942a634e3df4995fd5ac75c26a61.
+DR   BioSample; SAMN14225621.
+DR   EuropePMC; PMC4450983; 26031715.
+DR   EuropePMC; PMC87941; 11283058.
+XX
+CC   Draft entry and computer-readable sequence kindly submitted by
+CC   G.Ratti, 28-MAR-1990.
+XX
+FH   Key             Location/Qualifiers
+FH
+FT   source          1..7502
+FT                   /organism="Chlamydia trachomatis"
+FT                   /plasmid="pCHL1"
+FT                   /isolate="G0/86"
+FT                   /serotype="D"
+FT                   /mol_type="genomic RNA"
+FT                   /isolation_source="trachoma"
+FT                   /db_xref="taxon:813"
+XX   next line artificially split for test purposes!
+FT   CDS             join(7022..7502,
+FT                   1..437)
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP7-D"
+FT                   /db_xref="GOA:P0CE19"
+FT                   /db_xref="InterPro:IPR002104"
+FT                   /db_xref="InterPro:IPR011010"
+FT                   /db_xref="InterPro:IPR013762"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE19"
+FT                   /protein_id="AAA91567.1"
+FT                   /translation="MGSMAFHKSRLFLTFGDASEIWLSTLSYLTRKNYASGINFLVSLE
+FT                   ILDLSETLIKAISLDHSESLFKIKSLDVFNGKVVSEASKQARAACYISFTKFLYRLTKG
+FT                   YIKPAIPLKDFGNTTFFKIRDKIKTESISKQEWTVFFEALRIVNYRDYLIGKLIVQGIR
+FT                   KLDEILSLRTDDLFFASNQISFRIKKRQNKETKILITFPISLMEELQKYTCGRNGRVFV
+FT                   SKIGIPVTTSQVAHNFRLAEFHSAMKIKITPRVLRASALIHLKQIGLKDEEIMRISCLS
+FT                   SRQSVCSYCSGEEVIPLVQTPTIL"
+FT   CDS             complement(488..1480)
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP8-D"
+FT                   /db_xref="GOA:P0CE20"
+FT                   /db_xref="InterPro:IPR002104"
+FT                   /db_xref="InterPro:IPR011010"
+FT                   /db_xref="InterPro:IPR013762"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE20"
+FT                   /protein_id="AAA91568.1"
+FT                   /translation="MGKGILSLQQEMSLEYSEKSYQEVLKIRQESYWKRMKSFSLFEVI
+FT                   MHWTASLNKHTCRSYRGSFLSLEKIGLLSLDMNLQEFSLLNHNLILDAIKKVSSAKTSW
+FT                   TEGTKQVRAASYISLTRFLNRMTQGIVAIAQPSKQENSRTFFKTREIVKTDAMNSLQTA
+FT                   SFLKELKKINARDWLIAQTMLQGGKRSSEVLSLEISQICFQQATISFSQLKNRQTEKRI
+FT                   IITYPQKFMHFLQEYIGQRRGFVFVTRSGKMVGLRQIARTFSQAGLQAAIPFKITPHVL
+FT                   RATAVTEYKRLGCSDSDIMKVTGHATAKMIFAYDKSSREDNASKKMALI"
+FT   CDS             1579..2934
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP1-D"
+FT                   /db_xref="GOA:P0CE16"
+FT                   /db_xref="InterPro:IPR003593"
+FT                   /db_xref="InterPro:IPR007693"
+FT                   /db_xref="InterPro:IPR007694"
+FT                   /db_xref="InterPro:IPR027417"
+FT                   /db_xref="InterPro:IPR036185"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE16"
+FT                   /protein_id="AAA91569.1"
+FT                   /translation="MKTRSEIENRMQDIEYALLGKALIFEDSTEYILRQLANYEFKCSH
+FT                   HKNIFIVFKHLKDNGLPITVDSAWEELLRRRIKDMDKSYLGLMLHDALSNDKLRSVSHT
+FT                   VFLDDLSVCSAEENLSNFIFRSFNEYNENPLRRSPFLLLERIKGRLDSAIAKTFSIRSA
+FT                   RGRSIYDIFSQSEIGVLARIKKRRVAFSENQNSFFDGFPTGYKDIDDKGVILAKGNFVI
+FT                   IAARPSIGKTALAIDMAINLAVTQQRRVGFLSLEMSAGQIVERIIANLTGISGEKLQRG
+FT                   DLSKEELFRVEEAGETVRESHFYICSDSQYKLNLIANQIRLLRKEDRVDVIFIDYLQLI
+FT                   NSSVGENRQNEIADISRTLRGLASELNIPIVCLSQLSRKVEDRANKVPMLSDLRDSGQI
+FT                   EQDADVILFINRKESSSNCEITVGKNRHGSVFSSVLHFDPKISKFSAIKKVW"
+FT   CDS             2928..3992
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP2-D"
+FT                   /db_xref="InterPro:IPR040719"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE17"
+FT                   /protein_id="AAA91570.1"
+FT                   /translation="MVNYSNCHFIKSPIHLENQKFGRRPGQSIKISPKLAQNGMVEVIG
+FT                   LDFLSSHYHALAAIQRLLTATNYKGNTKGVVLSRESNSFQFEGWIPRIRFTKTEFLEAY
+FT                   GVKRYKTSRNKYEFSGKEAETALEALYHLGHQPFLIVATRTRWTNGTQIVDRYQTLSPI
+FT                   IRIYEGWEGLTDEENIDIDLTPFNSPPTRKHKGFVVEPCPILVDQIESYFVIKPANVYQ
+FT                   EIKMRFPNASKYAYTFIDWVITAAAKKRRKLTKDNSWPENLLLNVNVKSLAYILRMNRY
+FT                   ICTRNWKKIELAIDKCIEIAIQLGWLSRRKRIEFLDSSKLSKKEILYLNKERFEEITKK
+FT                   SKEQMEQLEQESIN"
+FT   CDS             4054..4848
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP3-D"
+FT                   /db_xref="InterPro:IPR008444"
+FT                   /db_xref="InterPro:IPR033758"
+FT                   /db_xref="InterPro:IPR038264"
+FT                   /db_xref="PDB:6GJT"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE18"
+FT                   /protein_id="AAA91571.1"
+FT                   /translation="MGNSGFYLYNTENCVFADNIKVGQMTEPLKDQQIILGTTSTPVAA
+FT                   KMTASDGISLTVSNNSSTNASITIGLDAEKAYQLILEKLGDQILDGIADTIVDSTVQDI
+FT                   LDKIKTDPSLGLLKAFNNFPITNKIQCNGLFTPSNIETLLGGTEIGKFTVTPKSSGSMF
+FT                   LVSADIIASRMEGGVVLALVREGDSKPCAISYGYSSGIPNLCSLRTSITNTGLTPTTYS
+FT                   LRVGGLESGVVWVNALSNGNDILGITNTSNVSFLEVIPQTNA"
+FT   CDS             4918..5226
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP4-D"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P0CE23"
+FT                   /protein_id="AAA91572.1"
+FT                   /translation="MQNKRKVRDDFIKIVKDVKKDFPELDLKIRVNKEKVTFLNSPLEL
+FT                   YHKSVSLILGLLQQIENSLGLFPDSPVLEKLEDNSLKLKKALIMLILSRKDMFSKAE"
+FT   CDS             5317..6048
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP5-D (gtg start codon)"
+FT                   /db_xref="GOA:P10559"
+FT                   /db_xref="InterPro:IPR025669"
+FT                   /db_xref="InterPro:IPR027417"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P10559"
+FT                   /protein_id="AAA91573.1"
+FT                   /translation="MGCNLAQFLGKKVLLADLDPQSNLSSGLGASVRSDQKGLHDIVYT
+FT                   SNDLKSIICETKKDSVDLIPASFSSEQFRELDIHRGPSNNLKLFLNEYCAPFYDICIID
+FT                   TPPSLGGLTKEAFVAGDKLIACLTPEPFSILGLQKIREFLSSVGKPEEEHILGIALSFW
+FT                   DDRNSTNQMYIDIIESIYKNKLFSTKIRRDISLSRSLLKEDSVANVYPNSRAAEDILKL
+FT                   THEIANILHIEYERDYSQRTT"
+FT   CDS             6045..6788
+FT                   /codon_start=1
+FT                   /transl_table=11
+FT                   /product="hypothetical protein"
+FT                   /note="pGP6-D (gtg start codon)"
+FT                   /db_xref="InterPro:IPR005350"
+FT                   /db_xref="UniProtKB/Swiss-Prot:P10560"
+FT                   /protein_id="AAA91574.1"
+FT                   /translation="MNKLKKEADVFFKKNQTAASLDFKKTLPSIELFSATLNSEESQSL
+FT                   DRLFLSESQNYSDEEFYQEDILAVKLLTGQIKSIQKQHVLLLGEKIYNARKILSKDHFS
+FT                   STTFSSWIELVFRTKSSAYNALAYYELFINLPNQTLQKEFQSIPYKSAYILAARKGDLK
+FT                   TKVDVIGKVCGMSNSSAIRVLDQFLPSSRNKDVRETIDKSDSEKNRQLSDFLIEILRIM
+FT                   CSGVSLSSYNENLLQQLFELFKQKS"
+FT   repeat_region   6857..6945
+FT                   /note="four tandem 22bp repeats"
+XX
+SQ   Sequence 7502 BP; 2460 A; 1285 C; 1433 G; 2324 T; 0 other;
+     ggatccgtaa gttagacgaa attttgtctt tgcgcacaga cgatctattt tttgcatcca        60
+     atcagatttc ctttcgcatt aaaaaaagac agaataaaga aaccaaaatt ctaatcacat       120
+     ttcctatcag cttaatggaa gagttgcaaa aatacacttg tgggagaaat gggagagtat       180
+     ttgtttctaa aatagggatt cctgtaacaa caagtcaggt tgcgcataat tttaggcttg       240
+     cagagttcca tagtgctatg aaaataaaaa ttactcccag agtacttcgt gcaagcgctt       300
+     tgattcattt aaagcaaata ggattaaaag atgaggaaat catgcgtatt tcctgtcttt       360
+     catcgagaca aagtgtgtgt tcttattgtt ctggggaaga ggtaattcct ctagtacaaa       420
+     cacccacaat attgtgatat aattaaaatt atattcatat tctgttgcca gaaaaaacac       480
+     ctttaggcta tattagagcc atcttctttg aagcgttgtc ttctcgagaa gatttatcgt       540
+     acgcaaatat catctttgcg gttgcgtgtc ctgtgacctt cattatgtcg gagtctgagc       600
+     accctaggcg tttgtactcc gtcacagcgg ttgctcgaag cacgtgcggg gttattttaa       660
+     aagggattgc agcttgtagt cctgcttgag agaacgtgcg ggcgatttgc cttaacccca       720
+     ccatttttcc ggagcgagtt acgaagacaa aacctcttcg ttgaccgatg tactcttgta       780
+     gaaagtgcat aaacttctga ggataagtta taataatcct cttttctgtc tgacggttct       840
+     taagctggga gaaagaaatg gtagcttgtt ggaaacaaat ctgactaatc tccaagctta       900
+     agacttcaga ggagcgttta cctccttgga gcattgtctg ggcgatcaac caatcccggg       960
+     cattgatttt ttttagctct tttaggaagg atgctgtttg caaactgttc atcgcatccg      1020
+     tttttactat ttccctggtt ttaaaaaatg ttcgactatt ttcttgttta gaaggttgcg      1080
+     ctatagcgac tattccttga gtcatcctgt ttaggaatct tgttaaggaa atatagcttg      1140
+     ctgctcgaac ttgtttagta ccttcggtcc aagaagtctt ggcagaggaa acttttttaa      1200
+     tcgcatctag gattagatta tgatttaaaa gggaaaactc ttgcagattc atatccaagg      1260
+     acaatagacc aatcttttct aaagacaaaa aagatcctcg atatgatcta caagtatgtt      1320
+     tgttgagtga tgcggtccaa tgcataataa cttcgaataa ggagaagctt ttcatgcgtt      1380
+     tccaatagga ttcttggcga atttttaaaa cttcctgata agacttttca ctatattcta      1440
+     acgacatttc ttgctgcaaa gataaaatcc ctttacccat gaaatccctc gtgatataac      1500
+     ctatccgtaa aatgtcctga ttagtgaaat aatcaggttg ttaacaggat agcacgctcg      1560
+     gtattttttt atataaacat gaaaactcgt tccgaaatag aaaatcgcat gcaagatatc      1620
+     gagtatgcgt tgttaggtaa agctctgata tttgaagact ctactgagta tattctgagg      1680
+     cagcttgcta attatgagtt taagtgttct catcataaaa acatattcat agtatttaaa      1740
+     cacttaaaag acaatggatt acctataact gtagactcgg cttgggaaga gcttttgcgg      1800
+     cgtcgtatca aagatatgga caaatcgtat ctcgggttaa tgttgcatga tgctttatca      1860
+     aatgacaagc ttagatccgt ttctcatacg gttttcctcg atgatttgag cgtgtgtagc      1920
+     gctgaagaaa atttgagtaa tttcattttc cgctcgttta atgagtacaa tgaaaatcca      1980
+     ttgcgtagat ctccgtttct attgcttgag cgtataaagg gaaggcttga tagtgctata      2040
+     gcaaagactt tttctattcg cagcgctaga ggccggtcta tttatgatat attctcacag      2100
+     tcagaaattg gagtgctggc tcgtataaaa aaaagacgag tagcgttctc tgagaatcaa      2160
+     aattctttct ttgatggctt cccaacagga tacaaggata ttgatgataa aggagttatc      2220
+     ttagctaaag gtaatttcgt gattatagca gctagaccat ctatagggaa aacagcttta      2280
+     gctatagaca tggcgataaa tcttgcggtt actcaacagc gtagagttgg tttcctatct      2340
+     ctagaaatga gcgcaggtca aattgttgag cggattattg ctaatttaac aggaatatct      2400
+     ggtgaaaaat tacaaagagg ggatctctct aaagaagaat tattccgagt agaagaagct      2460
+     ggagaaacgg ttagagaatc acatttttat atctgcagtg atagtcagta taagcttaac      2520
+     ttaatcgcga atcagatccg gttgctgaga aaagaagatc gagtagacgt aatatttatc      2580
+     gattacttgc agttgatcaa ctcatcggtt ggagaaaatc gtcaaaatga aatagcagat      2640
+     atatctagaa ccttaagagg tttagcctca gagctaaaca ttcctatagt ttgtttatcc      2700
+     caactatcta gaaaagttga ggatagagca aataaagttc ccatgctttc agatttgcga      2760
+     gacagcggtc aaatagagca agacgcagat gtgattttgt ttatcaatag gaaggaatcg      2820
+     tcttctaatt gtgagataac tgttgggaaa aatagacatg gatcggtttt ctcttcggta      2880
+     ttacatttcg atccaaaaat tagtaaattc tccgctatta aaaaagtatg gtaaattata      2940
+     gtaactgcca cttcatcaaa agtcctatcc accttgaaaa tcagaagttt ggaagaagac      3000
+     ctggtcaatc tattaagata tctcccaaat tggctcaaaa tgggatggta gaagttatag      3060
+     gtcttgattt tctttcatct cattaccatg cattagcagc tatccaaaga ttactgaccg      3120
+     caacgaatta caaggggaac acaaaagggg ttgttttatc cagagaatca aatagttttc      3180
+     aatttgaagg atggatacca agaatccgtt ttacaaaaac tgaattctta gaggcttatg      3240
+     gagttaagcg gtataaaaca tccagaaata agtatgagtt tagtggaaaa gaagctgaaa      3300
+     ctgctttaga agccttatac catttaggac atcaaccgtt tttaatagtg gcaactagaa      3360
+     ctcgatggac taatggaaca caaatagtag accgttacca aactctttct ccgatcatta      3420
+     ggatttacga aggatgggaa ggtttaactg acgaagaaaa tatagatata gacttaacac      3480
+     cttttaattc accacctaca cggaaacata aagggttcgt tgtagagcca tgtcctatct      3540
+     tggtagatca aatagaatcc tactttgtaa tcaagcctgc aaatgtatac caagaaataa      3600
+     aaatgcgttt cccaaatgca tcaaagtatg cttacacatt tatcgactgg gtgattacag      3660
+     cagctgcgaa aaagagacga aaattaacta aggataattc ttggccagaa aacttgttat      3720
+     taaacgttaa cgttaaaagt cttgcatata ttttaaggat gaatcggtac atctgtacaa      3780
+     ggaactggaa aaaaatcgag ttagctatcg ataaatgtat agaaatcgcc attcagcttg      3840
+     gctggttatc tagaagaaaa cgcattgaat ttctggattc ttctaaactc tctaaaaaag      3900
+     aaattctata tctaaataaa gagcgctttg aagaaataac taagaaatct aaagaacaaa      3960
+     tggaacaatt agaacaagaa tctattaatt aatagcaagc ttgaaactaa aaacctaatt      4020
+     tatttaaagc tcaaaataaa aaagagtttt aaaatgggaa attctggttt ttatttgtat      4080
+     aacactgaaa actgcgtctt tgctgataat atcaaagttg ggcaaatgac agagccgctc      4140
+     aaggaccagc aaataatcct tgggacaaca tcaacacctg tcgcagccaa aatgacagct      4200
+     tctgatggaa tatctttaac agtctccaat aattcatcaa ccaatgcttc tattacaatt      4260
+     ggtttggatg cggaaaaagc ttaccagctt attctagaaa agttgggaga tcaaattctt      4320
+     gatggaattg ctgatactat tgttgatagt acagtccaag atattttaga caaaatcaaa      4380
+     acagaccctt ctctaggttt gttgaaagct tttaacaact ttccaatcac taataaaatt      4440
+     caatgcaacg ggttattcac tcccagtaac attgaaactt tattaggagg aactgaaata      4500
+     ggaaaattca cagtcacacc caaaagctct gggagcatgt tcttagtctc agcagatatt      4560
+     attgcatcaa gaatggaagg cggcgttgtt ctagctttgg tacgagaagg tgattctaag      4620
+     ccctgcgcga ttagttatgg atactcatca ggcattccta atttatgtag tctaagaacc      4680
+     agtattacta atacaggatt gactccgaca acgtattcat tacgtgtagg cggtttagaa      4740
+     agcggtgtgg tatgggttaa tgccctttct aatggcaatg atattttagg aataacaaat      4800
+     acttctaatg tatctttttt agaggtaata cctcaaacaa acgcttaaac aatttttatt      4860
+     ggatttttct tataggtttt atatttagag aaaacagttc gaattacggg gtttgttatg      4920
+     caaaataaaa gaaaagtgag ggacgatttt attaaaattg ttaaagatgt gaaaaaagat      4980
+     ttccccgaat tagacctaaa aatacgagta aacaaggaaa aagtaacttt cttaaattct      5040
+     cccttagaac tctaccataa aagtgtctca ctaattctag gactgcttca acaaatagaa      5100
+     aactctttag gattattccc agactctcct gttcttgaaa aattagagga taacagttta      5160
+     aagctaaaaa aggctttgat tatgcttatc ttgtctagaa aagacatgtt ttccaaggct      5220
+     gaatagacaa cttactctaa cgttggagtt gatttgcaca ccttagtttt ttgctctttt      5280
+     aagggaggaa ctggaaaaac aacactttct ctaaacgtgg gatgcaactt ggcccaattt      5340
+     ttagggaaaa aagtgttact tgctgaccta gacccgcaat ccaatttatc ttctggattg      5400
+     ggggctagtg tcagaagtga ccaaaaaggc ttgcacgaca tagtatacac atcaaacgat      5460
+     ttaaaatcaa tcatttgcga aacaaaaaaa gatagtgtgg acctaattcc tgcatcattt      5520
+     tcatccgaac agtttagaga attggatatt catagaggac ctagtaacaa cttaaagtta      5580
+     tttctgaatg agtactgcgc tcctttttat gacatctgca taatagacac tccacctagc      5640
+     ctaggagggt taacgaaaga agcttttgtt gcaggagaca aattaattgc ttgtttaact      5700
+     ccagaacctt tttctattct agggttacaa aagatacgtg aattcttaag ttcggtcgga      5760
+     aaacctgaag aagaacacat tcttggaata gctttgtctt tttgggatga tcgtaactcg      5820
+     actaaccaaa tgtatataga cattatcgag tctatttaca aaaacaagct tttttcaaca      5880
+     aaaattcgtc gagatatttc tctcagccgt tctcttctta aagaagattc tgtagctaat      5940
+     gtctatccaa attctagggc cgcagaagat attctgaagt taacgcatga aatagcaaat      6000
+     attttgcata tcgaatatga acgagattac tctcagagga caacgtgaac aaactaaaaa      6060
+     aagaagcgga tgtctttttt aaaaaaaatc aaactgccgc ttctctagat tttaagaaga      6120
+     cgcttccctc cattgaacta ttctcagcaa ctttgaattc tgaggaaagt cagagtttgg      6180
+     atcgattatt tttatcagag tcccaaaact attcggatga agaattttat caagaagaca      6240
+     tcctagcggt aaaactgctt actggtcaga taaaatccat acagaagcaa cacgtacttc      6300
+     ttttaggaga aaaaatctat aatgctagaa aaatcctgag taaggatcac ttctcctcaa      6360
+     caactttttc atcttggata gagttagttt ttagaactaa gtcttctgct tacaatgctc      6420
+     ttgcatatta cgagcttttt ataaacctcc ccaaccaaac tctacaaaaa gagtttcaat      6480
+     cgatccccta taaatccgca tatattttgg ccgctagaaa aggcgattta aaaaccaagg      6540
+     tcgatgtgat agggaaagta tgtggaatgt cgaactcatc ggcgataagg gtgttggatc      6600
+     aatttcttcc ttcatctaga aacaaagacg ttagagaaac gatagataag tctgattcag      6660
+     agaagaatcg ccaattatct gatttcttaa tagagatact tcgcatcatg tgttccggag      6720
+     tttctttgtc ctcctataac gaaaatcttc tacaacagct ttttgaactt tttaagcaaa      6780
+     agagctgatc ctccgtcagc tcatatatat atatctatta tatatatata tttagggatt      6840
+     tgatttcacg agagagattt gcaactcttg gtggtagact ttgcaactct tggtggtaga      6900
+     ctttgcaact cttggtggta gactttgcaa ctcttggtgg tagacttggt cataatggac      6960
+     ttttgttaaa aaatttatta aaatcttaga gctccgattt tgaatagctt tggttaagaa      7020
+     aatgggctcg atggctttcc ataaaagtag attgttttta acttttgggg acgcgtcgga      7080
+     aatttggtta tctactttat cttatctaac tagaaaaaat tatgcgtctg ggattaactt      7140
+     tcttgtttct ttagagattc tggatttatc ggaaaccttg ataaaggcta tttctcttga      7200
+     ccacagcgaa tctttgttta aaatcaagtc tctagatgtt tttaatggaa aagttgtttc      7260
+     agaggcatct aaacaggcta gagcggcatg ctacatatct ttcacaaagt ttttgtatag      7320
+     attgaccaag ggatatatta aacccgctat tccattgaaa gattttggaa acactacatt      7380
+     ttttaaaatc cgagacaaaa tcaaaacaga atcgatttct aagcaggaat ggacagtttt      7440
+     ttttgaagcg ctccggatag tgaattatag agactattta atcggtaaat tgattgtaca      7500
+     ag                                                                     7502
+//
diff --git a/test/jalview/io/WindowsFileLoadAndSaveTest.java b/test/jalview/io/WindowsFileLoadAndSaveTest.java
new file mode 100644 (file)
index 0000000..2dd27b4
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+package jalview.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jalview.datamodel.AlignmentI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+
+/**
+ * WindowsFileSaveTest simply opens an alignment file and then tries to save it.
+ * This failed in Windows from 2.11.0 to 2.11.1.6 due to a combination of the
+ * opening file handle being left open ad infinitum, causing the BackupFiles
+ * operation of moving the saved (temp) file onto the original filename to fail,
+ * but only in Windows. See: https://issues.jalview.org/browse/JAL-3628
+ * https://issues.jalview.org/browse/JAL-3703
+ * https://issues.jalview.org/browse/JAL-3935 These issues are really all fixed
+ * by JAL-3703 This test is to ensure it doesn't start again, but note that this
+ * test will only fail in Windows.
+ */
+public class WindowsFileLoadAndSaveTest
+{
+
+  private final static String fileName = "examples" + File.separator
+          + "uniref50.fa";
+
+  private final static String testFileName = fileName + "-TEST";
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  /**
+   * Test saving and re-reading in a specified format
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void loadAndSaveAlignment() throws IOException
+  {
+    File file = new File(fileName);
+    File testFile = new File(testFileName);
+    Files.copy(file.toPath(), testFile.toPath(),
+            StandardCopyOption.REPLACE_EXISTING);
+    FormatAdapter fa = new FormatAdapter();
+    AlignmentI a = fa.readFile(testFile, DataSourceType.FILE,
+            FileFormat.Fasta);
+
+    AlignFrame af = new AlignFrame(a, 500, 500);
+    af.saveAlignment(testFileName, FileFormat.Fasta);
+
+    Assert.assertTrue(af.isSaveAlignmentSuccessful());
+  }
+
+  @AfterClass(alwaysRun = true)
+  private void cleanupTmpFiles()
+  {
+    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
+            .getSavedBackupEntry();
+    BackupFilesTest.cleanupTmpFiles(testFileName, bfpe.suffix, bfpe.digits);
+  }
+
+}
index a719cc4..a2bb08e 100644 (file)
@@ -6,6 +6,7 @@ import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.Mapping;
@@ -86,7 +87,7 @@ public class VCFLoaderTest
     Cache.setProperty("VCF_FIELDS", ".*");
     Cache.setProperty("VEP_FIELDS", ".*");
     Cache.setProperty("VCF_ASSEMBLY", "GRCh38=GRCh38");
-    Cache.initLogger();
+    Console.initLogger();
   }
 
   @BeforeTest(alwaysRun = true)
index eb66416..42d68a9 100644 (file)
@@ -33,6 +33,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.swing.JInternalFrame;
@@ -804,6 +805,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
               "Mismatch PDBEntry 'Type'");
       Assert.assertNotNull(recov.getFile(),
               "Recovered PDBEntry should have a non-null file entry");
+      Assert.assertEquals(recov.getFile().toLowerCase(Locale.ENGLISH).lastIndexOf("pdb"),recov.getFile().length()-3, "Recovered PDBEntry file should have PDB suffix");
     }
   }
 
index c1ad03a..5187167 100644 (file)
@@ -57,6 +57,7 @@ import jalview.schemes.JalviewColourScheme;
 import jalview.structure.AtomSpec;
 import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommandI;
+import jalview.structure.StructureCommandsI.AtomSpecType;
 import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
 import junit.extensions.PA;
@@ -470,7 +471,7 @@ public class AAStructureBindingModelTest
     Color mColor = new Color(0x82827d);
     AtomSpecModel atomSpec = colours.get(mColor);
     assertNotNull(atomSpec);
-    assertEquals(helper.getAtomSpec(atomSpec, false), "#0:21.A|#1:21.B");
+    assertEquals(helper.getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY), "#0:21.A|#1:21.B");
 
     /*
      * H colour is #60609f, seq1.2 mapped to structure 0 residue 22
@@ -478,7 +479,7 @@ public class AAStructureBindingModelTest
     Color hColor = new Color(0x60609f);
     atomSpec = colours.get(hColor);
     assertNotNull(atomSpec);
-    assertEquals(helper.getAtomSpec(atomSpec, false), "#0:22.A");
+    assertEquals(helper.getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY), "#0:22.A");
 
     /*
      * V colour is #ffff00, seq2.2 mapped to structure 1 residue 22
@@ -486,7 +487,7 @@ public class AAStructureBindingModelTest
     Color vColor = new Color(0xffff00);
     atomSpec = colours.get(vColor);
     assertNotNull(atomSpec);
-    assertEquals(helper.getAtomSpec(atomSpec, false), "#1:22.B");
+    assertEquals(helper.getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY), "#1:22.B");
 
     /*
      * hidden columns are Gray (128, 128, 128)
@@ -495,7 +496,7 @@ public class AAStructureBindingModelTest
     Color gray = new Color(128, 128, 128);
     atomSpec = colours.get(gray);
     assertNotNull(atomSpec);
-    assertEquals(helper.getAtomSpec(atomSpec, false), "#0:23-25.A|#1:23-25.B");
+    assertEquals(helper.getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY), "#0:23-25.A|#1:23-25.B");
 
     /*
      * S and G are both coloured #4949b6, structure residues 26-30
@@ -503,7 +504,7 @@ public class AAStructureBindingModelTest
     Color sgColour = new Color(0x4949b6);
     atomSpec = colours.get(sgColour);
     assertNotNull(atomSpec);
-    assertEquals(helper.getAtomSpec(atomSpec, false),
+    assertEquals(helper.getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY),
             "#0:26-30.A|#1:26-30.B");
   }
 }
\ No newline at end of file
diff --git a/test/jalview/util/Log4jTest.java b/test/jalview/util/Log4jTest.java
new file mode 100644 (file)
index 0000000..73bf207
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+package jalview.util;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.concurrent.TimeUnit;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ScanResult;
+import jalview.bin.Console;
+
+public class Log4jTest
+{
+  private static final int TIMEOUT = 10;
+
+  private static class Worker extends Thread
+  {
+    private final Process process;
+
+    private BufferedReader outputReader;
+
+    private BufferedReader errorReader;
+
+    private boolean exited;
+
+    private Worker(Process process)
+    {
+      this.process = process;
+    }
+
+    @Override
+    public void run()
+    {
+      try
+      {
+        exited = process.waitFor(TIMEOUT, TimeUnit.SECONDS);
+      } catch (InterruptedException ignore)
+      {
+        return;
+      }
+      this.interrupt();
+      this.process.destroy();
+    }
+
+    public BufferedReader getOutputReader()
+    {
+      return outputReader;
+    }
+
+    public void setOutputReader(BufferedReader outputReader)
+    {
+      this.outputReader = outputReader;
+    }
+
+    public BufferedReader getErrorReader()
+    {
+      return errorReader;
+    }
+
+    public void setErrorReader(BufferedReader errorReader)
+    {
+      this.errorReader = errorReader;
+    }
+  }
+
+  private static ClassGraph scanner = null;
+
+  private static String classpath = 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();
+      java_exe = System.getProperty("java.home") + File.separator + "bin"
+              + File.separator + "java";
+
+    }
+    while (classpath == null)
+    {
+      try
+      {
+        Thread.sleep(10);
+      } catch (InterruptedException x)
+      {
+
+      }
+    }
+    return classpath;
+  }
+
+  private Worker getJalviewDesktopRunner(String appArgs)
+  {
+    String classpath = getClassPath();
+    String cmd = java_exe + " " + " -classpath " + classpath + " "
+            + " jalview.bin.Jalview " + " "
+            + "-props test/jalview/util/log4jTestProps.jvprops " + appArgs;
+    Process proc = null;
+    Worker worker = null;
+    try
+    {
+      proc = Runtime.getRuntime().exec(cmd);
+    } catch (Throwable e)
+    {
+      e.printStackTrace();
+    }
+    if (proc != null)
+    {
+      BufferedReader outputReader = new BufferedReader(
+              new InputStreamReader(proc.getInputStream()));
+      BufferedReader errorReader = new BufferedReader(
+              new InputStreamReader(proc.getErrorStream()));
+      worker = new Worker(proc);
+      worker.start();
+      worker.setOutputReader(outputReader);
+      worker.setErrorReader(errorReader);
+    }
+    return worker;
+  }
+
+  @BeforeTest(alwaysRun = true)
+  public void initialize()
+  {
+    new Log4jTest();
+  }
+
+  @Test(groups = { "Functional" })
+  public void testLog4j()
+  {
+    String appArgs = " -open examples/uniref50.fa -nosplash -nonews -noquestionnaire -nousagestats -nowebservicediscovery";
+
+    Worker worker = getJalviewDesktopRunner(appArgs);
+    assertNotNull(worker, "worker is null");
+
+    String ln = null;
+    int count = 0;
+    boolean logTestFound = false;
+    try
+    {
+      while ((ln = worker.getErrorReader().readLine()) != null)
+      {
+        if (++count > 500)
+        {
+          break;
+        }
+        if (ln.contains(Console.LOGGING_TEST_MESSAGE))
+        {
+          logTestFound = true;
+          break;
+        }
+      }
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
+    if (worker != null && worker.exited == false)
+    {
+      worker.interrupt();
+      worker.process.destroy();
+    }
+    if (!logTestFound)
+    {
+      Assert.fail("Did not find Log4j Test message line '"
+              + Console.LOGGING_TEST_MESSAGE + "'");
+    }
+  }
+
+}
index 86dcc39..9e494e1 100644 (file)
@@ -25,20 +25,28 @@ import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 
-import jalview.gui.JvOptionPane;
-
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.List;
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import jalview.bin.Console;
+import jalview.gui.JvOptionPane;
+
 public class MapListTest
 {
-
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    Console.initLogger();
+  }
+  
   @BeforeClass(alwaysRun = true)
   public void setUpJvOptionPane()
   {
@@ -46,20 +54,23 @@ public class MapListTest
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
-  @Test(groups = { "Functional" })
+  @Test(groups = { "Functional" }, enabled = false)
   public void testSomething()
   {
-    MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
-        51, 1 }, 1, 3);
+    MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 },
+            new int[]
+            { 51, 1 }, 1, 3);
     MapList ml1 = new MapList(new int[] { 1, 3, 17, 4 },
-            new int[] { 51, 1 }, 1, 3);
+            new int[]
+            { 51, 1 }, 1, 3);
     MapList ml2 = new MapList(new int[] { 1, 60 }, new int[] { 1, 20 }, 3,
             1);
     // test internal consistency
     int to[] = new int[51];
     testMap(ml, 1, 60);
-    MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 }, new int[]
-    { 1, 3 }, 3, 1);
+    MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 },
+            new int[]
+            { 1, 3 }, 3, 1);
     int[] frm = mldna.locateInFrom(1, 1);
     testLocateFrom(mldna, 1, 1, new int[] { 2, 2, 6, 7 });
     testMap(mldna, 1, 3);
@@ -261,15 +272,25 @@ public class MapListTest
     assertEquals("[10, 12]", Arrays.toString(ml.locateInFrom(4, 4)));
     assertEquals("[1, 6]", Arrays.toString(ml.locateInFrom(1, 2)));
     assertEquals("[1, 9]", Arrays.toString(ml.locateInFrom(1, 3)));
+    // reversed range treated as if forwards:
+    assertEquals("[1, 9]", Arrays.toString(ml.locateInFrom(3, 1)));
     assertEquals("[1, 12]", Arrays.toString(ml.locateInFrom(1, 4)));
     assertEquals("[4, 9]", Arrays.toString(ml.locateInFrom(2, 3)));
     assertEquals("[4, 12]", Arrays.toString(ml.locateInFrom(2, 4)));
     assertEquals("[7, 12]", Arrays.toString(ml.locateInFrom(3, 4)));
     assertEquals("[10, 12]", Arrays.toString(ml.locateInFrom(4, 4)));
 
+    /*
+     * partial overlap
+     */
+    assertEquals("[1, 12]", Arrays.toString(ml.locateInFrom(1, 5)));
+    assertEquals("[1, 3]", Arrays.toString(ml.locateInFrom(-1, 1)));
+
+    /*
+     * no overlap
+     */
     assertNull(ml.locateInFrom(0, 0));
-    assertNull(ml.locateInFrom(1, 5));
-    assertNull(ml.locateInFrom(-1, 1));
+
   }
 
   /**
@@ -291,6 +312,108 @@ public class MapListTest
     assertEquals("[10, 10, 12, 12, 14, 14]",
             Arrays.toString(ml.locateInFrom(3, 3)));
     assertEquals("[16, 18]", Arrays.toString(ml.locateInFrom(4, 4)));
+
+    /*
+     * codons at 11-16, 21-26, 31-36 mapped to peptide positions 1, 3-4, 6-8
+     */
+    ml = new MapList(new int[] { 11, 16, 21, 26, 31, 36 },
+            new int[]
+            { 1, 1, 3, 4, 6, 8 }, 3, 1);
+    assertArrayEquals(new int[] { 11, 13 }, ml.locateInFrom(1, 1));
+    assertArrayEquals(new int[] { 11, 16 }, ml.locateInFrom(1, 3));
+    assertArrayEquals(new int[] { 11, 16, 21, 23 }, ml.locateInFrom(1, 4));
+    assertArrayEquals(new int[] { 14, 16, 21, 23 }, ml.locateInFrom(3, 4));
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testLocateInFrom_reverseStrand()
+  {
+    int[] codons = new int[] { 12, 1 };
+    int[] protein = new int[] { 1, 4 };
+    MapList ml = new MapList(codons, protein, 3, 1);
+    assertEquals("[12, 10]", Arrays.toString(ml.locateInFrom(1, 1)));
+    assertEquals("[9, 4]", Arrays.toString(ml.locateInFrom(2, 3)));
+  }
+
+  /**
+   * Tests for method that locates the overlap of the ranges in the 'from' map
+   * for given range in the 'to' map
+   */
+  @Test(groups = { "Functional" })
+  public void testGetOverlapsInFrom_withIntrons()
+  {
+    /*
+     * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [16, 17, 18] i.e.
+     * 2-3, 5-7, 9-10, 12-12, 14-14, 16-18
+     */
+    int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
+    int[] protein = { 11, 14 };
+    MapList ml = new MapList(codons, protein, 3, 1);
+
+    assertEquals("[2, 3, 5, 5]",
+            Arrays.toString(ml.getOverlapsInFrom(11, 11)));
+    assertEquals("[2, 3, 5, 7, 9, 9]",
+            Arrays.toString(ml.getOverlapsInFrom(11, 12)));
+    // out of range 5' :
+    assertEquals("[2, 3, 5, 7, 9, 9]",
+            Arrays.toString(ml.getOverlapsInFrom(8, 12)));
+    // out of range 3' :
+    assertEquals("[10, 10, 12, 12, 14, 14, 16, 18]",
+            Arrays.toString(ml.getOverlapsInFrom(13, 16)));
+    // out of range both :
+    assertEquals("[2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18]",
+            Arrays.toString(ml.getOverlapsInFrom(1, 16)));
+    // no overlap:
+    assertNull(ml.getOverlapsInFrom(20, 25));
+  }
+
+  /**
+   * Tests for method that locates the overlap of the ranges in the 'to' map for
+   * given range in the 'from' map
+   */
+  @Test(groups = { "Functional" })
+  public void testGetOverlapsInTo_withIntrons()
+  {
+    /*
+     * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [17, 18, 19] i.e.
+     * 2-3, 5-7, 9-10, 12-12, 14-14, 17-19
+     */
+    int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 17, 19 };
+    /*
+     * Mapped proteins at positions 1, 3, 4, 6 in the sequence
+     */
+    int[] protein = { 1, 1, 3, 4, 6, 6 };
+    MapList ml = new MapList(codons, protein, 3, 1);
+
+    /*
+     * Can't map from an unmapped position
+     */
+    assertNull(ml.getOverlapsInTo(1, 1));
+    assertNull(ml.getOverlapsInTo(4, 4));
+    assertNull(ml.getOverlapsInTo(15, 16));
+
+    /*
+     * nor from a range that includes no mapped position (exon)
+     */
+    assertNull(ml.getOverlapsInTo(15, 16));
+
+    // end of codon 1 maps to first peptide
+    assertEquals("[1, 1]", Arrays.toString(ml.getOverlapsInTo(2, 2)));
+    // end of codon 1 and start of codon 2 maps to first 2 peptides
+    assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(3, 7)));
+
+    // range overlaps 5' end of dna:
+    assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(1, 6)));
+    assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.getOverlapsInTo(1, 8)));
+
+    // range overlaps 3' end of dna:
+    assertEquals("[6, 6]", Arrays.toString(ml.getOverlapsInTo(17, 24)));
+    assertEquals("[6, 6]", Arrays.toString(ml.getOverlapsInTo(16, 24)));
+
+    // dna positions 8, 11 are intron but include end of exon 2 and start of
+    // exon 3
+    assertEquals("[3, 4]", Arrays.toString(ml.getOverlapsInTo(8, 11)));
   }
 
   /**
@@ -315,6 +438,8 @@ public class MapListTest
     assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(1, 12)));
     assertEquals("[2, 2]", Arrays.toString(ml.locateInTo(4, 6)));
     assertEquals("[2, 4]", Arrays.toString(ml.locateInTo(4, 12)));
+    // reverse range treated as if forwards:
+    assertEquals("[2, 4]", Arrays.toString(ml.locateInTo(12, 4)));
 
     /*
      * A part codon is treated as if a whole one.
@@ -326,9 +451,16 @@ public class MapListTest
     assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(3, 11)));
     assertEquals("[2, 4]", Arrays.toString(ml.locateInTo(5, 11)));
 
+    /*
+     * partial overlap
+     */
+    assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(1, 13)));
+    assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(-1, 2)));
+
+    /*
+     * no overlap
+     */
     assertNull(ml.locateInTo(0, 0));
-    assertNull(ml.locateInTo(1, 13));
-    assertNull(ml.locateInTo(-1, 1));
   }
 
   /**
@@ -350,14 +482,7 @@ public class MapListTest
     MapList ml = new MapList(codons, protein, 3, 1);
 
     /*
-     * Can't map from an unmapped position
-     */
-    assertNull(ml.locateInTo(1, 2));
-    assertNull(ml.locateInTo(2, 4));
-    assertNull(ml.locateInTo(4, 4));
-
-    /*
-     * Valid range or subrange of codon1 maps to protein1.
+     * Valid range or subrange of codon1 maps to protein1
      */
     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(2, 2)));
     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(3, 3)));
@@ -371,6 +496,17 @@ public class MapListTest
     // codon positions 7 to 17 (part) cover proteins 2/3/4 at positions 3/4/6
     assertEquals("[3, 4, 6, 6]", Arrays.toString(ml.locateInTo(7, 17)));
 
+    /*
+     * partial overlap
+     */
+    assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(1, 2)));
+    assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(1, 4)));
+    assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(2, 4)));
+
+    /*
+     * no overlap
+     */
+    assertNull(ml.locateInTo(4, 4));
   }
 
   /**
@@ -431,7 +567,8 @@ public class MapListTest
     List<int[]> ranges = new ArrayList<>();
     ranges.add(new int[] { 2, 3 });
     ranges.add(new int[] { 5, 6 });
-    assertEquals("[2, 3, 5, 6]", Arrays.toString(MapList.getRanges(ranges)));
+    assertEquals("[2, 3, 5, 6]",
+            Arrays.toString(MapList.getRanges(ranges)));
   }
 
   /**
@@ -463,7 +600,8 @@ public class MapListTest
     assertEquals(6, ml2.getToHighest());
     assertEquals("{[2, 3], [5, 7], [9, 10], [12, 12], [14, 14], [16, 18]}",
             prettyPrint(ml2.getFromRanges()));
-    assertEquals("{[1, 1], [3, 4], [6, 6]}", prettyPrint(ml2.getToRanges()));
+    assertEquals("{[1, 1], [3, 4], [6, 6]}",
+            prettyPrint(ml2.getToRanges()));
 
     /*
      * reverse direction
@@ -478,22 +616,23 @@ public class MapListTest
   }
 
   /**
-   * Test constructor can merge consecutive ranges
+   * Test constructor used to merge consecutive ranges but now just leaves them
+   * as supplied (JAL-3751)
    */
   @Test(groups = { "Functional" })
   public void testConstructor_mergeRanges()
   {
-    int[] codons = { 2, 3, 3, 7, 9, 10, 12, 12, 14, 14, 16, 17 };
-    int[] protein = { 1, 1, 1, 3, 6, 6 };
+    int[] codons = { 2, 3, 3, 7, 9, 10, 12, 12, 13, 14, 16, 17 };
+    int[] protein = { 1, 1, 2, 3, 6, 6 };
     MapList ml = new MapList(codons, protein, 3, 1);
     assertEquals(3, ml.getFromRatio());
     assertEquals(2, ml.getFromLowest());
     assertEquals(17, ml.getFromHighest());
     assertEquals(1, ml.getToLowest());
     assertEquals(6, ml.getToHighest());
-    assertEquals("{[2, 7], [9, 10], [12, 12], [14, 14], [16, 17]}",
+    assertEquals("{[2, 3], [3, 7], [9, 10], [12, 12], [13, 14], [16, 17]}",
             prettyPrint(ml.getFromRanges()));
-    assertEquals("{[1, 3], [6, 6]}", prettyPrint(ml.getToRanges()));
+    assertEquals("{[1, 1], [2, 3], [6, 6]}", prettyPrint(ml.getToRanges()));
   }
 
   /**
@@ -544,8 +683,9 @@ public class MapListTest
   @Test(groups = { "Functional" })
   public void testToString()
   {
-    MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
-        51, 1 }, 1, 3);
+    MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 },
+            new int[]
+            { 51, 1 }, 1, 3);
     String s = ml.toString();
     assertEquals("[ [1, 5] [10, 15] [25, 20] ] 1:3 to [ [51, 1] ]", s);
   }
@@ -554,14 +694,16 @@ public class MapListTest
   public void testAddMapList()
   {
     MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
-            new int[] { 72, 22 }, 1, 3);
+            new int[]
+            { 72, 22 }, 1, 3);
     assertEquals(11, ml.getFromLowest());
     assertEquals(35, ml.getFromHighest());
     assertEquals(22, ml.getToLowest());
     assertEquals(72, ml.getToHighest());
 
-    MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 }, new int[] { 12,
-        17, 78, 83, 88, 96 }, 1, 3);
+    MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 },
+            new int[]
+            { 12, 17, 78, 83, 88, 96 }, 1, 3);
     ml.addMapList(ml2);
     assertEquals(2, ml.getFromLowest());
     assertEquals(40, ml.getFromHighest());
@@ -581,7 +723,8 @@ public class MapListTest
   public void testAddMapList_sameMap()
   {
     MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
-            new int[] { 72, 22 }, 1, 3);
+            new int[]
+            { 72, 22 }, 1, 3);
     String before = ml.toString();
     ml.addMapList(ml);
     assertEquals(before, ml.toString());
@@ -595,8 +738,8 @@ public class MapListTest
     MapList ml = new MapList(new int[] { 11, 15 }, new int[] { 72, 58 }, 1,
             3);
 
-    MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 },
-            1, 3);
+    MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 }, 1,
+            3);
     ml.addMapList(ml2);
     assertEquals("[ [11, 16] ] 1:3 to [ [72, 53] ]", ml.toString());
   }
@@ -682,13 +825,15 @@ public class MapListTest
   public void testIsFromForwardStrand()
   {
     // [3-9] declares forward strand
-    MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 }, new int[] {
-        20, 11 }, 1, 1);
+    MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 },
+            new int[]
+            { 20, 11 }, 1, 1);
     assertTrue(ml.isFromForwardStrand());
 
     // [11-5] declares reverse strand ([13-14] is ignored)
     ml = new MapList(new int[] { 2, 2, 11, 5, 13, 14 },
-            new int[] { 20, 11 }, 1, 1);
+            new int[]
+            { 20, 11 }, 1, 1);
     assertFalse(ml.isFromForwardStrand());
 
     // all single position ranges - defaults to forward strand
@@ -698,7 +843,7 @@ public class MapListTest
   }
 
   /**
-   * Test the method that merges a list of ranges where possible
+   * Test the method that merges contiguous ranges
    */
   @Test(groups = { "Functional" })
   public void testCoalesceRanges()
@@ -720,101 +865,58 @@ public class MapListTest
     // merging in forward direction:
     ranges.clear();
     ranges.add(new int[] { 1, 3 });
-    ranges.add(new int[] { 4, 5 });
-    ranges.add(new int[] { 5, 5 });
-    ranges.add(new int[] { 5, 7 });
+    ranges.add(new int[] { 4, 5 }); // contiguous
+    ranges.add(new int[] { 5, 5 }); // overlap!
+    ranges.add(new int[] { 6, 7 }); // contiguous
     List<int[]> merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
-    assertArrayEquals(new int[] { 1, 7 }, merged.get(0));
+    assertEquals(2, merged.size());
+    assertArrayEquals(new int[] { 1, 5 }, merged.get(0));
+    assertArrayEquals(new int[] { 5, 7 }, merged.get(1));
     // verify input list is unchanged
     assertEquals(4, ranges.size());
     assertArrayEquals(new int[] { 1, 3 }, ranges.get(0));
     assertArrayEquals(new int[] { 4, 5 }, ranges.get(1));
     assertArrayEquals(new int[] { 5, 5 }, ranges.get(2));
-    assertArrayEquals(new int[] { 5, 7 }, ranges.get(3));
+    assertArrayEquals(new int[] { 6, 7 }, ranges.get(3));
 
     // merging in reverse direction:
     ranges.clear();
     ranges.add(new int[] { 7, 5 });
-    ranges.add(new int[] { 5, 4 });
-    ranges.add(new int[] { 4, 4 });
-    ranges.add(new int[] { 3, 1 });
+    ranges.add(new int[] { 5, 4 }); // overlap
+    ranges.add(new int[] { 4, 4 }); // overlap
+    ranges.add(new int[] { 3, 1 }); // contiguous
     merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
-    assertArrayEquals(new int[] { 7, 1 }, merged.get(0));
+    assertEquals(3, merged.size());
+    assertArrayEquals(new int[] { 7, 5 }, merged.get(0));
+    assertArrayEquals(new int[] { 5, 4 }, merged.get(1));
+    assertArrayEquals(new int[] { 4, 1 }, merged.get(2));
 
     // merging with switches of direction:
     ranges.clear();
     ranges.add(new int[] { 1, 3 });
-    ranges.add(new int[] { 4, 5 });
-    ranges.add(new int[] { 5, 5 });
-    ranges.add(new int[] { 6, 6 });
+    ranges.add(new int[] { 4, 5 }); // contiguous
+    ranges.add(new int[] { 5, 5 }); // overlap
+    ranges.add(new int[] { 6, 6 }); // contiguous
     ranges.add(new int[] { 12, 10 });
-    ranges.add(new int[] { 9, 8 });
-    ranges.add(new int[] { 8, 8 });
-    ranges.add(new int[] { 7, 7 });
+    ranges.add(new int[] { 9, 8 }); // contiguous
+    ranges.add(new int[] { 8, 8 }); // overlap
+    ranges.add(new int[] { 7, 7 }); // contiguous
     merged = MapList.coalesceRanges(ranges);
-    assertEquals(2, merged.size());
-    assertArrayEquals(new int[] { 1, 6 }, merged.get(0));
-    assertArrayEquals(new int[] { 12, 7 }, merged.get(1));
-  }
-
-  /**
-   * Test the method that merges a list of ranges where possible
-   */
-  @Test(groups = { "Functional" })
-  public void testCoalesceRanges_withOverlap()
-  {
-    List<int[]> ranges = new ArrayList<>();
-    ranges.add(new int[] { 1, 3 });
-    ranges.add(new int[] { 2, 5 });
-
-    /*
-     * [2, 5] should extend [1, 3]
-     */
-    List<int[]> merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
+    assertEquals(4, merged.size());
     assertArrayEquals(new int[] { 1, 5 }, merged.get(0));
-
-    /*
-     * a subsumed interval should be dropped
-     */
-    ranges.clear();
-    ranges.add(new int[] { 1, 6 });
-    ranges.add(new int[] { 2, 4 });
-    merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
-    assertArrayEquals(new int[] { 1, 6 }, merged.get(0));
-
-    ranges.clear();
-    ranges.add(new int[] { 1, 5 });
-    ranges.add(new int[] { 1, 6 });
-    merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
-    assertArrayEquals(new int[] { 1, 6 }, merged.get(0));
-
-    /*
-     * merge duplicate ranges
-     */
+    assertArrayEquals(new int[] { 5, 6 }, merged.get(1));
+    assertArrayEquals(new int[] { 12, 8 }, merged.get(2));
+    assertArrayEquals(new int[] { 8, 7 }, merged.get(3));
+    
+    // 'subsumed' ranges are preserved
     ranges.clear();
-    ranges.add(new int[] { 1, 3 });
-    ranges.add(new int[] { 1, 3 });
-    merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
-    assertArrayEquals(new int[] { 1, 3 }, merged.get(0));
+    ranges.add(new int[] { 10, 30 });
+    ranges.add(new int[] { 15, 25 }); 
 
-    /*
-     * reverse direction
-     */
-    ranges.clear();
-    ranges.add(new int[] { 9, 5 });
-    ranges.add(new int[] { 9, 4 });
-    ranges.add(new int[] { 8, 3 });
-    ranges.add(new int[] { 3, 2 });
-    ranges.add(new int[] { 1, 0 });
     merged = MapList.coalesceRanges(ranges);
-    assertEquals(1, merged.size());
-    assertArrayEquals(new int[] { 9, 0 }, merged.get(0));
+    assertEquals(2, merged.size());
+    assertArrayEquals(new int[] { 10, 30 }, merged.get(0));
+    assertArrayEquals(new int[] { 15, 25 }, merged.get(1));
   }
 
   /**
@@ -826,13 +928,15 @@ public class MapListTest
     /*
      * simple 1:1 plus 1:1 forwards
      */
-    MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 }, new int[] { 5, 8,
-        11, 13 }, 1, 1);
+    MapList ml1 = new MapList(new int[] { 3, 4, 8, 12 },
+            new int[]
+            { 5, 8, 11, 13 }, 1, 1);
     assertEquals("{[3, 4], [8, 12]}", prettyPrint(ml1.getFromRanges()));
     assertEquals("{[5, 8], [11, 13]}", prettyPrint(ml1.getToRanges()));
 
-    MapList ml2 = new MapList(new int[] { 1, 50 }, new int[] { 40, 45, 70,
-        75, 90, 127 }, 1, 1);
+    MapList ml2 = new MapList(new int[] { 1, 50 },
+            new int[]
+            { 40, 45, 70, 75, 90, 127 }, 1, 1);
     assertEquals("{[1, 50]}", prettyPrint(ml2.getFromRanges()));
     assertEquals("{[40, 45], [70, 75], [90, 127]}",
             prettyPrint(ml2.getToRanges()));
@@ -859,7 +963,8 @@ public class MapListTest
      */
     ml1 = new MapList(new int[] { 1, 50 }, new int[] { 70, 119 }, 1, 1);
     ml2 = new MapList(new int[] { 1, 500 },
-            new int[] { 1000, 901, 600, 201 }, 1, 1);
+            new int[]
+            { 1000, 901, 600, 201 }, 1, 1);
     compound = ml1.traverse(ml2);
 
     assertEquals(1, compound.getFromRatio());
@@ -876,8 +981,8 @@ public class MapListTest
      * 1:1 plus 1:3 should result in 1:3
      */
     ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 40 }, 1, 1);
-    ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 },
-            1, 3);
+    ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 50, 91, 340 }, 1,
+            3);
     compound = ml1.traverse(ml2);
 
     assertEquals(1, compound.getFromRatio());
@@ -895,8 +1000,8 @@ public class MapListTest
      * 3:1 plus 1:1 should result in 3:1
      */
     ml1 = new MapList(new int[] { 1, 30 }, new int[] { 11, 20 }, 3, 1);
-    ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 },
-            1, 1);
+    ml2 = new MapList(new int[] { 1, 100 }, new int[] { 1, 15, 91, 175 }, 1,
+            1);
     compound = ml1.traverse(ml2);
 
     assertEquals(3, compound.getFromRatio());
@@ -949,17 +1054,17 @@ public class MapListTest
     assertArrayEquals(new int[] { 71, 126 }, toRanges.get(1));
 
     /*
-     * method returns null if not all regions are mapped through
+     * if not all regions are mapped through, returns what is
      */
     ml1 = new MapList(new int[] { 1, 50 }, new int[] { 101, 150 }, 1, 1);
-    ml2 = new MapList(new int[] { 131, 180 }, new int[] { 201, 250 }, 1, 3);
+    ml2 = new MapList(new int[] { 131, 180 }, new int[] { 201, 250 }, 1, 1);
     compound = ml1.traverse(ml2);
     assertNull(compound);
   }
 
   /**
-   * Test that method that inspects for the (first) forward or reverse 'to' range.
-   * Single position ranges are ignored.
+   * Test that method that inspects for the (first) forward or reverse 'to'
+   * range. Single position ranges are ignored.
    */
   @Test(groups = { "Functional" })
   public void testIsToForwardsStrand()
@@ -981,4 +1086,433 @@ public class MapListTest
             1);
     assertTrue(ml.isToForwardStrand());
   }
+
+  /**
+   * Test for mapping with overlapping ranges
+   */
+  @Test(groups = { "Functional" })
+  public void testLocateInFrom_withOverlap()
+  {
+    /*
+     * gene to protein...
+     */
+    int[] codons = new int[] { 1, 12, 12, 17 };
+    int[] protein = new int[] { 1, 6 };
+    MapList ml = new MapList(codons, protein, 3, 1);
+    assertEquals("[1, 3]", Arrays.toString(ml.locateInFrom(1, 1)));
+    assertEquals("[4, 6]", Arrays.toString(ml.locateInFrom(2, 2)));
+    assertEquals("[7, 9]", Arrays.toString(ml.locateInFrom(3, 3)));
+    assertEquals("[10, 12]", Arrays.toString(ml.locateInFrom(4, 4)));
+    assertEquals("[12, 14]", Arrays.toString(ml.locateInFrom(5, 5)));
+    assertEquals("[15, 17]", Arrays.toString(ml.locateInFrom(6, 6)));
+    assertEquals("[1, 6]", Arrays.toString(ml.locateInFrom(1, 2)));
+    assertEquals("[1, 9]", Arrays.toString(ml.locateInFrom(1, 3)));
+    assertEquals("[1, 12]", Arrays.toString(ml.locateInFrom(1, 4)));
+    assertEquals("[1, 12, 12, 14]", Arrays.toString(ml.locateInFrom(1, 5)));
+    assertEquals("[1, 12, 12, 17]", Arrays.toString(ml.locateInFrom(1, 6)));
+    assertEquals("[4, 9]", Arrays.toString(ml.locateInFrom(2, 3)));
+    assertEquals("[7, 12, 12, 17]", Arrays.toString(ml.locateInFrom(3, 6)));
+
+    /*
+     * partial overlap of range
+     */
+    assertEquals("[4, 12, 12, 17]", Arrays.toString(ml.locateInFrom(2, 7)));
+    assertEquals("[1, 3]", Arrays.toString(ml.locateInFrom(-1, 1)));
+
+    /*
+     * no overlap in range
+     */
+    assertNull(ml.locateInFrom(0, 0));
+
+    /*
+     * gene to CDS...from EMBL:MN908947
+     */
+    int[] gene = new int[] { 266, 13468, 13468, 21555 };
+    int[] cds = new int[] { 1, 21291 };
+    ml = new MapList(gene, cds, 1, 1);
+    assertEquals("[13468, 13468]",
+            Arrays.toString(ml.locateInFrom(13203, 13203)));
+    assertEquals("[13468, 13468]",
+            Arrays.toString(ml.locateInFrom(13204, 13204)));
+    assertEquals("[13468, 13468, 13468, 13468]",
+            Arrays.toString(ml.locateInFrom(13203, 13204)));
+  }
+
+  /**
+   * Test for mapping with overlapping ranges
+   */
+  @Test(groups = { "Functional" })
+  public void testLocateInTo_withOverlap()
+  {
+    /*
+     * gene to protein...
+     */
+    int[] codons = new int[] { 1, 12, 12, 17 };
+    int[] protein = new int[] { 1, 6 };
+    MapList ml = new MapList(codons, protein, 3, 1);
+    assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(1, 1)));
+    assertEquals("[1, 3]", Arrays.toString(ml.locateInTo(3, 8)));
+    assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(2, 11)));
+    assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(3, 11)));
+
+    // we want base 12 to map to both of the amino acids it codes for
+    assertEquals("[4, 5]", Arrays.toString(ml.locateInTo(12, 12)));
+    assertEquals("[4, 5]", Arrays.toString(ml.locateInTo(11, 12)));
+    assertEquals("[4, 6]", Arrays.toString(ml.locateInTo(11, 15)));
+    assertEquals("[6, 6]", Arrays.toString(ml.locateInTo(15, 17)));
+
+    /*
+     * no overlap
+     */
+    assertNull(ml.locateInTo(0, 0));
+
+    /*
+     * partial overlap
+     */
+    assertEquals("[1, 6]", Arrays.toString(ml.locateInTo(1, 18)));
+    assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(-1, 1)));
+
+    /*
+     * gene to CDS...from EMBL:MN908947
+     * the base at 13468 is used twice in transcription
+     */
+    int[] gene = new int[] { 266, 13468, 13468, 21555 };
+    int[] cds = new int[] { 1, 21291 };
+    ml = new MapList(gene, cds, 1, 1);
+    assertEquals("[13203, 13204]",
+            Arrays.toString(ml.locateInTo(13468, 13468)));
+
+    /*
+     * gene to protein
+     * the base at 13468 is in the codon for 4401N and also 4402R
+     */
+    gene = new int[] { 266, 13468, 13468, 21552 }; // stop codon excluded
+    protein = new int[] { 1, 7096 };
+    ml = new MapList(gene, protein, 3, 1);
+    assertEquals("[4401, 4402]",
+            Arrays.toString(ml.locateInTo(13468, 13468)));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testTraverseToPosition()
+  {
+    List<int[]> ranges = new ArrayList<>();
+    assertNull(MapList.traverseToPosition(ranges, 0));
+
+    ranges.add(new int[] { 3, 6 });
+    assertNull(MapList.traverseToPosition(ranges, 0));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testCountPositions()
+  {
+    try
+    {
+      MapList.countPositions(null, 1);
+      fail("expected exception");
+    } catch (NullPointerException e)
+    {
+      // expected
+    }
+
+    List<int[]> intervals = new ArrayList<>();
+    assertNull(MapList.countPositions(intervals, 1));
+
+    /*
+     * forward strand
+     */
+    intervals.add(new int[] { 10, 20 });
+    assertNull(MapList.countPositions(intervals, 9));
+    assertNull(MapList.countPositions(intervals, 21));
+    assertArrayEquals(new int[] { 1, 1 },
+            MapList.countPositions(intervals, 10));
+    assertArrayEquals(new int[] { 6, 1 },
+            MapList.countPositions(intervals, 15));
+    assertArrayEquals(new int[] { 11, 1 },
+            MapList.countPositions(intervals, 20));
+
+    intervals.add(new int[] { 25, 25 });
+    assertArrayEquals(new int[] { 12, 1 },
+            MapList.countPositions(intervals, 25));
+
+    // next interval repeats position 25 - which should be counted twice if
+    // traversed
+    intervals.add(new int[] { 25, 26 });
+    assertArrayEquals(new int[] { 12, 1 },
+            MapList.countPositions(intervals, 25));
+    assertArrayEquals(new int[] { 14, 1 },
+            MapList.countPositions(intervals, 26));
+
+    /*
+     * reverse strand
+     */
+    intervals.clear();
+    intervals.add(new int[] { 5, -5 });
+    assertNull(MapList.countPositions(intervals, 6));
+    assertNull(MapList.countPositions(intervals, -6));
+    assertArrayEquals(new int[] { 1, -1 },
+            MapList.countPositions(intervals, 5));
+    assertArrayEquals(new int[] { 7, -1 },
+            MapList.countPositions(intervals, -1));
+    assertArrayEquals(new int[] { 11, -1 },
+            MapList.countPositions(intervals, -5));
+
+    /*
+     * reverse then forward
+     */
+    intervals.add(new int[] { 5, 10 });
+    assertArrayEquals(new int[] { 13, 1 },
+            MapList.countPositions(intervals, 6));
+
+    /*
+     * reverse then forward then reverse
+     */
+    intervals.add(new int[] { -10, -20 });
+    assertArrayEquals(new int[] { 20, -1 },
+            MapList.countPositions(intervals, -12));
+
+    /*
+     * an interval [x, x] is treated as forward
+     */
+    intervals.add(new int[] { 30, 30 });
+    assertArrayEquals(new int[] { 29, 1 },
+            MapList.countPositions(intervals, 30));
+
+    /*
+     * it is the first matched occurrence that is returned
+     */
+    intervals.clear();
+    intervals.add(new int[] { 1, 2 });
+    intervals.add(new int[] { 2, 3 });
+    assertArrayEquals(new int[] { 2, 1 },
+            MapList.countPositions(intervals, 2));
+    intervals.add(new int[] { -1, -2 });
+    intervals.add(new int[] { -2, -3 });
+    assertArrayEquals(new int[] { 6, -1 },
+            MapList.countPositions(intervals, -2));
+  }
+
+  /**
+   * Tests for helper method that adds any overlap (plus offset) to a set of
+   * overlaps
+   */
+  @Test(groups = { "Functional" })
+  public void testAddOffsetPositions()
+  {
+    List<int[]> mapped = new ArrayList<>();
+    int[] range = new int[] { 10, 20 };
+    BitSet offsets = new BitSet();
+
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertTrue(mapped.isEmpty()); // nothing marked for overlap
+
+    offsets.set(11);
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertTrue(mapped.isEmpty()); // no offset 11 in range
+
+    offsets.set(4, 6); // this sets bits 4 and 5
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertEquals(1, mapped.size());
+    assertArrayEquals(new int[] { 14, 15 }, mapped.get(0));
+
+    mapped.clear();
+    offsets.set(10);
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertEquals(2, mapped.size());
+    assertArrayEquals(new int[] { 14, 15 }, mapped.get(0));
+    assertArrayEquals(new int[] { 20, 20 }, mapped.get(1));
+
+    /*
+     * reverse range
+     */
+    range = new int[] { 20, 10 };
+    mapped.clear();
+    offsets.clear();
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertTrue(mapped.isEmpty()); // nothing marked for overlap
+    offsets.set(11);
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertTrue(mapped.isEmpty()); // no offset 11 in range
+    offsets.set(0);
+    offsets.set(10);
+    offsets.set(6, 8); // sets bits 6 and 7
+    MapList.addOffsetPositions(mapped, 0, range, offsets);
+    assertEquals(3, mapped.size());
+    assertArrayEquals(new int[] { 20, 20 }, mapped.get(0));
+    assertArrayEquals(new int[] { 14, 13 }, mapped.get(1));
+    assertArrayEquals(new int[] { 10, 10 }, mapped.get(2));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetPositionsForOffsets()
+  {
+    List<int[]> ranges = new ArrayList<>();
+    BitSet offsets = new BitSet();
+    List<int[]> mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertTrue(mapped.isEmpty()); // no ranges and no offsets!
+
+    offsets.set(5, 1000);
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertTrue(mapped.isEmpty()); // no ranges
+
+    /*
+     * one range with overlap of offsets
+     */
+    ranges.add(new int[] { 15, 25 });
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertEquals(1, mapped.size());
+    assertArrayEquals(new int[] { 20, 25 }, mapped.get(0));
+
+    /*
+     * two ranges
+     */
+    ranges.add(new int[] { 300, 320 });
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertEquals(2, mapped.size());
+    assertArrayEquals(new int[] { 20, 25 }, mapped.get(0));
+    assertArrayEquals(new int[] { 300, 320 }, mapped.get(1));
+
+    /*
+     * boundary case - right end of first range overlaps
+     */
+    offsets.clear();
+    offsets.set(10);
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertEquals(1, mapped.size());
+    assertArrayEquals(new int[] { 25, 25 }, mapped.get(0));
+
+    /*
+     * boundary case - left end of second range overlaps
+     */
+    offsets.set(11);
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertEquals(2, mapped.size());
+    assertArrayEquals(new int[] { 25, 25 }, mapped.get(0));
+    assertArrayEquals(new int[] { 300, 300 }, mapped.get(1));
+
+    /*
+     * offsets into a circular range are reported in
+     * the order in which they are traversed
+     */
+    ranges.clear();
+    ranges.add(new int[] { 100, 150 });
+    ranges.add(new int[] { 60, 80 });
+    offsets.clear();
+    offsets.set(45, 55); // sets bits 45 to 54
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertEquals(2, mapped.size());
+    assertArrayEquals(new int[] { 145, 150 }, mapped.get(0)); // offsets 45-50
+    assertArrayEquals(new int[] { 60, 63 }, mapped.get(1)); // offsets 51-54
+
+    /*
+     * reverse range overlap is reported with start < end
+     */
+    ranges.clear();
+    ranges.add(new int[] { 4321, 4000 });
+    offsets.clear();
+    offsets.set(20, 22); // sets bits 20 and 21
+    offsets.set(30);
+    mapped = MapList.getPositionsForOffsets(ranges, offsets);
+    assertEquals(2, mapped.size());
+    assertArrayEquals(new int[] { 4301, 4300 }, mapped.get(0));
+    assertArrayEquals(new int[] { 4291, 4291 }, mapped.get(1));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetMappedOffsetsForPositions()
+  {
+    /*
+     * start by verifying the examples in the method's Javadoc!
+     */
+    List<int[]> ranges = new ArrayList<>();
+    ranges.add(new int[] { 10, 20 });
+    ranges.add(new int[] { 31, 40 });
+    BitSet overlaps = MapList.getMappedOffsetsForPositions(1, 9, ranges, 1,
+            1);
+    assertTrue(overlaps.isEmpty());
+    overlaps = MapList.getMappedOffsetsForPositions(1, 11, ranges, 1, 1);
+    assertEquals(2, overlaps.cardinality());
+    assertTrue(overlaps.get(0));
+    assertTrue(overlaps.get(1));
+    overlaps = MapList.getMappedOffsetsForPositions(15, 35, ranges, 1, 1);
+    assertEquals(11, overlaps.cardinality());
+    for (int i = 5; i <= 11; i++)
+    {
+      assertTrue(overlaps.get(i));
+    }
+
+    ranges.clear();
+    ranges.add(new int[] { 1, 200 });
+    overlaps = MapList.getMappedOffsetsForPositions(9, 9, ranges, 1, 3);
+    assertEquals(3, overlaps.cardinality());
+    assertTrue(overlaps.get(24));
+    assertTrue(overlaps.get(25));
+    assertTrue(overlaps.get(26));
+
+    ranges.clear();
+    ranges.add(new int[] { 101, 150 });
+    ranges.add(new int[] { 171, 180 });
+    overlaps = MapList.getMappedOffsetsForPositions(101, 102, ranges, 3, 1);
+    assertEquals(1, overlaps.cardinality());
+    assertTrue(overlaps.get(0));
+    overlaps = MapList.getMappedOffsetsForPositions(150, 171, ranges, 3, 1);
+    assertEquals(1, overlaps.cardinality());
+    assertTrue(overlaps.get(16));
+
+    ranges.clear();
+    ranges.add(new int[] { 101, 150 });
+    ranges.add(new int[] { 21, 30 });
+    overlaps = MapList.getMappedOffsetsForPositions(24, 40, ranges, 3, 1);
+    assertEquals(3, overlaps.cardinality());
+    assertTrue(overlaps.get(17));
+    assertTrue(overlaps.get(18));
+    assertTrue(overlaps.get(19));
+
+    /*
+     * reverse range 1:1 (e.g. reverse strand gene to transcript)
+     */
+    ranges.clear();
+    ranges.add(new int[] { 20, 10 });
+    overlaps = MapList.getMappedOffsetsForPositions(12, 13, ranges, 1, 1);
+    assertEquals(2, overlaps.cardinality());
+    assertTrue(overlaps.get(7));
+    assertTrue(overlaps.get(8));
+
+    /*
+     * reverse range 3:1 (e.g. reverse strand gene to peptide)
+     * from EMBL:J03321 to P0CE20
+     */
+    ranges.clear();
+    ranges.add(new int[] { 1480, 488 });
+    overlaps = MapList.getMappedOffsetsForPositions(1460, 1460, ranges, 3,
+            1);
+    // 1460 is the end of the 7th codon
+    assertEquals(1, overlaps.cardinality());
+    assertTrue(overlaps.get(6));
+    // add one base (part codon)
+    overlaps = MapList.getMappedOffsetsForPositions(1459, 1460, ranges, 3,
+            1);
+    assertEquals(2, overlaps.cardinality());
+    assertTrue(overlaps.get(6));
+    assertTrue(overlaps.get(7));
+    // add second base (part codon)
+    overlaps = MapList.getMappedOffsetsForPositions(1458, 1460, ranges, 3,
+            1);
+    assertEquals(2, overlaps.cardinality());
+    assertTrue(overlaps.get(6));
+    assertTrue(overlaps.get(7));
+    // add third base (whole codon)
+    overlaps = MapList.getMappedOffsetsForPositions(1457, 1460, ranges, 3,
+            1);
+    assertEquals(2, overlaps.cardinality());
+    assertTrue(overlaps.get(6));
+    assertTrue(overlaps.get(7));
+    // add one more base (part codon)
+    overlaps = MapList.getMappedOffsetsForPositions(1456, 1460, ranges, 3,
+            1);
+    assertEquals(3, overlaps.cardinality());
+    assertTrue(overlaps.get(6));
+    assertTrue(overlaps.get(7));
+    assertTrue(overlaps.get(8));
+  }
 }
index 097ccd4..1420cee 100644 (file)
@@ -22,10 +22,23 @@ package jalview.util;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
 
 import jalview.api.AlignViewportI;
+import jalview.bin.Console;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
@@ -46,18 +59,13 @@ import jalview.io.FileFormat;
 import jalview.io.FileFormatI;
 import jalview.io.FormatAdapter;
 
-import java.awt.Color;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
 public class MappingUtilsTest
 {
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    Console.initLogger();
+  }
 
   @BeforeClass(alwaysRun = true)
   public void setUpJvOptionPane()
@@ -89,8 +97,9 @@ public class MappingUtilsTest
     MapList map = new MapList(new int[] { 5, 10 }, new int[] { 12, 13 }, 3,
             1);
     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
-    List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
-    { acf });
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
 
     /*
      * Check protein residue 12 maps to codon 5-7, 13 to codon 8-10
@@ -139,11 +148,14 @@ public class MappingUtilsTest
      * Map dna bases [6, 8, 9], [11, 13, 115] to protein residues 8 and 9
      */
     AlignedCodonFrame acf = new AlignedCodonFrame();
-    MapList map = new MapList(new int[] { 6, 6, 8, 9, 11, 11, 13, 13, 15,
-        15 }, new int[] { 8, 9 }, 3, 1);
+    MapList map = new MapList(
+            new int[]
+            { 6, 6, 8, 9, 11, 11, 13, 13, 15, 15 }, new int[] { 8, 9 }, 3,
+            1);
     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
-    List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
-    { acf });
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
 
     /*
      * Check protein residue 8 maps to [6, 8, 9]
@@ -183,8 +195,8 @@ public class MappingUtilsTest
     for (int i = 5; i < 18; i++)
     {
       sr = MappingUtils.buildSearchResults(seq1, i, acfList);
-      int residue = (i == 6 || i == 8 || i == 9) ? 8 : (i == 11 || i == 13
-              || i == 15 ? 9 : 0);
+      int residue = (i == 6 || i == 8 || i == 9) ? 8
+              : (i == 11 || i == 13 || i == 15 ? 9 : 0);
       if (residue == 0)
       {
         assertEquals(0, sr.getResults().size());
@@ -220,18 +232,19 @@ public class MappingUtilsTest
     MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 3, 1);
     for (int seq = 0; seq < 3; seq++)
     {
-      acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
-              .getSequenceAt(seq).getDatasetSequence(), map);
+      acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
+              protein.getSequenceAt(seq).getDatasetSequence(), map);
     }
-    List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
-    { acf });
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
 
     AlignViewportI dnaView = new AlignViewport(cdna);
     AlignViewportI proteinView = new AlignViewport(protein);
     protein.setCodonFrames(acfList);
 
     /*
-     * Select Seq1 and Seq3 in the protein (startRes=endRes=0)
+     * Select Seq1 and Seq3 in the protein
      */
     SequenceGroup sg = new SequenceGroup();
     sg.setColourText(true);
@@ -239,6 +252,7 @@ public class MappingUtilsTest
     sg.setOutlineColour(Color.LIGHT_GRAY);
     sg.addSequence(protein.getSequenceAt(0), false);
     sg.addSequence(protein.getSequenceAt(2), false);
+    sg.setEndRes(protein.getWidth() - 1);
 
     /*
      * Verify the mapped sequence group in dna
@@ -252,7 +266,7 @@ public class MappingUtilsTest
     assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
     assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
     assertEquals(0, mappedGroup.getStartRes());
-    assertEquals(2, mappedGroup.getEndRes());
+    assertEquals(2, mappedGroup.getEndRes()); // 3 columns (1 codon)
 
     /*
      * Verify mapping sequence group from dna to protein
@@ -285,8 +299,8 @@ public class MappingUtilsTest
   protected AlignmentI loadAlignment(final String data, FileFormatI format)
           throws IOException
   {
-    AlignmentI a = new FormatAdapter().readFile(data,
-            DataSourceType.PASTE, format);
+    AlignmentI a = new FormatAdapter().readFile(data, DataSourceType.PASTE,
+            format);
     a.setDataset(null);
     return a;
   }
@@ -331,8 +345,8 @@ public class MappingUtilsTest
     cs.clear();
     colsel.clear();
     colsel.addElement(2);
-    MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
-            dnaView, cs, hs);
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+            cs, hs);
     assertEquals("[]", cs.getSelected().toString());
 
     /*
@@ -342,8 +356,8 @@ public class MappingUtilsTest
     cs.clear();
     colsel.clear();
     colsel.addElement(3);
-    MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
-            dnaView, cs, hs);
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+            cs, hs);
     assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
 
     /*
@@ -354,10 +368,10 @@ public class MappingUtilsTest
     colsel.clear();
     colsel.addElement(1);
     colsel.addElement(3);
-    MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
-            dnaView, cs, hs);
-    assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
-            .toString());
+    MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
+            cs, hs);
+    assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]",
+            cs.getSelected().toString());
   }
 
   /**
@@ -386,23 +400,27 @@ public class MappingUtilsTest
     // map first dna to first protein seq
     AlignedCodonFrame acf = new AlignedCodonFrame();
     MapList map = new MapList(new int[] { 10, 12, 15, 15, 17, 18 },
-            new int[] { 40, 41 }, 3, 1);
-    acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(), protein
-            .getSequenceAt(0).getDatasetSequence(), map);
+            new int[]
+            { 40, 41 }, 3, 1);
+    acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(),
+            protein.getSequenceAt(0).getDatasetSequence(), map);
 
     // map second dna to second protein seq
-    map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 }, new int[] { 50,
-        51 }, 3, 1);
-    acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(), protein
-            .getSequenceAt(1).getDatasetSequence(), map);
+    map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 },
+            new int[]
+            { 50, 51 }, 3, 1);
+    acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(),
+            protein.getSequenceAt(1).getDatasetSequence(), map);
 
     // map third dna to third protein seq
-    map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 }, new int[] { 60,
-        61 }, 3, 1);
-    acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(), protein
-            .getSequenceAt(2).getDatasetSequence(), map);
-    List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
-    { acf });
+    map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 },
+            new int[]
+            { 60, 61 }, 3, 1);
+    acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(),
+            protein.getSequenceAt(2).getDatasetSequence(), map);
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
 
     dnaView = new AlignViewport(cdna);
     proteinView = new AlignViewport(protein);
@@ -465,24 +483,21 @@ public class MappingUtilsTest
   public void testFlattenRanges()
   {
     assertEquals("[1, 2, 3, 4]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4 })));
-    assertEquals(
-            "[1, 2, 3, 4]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 2, 3,
-                4 })));
-    assertEquals(
-            "[1, 2, 3, 4]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 1, 2,
-                2, 3, 3, 4, 4 })));
-    assertEquals(
-            "[1, 2, 3, 4, 7, 8, 9, 12]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
-                9, 12, 12 })));
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 1, 4 })));
+    assertEquals("[1, 2, 3, 4]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 1, 2, 3, 4 })));
+    assertEquals("[1, 2, 3, 4]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 1, 1, 2, 2, 3, 3, 4, 4 })));
+    assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 1, 4, 7, 9, 12, 12 })));
     // trailing unpaired start position is ignored:
-    assertEquals(
-            "[1, 2, 3, 4, 7, 8, 9, 12]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
-                9, 12, 12, 15 })));
+    assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 1, 4, 7, 9, 12, 12, 15 })));
   }
 
   /**
@@ -508,11 +523,12 @@ public class MappingUtilsTest
     MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
     for (int seq = 0; seq < 3; seq++)
     {
-      acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
-              .getSequenceAt(seq).getDatasetSequence(), map);
+      acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
+              protein.getSequenceAt(seq).getDatasetSequence(), map);
     }
-    List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
-    { acf });
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
 
     AlignViewportI dnaView = new AlignViewport(cdna);
     AlignViewportI proteinView = new AlignViewport(protein);
@@ -585,17 +601,19 @@ public class MappingUtilsTest
             FileFormat.Fasta);
     cdna.setDataset(null);
     AlignmentI protein = loadAlignment(
-            ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n", FileFormat.Fasta);
+            ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n",
+            FileFormat.Fasta);
     protein.setDataset(null);
     AlignedCodonFrame acf = new AlignedCodonFrame();
     MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
     for (int seq = 0; seq < 3; seq++)
     {
-      acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
-              .getSequenceAt(seq).getDatasetSequence(), map);
+      acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
+              protein.getSequenceAt(seq).getDatasetSequence(), map);
     }
-    List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
-    { acf });
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
 
     AlignViewportI dnaView = new AlignViewport(cdna);
     AlignViewportI proteinView = new AlignViewport(protein);
@@ -698,8 +716,8 @@ public class MappingUtilsTest
     /*
      * Seq1 has three mappings
      */
-    List<AlignedCodonFrame> result = MappingUtils.findMappingsForSequence(
-            seq1, mappings);
+    List<AlignedCodonFrame> result = MappingUtils
+            .findMappingsForSequence(seq1, mappings);
     assertEquals(3, result.size());
     assertTrue(result.contains(acf1));
     assertTrue(result.contains(acf2));
@@ -776,22 +794,22 @@ public class MappingUtilsTest
      */
     List<AlignedCodonFrame> result = MappingUtils
             .findMappingsForSequenceAndOthers(null, mappings,
-                    Arrays.asList(new SequenceI[] { seq1, seq2 }));
+                    Arrays.asList(new SequenceI[]
+                    { seq1, seq2 }));
     assertTrue(result.isEmpty());
 
     result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null,
-            Arrays.asList(new SequenceI[] { seq1, seq2 }));
+            Arrays.asList(new SequenceI[]
+            { seq1, seq2 }));
     assertTrue(result.isEmpty());
 
     /*
      * Seq1 has three mappings, but filter argument will only accept
      * those to seq2
      */
-    result = MappingUtils.findMappingsForSequenceAndOthers(
-            seq1,
-            mappings,
-            Arrays.asList(new SequenceI[] { seq1, seq2,
-                seq1.getDatasetSequence() }));
+    result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
+            Arrays.asList(new SequenceI[]
+            { seq1, seq2, seq1.getDatasetSequence() }));
     assertEquals(2, result.size());
     assertTrue(result.contains(acf1));
     assertTrue(result.contains(acf2));
@@ -820,7 +838,8 @@ public class MappingUtilsTest
     dna.createDatasetSequence();
     protein.createDatasetSequence();
     AlignedCodonFrame acf = new AlignedCodonFrame();
-    MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3, 1);
+    MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3,
+            1);
     acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map);
     List<AlignedCodonFrame> mappings = new ArrayList<>();
     mappings.add(acf);
@@ -835,7 +854,8 @@ public class MappingUtilsTest
      */
     EditCommand ec = new EditCommand();
     final Edit edit = ec.new Edit(Action.INSERT_GAP,
-            new SequenceI[] { protein }, 4, 2, '-');
+            new SequenceI[]
+            { protein }, 4, 2, '-');
     ec.appendEdit(edit, prot, true, null);
 
     /*
@@ -861,34 +881,29 @@ public class MappingUtilsTest
   public void testFlattenRanges_reverseStrand()
   {
     assertEquals("[4, 3, 2, 1]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 1 })));
-    assertEquals(
-            "[4, 3, 2, 1]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 3, 2,
-                1 })));
-    assertEquals(
-            "[4, 3, 2, 1]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 4, 3,
-                3, 2, 2, 1, 1 })));
-    assertEquals(
-            "[12, 9, 8, 7, 4, 3, 2, 1]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 12, 12,
-                9, 7, 4, 1 })));
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 4, 1 })));
+    assertEquals("[4, 3, 2, 1]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 4, 3, 2, 1 })));
+    assertEquals("[4, 3, 2, 1]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 4, 4, 3, 3, 2, 2, 1, 1 })));
+    assertEquals("[12, 9, 8, 7, 4, 3, 2, 1]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 12, 12, 9, 7, 4, 1 })));
     // forwards and backwards anyone?
-    assertEquals(
-            "[4, 5, 6, 3, 2, 1]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 6, 3,
-                1 })));
+    assertEquals("[4, 5, 6, 3, 2, 1]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 4, 6, 3, 1 })));
     // backwards and forwards
-    assertEquals(
-            "[3, 2, 1, 4, 5, 6]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 3, 1, 4,
-                6 })));
+    assertEquals("[3, 2, 1, 4, 5, 6]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 3, 1, 4, 6 })));
     // trailing unpaired start position is ignored:
-    assertEquals(
-            "[12, 9, 8, 7, 4, 3, 2]",
-            Arrays.toString(MappingUtils.flattenRanges(new int[] { 12, 12,
-                9, 7, 4, 2, 1 })));
+    assertEquals("[12, 9, 8, 7, 4, 3, 2]",
+            Arrays.toString(MappingUtils.flattenRanges(new int[]
+            { 12, 12, 9, 7, 4, 2, 1 })));
   }
 
   /**
@@ -1156,85 +1171,115 @@ public class MappingUtilsTest
     /*
      * both forward ranges
      */
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        1, 10 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        2, 10 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        1, 9 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        4, 5 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        0, 9 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        -10, -9 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        1, 11 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        11, 12 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 1, 10 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 2, 10 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 1, 9 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 4, 5 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 0, 9 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { -10, -9 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 1, 11 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 11, 12 }));
 
     /*
      * forward range, reverse query
      */
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        10, 1 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        9, 1 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        10, 2 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        5, 5 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        11, 1 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, new int[] {
-        10, 0 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 10, 1 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 9, 1 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 10, 2 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 5, 5 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 11, 1 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 10, 0 }));
 
     /*
      * reverse range, forward query
      */
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        1, 10 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        1, 9 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        2, 10 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        6, 6 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        6, 11 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        11, 20 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        -3, -2 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 1, 10 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 1, 9 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 2, 10 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 6, 6 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 6, 11 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 11, 20 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { -3, -2 }));
 
     /*
      * both reverse
      */
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        10, 1 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        9, 1 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        10, 2 }));
-    assertTrue(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        3, 3 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        11, 1 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        10, 0 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        12, 11 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 10, 1 }, new int[] {
-        -5, -8 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 10, 1 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 9, 1 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 10, 2 }));
+    assertTrue(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 3, 3 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 11, 1 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 10, 0 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { 12, 11 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 10, 1 }, new int[] { -5, -8 }));
 
     /*
      * bad arguments
      */
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10, 12 },
-            new int[] {
-        1, 10 }));
-    assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 },
-            new int[] { 1 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10, 12 }, new int[] { 1, 10 }));
+    assertFalse(
+            MappingUtils.rangeContains(new int[]
+            { 1, 10 }, new int[] { 1 }));
     assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, null));
     assertFalse(MappingUtils.rangeContains(null, new int[] { 1, 10 }));
   }
@@ -1284,4 +1329,123 @@ public class MappingUtilsTest
     assertEquals(1, ranges.size());
     assertEquals(9, ranges.get(0)[1]);
   }
+
+  @Test(groups = "Functional")
+  public void testFindOverlap()
+  {
+    List<int[]> ranges = new ArrayList<>();
+    ranges.add(new int[] { 4, 8 });
+    ranges.add(new int[] { 10, 12 });
+    ranges.add(new int[] { 16, 19 });
+
+    int[] overlap = MappingUtils.findOverlap(ranges, 5, 13);
+    assertArrayEquals(overlap, new int[] { 5, 12 });
+    overlap = MappingUtils.findOverlap(ranges, -100, 100);
+    assertArrayEquals(overlap, new int[] { 4, 19 });
+    overlap = MappingUtils.findOverlap(ranges, 7, 17);
+    assertArrayEquals(overlap, new int[] { 7, 17 });
+    overlap = MappingUtils.findOverlap(ranges, 13, 15);
+    assertNull(overlap);
+  }
+  
+  /**
+   * Test mapping a sequence group where sequences in and outside the group
+   * share a dataset sequence (e.g. alternative CDS for the same gene)
+   * <p>
+   * This scenario doesn't arise after JAL-3763 changes, but test left as still valid
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void testMapSequenceGroup_sharedDataset() throws IOException
+  {
+    /*
+     * Set up dna and protein Seq1/2/3 with mappings (held on the protein
+     * viewport). CDS sequences share the same 'gene' dataset sequence.
+     */
+    SequenceI dna = new Sequence("dna", "aaatttgggcccaaatttgggccc");
+    SequenceI cds1 = new Sequence("cds1/1-6", "aaattt");
+    SequenceI cds2 = new Sequence("cds1/4-9", "tttggg");
+    SequenceI cds3 = new Sequence("cds1/19-24", "gggccc");
+
+    cds1.setDatasetSequence(dna);
+    cds2.setDatasetSequence(dna);
+    cds3.setDatasetSequence(dna);
+
+    SequenceI pep1 = new Sequence("pep1", "KF");
+    SequenceI pep2 = new Sequence("pep2", "FG");
+    SequenceI pep3 = new Sequence("pep3", "GP");
+    pep1.createDatasetSequence();
+    pep2.createDatasetSequence();
+    pep3.createDatasetSequence();
+
+    /*
+     * add mappings from coding positions of dna to respective peptides
+     */
+    AlignedCodonFrame acf = new AlignedCodonFrame();
+    acf.addMap(dna, pep1,
+            new MapList(new int[]
+            { 1, 6 }, new int[] { 1, 2 }, 3, 1));
+    acf.addMap(dna, pep2,
+            new MapList(new int[]
+            { 4, 9 }, new int[] { 1, 2 }, 3, 1));
+    acf.addMap(dna, pep3,
+            new MapList(new int[]
+            { 19, 24 }, new int[] { 1, 2 }, 3, 1));
+
+    List<AlignedCodonFrame> acfList = Arrays
+            .asList(new AlignedCodonFrame[]
+            { acf });
+
+    AlignmentI cdna = new Alignment(new SequenceI[] { cds1, cds2, cds3 });
+    AlignmentI protein = new Alignment(
+            new SequenceI[]
+            { pep1, pep2, pep3 });
+    AlignViewportI cdnaView = new AlignViewport(cdna);
+    AlignViewportI peptideView = new AlignViewport(protein);
+    protein.setCodonFrames(acfList);
+
+    /*
+     * Select pep1 and pep3 in the protein alignment
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setColourText(true);
+    sg.setIdColour(Color.GREEN);
+    sg.setOutlineColour(Color.LIGHT_GRAY);
+    sg.addSequence(pep1, false);
+    sg.addSequence(pep3, false);
+    sg.setEndRes(protein.getWidth() - 1);
+
+    /*
+     * Verify the mapped sequence group in dna is cds1 and cds3
+     */
+    SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
+            peptideView, cdnaView);
+    assertTrue(mappedGroup.getColourText());
+    assertSame(sg.getIdColour(), mappedGroup.getIdColour());
+    assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
+    assertEquals(2, mappedGroup.getSequences().size());
+    assertSame(cds1, mappedGroup.getSequences().get(0));
+    assertSame(cds3, mappedGroup.getSequences().get(1));
+    // columns 1-6 selected (0-5 base zero)
+    assertEquals(0, mappedGroup.getStartRes());
+    assertEquals(5, mappedGroup.getEndRes());
+
+    /*
+     * Select mapping sequence group from dna to protein
+     */
+    sg.clear();
+    sg.addSequence(cds2, false);
+    sg.addSequence(cds1, false);
+    sg.setStartRes(0);
+    sg.setEndRes(cdna.getWidth() - 1);
+    mappedGroup = MappingUtils.mapSequenceGroup(sg, cdnaView, peptideView);
+    assertTrue(mappedGroup.getColourText());
+    assertSame(sg.getIdColour(), mappedGroup.getIdColour());
+    assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
+    assertEquals(2, mappedGroup.getSequences().size());
+    assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
+    assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
+    assertEquals(0, mappedGroup.getStartRes());
+    assertEquals(1, mappedGroup.getEndRes()); // two columns
+  }
 }
diff --git a/test/jalview/util/log4jTestProps.jvprops b/test/jalview/util/log4jTestProps.jvprops
new file mode 100644 (file)
index 0000000..c640dd1
--- /dev/null
@@ -0,0 +1,15 @@
+#---JalviewX Properties File---
+# HiDPI screen
+SCREENGEOMETRY_WIDTH=3840
+SCREENGEOMETRY_HEIGHT=2160
+SCREEN_WIDTH=3000
+SCREEN_HEIGHT=2000
+USAGESTATS=false
+STARTUP_FILE=examples/uniref50.fa
+SHOW_STARTUP_FILE=false
+FONT_STYLE=plain
+FONT_SIZE=10
+ANTI_ALIAS=false
+SHOW_JAVA_CONSOLE=false
+DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+logs.Jalview.level=DEBUG
@@ -26,6 +26,15 @@ import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceI;
@@ -35,14 +44,7 @@ import jalview.xml.binding.embl.EntryType.Feature;
 import jalview.xml.binding.embl.EntryType.Feature.Qualifier;
 import jalview.xml.binding.embl.XrefType;
 
-import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.testng.annotations.Test;
-
-public class EmblSourceTest
+public class EmblXmlSourceTest
 {
 
   // adapted from http://www.ebi.ac.uk/ena/data/view/X07547&display=xml
@@ -95,16 +97,49 @@ public class EmblSourceTest
           + "ACCCCCAATATTGTGATATAATTAAAAACATAGCAT"
           + "</sequence></entry></ROOT>";
 
+  private EmblXmlSource testee;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
+    testee = new EmblXmlSource()
+    {
+
+      @Override
+      public String getDbSource()
+      {
+        return null;
+      }
+
+      @Override
+      public String getDbName()
+      {
+        return null;
+      }
+
+      @Override
+      public String getTestQuery()
+      {
+        return null;
+      }
+
+      @Override
+      public AlignmentI getSequenceRecords(String queries) throws Exception
+      {
+        return null;
+      }
+    };
+  }
+
   @Test(groups = "Functional")
   public void testGetCdsRanges()
   {
-    EmblSource testee = new EmblSource();
-
     /*
      * Make a (CDS) Feature with 5 locations
      */
     Feature cds = new Feature();
-    cds.setLocation("join(10..20,complement(30..40),50..60,70..80,complement(110..120))");
+    cds.setLocation(
+            "join(10..20,complement(30..40),50..60,70..80,complement(110..120))");
 
     int[] exons = testee.getCdsRanges("EMBL", cds);
     assertEquals("[10, 20, 40, 30, 50, 60, 70, 80, 120, 110]",
@@ -116,10 +151,9 @@ public class EmblSourceTest
   {
     // not the whole sequence but enough for this test...
     List<SequenceI> peptides = new ArrayList<>();
-    List<EntryType> entries = EmblSourceTest.getEmblEntries();
+    List<EntryType> entries = getEmblEntries();
     assertEquals(1, entries.size());
     EntryType entry = entries.get(0);
-    EmblSource testee = new EmblSource();
     String sourceDb = "EMBL";
     SequenceI dna = testee.getSequence(sourceDb, entry, peptides);
 
@@ -165,8 +199,9 @@ public class EmblSourceTest
             3, 1);
     MapList cds2Map = new MapList(new int[] { 4, 15 }, new int[] { 1, 4 },
             3, 1);
-    MapList cds3Map = new MapList(new int[] { 4, 6, 10, 15 }, new int[] {
-        1, 3 }, 3, 1);
+    MapList cds3Map = new MapList(new int[] { 4, 6, 10, 15 },
+            new int[]
+            { 1, 3 }, 3, 1);
 
     List<DBRefEntry> dbrefs = dna.getDBRefs();
     assertEquals(7, dbrefs.size());
@@ -222,10 +257,12 @@ public class EmblSourceTest
      * - to EMBLCDS (with 1:3 mapping)
      * - direct (no mapping) to other protein accessions
      */
-    MapList proteinToCdsMap1 = new MapList(new int[] { 1, 4 }, new int[] {
-        1, 12 }, 1, 3);
-    MapList proteinToCdsMap2 = new MapList(new int[] { 1, 3 }, new int[] {
-        1, 9 }, 1, 3);
+    MapList proteinToCdsMap1 = new MapList(new int[] { 1, 4 },
+            new int[]
+            { 1, 12 }, 1, 3);
+    MapList proteinToCdsMap2 = new MapList(new int[] { 1, 3 },
+            new int[]
+            { 1, 9 }, 1, 3);
 
     // dbrefs for first CDS EMBL product CAA30420.1
     dbrefs = peptides.get(0).getDBRefs();
@@ -315,11 +352,12 @@ public class EmblSourceTest
     // exact length match:
     assertSame(exons, EmblXmlSource.adjustForProteinLength(6, exons));
 
-    // match if we assume exons include stop codon not in protein:
-    assertSame(exons, EmblXmlSource.adjustForProteinLength(5, exons));
+    // truncate last exon by 3bp (e.g. stop codon)
+    int[] truncated = EmblXmlSource.adjustForProteinLength(5, exons);
+    assertEquals("[11, 15, 21, 25, 31, 35]", Arrays.toString(truncated));
 
     // truncate last exon by 6bp
-    int[] truncated = EmblXmlSource.adjustForProteinLength(4, exons);
+    truncated = EmblXmlSource.adjustForProteinLength(4, exons);
     assertEquals("[11, 15, 21, 25, 31, 32]", Arrays.toString(truncated));
 
     // remove last exon and truncate preceding by 1bp
@@ -339,10 +377,10 @@ public class EmblSourceTest
   @Test(groups = { "Functional" })
   public void testGetEmblEntries()
   {
-    List<EntryType> entries = EmblSourceTest.getEmblEntries();
+    List<EntryType> entries = getEmblEntries();
     assertEquals(1, entries.size());
     EntryType entry = entries.get(0);
-  
+
     assertEquals("X07547", entry.getAccession());
     assertEquals("C. trachomatis plasmid", entry.getDescription());
     assertEquals("STD", entry.getDataClass());
@@ -359,7 +397,7 @@ public class EmblSourceTest
     assertEquals(2, entry.getKeyword().size());
     assertEquals("plasmid", entry.getKeyword().get(0));
     assertEquals("unidentified reading frame", entry.getKeyword().get(1));
-  
+
     /*
      * dbrefs
      */
@@ -372,7 +410,7 @@ public class EmblSourceTest
     assertEquals("MD5", dbref.getDb());
     assertEquals("ac73317", dbref.getId());
     assertNull(dbref.getSecondaryId());
-  
+
     /*
      * three sequence features for CDS
      */
@@ -403,7 +441,7 @@ public class EmblSourceTest
     q = ef.getQualifier().get(2);
     assertEquals("translation", q.getName());
     assertEquals("MLCF", q.getValue());
-  
+
     /*
      * second CDS
      */
@@ -422,7 +460,7 @@ public class EmblSourceTest
     q = ef.getQualifier().get(1);
     assertEquals("translation", q.getName());
     assertEquals("MSSS", q.getValue());
-  
+
     /*
      * third CDS
      */
@@ -438,16 +476,14 @@ public class EmblSourceTest
     q = ef.getQualifier().get(1);
     assertEquals("translation", q.getName());
     assertEquals("MSS", q.getValue());
-  
+
     /*
      * Sequence - raw data before removal of newlines
      */
     String seq = entry.getSequence();
-    assertEquals(
-            "GGTATGTCCTCTAGTACAAAC\n"
-                    + "ACCCCCAATATTGTGATATAATTAAAAACATAGCAT",
-            seq);
-  
+    assertEquals("GGTATGTCCTCTAGTACAAAC\n"
+            + "ACCCCCAATATTGTGATATAATTAAAAACATAGCAT", seq);
+
     /*
      * getSequence() converts empty DBRefEntry.version to "0"
      */
@@ -455,9 +491,9 @@ public class EmblSourceTest
     assertNull(entry.getFeature().get(0).getXref().get(1).getSecondaryId());
   }
 
-  static List<EntryType> getEmblEntries()
+  List<EntryType> getEmblEntries()
   {
-    return new EmblSource()
+    return testee
             .getEmblEntries(new ByteArrayInputStream(TESTDATA.getBytes()));
   }
 }
index d8ed08e..8bfaef0 100644 (file)
  */
 package jalview.ws.dbsources;
 
+import static org.testng.Assert.assertFalse;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceI;
 import jalview.gui.JvOptionPane;
+import jalview.util.DBRefUtils;
 import jalview.xml.binding.uniprot.DbReferenceType;
 import jalview.xml.binding.uniprot.Entry;
 import jalview.xml.binding.uniprot.FeatureType;
@@ -218,6 +222,17 @@ public class UniprotTest
     assertEquals(6, seq.getDBRefs().size()); // 2*Uniprot, PDB, PDBsum, 2*EMBL
     assertEquals(seq.getSequenceAsString(),
             seq.createDatasetSequence().getSequenceAsString());
+    assertEquals(2,seq.getPrimaryDBRefs().size());
+    List<DBRefEntry> res = DBRefUtils.searchRefs(seq.getPrimaryDBRefs(), "A9CKP4");
+    assertEquals(1,res.size());
+    assertTrue(res.get(0).isCanonical());
+    res = DBRefUtils.searchRefsForSource(seq.getDBRefs(), DBRefSource.UNIPROT);
+    assertEquals(2,res.size());
+    /*
+     * NB this test fragile - relies on ordering being preserved
+     */
+    assertTrue(res.get(0).isCanonical());
+    assertFalse(res.get(1).isCanonical());
   }
 
   /**
index c559966..c3fae6c 100644 (file)
@@ -47,13 +47,13 @@ public class EBIFetchClientTest
     /*
      * EMBL
      */
-    assertEquals("https://www.ebi.ac.uk/ena/data/view/x53838&display=xml",
+    assertEquals("https://www.ebi.ac.uk/ena/browser/api/embl/x53838?download=true&gzip=true",
             EBIFetchClient.buildUrl("X53838", "EMBL", "display=xml"));
 
     /*
      * EMBLCDS
      */
-    assertEquals("https://www.ebi.ac.uk/ena/data/view/caa37824&display=xml",
+    assertEquals("https://www.ebi.ac.uk/ena/browser/api/embl/caa37824?download=true&gzip=true",
             EBIFetchClient.buildUrl("CAA37824", "EMBL", "display=xml"));
 
     /*
index 80b48c3..f04326b 100644 (file)
  */
 package jalview.ws.gui;
 
+import java.util.Locale;
+
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.JvOptionPane;
 import jalview.gui.WsJobParameters;
 import jalview.util.MessageManager;
@@ -66,7 +69,7 @@ public class Jws2ParamView
   public static List<String> presetTests = new ArrayList<String>();
   static
   {
-    serviceTests.add("AAConWS".toLowerCase());
+    serviceTests.add("AAConWS".toLowerCase(Locale.ROOT));
   }
 
   public static Jws2Discoverer disc = null;
@@ -75,7 +78,7 @@ public class Jws2ParamView
   public static void setUpBeforeClass() throws Exception
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.initLogger();
+    Console.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
   }
 
@@ -91,7 +94,7 @@ public class Jws2ParamView
     for (Jws2Instance service : disc.getServices())
     {
       if (serviceTests.size() == 0
-              || serviceTests.contains(service.serviceType.toLowerCase()))
+              || serviceTests.contains(service.serviceType.toLowerCase(Locale.ROOT)))
       {
         List<Preset> prl = null;
         Preset pr = null;
index e8b6c2b..5656a6d 100644 (file)
  */
 package jalview.ws.jabaws;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.gui.JvOptionPane;
@@ -73,7 +76,7 @@ public class DisorderAnnotExportImport
   public static void setUpBeforeClass() throws Exception
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.initLogger();
+    Console.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
 
     while (disc.isRunning())
@@ -85,7 +88,7 @@ public class DisorderAnnotExportImport
     iupreds = new ArrayList<Jws2Instance>();
     for (Jws2Instance svc : disc.getServices())
     {
-      if (svc.getServiceTypeURI().toLowerCase().contains("iupredws"))
+      if (svc.getServiceTypeURI().toLowerCase(Locale.ROOT).contains("iupredws"))
       {
         iupreds.add(svc);
       }
index 889c003..e66f016 100644 (file)
  */
 package jalview.ws.jabaws;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.gui.JvOptionPane;
@@ -86,7 +89,7 @@ public class RNAStructExportImport
   public static void setUpBeforeClass() throws Exception
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.initLogger();
+    Console.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false);
 
     while (disc.isRunning())
@@ -98,7 +101,7 @@ public class RNAStructExportImport
     for (Jws2Instance svc : disc.getServices())
     {
 
-      if (svc.getServiceTypeURI().toLowerCase().contains("rnaalifoldws"))
+      if (svc.getServiceTypeURI().toLowerCase(Locale.ROOT).contains("rnaalifoldws"))
       {
         rnaalifoldws = svc;
       }
index c0aa2ee..052d62f 100644 (file)
  */
 package jalview.ws.jws2;
 
+import java.util.Locale;
+
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.gui.JvOptionPane;
 import jalview.ws.jabaws.JalviewJabawsTestUtils;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
@@ -68,9 +71,9 @@ public class ParameterUtilsTest
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-    serviceTests.add("AAConWS".toLowerCase());
+    serviceTests.add("AAConWS".toLowerCase(Locale.ROOT));
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.initLogger();
+    Console.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
   }
 
@@ -131,7 +134,7 @@ public class ParameterUtilsTest
   public boolean isForTesting(Jws2Instance service)
   {
     return serviceTests.size() == 0
-            || serviceTests.contains(service.serviceType.toLowerCase());
+            || serviceTests.contains(service.serviceType.toLowerCase(Locale.ROOT));
   }
 
   @Test(groups = { "Network" })
index 709f2c5..a9668a9 100644 (file)
@@ -75,7 +75,7 @@ public class ShmmrRSBSService
     RestClient rc = new RestClient(_rc.service, alf, true);
 
     assertNotNull("Couldn't creat RestClient job.", rc);
-    jalview.bin.Cache.initLogger();
+    jalview.bin.Console.initLogger();
     RestJob rjb = new RestJob(0, new RestJobThread(rc),
             rc.av.getAlignment(), null);
     rjb.setAlignmentForInputs(rc.service.getInputParams().values(),
index bf34ea5..851ab2d 100644 (file)
@@ -32,10 +32,12 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.FeatureProperties;
+import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.JvOptionPane;
 import jalview.util.DBRefUtils;
+import jalview.ws.DBRefFetcher;
 import jalview.ws.SequenceFetcher;
 import jalview.ws.dbsources.EBIAlfaFold;
 import jalview.ws.dbsources.Pdb;
@@ -70,7 +72,7 @@ public class DbRefFetcherTest
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-    jalview.bin.Cache.initLogger();
+    jalview.bin.Console.initLogger();
   }
 
   /**
@@ -81,6 +83,26 @@ public class DbRefFetcherTest
   {
   }
 
+  @Test(groups= {"Network"})
+  public void checkUniprotCanonicalFlagSet()
+  {
+    // TODO - mock this  - for moment it is a live request.
+    SequenceI uniprotSeq = new Sequence("FER1_SPIOL",
+            "MAATTTTMMGMATTFVPKPQAPPMMAALPSNTGRSLFGLKTGSRGGRMTMAAYKVTLVTPTGNVEFQCPDDV"
+            + "YILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLDDDQIDEGWVLTCAAYPVSDVTIETHKEEE"
+            + "LTA");
+    DBRefFetcher dbr = new DBRefFetcher(new SequenceI[] { uniprotSeq });
+    dbr.fetchDBRefs(true);
+    List<DBRefEntry> primRefs = uniprotSeq.getPrimaryDBRefs();
+    assertNotNull(primRefs);
+    assertTrue(primRefs.size()>0);
+    boolean canonicalUp=false;
+    for (DBRefEntry ref:primRefs) {
+      assertEquals(DBRefSource.UNIPROT, ref.getCanonicalSourceName());
+      canonicalUp |= ref.isCanonical();
+    }
+    assertTrue("No Canonical Uniprot reference detected", canonicalUp);
+  }
   /**
    * Tests that standard protein database sources include Uniprot (as the first)
    * and also PDB. (Additional sources are dependent on availability of DAS
index 23f1c6e..c5c0f04 100644 (file)
@@ -15,6 +15,8 @@
  */
 package junit.extensions;
 
+import java.util.Locale;
+
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -432,7 +434,7 @@ final class PrivilegedAccessor
       {
         return false;
       }
-      if (className.startsWith(className.substring(0, 1).toUpperCase()))
+      if (className.startsWith(className.substring(0, 1).toUpperCase(Locale.ROOT)))
       {
         return true;
       }
index 3e7e153..15b162f 100644 (file)
@@ -16,4 +16,4 @@ uod_banner.28=/images/UoD_banner-28.png
 uod_banner.30=/images/UoD_banner-30.png
 uod_banner.32=/images/UoD_banner-32.png
 default_appbase=https://www.jalview.org/getdown/release/1.8
-preferences.filename=.jalview_properties
+preferences.filename=.jalview_nonrelease_properties
index 4ef11c3..5830354 100644 (file)
@@ -8,13 +8,13 @@
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="210mm"
-   height="297mm"
-   viewBox="0 0 210 297"
+   width="132.29233mm"
+   height="132.29326mm"
+   viewBox="0 0 132.29233 132.29326"
    version="1.1"
    id="svg8"
-   inkscape:version="1.0.1 (0767f8302a, 2020-10-17)"
-   sodipodi:docname="JalviewDevelopLogo2.svg">
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+   sodipodi:docname="jalview_develop_logo.svg">
   <defs
      id="defs2">
     <linearGradient
        clipPathUnits="userSpaceOnUse"
        id="clipPath1000">
       <path
-         style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         style="fill:none;stroke:#000000;stroke-width:0.26458299px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
          d="M 87.312506,136.26042 162.71876,190.5 133.61459,206.375 H 107.15626 L 84.666668,186.53125 80.697918,158.75 Z"
-         id="path1002" />
+         id="path1002"
+         inkscape:connector-curvature="0" />
     </clipPath>
     <clipPath
        clipPathUnits="userSpaceOnUse"
        id="clipPath1093-1">
       <rect
-         style="fill:#256c7a;fill-opacity:1;stroke:#000000;stroke-width:0.850394;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:#256c7a;fill-opacity:1;stroke:#000000;stroke-width:0.85039401;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1095-8"
          width="105"
          height="229.99998"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1281">
       <rect
-         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.256539;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.25653899;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1283"
          width="34.395832"
          height="74.083336"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1285">
       <rect
-         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.256539;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.25653899;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1287"
          width="34.395832"
          height="74.083336"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1333">
       <rect
-         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.22499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1335"
          width="62.177082"
          height="54.239582"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1375">
       <rect
-         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.22499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1377"
          width="64.822914"
          height="64.822914"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1675">
       <rect
-         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.204471;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.20447101;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1677"
          width="33.037834"
          height="66.145836"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1680">
       <rect
-         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.515557;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.51555699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          id="rect1682"
          width="68.626167"
          height="129.34053"
        clipPathUnits="userSpaceOnUse"
        id="clipPath1692">
       <path
-         style="fill:none;stroke:#000000;stroke-width:0.989976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         style="fill:none;stroke:#000000;stroke-width:0.98997599px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
          d="m 162.06065,485.50479 v 69.97715 l 53.92055,4.99839 24.50939,39.98694 14.70561,4.99839 h 14.70561 V 480.5064 H 162.06065 Z"
-         id="path1694" />
+         id="path1694"
+         inkscape:connector-curvature="0" />
     </clipPath>
     <clipPath
        clipPathUnits="userSpaceOnUse"
       <path
          id="mask-powermask-path-effect945_box"
          style="fill:#ffffff;fill-opacity:1"
-         d="M 43.979163,54.562507 H 167.06656 V 178.27083 H 43.979163 Z" />
+         d="M 43.979163,54.562507 H 167.06656 V 178.27083 H 43.979163 Z"
+         inkscape:connector-curvature="0" />
       <g
          id="g943"
          style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
          transform="matrix(0.91530618,0,0,0.91999994,3.6852506,4.2711328)">
         <path
-           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
            d="m 67.791016,78.375 v 62.85352 h 25.8125 V 104.1875 h 58.855464 v 58.85352 H 44.978516 v 1 l -0.707032,0.70703 24.105469,24.10547 H 178.27148 V 78.375 Z m 2,2 H 176.27148 V 186.85352 H 69.205078 l -21.8125,-21.8125 H 154.45898 V 102.1875 H 91.603516 v 37.04102 h -21.8125 z"
-           id="path939" />
+           id="path939"
+           inkscape:connector-curvature="0" />
         <path
-           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
            d="M 43.978516,54.5625 V 165.04102 H 154.45898 V 102.1875 h -25.8125 v 37.04102 H 69.791016 V 80.375 H 177.27148 v -1 L 177.97852,78.667969 153.87305,54.5625 Z m 2,2 H 153.04492 l 21.8125,21.8125 H 67.791016 v 62.85352 H 130.64648 V 104.1875 h 21.8125 v 58.85352 H 45.978516 Z"
-           id="path941" />
+           id="path941"
+           inkscape:connector-curvature="0" />
       </g>
     </mask>
     <filter
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="1.63"
-     inkscape:cx="357.63388"
-     inkscape:cy="452.52787"
+     inkscape:zoom="4.6103362"
+     inkscape:cx="237.96116"
+     inkscape:cy="274.8671"
      inkscape:document-units="mm"
      inkscape:current-layer="layer1"
      inkscape:document-rotation="0"
      showgrid="true"
      inkscape:window-width="3840"
-     inkscape:window-height="1989"
+     inkscape:window-height="1997"
      inkscape:window-x="0"
      inkscape:window-y="0"
-     inkscape:window-maximized="1">
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0">
     <inkscape:grid
        type="xygrid"
-       id="grid10" />
+       id="grid10"
+       originx="-42.332674"
+       originy="-109.80208" />
   </sodipodi:namedview>
   <metadata
      id="metadata5">
     </rdf:RDF>
   </metadata>
   <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="underneath"
+     transform="translate(0.01538153)" />
+  <g
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
-     id="layer1">
+     id="layer1"
+     transform="translate(-42.332673,-54.904652)">
     <g
-       id="g1189"
-       transform="matrix(1.0925306,0,0,1.0869566,-4.026249,-4.642536)"
-       style="stroke:none"
-       mask="url(#mask-powermask-path-effect945)"
-       inkscape:path-effect="#path-effect945"
-       inkscape:export-xdpi="1.54"
-       inkscape:export-ydpi="1.54">
+       id="g1000">
       <path
-         style="fill:#a8008c;fill-opacity:1;stroke:none;stroke-width:0.62096px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 44.979174,55.562507 h 99.353746 l 21.73364,21.733639 H 66.712812 V 133.1826 H 44.979174 Z"
+         style="fill:#a8008c;fill-opacity:1;stroke:none;stroke-width:0.67668498px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 42.348072,54.904652 H 150.89508 l 21.08409,21.168255 H 63.5 V 142.21874 H 42.333333 Z"
          id="path12-7-3"
          sodipodi:nodetypes="ccccccc"
-         inkscape:original-d="m 44.979174,55.562507 h 99.353746 l 21.73364,21.733639 H 66.712812 V 133.1826 H 44.979174 Z" />
+         inkscape:connector-curvature="0" />
       <path
-         style="fill:#ff7200;fill-opacity:1;stroke:none;stroke-width:0.62096px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 66.712812,77.296146 h 99.353748 l -2e-5,21.733614 H 88.446427 V 133.1826 H 66.712812 Z"
+         style="fill:#ff7200;fill-opacity:1;stroke:none;stroke-width:0.67668498px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 66.145833,78.718741 H 174.625 v 21.166666 l -87.31255,-3e-6 5e-5,39.687506 H 66.145833 Z"
          id="path12-3-5-1"
          sodipodi:nodetypes="ccccccc"
-         inkscape:original-d="m 66.712812,77.296146 h 99.353748 l -2e-5,21.733614 H 88.446427 V 133.1826 H 66.712812 Z" />
+         inkscape:connector-curvature="0" />
       <path
-         style="fill:#0064b4;fill-opacity:1;stroke:none;stroke-width:0.62096px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="M 166.06654,177.27083 66.712789,176.64985 44.979174,154.91624 H 144.33292 V 99.02976 h 21.73362 z"
+         style="fill:#0064b4;fill-opacity:1;stroke:none;stroke-width:0.67668498px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 174.625,187.19791 H 66.145833 L 44.979167,166.03124 153.45834,165.76666 V 103.58958 H 174.625 Z"
          id="path12-6-9-9"
          sodipodi:nodetypes="ccccccc"
-         inkscape:original-d="M 166.06654,177.27083 66.712789,176.64985 44.979174,154.91624 H 144.33292 V 99.02976 h 21.73362 z" />
+         inkscape:connector-curvature="0" />
       <path
-         style="fill:#54c800;fill-opacity:1;stroke:none;stroke-width:0.62096px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="M 144.33292,154.91624 H 44.979174 V 133.1826 H 122.59928 V 99.02976 h 21.73364 z"
+         style="fill:#54c800;fill-opacity:1;stroke:none;stroke-width:0.67668498px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 150.8125,163.38541 H 42.333333 v -21.16667 h 87.312497 v -39.6875 h 21.16667 z"
          id="path12-3-7-2-4"
          sodipodi:nodetypes="ccccccc"
-         inkscape:original-d="M 144.33292,154.91624 H 44.979174 V 133.1826 H 122.59928 V 99.02976 h 21.73364 z" />
+         inkscape:connector-curvature="0" />
       <path
-         style="fill:url(#linearGradient1484);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 111.125,148.16666 v 30.42709 h 33.07292 v -9.26042 h -23.8125 v -21.16667 z"
+         style="fill:url(#linearGradient1484);fill-opacity:1;stroke:none;stroke-width:0.26458299px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 111.125,148.16666 -0.006,30.61821 h 34.05188 v -8.29733 h -25.79662 l -2.6e-4,-22.29908 z"
          id="path1329-7"
          sodipodi:nodetypes="ccccccc"
          clip-path="url(#clipPath1466)"
-         transform="matrix(2.3469387,0,0,2.3469387,-215.8244,-264.23234)"
-         inkscape:original-d="m 111.125,148.16666 v 30.42709 h 33.07292 v -9.26042 h -23.8125 v -21.16667 z" />
+         transform="matrix(2.5641023,0,0,2.5510205,-242.58781,-292.69847)"
+         inkscape:connector-curvature="0" />
       <path
-         style="fill:url(#linearGradient1486);fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 129.64583,145.52083 33.07292,1e-5 v 33.07291 h -9.26042 l 1e-5,-23.8125 h -23.81251 v -9.26042"
+         style="fill:url(#linearGradient1486);fill-opacity:1;stroke:none;stroke-width:0.26458299px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 128.66113,145.59554 h 34.05188 v 34.2265 h -8.255 v -25.92918 h -25.79687 v -8.29733"
          id="path1363-8"
          clip-path="url(#clipPath1471)"
-         transform="matrix(2.3469387,0,0,2.3469387,-215.8244,-264.23234)"
+         transform="matrix(2.5641023,0,0,2.5510205,-242.58781,-292.69847)"
          sodipodi:nodetypes="ccccccc"
-         inkscape:original-d="m 129.64583,145.52083 33.07292,1e-5 v 33.07291 h -9.26042 l 1e-5,-23.8125 h -23.81251 v -9.26042" />
+         inkscape:connector-curvature="0" />
     </g>
   </g>
   <g
      inkscape:groupmode="layer"
      id="layer2"
      inkscape:label="Layer 2"
-     style="display:inline;mix-blend-mode:lighten" />
+     style="display:inline;mix-blend-mode:lighten"
+     transform="translate(-42.332673,-54.904652)" />
   <g
      inkscape:groupmode="layer"
      id="layer3"
      inkscape:label="Layer 3"
-     style="display:inline;mix-blend-mode:normal" />
+     style="display:inline;mix-blend-mode:normal"
+     transform="translate(-42.332673,-54.904652)" />
 </svg>
index c7f3dba..d2ebdec 100644 (file)
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-        width="595.238px" height="595.238px" viewBox="0 0 595.238 595.238" enable-background="new 0 0 595.238 595.238"
-        xml:space="preserve">
-<rect x="234.925" y="234.464" fill="#0084A9" width="127.944" height="127.942"/>
-<polygon fill="#AD208E" points="395.955,38.359 38.788,38.359 38.823,362.389 103.187,362.389 103.187,102.72 460.325,102.72 "/>
-<polygon fill="#F78E1E" points="202.144,362.313 202.144,201.678 559.28,201.678 497.633,140.041 140.481,140.041 140.481,362.313 
-       "/>
-<polygon fill="#009DDC" points="202.225,558.595 560.882,558.607 560.848,234.574 496.501,234.574 496.501,494.26 137.861,494.236 
-       "/>
-<polygon fill="#C1D82F" points="395.688,234.646 395.688,395.282 38.904,395.282 100.535,456.929 457.329,456.929 457.329,234.646 
-       "/>
-<polygon fill="#008FC9" points="205.667,554.03 554.448,554.03 554.412,240.517 544.805,240.615 544.805,545.863 197.488,545.863 
-       "/>
-<polyline fill="#B0C62B" points="103.158,450.545 452.339,450.545 452.339,240.505 445.537,240.505 445.537,443.737 96.374,443.737 
-       "/>
-<polygon fill="#007799" points="356.649,240.339 241.236,240.339 241.236,356.261 247.337,356.261 247.337,246.708 356.649,246.708 
-       "/>
-<polygon fill="#0095B7" points="251.131,356.191 356.649,356.191 356.649,250.696 350.543,250.696 350.543,350.185 251.131,350.185 
-       "/>
-<polygon fill="#B956A0" points="97.55,356.417 97.55,96.444 446.327,96.444 436.58,86.163 87.278,86.163 87.278,356.347 "/>
-<polygon fill="#35ABE1" points="502.531,240.517 502.414,499.929 151.207,499.929 160.779,509.2 512.916,509.2 512.823,240.485 "/>
-<polygon fill="#CDDE5C" points="402.263,240.345 402.263,401.857 53.901,401.857 59.797,407.742 408.142,407.742 408.142,240.345 
-       "/>
-<polygon fill="#911076" points="53.112,356.377 53.112,52.218 404.342,52.102 395.792,43.38 43.473,43.363 43.504,356.377 "/>
-<polygon fill="#F9A24A" points="197.059,356.365 197.059,196.854 546.188,196.854 540.054,190.97 191.181,190.97 191.181,356.365 
-       "/>
-<polygon fill="#E4841C" points="155.107,356.365 155.2,153.2 502.403,153.2 495.595,146.38 147.283,146.38 147.283,356.365 "/>
-<path fill="none" stroke="#000000" stroke-width="0.1" d="M41.451,391.681"/>
-<path fill="none" stroke="#000000" stroke-width="0.1" d="M211.905,562.132"/>
-</svg>
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   width="522.09399"
+   height="522.09399"
+   viewBox="0 0 522.09402 522.09402"
+   enable-background="new 0 0 595.238 595.238"
+   xml:space="preserve"
+   sodipodi:docname="jalview_test-release_logo.svg"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
+   id="metadata41"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+   id="defs39" /><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="2569"
+   inkscape:window-height="1721"
+   id="namedview37"
+   showgrid="false"
+   fit-margin-top="0"
+   fit-margin-left="0"
+   fit-margin-right="0"
+   fit-margin-bottom="0"
+   inkscape:zoom="2.24283"
+   inkscape:cx="258.83099"
+   inkscape:cy="260.988"
+   inkscape:window-x="0"
+   inkscape:window-y="0"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Layer_1" />
+<rect
+   x="196.13701"
+   y="197.95102"
+   width="127.944"
+   height="127.942"
+   id="rect2"
+   style="fill:#0084a9" />
+<polygon
+   points="38.823,362.389 103.187,362.389 103.187,102.72 460.325,102.72 395.955,38.359 38.788,38.359 "
+   id="polygon4"
+   style="fill:#ad208e"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="559.28,201.678 497.633,140.041 140.481,140.041 140.481,362.313 202.144,362.313 202.144,201.678 "
+   id="polygon6"
+   style="fill:#f78e1e"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="560.848,234.574 496.501,234.574 496.501,494.26 137.861,494.236 202.225,558.595 560.882,558.607 "
+   id="polygon8"
+   style="fill:#009ddc"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="38.904,395.282 100.535,456.929 457.329,456.929 457.329,234.646 395.688,234.646 395.688,395.282 "
+   id="polygon10"
+   style="fill:#c1d82f"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="554.412,240.517 544.805,240.615 544.805,545.863 197.488,545.863 205.667,554.03 554.448,554.03 "
+   id="polygon12"
+   style="fill:#008fc9"
+   transform="translate(-38.788,-36.512996)" />
+<polyline
+   points="103.158,450.545 452.339,450.545 452.339,240.505 445.537,240.505 445.537,443.737 96.374,443.737   "
+   id="polyline14"
+   style="fill:#b0c62b"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="241.236,356.261 247.337,356.261 247.337,246.708 356.649,246.708 356.649,240.339 241.236,240.339 "
+   id="polygon16"
+   style="fill:#007799"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="356.649,250.696 350.543,250.696 350.543,350.185 251.131,350.185 251.131,356.191 356.649,356.191 "
+   id="polygon18"
+   style="fill:#0095b7"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="446.327,96.444 436.58,86.163 87.278,86.163 87.278,356.347 97.55,356.417 97.55,96.444 "
+   id="polygon20"
+   style="fill:#b956a0"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="151.207,499.929 160.779,509.2 512.916,509.2 512.823,240.485 502.531,240.517 502.414,499.929 "
+   id="polygon22"
+   style="fill:#35abe1"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="53.901,401.857 59.797,407.742 408.142,407.742 408.142,240.345 402.263,240.345 402.263,401.857 "
+   id="polygon24"
+   style="fill:#cdde5c"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="404.342,52.102 395.792,43.38 43.473,43.363 43.504,356.377 53.112,356.377 53.112,52.218 "
+   id="polygon26"
+   style="fill:#911076"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="546.188,196.854 540.054,190.97 191.181,190.97 191.181,356.365 197.059,356.365 197.059,196.854 "
+   id="polygon28"
+   style="fill:#f9a24a"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="502.403,153.2 495.595,146.38 147.283,146.38 147.283,356.365 155.107,356.365 155.2,153.2 "
+   id="polygon30"
+   style="fill:#e4841c"
+   transform="translate(-38.788,-36.512996)" />
+<path
+   d="M 2.663,355.168"
+   id="path32"
+   inkscape:connector-curvature="0"
+   style="fill:none;stroke:#000000;stroke-width:0.1" />
+
+</svg>
\ No newline at end of file
index cd9bf74..8247729 100644 (file)
@@ -6,16 +6,16 @@ getdown_background_image = jalview_test-release_getdown_background.png
 getdown_instant_background_image = jalview_test-release_getdown_background_initialising.png
 getdown_error_background = jalview_test-release_getdown_background_error.png
 getdown_progress_image = jalview_getdown_progress_bar.png
-getdown_mac_dock_icon = jalview_logo.icns
-getdown_icon = jalview_logo.png
+getdown_mac_dock_icon = jalview_test-release_logo.icns
+getdown_icon = jalview_test-release_logo.png
 getdown_txt_allow_offline = true
 getdown_txt_max_concurrent_downloads = 10
 getdown_txt_ui.install_error = https://www.jalview.org/faq/getdownerror
 getdown_txt_ui.hide_decorations = true
 install4j_images_dir = utils/channels/test-release/images
-install4j_mac_icons_file = jalview_logo.icns
-install4j_windows_icons_file = jalview_logo.ico
-install4j_png_icon_file = jalview_logo.png
+install4j_mac_icons_file = jalview_test-release_logo.icns
+install4j_windows_icons_file = jalview_test-release_logo.ico
+install4j_png_icon_file = jalview_test-release_logo.png
 install4j_background = jalview_logo_background_fade-640x480.png
 install4j_dmg_background = jalview_test-release_dmg_background-72dpi.png
 install4j_dmg_ds_store = jalview_test-release_dmg_DS_Store
diff --git a/utils/channels/test-release/images/jalview_logo.icns b/utils/channels/test-release/images/jalview_logo.icns
deleted file mode 100644 (file)
index 7f03345..0000000
Binary files a/utils/channels/test-release/images/jalview_logo.icns and /dev/null differ
diff --git a/utils/channels/test-release/images/jalview_logo.ico b/utils/channels/test-release/images/jalview_logo.ico
deleted file mode 100644 (file)
index 1fe7f0f..0000000
Binary files a/utils/channels/test-release/images/jalview_logo.ico and /dev/null differ
diff --git a/utils/channels/test-release/images/jalview_logo.png b/utils/channels/test-release/images/jalview_logo.png
deleted file mode 100644 (file)
index 340f8e5..0000000
Binary files a/utils/channels/test-release/images/jalview_logo.png and /dev/null differ
diff --git a/utils/channels/test-release/images/jalview_logo.svg b/utils/channels/test-release/images/jalview_logo.svg
deleted file mode 100644 (file)
index c7f3dba..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-        width="595.238px" height="595.238px" viewBox="0 0 595.238 595.238" enable-background="new 0 0 595.238 595.238"
-        xml:space="preserve">
-<rect x="234.925" y="234.464" fill="#0084A9" width="127.944" height="127.942"/>
-<polygon fill="#AD208E" points="395.955,38.359 38.788,38.359 38.823,362.389 103.187,362.389 103.187,102.72 460.325,102.72 "/>
-<polygon fill="#F78E1E" points="202.144,362.313 202.144,201.678 559.28,201.678 497.633,140.041 140.481,140.041 140.481,362.313 
-       "/>
-<polygon fill="#009DDC" points="202.225,558.595 560.882,558.607 560.848,234.574 496.501,234.574 496.501,494.26 137.861,494.236 
-       "/>
-<polygon fill="#C1D82F" points="395.688,234.646 395.688,395.282 38.904,395.282 100.535,456.929 457.329,456.929 457.329,234.646 
-       "/>
-<polygon fill="#008FC9" points="205.667,554.03 554.448,554.03 554.412,240.517 544.805,240.615 544.805,545.863 197.488,545.863 
-       "/>
-<polyline fill="#B0C62B" points="103.158,450.545 452.339,450.545 452.339,240.505 445.537,240.505 445.537,443.737 96.374,443.737 
-       "/>
-<polygon fill="#007799" points="356.649,240.339 241.236,240.339 241.236,356.261 247.337,356.261 247.337,246.708 356.649,246.708 
-       "/>
-<polygon fill="#0095B7" points="251.131,356.191 356.649,356.191 356.649,250.696 350.543,250.696 350.543,350.185 251.131,350.185 
-       "/>
-<polygon fill="#B956A0" points="97.55,356.417 97.55,96.444 446.327,96.444 436.58,86.163 87.278,86.163 87.278,356.347 "/>
-<polygon fill="#35ABE1" points="502.531,240.517 502.414,499.929 151.207,499.929 160.779,509.2 512.916,509.2 512.823,240.485 "/>
-<polygon fill="#CDDE5C" points="402.263,240.345 402.263,401.857 53.901,401.857 59.797,407.742 408.142,407.742 408.142,240.345 
-       "/>
-<polygon fill="#911076" points="53.112,356.377 53.112,52.218 404.342,52.102 395.792,43.38 43.473,43.363 43.504,356.377 "/>
-<polygon fill="#F9A24A" points="197.059,356.365 197.059,196.854 546.188,196.854 540.054,190.97 191.181,190.97 191.181,356.365 
-       "/>
-<polygon fill="#E4841C" points="155.107,356.365 155.2,153.2 502.403,153.2 495.595,146.38 147.283,146.38 147.283,356.365 "/>
-<path fill="none" stroke="#000000" stroke-width="0.1" d="M41.451,391.681"/>
-<path fill="none" stroke="#000000" stroke-width="0.1" d="M211.905,562.132"/>
-</svg>
index b7ea557..a5b6be1 100644 (file)
Binary files a/utils/channels/test-release/images/jalview_test-release_banner.xcf and b/utils/channels/test-release/images/jalview_test-release_banner.xcf differ
index e73f842..ba614d9 100644 (file)
Binary files a/utils/channels/test-release/images/jalview_test-release_getdown_background.png and b/utils/channels/test-release/images/jalview_test-release_getdown_background.png differ
similarity index 98%
rename from utils/channels/test-release/images/jalview_getdown_background.xcf
rename to utils/channels/test-release/images/jalview_test-release_getdown_background.xcf
index 8cabadd..4f0f355 100644 (file)
Binary files a/utils/channels/test-release/images/jalview_getdown_background.xcf and b/utils/channels/test-release/images/jalview_test-release_getdown_background.xcf differ
index 05b2a24..cb34bce 100644 (file)
Binary files a/utils/channels/test-release/images/jalview_test-release_getdown_background_error.png and b/utils/channels/test-release/images/jalview_test-release_getdown_background_error.png differ
index 0d6e554..fa24e1f 100644 (file)
Binary files a/utils/channels/test-release/images/jalview_test-release_getdown_background_initialising.png and b/utils/channels/test-release/images/jalview_test-release_getdown_background_initialising.png differ
diff --git a/utils/channels/test-release/images/jalview_test-release_logo-84.png b/utils/channels/test-release/images/jalview_test-release_logo-84.png
new file mode 100644 (file)
index 0000000..57ee645
Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo-84.png differ
diff --git a/utils/channels/test-release/images/jalview_test-release_logo-88.png b/utils/channels/test-release/images/jalview_test-release_logo-88.png
new file mode 100644 (file)
index 0000000..15c2111
Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo-88.png differ
diff --git a/utils/channels/test-release/images/jalview_test-release_logo.icns b/utils/channels/test-release/images/jalview_test-release_logo.icns
new file mode 100644 (file)
index 0000000..ac3b0a6
Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo.icns differ
diff --git a/utils/channels/test-release/images/jalview_test-release_logo.ico b/utils/channels/test-release/images/jalview_test-release_logo.ico
new file mode 100644 (file)
index 0000000..c86bbac
Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo.ico differ
diff --git a/utils/channels/test-release/images/jalview_test-release_logo.png b/utils/channels/test-release/images/jalview_test-release_logo.png
new file mode 100644 (file)
index 0000000..623ffaa
Binary files /dev/null and b/utils/channels/test-release/images/jalview_test-release_logo.png differ
diff --git a/utils/channels/test-release/images/jalview_test-release_logo.svg b/utils/channels/test-release/images/jalview_test-release_logo.svg
new file mode 100644 (file)
index 0000000..f9b05b8
--- /dev/null
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   width="522.09399"
+   height="522.09399"
+   viewBox="0 0 522.09402 522.09402"
+   enable-background="new 0 0 595.238 595.238"
+   xml:space="preserve"
+   sodipodi:docname="jalview_test-release_logo.svg"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+   inkscape:export-filename="/home/bsoares/Work/git/develop/jalview/utils/channels/tmp/jalview_test-release_logo-512.png"
+   inkscape:export-xdpi="94.139999"
+   inkscape:export-ydpi="94.139999"><metadata
+   id="metadata41"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+   id="defs39" /><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="2569"
+   inkscape:window-height="1721"
+   id="namedview37"
+   showgrid="false"
+   fit-margin-top="0"
+   fit-margin-left="0"
+   fit-margin-right="0"
+   fit-margin-bottom="0"
+   inkscape:zoom="0.56070751"
+   inkscape:cx="258.83099"
+   inkscape:cy="260.988"
+   inkscape:window-x="0"
+   inkscape:window-y="0"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Layer_1" />
+<rect
+   x="196.13701"
+   y="197.95102"
+   width="127.944"
+   height="127.942"
+   id="rect2"
+   style="fill:#ffffff;fill-opacity:1" />
+<polygon
+   points="38.823,362.389 103.187,362.389 103.187,102.72 460.325,102.72 395.955,38.359 38.788,38.359 "
+   id="polygon4"
+   style="fill:#ad208e"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="559.28,201.678 497.633,140.041 140.481,140.041 140.481,362.313 202.144,362.313 202.144,201.678 "
+   id="polygon6"
+   style="fill:#f78e1e"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="560.848,234.574 496.501,234.574 496.501,494.26 137.861,494.236 202.225,558.595 560.882,558.607 "
+   id="polygon8"
+   style="fill:#009ddc"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="38.904,395.282 100.535,456.929 457.329,456.929 457.329,234.646 395.688,234.646 395.688,395.282 "
+   id="polygon10"
+   style="fill:#c1d82f"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="554.412,240.517 544.805,240.615 544.805,545.863 197.488,545.863 205.667,554.03 554.448,554.03 "
+   id="polygon12"
+   style="fill:#008fc9"
+   transform="translate(-38.788,-36.512996)" />
+<polyline
+   points="103.158,450.545 452.339,450.545 452.339,240.505 445.537,240.505 445.537,443.737 96.374,443.737   "
+   id="polyline14"
+   style="fill:#b0c62b"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="241.236,356.261 247.337,356.261 247.337,246.708 356.649,246.708 356.649,240.339 241.236,240.339 "
+   id="polygon16"
+   style="fill:#d4d4d4;fill-opacity:1"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="356.649,250.696 350.543,250.696 350.543,350.185 251.131,350.185 251.131,356.191 356.649,356.191 "
+   id="polygon18"
+   style="fill:#f1f1f1;fill-opacity:1"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="446.327,96.444 436.58,86.163 87.278,86.163 87.278,356.347 97.55,356.417 97.55,96.444 "
+   id="polygon20"
+   style="fill:#b956a0"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="151.207,499.929 160.779,509.2 512.916,509.2 512.823,240.485 502.531,240.517 502.414,499.929 "
+   id="polygon22"
+   style="fill:#35abe1"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="53.901,401.857 59.797,407.742 408.142,407.742 408.142,240.345 402.263,240.345 402.263,401.857 "
+   id="polygon24"
+   style="fill:#cdde5c"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="404.342,52.102 395.792,43.38 43.473,43.363 43.504,356.377 53.112,356.377 53.112,52.218 "
+   id="polygon26"
+   style="fill:#911076"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="546.188,196.854 540.054,190.97 191.181,190.97 191.181,356.365 197.059,356.365 197.059,196.854 "
+   id="polygon28"
+   style="fill:#f9a24a"
+   transform="translate(-38.788,-36.512996)" />
+<polygon
+   points="502.403,153.2 495.595,146.38 147.283,146.38 147.283,356.365 155.107,356.365 155.2,153.2 "
+   id="polygon30"
+   style="fill:#e4841c"
+   transform="translate(-38.788,-36.512996)" />
+<path
+   d="M 2.663,355.168"
+   id="path32"
+   inkscape:connector-curvature="0"
+   style="fill:none;stroke:#000000;stroke-width:0.1" />
+
+</svg>
\ No newline at end of file
index 0ab4f86..e337bf8 100644 (file)
@@ -1,19 +1,19 @@
 app_name=Jalview Test
 banner=/images/jalview_test-release_banner.png
-logo.16=/images/jalview_logo-16.png
-logo.32=/images/jalview_logo-32.png
-logo.38=/images/jalview_logo-38.png
-logo.48=/images/jalview_logo-48.png
-logo.64=/images/jalview_logo-64.png
-logo.128=/images/jalview_logo-128.png
-logo.256=/images/jalview_logo-256.png
-logo.512=/images/jalview_logo-512.png
-rotatable_logo.48=/images/rotatable_jalview_logo-38.png
+logo.16=/images/jalview_test-release_logo-16.png
+logo.32=/images/jalview_test-release_logo-32.png
+logo.38=/images/jalview_test-release_logo-38.png
+logo.48=/images/jalview_test-release_logo-48.png
+logo.64=/images/jalview_test-release_logo-64.png
+logo.128=/images/jalview_test-release_logo-128.png
+logo.256=/images/jalview_test-release_logo-256.png
+logo.512=/images/jalview_test-release_logo-512.png
+rotatable_logo.48=/images/rotatable_jalview_test-release_logo-38.png
 bg_logo.28=/images/barton_group-28.png
 bg_logo.30=/images/barton_group-30.png
 bg_logo.32=/images/barton_group-32.png
 uod_banner.28=/images/UoD_banner-28.png
 uod_banner.30=/images/UoD_banner-30.png
 uod_banner.32=/images/UoD_banner-32.png
-default_appbase=https://www.jalview.org/getdown/release/1.8
-preferences.filename=.jalview_properties
+default_appbase=https://www.jalview.org/getdown/test-release/1.8
+preferences.filename=.jalview_test_properties
diff --git a/utils/channels/test-release/resources/images/jalview_logo-128.png b/utils/channels/test-release/resources/images/jalview_logo-128.png
deleted file mode 100644 (file)
index 63fa253..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-128.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-16.png b/utils/channels/test-release/resources/images/jalview_logo-16.png
deleted file mode 100644 (file)
index 9a1adfb..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-16.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-256.png b/utils/channels/test-release/resources/images/jalview_logo-256.png
deleted file mode 100644 (file)
index 6963612..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-256.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-32.png b/utils/channels/test-release/resources/images/jalview_logo-32.png
deleted file mode 100644 (file)
index 7af5791..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-32.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-38.png b/utils/channels/test-release/resources/images/jalview_logo-38.png
deleted file mode 100644 (file)
index 0b60196..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-38.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-48.png b/utils/channels/test-release/resources/images/jalview_logo-48.png
deleted file mode 100644 (file)
index 297e6cc..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-48.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-512.png b/utils/channels/test-release/resources/images/jalview_logo-512.png
deleted file mode 100644 (file)
index 340f8e5..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-512.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/jalview_logo-64.png b/utils/channels/test-release/resources/images/jalview_logo-64.png
deleted file mode 100644 (file)
index 2505ae9..0000000
Binary files a/utils/channels/test-release/resources/images/jalview_logo-64.png and /dev/null differ
index e4aed51..5ba07b8 100644 (file)
Binary files a/utils/channels/test-release/resources/images/jalview_test-release_banner.png and b/utils/channels/test-release/resources/images/jalview_test-release_banner.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-128.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-128.png
new file mode 100644 (file)
index 0000000..5e351f8
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-128.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-16.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-16.png
new file mode 100644 (file)
index 0000000..6c398dd
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-16.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-256.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-256.png
new file mode 100644 (file)
index 0000000..7f9af58
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-256.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-32.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-32.png
new file mode 100644 (file)
index 0000000..ecc0a38
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-32.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-38.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-38.png
new file mode 100644 (file)
index 0000000..5438d4e
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-38.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-48.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-48.png
new file mode 100644 (file)
index 0000000..108f927
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-48.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-512.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-512.png
new file mode 100644 (file)
index 0000000..623ffaa
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-512.png differ
diff --git a/utils/channels/test-release/resources/images/jalview_test-release_logo-64.png b/utils/channels/test-release/resources/images/jalview_test-release_logo-64.png
new file mode 100644 (file)
index 0000000..a599ba3
Binary files /dev/null and b/utils/channels/test-release/resources/images/jalview_test-release_logo-64.png differ
diff --git a/utils/channels/test-release/resources/images/rotatable_jalview_logo-38.png b/utils/channels/test-release/resources/images/rotatable_jalview_logo-38.png
deleted file mode 100644 (file)
index e584298..0000000
Binary files a/utils/channels/test-release/resources/images/rotatable_jalview_logo-38.png and /dev/null differ
diff --git a/utils/channels/test-release/resources/images/rotatable_jalview_test-release_logo-38.png b/utils/channels/test-release/resources/images/rotatable_jalview_test-release_logo-38.png
new file mode 100644 (file)
index 0000000..53b6ec7
Binary files /dev/null and b/utils/channels/test-release/resources/images/rotatable_jalview_test-release_logo-38.png differ
diff --git a/utils/create_iconfiles.sh b/utils/create_iconfiles.sh
deleted file mode 100755 (executable)
index 241c195..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env bash
-
-# given a list of differently sized png files with the size in the filename like this:
-# myiconfile-16.png myiconfile-32.png myiconfile-48.png myiconfile-64.png myiconfile-128.png myiconfile-256.png myiconfile-512.png
-# run
-# create_iconfiles.sh myiconfile-*.png
-# to create an ICO file (for Windows) myiconfile.ico and an ICNS file (for macOS) myiconfile.icns
-
-BASENAME=${1%-*}
-if [ x$BASENAME = x ]; then
-  echo "Could not calculate basename from '${1}'"
-  exit 1
-fi
-
-ICOFILE=${BASENAME}.ico
-echo "Creating ${ICOFILE}"
-convert $* ${ICOFILE}
-
-ICNSFILE=${BASENAME}.icns
-echo "Creating ${ICNSFILE}"
-# dont' include 64x64 icon (for some reason they're not allowed in icns file)
-ICNSARGS=""
-for ARG in $*; do
-  NUM=${ARG##*-}
-  NUM=${NUM%px*}
-  NUM=${NUM%x*}
-  NUM=${NUM%.*}
-  if [ x$NUM != x64 -a x$NUM != x38 ]; then
-    ICNSARGS="${ICNSARGS} $ARG"
-  fi
-done
-png2icns ${ICNSFILE} ${ICNSARGS}
diff --git a/utils/debian/build_gradle.patch b/utils/debian/build_gradle.patch
new file mode 100644 (file)
index 0000000..1527c79
--- /dev/null
@@ -0,0 +1,2909 @@
+--- a/build.gradle     2021-09-21 09:52:04.653972716 +0100
++++ b/build.gradle     2021-09-21 09:52:18.117985307 +0100
+@@ -2,56 +2,12 @@
+  * For properties set within build.gradle, use camelCaseNoSpace.
+  */
+ import org.apache.tools.ant.filters.ReplaceTokens
+-import org.gradle.internal.os.OperatingSystem
+-import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
+-import org.gradle.api.internal.PropertiesTransformer
+-import org.gradle.util.ConfigureUtil
+-import org.gradle.plugins.ide.eclipse.model.Output
+-import org.gradle.plugins.ide.eclipse.model.Library
+-import java.security.MessageDigest
+-import groovy.transform.ExternalizeMethods
+-import groovy.util.XmlParser
+-import groovy.xml.XmlUtil
+-import com.vladsch.flexmark.util.ast.Node
+-import com.vladsch.flexmark.html.HtmlRenderer
+-import com.vladsch.flexmark.parser.Parser
+-import com.vladsch.flexmark.util.data.MutableDataSet
+-import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
+-import com.vladsch.flexmark.ext.tables.TablesExtension
+-import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
+-import com.vladsch.flexmark.ext.autolink.AutolinkExtension
+-import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
+-import com.vladsch.flexmark.ext.toc.TocExtension
+-
+-buildscript {
+-  repositories {
+-    mavenCentral()
+-    mavenLocal()
+-  }
+-  dependencies {
+-    classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
+-  }
+-}
+-
+ plugins {
+   id 'java'
+   id 'application'
+-  id 'eclipse'
+-  id "com.diffplug.gradle.spotless" version "3.28.0"
+-  id 'com.github.johnrengelman.shadow' version '4.0.3'
+-  id 'com.install4j.gradle' version '8.0.10'
+-  id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
+-  id 'com.palantir.git-version' version '0.12.3'
+-}
+-
+-repositories {
+-  jcenter()
+-  mavenCentral()
+-  mavenLocal()
+ }
+-
+ // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
+ def string(Object o) {
+   return o == null ? "" : o.toString()
+@@ -92,23 +48,15 @@
+   }
+ }
+-ext {
++project.ext {
+   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
+   jalviewDirRelativePath = jalviewDir
+-  getdownChannelName = CHANNEL.toLowerCase()
+-  // default to "default". Currently only has different cosmetics for "develop", "release", "default"
+-  propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
+-  // Import channel_properties
++  propertiesChannelName = "release"
+   channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
+   channelGradleProperties = string("${channelDir}/channel_gradle.properties")
+   overrideProperties(channelGradleProperties, false)
+-  // local build environment properties
+-  // can be "projectDir/local.properties"
+-  overrideProperties("${projectDir}/local.properties", true)
+-  // or "../projectDir_local.properties"
+-  overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
+-
++  
+   ////  
+   // Import releaseProps from the RELEASE file
+   // or a file specified via JALVIEW_RELEASE_FILE if defined
+@@ -128,41 +76,6 @@
+   if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
+     JALVIEW_VERSION = releaseProps.get("jalview.version")
+   }
+-  
+-  // this property set when running Eclipse headlessly
+-  j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
+-  // this property set by Eclipse
+-  eclipseApplicationProperty = string("eclipse.application")
+-  // CHECK IF RUNNING FROM WITHIN ECLIPSE
+-  def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
+-  IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
+-  // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
+-  if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
+-    println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
+-    IN_ECLIPSE = false
+-  }
+-  if (IN_ECLIPSE) {
+-    println("WITHIN ECLIPSE IDE")
+-  } else {
+-    println("HEADLESS BUILD")
+-  }
+-  
+-  J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
+-  if (J2S_ENABLED) {
+-    println("J2S ENABLED")
+-  } 
+-  /* *-/
+-  System.properties.sort { it.key }.each {
+-    key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
+-  }
+-  /-* *-/
+-  if (false && IN_ECLIPSE) {
+-    jalviewDir = jalviewDirAbsolutePath
+-  }
+-  */
+-
+-  // datestamp
+-  buildDate = new Date().format("yyyyMMdd")
+   // essentials
+   bareSourceDir = string(source_dir)
+@@ -173,218 +86,18 @@
+   classesDir = string("${jalviewDir}/${classes_dir}")
+-  // clover
+-  useClover = clover.equals("true")
+-  cloverBuildDir = "${buildDir}/clover"
+-  cloverInstrDir = file("${cloverBuildDir}/clover-instr")
+-  cloverClassesDir = file("${cloverBuildDir}/clover-classes")
+-  cloverReportDir = file("${buildDir}/reports/clover")
+-  cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
+-  cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
+-  //cloverTestClassesDir = cloverClassesDir
+-  cloverDb = string("${cloverBuildDir}/clover.db")
+-
+-  testSourceDir = useClover ? cloverTestInstrDir : testDir
+-  testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
+-
+-  getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
+-  buildDist = true
+-  buildProperties = null
+-
+-  // the following values might be overridden by the CHANNEL switch
+-  getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
+-  getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
+-  getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
+-  getdownAppDistDir = getdown_app_dir_alt
+-  getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
+-  getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
+-  reportRsyncCommand = false
+-  jvlChannelName = CHANNEL.toLowerCase()
+-  install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
+-  install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
+-  install4jDMGBackgroundImage = "${install4j_images_dir}/${install4j_dmg_background}"
+-  install4jInstallerName = "${jalview_name} Non-Release Installer"
+-  install4jExecutableName = install4j_executable_name
+-  install4jExtraScheme = "jalviewx"
+-  install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
+-  install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
+-  install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
+-  install4jBackground = string("${install4j_images_dir}/${install4j_background}")
+-  switch (CHANNEL) {
+-
+-    case "BUILD":
+-    // TODO: get bamboo build artifact URL for getdown artifacts
+-    getdown_channel_base = bamboo_channelbase
+-    getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
+-    getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
+-    jvlChannelName += "_${getdownChannelName}"
+-    // automatically add the test group Not-bamboo for exclusion 
+-    if ("".equals(testng_excluded_groups)) { 
+-      testng_excluded_groups = "Not-bamboo"
+-    }
+-    install4jExtraScheme = "jalviewb"
+-    break
++  useClover = false
+-    case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
+-    getdownAppDistDir = getdown_app_dir_release
+-    reportRsyncCommand = true
+-    install4jSuffix = ""
+-    install4jInstallerName = "${jalview_name} Installer"
+-    break
+-
+-    case "ARCHIVE":
+-    getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
+-    getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
+-    getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
+-    if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
+-      throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
+-    } else {
+-      package_dir = string("${ARCHIVEDIR}/${package_dir}")
+-      buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
+-      buildDist = false
+-    }
+-    reportRsyncCommand = true
+-    install4jExtraScheme = "jalviewa"
+-    break
+-
+-    case "ARCHIVELOCAL":
+-    getdownChannelName = string("archive/${JALVIEW_VERSION}")
+-    getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
+-    getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+-    if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
+-      throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
+-    } else {
+-      package_dir = string("${ARCHIVEDIR}/${package_dir}")
+-      buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
+-      buildDist = false
+-    }
+-    reportRsyncCommand = true
+-    getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+-    install4jSuffix = "Archive"
+-    install4jExtraScheme = "jalviewa"
+-    break
+-
+-    case "DEVELOP":
+-    reportRsyncCommand = true
+-    getdownSetAppBaseProperty = true
+-    // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
+-    JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
+-    
+-    install4jSuffix = "Develop"
+-    install4jExtraScheme = "jalviewd"
+-    install4jInstallerName = "${jalview_name} Develop Installer"
+-    break
+-
+-    case "TEST-RELEASE":
+-    reportRsyncCommand = true
+-    // Don't ignore transpile errors for release build
+-    if (jalviewjs_ignore_transpile_errors.equals("true")) {
+-      jalviewjs_ignore_transpile_errors = "false"
+-      println("Setting jalviewjs_ignore_transpile_errors to 'false'")
+-    }
+-    JALVIEW_VERSION = JALVIEW_VERSION+"-test"
+-    install4jSuffix = "Test"
+-    install4jExtraScheme = "jalviewt"
+-    install4jInstallerName = "${jalview_name} Test Installer"
+-    break
+-
+-    case ~/^SCRATCH(|-[-\w]*)$/:
+-    getdownChannelName = CHANNEL
+-    JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
+-    
+-    getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
+-    getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
+-    reportRsyncCommand = true
+-    install4jSuffix = "Scratch"
+-    break
+-
+-    case "TEST-LOCAL":
+-    if (!file("${LOCALDIR}").exists()) {
+-      throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
+-    } else {
+-      getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
+-      getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+-    }
+-    JALVIEW_VERSION = "TEST"
+-    install4jSuffix = "Test-Local"
+-    install4jExtraScheme = "jalviewt"
+-    install4jInstallerName = "${jalview_name} Test Installer"
+-    break
+-
+-    case [ "LOCAL", "JALVIEWJS" ]:
+-    JALVIEW_VERSION = "TEST"
+-    getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+-    getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+-    install4jExtraScheme = "jalviewl"
+-    break
+-
+-    default: // something wrong specified
+-    throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
+-    break
+-
+-  }
+-  // override getdownAppBase if requested
+-  if (findProperty("getdown_appbase_override") != null) {
+-    // revert to LOCAL if empty string
+-    if (string(getdown_appbase_override) == "") {
+-      getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+-      getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+-    } else if (string(getdown_appbase_override).startsWith("file://")) {
+-      getdownAppBase = string(getdown_appbase_override)
+-      getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+-    } else {
+-      getdownAppBase = string(getdown_appbase_override)
+-    }
+-    println("Overriding getdown appbase with '${getdownAppBase}'")
+-  }
+-  // sanitise file name for jalview launcher file for this channel
+-  jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
+-  // install4j application and folder names
+-  if (install4jSuffix == "") {
+-    install4jApplicationName = "${jalview_name}"
+-    install4jBundleId = "${install4j_bundle_id}"
+-    install4jWinApplicationId = install4j_release_win_application_id
+-  } else {
+-    install4jApplicationName = "${jalview_name} ${install4jSuffix}"
+-    install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
+-    // add int hash of install4jSuffix to the last part of the application_id
+-    def id = install4j_release_win_application_id
+-    def idsplitreverse = id.split("-").reverse()
+-    idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
+-    install4jWinApplicationId = idsplitreverse.reverse().join("-")
+-  }
+-  // sanitise folder and id names
+-  // install4jApplicationFolder = e.g. "Jalview Build"
+-  install4jApplicationFolder = install4jApplicationName
+-                                    .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
+-                                    .replaceAll("_+", "_") // collapse __
+-  install4jInternalId = install4jApplicationName
+-                                    .replaceAll(" ","_")
+-                                    .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
+-                                    .replaceAll("_+", "") // collapse __
+-                                    //.replaceAll("_*-_*", "-") // collapse _-_
+-  install4jUnixApplicationFolder = install4jApplicationName
+-                                    .replaceAll(" ","_")
+-                                    .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
+-                                    .replaceAll("_+", "_") // collapse __
+-                                    .replaceAll("_*-_*", "-") // collapse _-_
+-                                    .toLowerCase()
+-
+-  getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
+-  getdownAppDir = string("${getdownWebsiteDir}/${getdownAppDistDir}")
+-  //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
+-  getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
+-  getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
+-  getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
+-  getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
+-  /* compile without modules -- using classpath libraries
+-  modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
+-  modules_runtimeClasspath = modules_compileClasspath
+-  */
+-  def details = versionDetails()
+-  gitHash = details.gitHash
+-  gitBranch = details.branchName
++  resourceClassesDir = classesDir
++
++  testSourceDir = testDir
++  testClassesDir = "${jalviewDir}/${test_output_dir}"
++  buildProperties = string("${classesDir}/${build_properties_file}")
++  getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
++
++  install4jApplicationName = "${jalview_name}"
++  
+   println("Using a ${CHANNEL} profile.")
+   additional_compiler_args = []
+@@ -396,71 +109,16 @@
+     libDistDir = j8libDir
+     compile_source_compatibility = 1.8
+     compile_target_compatibility = 1.8
+-    // these are getdown.txt properties defined dependent on the JAVA_VERSION
+-    getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
+-    getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
+-    // this property is assigned below and expanded to multiple lines in the getdown task
+-    getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
+-    // this property is for the Java library used in eclipse
+-    eclipseJavaRuntimeName = string("JavaSE-1.8")
+   } else if (JAVA_VERSION.equals("11")) {
+     JAVA_INTEGER_VERSION = string("11")
+     libDir = j11libDir
+     libDistDir = j11libDir
+     compile_source_compatibility = 11
+     compile_target_compatibility = 11
+-    getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
+-    getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
+-    getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
+-    eclipseJavaRuntimeName = string("JavaSE-11")
+-    /* compile without modules -- using classpath libraries
+-    additional_compiler_args += [
+-    '--module-path', modules_compileClasspath.asPath,
+-    '--add-modules', j11modules
+-    ]
+-     */
+-  } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
+-    JAVA_INTEGER_VERSION = JAVA_VERSION
+-    libDir = j11libDir
+-    libDistDir = j11libDir
+-    compile_source_compatibility = JAVA_VERSION
+-    compile_target_compatibility = JAVA_VERSION
+-    getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
+-    getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
+-    getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
+-    eclipseJavaRuntimeName = string("JavaSE-11")
+-    /* compile without modules -- using classpath libraries
+-    additional_compiler_args += [
+-    '--module-path', modules_compileClasspath.asPath,
+-    '--add-modules', j11modules
+-    ]
+-     */
+   } else {
+     throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
+   }
+-
+-  // for install4j
+-  JAVA_MIN_VERSION = JAVA_VERSION
+-  JAVA_MAX_VERSION = JAVA_VERSION
+-  def jreInstallsDir = string(jre_installs_dir)
+-  if (jreInstallsDir.startsWith("~/")) {
+-    jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
+-  }
+-  macosJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-mac-x64/jre")
+-  macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-mac-x64.tar.gz")
+-  windowsJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-windows-x64/jre")
+-  windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-windows-x64.tar.gz")
+-  linuxJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-linux-x64/jre")
+-  linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-linux-x64.tar.gz")
+-  install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
+-  install4jConfFileName = string("jalview-install4j-conf.install4j")
+-  install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
+-  install4jHomeDir = install4j_home_dir
+-  if (install4jHomeDir.startsWith("~/")) {
+-    install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
+-  }
+-
+   resourceBuildDir = string("${buildDir}/resources")
+   resourcesBuildDir = string("${resourceBuildDir}/resources_build")
+   helpBuildDir = string("${resourceBuildDir}/help_build")
+@@ -474,31 +132,6 @@
+   helpSourceDir = string("${helpParentDir}/${help_dir}")
+   helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
+-
+-  relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
+-  jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
+-  jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
+-  if (IN_ECLIPSE) {
+-    jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
+-  } else {
+-    jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
+-  }
+-  jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
+-  jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
+-  jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
+-  jalviewjsJalviewCoreHtmlFile = string("")
+-  jalviewjsJalviewCoreName = string(jalviewjs_core_name)
+-  jalviewjsCoreClasslists = []
+-  jalviewjsJalviewTemplateName = string(jalviewjs_name)
+-  jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
+-  jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
+-  jalviewjsJ2sProps = null
+-  jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
+-
+-  eclipseWorkspace = null
+-  eclipseBinary = string("")
+-  eclipseVersion = string("")
+-  eclipseDebug = false
+   // ENDEXT
+ }
+@@ -517,27 +150,12 @@
+     compileClasspath = files(sourceSets.main.java.outputDir)
+     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
+-    runtimeClasspath = compileClasspath
+-    runtimeClasspath += files(sourceSets.main.resources.srcDirs)
+-  }
+-
+-  clover {
+-    java {
+-      srcDirs cloverInstrDir
+-      outputDir = cloverClassesDir
+-    }
+-
+-    resources {
+-      srcDirs = sourceSets.main.resources.srcDirs
+-    }
+-    compileClasspath = files( sourceSets.clover.java.outputDir )
+-    //compileClasspath += files( testClassesDir )
++    compileClasspath = files(sourceSets.main.java.outputDir)
+     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
+-    compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
+-    compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
+     runtimeClasspath = compileClasspath
++    runtimeClasspath += files(sourceSets.main.resources.srcDirs)
+   }
+   test {
+@@ -557,453 +175,41 @@
+     runtimeClasspath = compileClasspath
+     runtimeClasspath += files(sourceSets.test.resources.srcDirs)
+   }
+-
+-}
+-
+-
+-// eclipse project and settings files creation, also used by buildship
+-eclipse {
+-  project {
+-    name = eclipse_project_name
+-
+-    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
+-    configurations.each{ c->
+-      if (c.isCanBeResolved()) {
+-        minusConfigurations += [c]
+-      }
+-    }
+-
+-    plusConfigurations = [ ]
+-    file {
+-
+-      whenMerged { cp ->
+-        def removeTheseToo = []
+-        HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
+-        cp.entries.each { entry ->
+-          // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
+-          // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
+-          // we add the resources and help/help dirs in as libs afterwards (see below)
+-          if (entry.kind == 'src') {
+-            if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
+-              removeTheseToo += entry
+-            } else {
+-              alreadyAddedSrcPath.putAt(entry.path, true)
+-            }
+-          }
+-
+-        }
+-        cp.entries.removeAll(removeTheseToo)
+-
+-        //cp.entries += new Output("${eclipse_bin_dir}/main")
+-        if (file(helpParentDir).isDirectory()) {
+-          cp.entries += new Library(fileReference(helpParentDir))
+-        }
+-        if (file(resourceDir).isDirectory()) {
+-          cp.entries += new Library(fileReference(resourceDir))
+-        }
+-
+-        HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
+-
+-        sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
+-          //don't 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, especially if they don't exist
+-            return false // groovy "continue" in .any closure
+-          }
+-          def itPath = it.toString()
+-          if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
+-            // make relative path
+-            itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
+-          }
+-          if (alreadyAddedLibPath.get(itPath)) {
+-            //println("Not adding duplicate entry "+itPath)
+-          } else {
+-            //println("Adding entry "+itPath)
+-            cp.entries += new Library(fileReference(itPath))
+-            alreadyAddedLibPath.put(itPath, true)
+-          }
+-        }
+-
+-        sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
+-          //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
+-            return false // groovy "continue" in .any closure
+-          }
+-
+-          def itPath = it.toString()
+-          if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
+-            itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
+-          }
+-          if (alreadyAddedLibPath.get(itPath)) {
+-            // don't duplicate
+-          } else {
+-            def lib = new Library(fileReference(itPath))
+-            lib.entryAttributes["test"] = "true"
+-            cp.entries += lib
+-            alreadyAddedLibPath.put(itPath, true)
+-          }
+-        }
+-
+-      } // whenMerged
+-
+-    } // file
+-
+-    containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
+-
+-  } // classpath
+-
+-  jdt {
+-    // for the IDE, use java 11 compatibility
+-    sourceCompatibility = compile_source_compatibility
+-    targetCompatibility = compile_target_compatibility
+-    javaRuntimeName = eclipseJavaRuntimeName
+-
+-    // add in jalview project specific properties/preferences into eclipse core preferences
+-    file {
+-      withProperties { props ->
+-        def jalview_prefs = new Properties()
+-        def ins = new FileInputStream("${jalviewDirAbsolutePath}/${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)
+-          }
+-        }
+-        // codestyle file -- overrides previous formatter prefs
+-        def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
+-        if (csFile.exists()) {
+-          XmlParser parser = new XmlParser()
+-          def profiles = parser.parse(csFile)
+-          def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
+-          if (profile != null) {
+-            profile.'setting'.each { s ->
+-              def id = s.'@id'
+-              def value = s.'@value'
+-              if (id != null && value != null) {
+-                props.putAt(id, value)
+-              }
+-            }
+-          }
+-        }
+-      }
+-    }
+-
+-  } // jdt
+-
+-  if (IN_ECLIPSE) {
+-    // Don't want these to be activated if in headless build
+-    synchronizationTasks "eclipseSynchronizationTask"
+-    //autoBuildTasks "eclipseAutoBuildTask"
+-
+-  }
+-}
+-
+-
+-/* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
+-// Class to allow updating arbitrary properties files
+-class PropertiesFile extends PropertiesPersistableConfigurationObject {
+-  public PropertiesFile(PropertiesTransformer t) { super(t); }
+-  @Override protected void load(Properties properties) { }
+-  @Override protected void store(Properties properties) { }
+-  @Override protected String getDefaultResourceName() { return ""; }
+-  // This is necessary, because PropertiesPersistableConfigurationObject fails
+-  // if no default properties file exists.
+-  @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
+-}
+-
+-// Task to update arbitrary properties files (set outputFile)
+-class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
+-  private final PropertiesFileContentMerger file;
+-  public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
+-  protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
+-  protected void configure(PropertiesFile props) {
+-    file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
+-  }
+-  public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
+-}
+-
+-task eclipseUIPreferences(type: PropertiesFileTask) {
+-  description = "Generate Eclipse additional settings"
+-  def filename = "org.eclipse.jdt.ui.prefs"
+-  outputFile = "$projectDir/.settings/${filename}" as File
+-  file {
+-    withProperties {
+-      it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
++ /*  test {
++    java {
++      srcDirs testSourceDir
++      outputDir = file(testClassesDir)
+     }
+-  }
+-}
+-task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
+-  description = "Generate Eclipse additional settings"
+-  def filename = "org.eclipse.jdt.groovy.core.prefs"
+-  outputFile = "$projectDir/.settings/${filename}" as File
+-  file {
+-    withProperties {
+-      it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
++    resources {
++      srcDirs = sourceSets.main.resources.srcDirs
+     }
+-  }
+-}
+-
+-task eclipseAllPreferences {
+-  dependsOn eclipseJdt
+-  dependsOn eclipseUIPreferences
+-  dependsOn eclipseGroovyCorePreferences
+-}
+-
+-eclipseUIPreferences.mustRunAfter eclipseJdt
+-eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
+-
+-/* end of eclipse preferences hack */
+-
+-
+-// clover bits
+-
+-
+-task cleanClover {
+-  doFirst {
+-    delete cloverBuildDir
+-    delete cloverReportDir
+-  }
+-}
+-
+-
+-task cloverInstrJava(type: JavaExec) {
+-  group = "Verification"
+-  description = "Create clover instrumented source java files"
+-
+-  dependsOn cleanClover
+-
+-  inputs.files(sourceSets.main.allJava)
+-  outputs.dir(cloverInstrDir)
+-
+-  //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
+-  classpath = sourceSets.clover.compileClasspath
+-  main = "com.atlassian.clover.CloverInstr"
+-
+-  def argsList = [
+-    "--encoding",
+-    "UTF-8",
+-    "--initstring",
+-    cloverDb,
+-    "--destdir",
+-    cloverInstrDir.getPath(),
+-  ]
+-  def srcFiles = sourceSets.main.allJava.files
+-  argsList.addAll(
+-    srcFiles.collect(
+-      { file -> file.absolutePath }
+-    )
+-  )
+-  args argsList.toArray()
+-
+-  doFirst {
+-    delete cloverInstrDir
+-    println("Clover: About to instrument "+srcFiles.size() +" files")
+-  }
+-}
+-
+-
+-task cloverInstrTests(type: JavaExec) {
+-  group = "Verification"
+-  description = "Create clover instrumented source test files"
+-
+-  dependsOn cleanClover
+-
+-  inputs.files(testDir)
+-  outputs.dir(cloverTestInstrDir)
+-
+-  classpath = sourceSets.clover.compileClasspath
+-  main = "com.atlassian.clover.CloverInstr"
+-
+-  def argsList = [
+-    "--encoding",
+-    "UTF-8",
+-    "--initstring",
+-    cloverDb,
+-    "--srcdir",
+-    testDir,
+-    "--destdir",
+-    cloverTestInstrDir.getPath(),
+-  ]
+-  args argsList.toArray()
+-
+-  doFirst {
+-    delete cloverTestInstrDir
+-    println("Clover: About to instrument test files")
+-  }
+-}
+-
+-
+-task cloverInstr {
+-  group = "Verification"
+-  description = "Create clover instrumented all source files"
+-
+-  dependsOn cloverInstrJava
+-  dependsOn cloverInstrTests
+-}
+-
+-
+-cloverClasses.dependsOn cloverInstr
+-
+-
+-task cloverConsoleReport(type: JavaExec) {
+-  group = "Verification"
+-  description = "Creates clover console report"
+-
+-  onlyIf {
+-    file(cloverDb).exists()
+-  }
+-
+-  inputs.dir cloverClassesDir
+-
+-  classpath = sourceSets.clover.runtimeClasspath
+-  main = "com.atlassian.clover.reporters.console.ConsoleReporter"
+-
+-  if (cloverreport_mem.length() > 0) {
+-    maxHeapSize = cloverreport_mem
+-  }
+-  if (cloverreport_jvmargs.length() > 0) {
+-    jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
+-  }
+-
+-  def argsList = [
+-    "--alwaysreport",
+-    "--initstring",
+-    cloverDb,
+-    "--unittests"
+-  ]
+-
+-  args argsList.toArray()
+-}
+-
+-
+-task cloverHtmlReport(type: JavaExec) {
+-  group = "Verification"
+-  description = "Creates clover HTML report"
+-
+-  onlyIf {
+-    file(cloverDb).exists()
+-  }
+-
+-  def cloverHtmlDir = cloverReportDir
+-  inputs.dir cloverClassesDir
+-  outputs.dir cloverHtmlDir
+-
+-  classpath = sourceSets.clover.runtimeClasspath
+-  main = "com.atlassian.clover.reporters.html.HtmlReporter"
+-
+-  if (cloverreport_mem.length() > 0) {
+-    maxHeapSize = cloverreport_mem
+-  }
+-  if (cloverreport_jvmargs.length() > 0) {
+-    jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
+-  }
+-
+-  def argsList = [
+-    "--alwaysreport",
+-    "--initstring",
+-    cloverDb,
+-    "--outputdir",
+-    cloverHtmlDir
+-  ]
+-
+-  if (cloverreport_html_options.length() > 0) {
+-    argsList += cloverreport_html_options.split(" ")
+-  }
+-
+-  args argsList.toArray()
+-}
+-
+-
+-task cloverXmlReport(type: JavaExec) {
+-  group = "Verification"
+-  description = "Creates clover XML report"
+-
+-  onlyIf {
+-    file(cloverDb).exists()
+-  }
+-
+-  def cloverXmlFile = "${cloverReportDir}/clover.xml"
+-  inputs.dir cloverClassesDir
+-  outputs.file cloverXmlFile
+-
+-  classpath = sourceSets.clover.runtimeClasspath
+-  main = "com.atlassian.clover.reporters.xml.XMLReporter"
+-
+-  if (cloverreport_mem.length() > 0) {
+-    maxHeapSize = cloverreport_mem
+-  }
+-  if (cloverreport_jvmargs.length() > 0) {
+-    jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
+-  }
+-
+-  def argsList = [
+-    "--alwaysreport",
+-    "--initstring",
+-    cloverDb,
+-    "--outfile",
+-    cloverXmlFile
+-  ]
+-
+-  if (cloverreport_xml_options.length() > 0) {
+-    argsList += cloverreport_xml_options.split(" ")
+-  }
+-
+-  args argsList.toArray()
+-}
++    compileClasspath = files( sourceSets.test.java.outputDir )
++    compileClasspath += sourceSets.main.compileClasspath
++    compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**   REMOVE_THIS_GAP  /*.jar"])
+-task cloverReport {
+-  group = "Verification"
+-  description = "Creates clover reports"
+-
+-  dependsOn cloverXmlReport
+-  dependsOn cloverHtmlReport
+-}
+-
+-
+-compileCloverJava {
+-
+-  doFirst {
+-    sourceCompatibility = compile_source_compatibility
+-    targetCompatibility = compile_target_compatibility
+-    options.compilerArgs += additional_compiler_args
+-    print ("Setting target compatibility to "+targetCompatibility+"\n")
++    runtimeClasspath = compileClasspath
+   }
+-  //classpath += configurations.cloverRuntime
++*/
+ }
+-// end clover bits
+ compileJava {
+-  // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
+   sourceCompatibility = compile_source_compatibility
+   targetCompatibility = compile_target_compatibility
+   options.compilerArgs = additional_compiler_args
+-  options.encoding = "UTF-8"
+   doFirst {
+     print ("Setting target compatibility to "+compile_target_compatibility+"\n")
+   }
+-
+ }
+ compileTestJava {
+-  sourceCompatibility = compile_source_compatibility
+-  targetCompatibility = compile_target_compatibility
+-  options.compilerArgs = additional_compiler_args
+   doFirst {
++    sourceCompatibility = compile_source_compatibility
++    targetCompatibility = compile_target_compatibility
++    options.compilerArgs = additional_compiler_args
+     print ("Setting target compatibility to "+targetCompatibility+"\n")
+   }
+ }
+@@ -1017,7 +223,6 @@
+ cleanTest {
+-  dependsOn cleanClover
+   doFirst {
+     delete sourceSets.test.java.outputDir
+   }
+@@ -1031,85 +236,6 @@
+ }
+-def convertMdToHtml (FileTree mdFiles, File cssFile) {
+-  MutableDataSet options = new MutableDataSet()
+-
+-  def extensions = new ArrayList<>()
+-  extensions.add(AnchorLinkExtension.create()) 
+-  extensions.add(AutolinkExtension.create())
+-  extensions.add(StrikethroughExtension.create())
+-  extensions.add(TaskListExtension.create())
+-  extensions.add(TablesExtension.create())
+-  extensions.add(TocExtension.create())
+-  
+-  options.set(Parser.EXTENSIONS, extensions)
+-
+-  // set GFM table parsing options
+-  options.set(TablesExtension.WITH_CAPTION, false)
+-  options.set(TablesExtension.COLUMN_SPANS, false)
+-  options.set(TablesExtension.MIN_HEADER_ROWS, 1)
+-  options.set(TablesExtension.MAX_HEADER_ROWS, 1)
+-  options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
+-  options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
+-  options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
+-  // GFM anchor links
+-  options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
+-  options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
+-  options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
+-  options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
+-
+-  Parser parser = Parser.builder(options).build()
+-  HtmlRenderer renderer = HtmlRenderer.builder(options).build()
+-
+-  mdFiles.each { mdFile ->
+-    // add table of contents
+-    def mdText = "[TOC]\n"+mdFile.text
+-
+-    // grab the first top-level title
+-    def title = null
+-    def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
+-    def matcher = mdText =~ titleRegex
+-    if (matcher.size() > 0) {
+-      // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
+-      title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
+-    }
+-    // or use the filename if none found
+-    if (title == null) {
+-      title = mdFile.getName()
+-    }
+-
+-    Node document = parser.parse(mdText)
+-    String htmlBody = renderer.render(document)
+-    def htmlText = '''<html>
+-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+-<html xmlns="http://www.w3.org/1999/xhtml">
+-  <head>
+-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+-    <meta http-equiv="Content-Style-Type" content="text/css" />
+-    <meta name="generator" content="flexmark" />
+-'''
+-    htmlText += ((title != null) ? "  <title>${title}</title>" : '' )
+-    htmlText += '''
+-    <style type="text/css">code{white-space: pre;}</style>
+-'''
+-    htmlText += ((cssFile != null) ? cssFile.text : '')
+-    htmlText += '''</head>
+-  <body>
+-'''
+-    htmlText += htmlBody
+-    htmlText += '''
+-  </body>
+-</html>
+-'''
+-
+-    def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
+-    def htmlFile = file(htmlFilePath)
+-    println("Creating ${htmlFilePath}")
+-    htmlFile.text = htmlText
+-  }
+-}
+-
+-
+ task copyDocs(type: Copy) {
+   def inputDir = "${jalviewDir}/${doc_dir}"
+   def outputDir = "${docBuildDir}/${doc_dir}"
+@@ -1140,27 +266,6 @@
+ }
+-task convertMdFiles {
+-  dependsOn copyDocs
+-  def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
+-  def cssFile = file("${jalviewDir}/${flexmark_css}")
+-
+-  doLast {
+-    convertMdToHtml(mdFiles, cssFile)
+-  }
+-
+-  inputs.files(mdFiles)
+-  inputs.file(cssFile)
+-
+-  def htmlFiles = []
+-  mdFiles.each { mdFile ->
+-    def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
+-    htmlFiles.add(file(htmlFilePath))
+-  }
+-  outputs.files(htmlFiles)
+-}
+-
+-
+ task copyHelp(type: Copy) {
+   def inputDir = helpSourceDir
+   def outputDir = "${helpBuildDir}/${help_dir}"
+@@ -1242,24 +347,15 @@
+   outputs.dir(outputDir)
+ }
+-task createBuildProperties(type: WriteProperties) {
+-  dependsOn copyResources
+-  group = "build"
+-  description = "Create the ${buildProperties} file"
+-  
+-  inputs.dir(sourceDir)
+-  inputs.dir(resourcesBuildDir)
+-  outputFile (buildProperties)
+-  // taking time 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("HH:mm:ss dd MMMM yyyy")
+-  property "VERSION", JALVIEW_VERSION
+-  property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
+-  if (getdownSetAppBaseProperty) {
+-    property "GETDOWNAPPBASE", getdownAppBase
+-    property "GETDOWNAPPDISTDIR", getdownAppDistDir
+-  }
++task createBuildProperties(type: Copy) {
++  // using the build_properties already included in the source tarball
++  def inputFile = "build_properties"
++  def outputFile = buildProperties
++  from inputFile
++  into file(outputFile).getParent()
++  rename(file(inputFile).getName(), file(outputFile).getName())
++
++  inputs.file(inputFile)
+   outputs.file(outputFile)
+ }
+@@ -1293,7 +389,6 @@
+   dependsOn buildResources
+   dependsOn copyDocs
+   dependsOn copyHelp
+-  dependsOn convertMdFiles
+   dependsOn buildIndices
+ }
+@@ -1306,12 +401,7 @@
+ //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
+ test {
+   dependsOn prepare
+-
+-  if (useClover) {
+-    dependsOn cloverClasses
+-   } else { //?
+-    dependsOn compileJava //?
+-  }
++  dependsOn compileJava //?
+   useTestNG() {
+     includeGroups testng_groups
+@@ -1323,6 +413,7 @@
+   maxHeapSize = "1024m"
+   workingDir = jalviewDir
++  //systemProperties 'clover.jar' System.properties.clover.jar
+   def testLaf = project.findProperty("test_laf")
+   if (testLaf != null) {
+     println("Setting Test LaF to '${testLaf}'")
+@@ -1338,9 +429,6 @@
+   jvmArgs += additional_compiler_args
+   doFirst {
+-    if (useClover) {
+-      println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
+-    }
+   }
+ }
+@@ -1420,1752 +508,7 @@
+   sourceSets.main.resources.srcDirs.each{ dir ->
+     inputs.dir(dir)
+   }
+-  outputs.file("${outputDir}/${archiveFileName}")
+-}
+-
+-
+-task copyJars(type: Copy) {
+-  from fileTree(dir: classesDir, include: "**/*.jar").files
+-  into "${jalviewDir}/${package_dir}"
+-}
+-
+-
+-// doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
+-task syncJars(type: Sync) {
+-  dependsOn jar
+-  from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
+-  into "${jalviewDir}/${package_dir}"
+-  preserve {
+-    include jar.archiveFileName.getOrNull()
+-  }
+-}
+-
+-
+-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}/${package_dir}")
+-}
+-
+-
+-task cleanDist {
+-  dependsOn cleanPackageDir
+-  dependsOn cleanTest
+-  dependsOn clean
+-}
+-
+-
+-shadowJar {
+-  group = "distribution"
+-  description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
+-  if (buildDist) {
+-    dependsOn makeDist
+-  }
+-  from ("${jalviewDir}/${libDistDir}") {
+-    include("*.jar")
+-  }
+-  manifest {
+-    attributes "Implementation-Version": JALVIEW_VERSION,
+-    "Application-Name": install4jApplicationName
+-  }
+-  mainClassName = shadow_jar_main_class
+-  mergeServiceFiles()
+-  classifier = "all-"+JALVIEW_VERSION+"-j"+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"
+-  if (buildDist) {
+-    dependsOn makeDist
+-  }
+-
+-  def getdownWebsiteResourceFilenames = []
+-  def getdownTextString = ""
+-  def getdownResourceDir = getdownResourceDir
+-  def getdownResourceFilenames = []
+-
+-  doFirst {
+-    // clean the getdown website and files dir before creating getdown folders
+-    delete getdownWebsiteDir
+-    delete getdownFilesDir
+-
+-    copy {
+-      from buildProperties
+-      rename(file(buildProperties).getName(), getdown_build_properties)
+-      into getdownAppDir
+-    }
+-    getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
+-
+-    // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
+-    def props = project.properties.sort { it.key }
+-    if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
+-      props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
+-    }
+-    if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
+-      props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
+-    }
+-    if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
+-      props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
+-    }
+-    if (getdownImagesDir != null && file(getdownImagesDir).exists()) {
+-      props.put("getdown_txt_ui.background_image", "${getdownImagesDir}/${getdown_background_image}")
+-      props.put("getdown_txt_ui.instant_background_image", "${getdownImagesDir}/${getdown_instant_background_image}")
+-      props.put("getdown_txt_ui.error_background", "${getdownImagesDir}/${getdown_error_background}")
+-      props.put("getdown_txt_ui.progress_image", "${getdownImagesDir}/${getdown_progress_image}")
+-      props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
+-      props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
+-    }
+-
+-    props.put("getdown_txt_title", jalview_name)
+-    props.put("getdown_txt_ui.name", install4jApplicationName)
+-
+-    // start with appbase
+-    getdownTextString += "appbase = ${getdownAppBase}\n"
+-    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 || prop.startsWith("getdown_txt_resource")) {
+-            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()
+-            }
+-          }
+-          if (! prop.startsWith("getdown_txt_resource")) {
+-            def line = prop.substring(12) + " = ${val}\n"
+-            getdownTextString += line
+-          }
+-        }
+-      }
+-    }
+-
+-    getdownWebsiteResourceFilenames.each{ filename ->
+-      getdownTextString += "resource = ${filename}\n"
+-    }
+-    getdownResourceFilenames.each{ filename ->
+-      copy {
+-        from filename
+-        into getdownResourceDir
+-      }
+-    }
+-    
+-    def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
+-    getdownWrapperScripts.each{ script ->
+-      def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
+-      if (s.exists()) {
+-        copy {
+-          from s
+-          into "${getdownWebsiteDir}/${getdown_wrapper_script_dir}"
+-        }
+-        getdownTextString += "resource = ${getdown_wrapper_script_dir}/${script}\n"
+-      }
+-    }
+-
+-    def codeFiles = []
+-    fileTree(file(package_dir)).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 name = f.getName()
+-      def line = "code = ${getdownAppDistDir}/${name}\n"
+-      getdownTextString += line
+-      copy {
+-        from f.getPath()
+-        into 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 name = f.getName()
+-    def line = "code = ${getdown_j11lib_dir}/${name}\n"
+-    getdownTextString += line
+-    copy {
+-    from f.getPath()
+-    into getdownJ11libDir
+-    }
+-    }
+-    }
+-     */
+-
+-    // getdown-launcher.jar should not be in main application class path so the main application can move it when updated.  Listed as a resource so it gets updated.
+-    //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
+-    getdownTextString += "resource = ${getdown_launcher_new}\n"
+-    getdownTextString += "class = ${main_class}\n"
+-    // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
+-    if (getdownSetAppBaseProperty) {
+-      getdownTextString += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}\n"
+-      getdownTextString += "jvmarg = -Dgetdownappbase=${getdownAppBase}\n"
+-    }
+-
+-    def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
+-    getdown_txt.write(getdownTextString)
+-
+-    def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
+-    def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
+-    launchJvl.write("appbase=${getdownAppBase}")
+-
+-    // files going into the getdown website dir: getdown-launcher.jar
+-    copy {
+-      from getdownLauncher
+-      rename(file(getdownLauncher).getName(), getdown_launcher_new)
+-      into getdownWebsiteDir
+-    }
+-
+-    // files going into the getdown website dir: getdown-launcher(-local).jar
+-    copy {
+-      from getdownLauncher
+-      if (file(getdownLauncher).getName() != getdown_launcher) {
+-        rename(file(getdownLauncher).getName(), getdown_launcher)
+-      }
+-      into getdownWebsiteDir
+-    }
+-
+-    // files going into the getdown website dir: ./install dir and files
+-    if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
+-      copy {
+-        from getdown_txt
+-        from getdownLauncher
+-        from "${getdownAppDir}/${getdown_build_properties}"
+-        if (file(getdownLauncher).getName() != getdown_launcher) {
+-          rename(file(getdownLauncher).getName(), getdown_launcher)
+-        }
+-        into getdownInstallDir
+-      }
+-
+-      // and make a copy in the getdown files dir (these are not downloaded by getdown)
+-      copy {
+-        from getdownInstallDir
+-        into getdownFilesInstallDir
+-      }
+-    }
+-
+-    // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
+-    copy {
+-      from getdown_txt
+-      from launchJvl
+-      from getdownLauncher
+-      from "${getdownWebsiteDir}/${getdown_build_properties}"
+-      if (file(getdownLauncher).getName() != getdown_launcher) {
+-        rename(file(getdownLauncher).getName(), getdown_launcher)
+-      }
+-      into getdownFilesDir
+-    }
+-
+-    // and ./resources (not all downloaded by getdown)
+-    copy {
+-      from getdownResourceDir
+-      into "${getdownFilesDir}/${getdown_resource_dir}"
+-    }
+-  }
+-
+-  if (buildDist) {
+-    inputs.dir("${jalviewDir}/${package_dir}")
+-  }
+-  outputs.dir(getdownWebsiteDir)
+-  outputs.dir(getdownFilesDir)
+-}
+-
+-
+-// a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
+-task getdownDigestDir(type: JavaExec) {
+-  group "Help"
+-  description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
+-
+-  def digestDirPropertyName = "DIGESTDIR"
+-  doFirst {
+-    classpath = files(getdownLauncher)
+-    def digestDir = findProperty(digestDirPropertyName)
+-    if (digestDir == null) {
+-      throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
+-    }
+-    args digestDir
+-  }
+-  main = "com.threerings.getdown.tools.Digester"
+-}
+-
+-
+-task getdownDigest(type: JavaExec) {
+-  group = "distribution"
+-  description = "Digest the getdown website folder"
+-  dependsOn getdownWebsite
+-  doFirst {
+-    classpath = files(getdownLauncher)
+-  }
+-  main = "com.threerings.getdown.tools.Digester"
+-  args getdownWebsiteDir
+-  inputs.dir(getdownWebsiteDir)
+-  outputs.file("${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
+-  doLast {
+-    if (reportRsyncCommand) {
+-      def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
+-      def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
+-      println "LIKELY RSYNC COMMAND:"
+-      println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
+-      if (RUNRSYNC == "true") {
+-        exec {
+-          commandLine "mkdir", "-p", toDir
+-        }
+-        exec {
+-          commandLine "rsync", "-avh", "--delete", fromDir, toDir
+-        }
+-      }
+-    }
+-  }
+-}
+-
+-
+-tasks.withType(JavaCompile) {
+-      options.encoding = 'UTF-8'
+-}
+-
+-
+-clean {
+-  doFirst {
+-    delete getdownWebsiteDir
+-    delete getdownFilesDir
+-  }
+-}
+-
+-
+-install4j {
+-  if (file(install4jHomeDir).exists()) {
+-    // good to go!
+-  } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
+-    install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
+-  } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
+-    install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
+-  }
+-  installDir(file(install4jHomeDir))
+-
+-  mediaTypes = Arrays.asList(install4j_media_types.split(","))
+-}
+-
+-
+-task copyInstall4jTemplate {
+-  def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
+-  def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
+-  inputs.file(install4jTemplateFile)
+-  inputs.file(install4jFileAssociationsFile)
+-  inputs.property("CHANNEL", { CHANNEL })
+-  outputs.file(install4jConfFile)
+-
+-  doLast {
+-    def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
+-
+-    // turn off code signing if no OSX_KEYPASS
+-    if (OSX_KEYPASS == "") {
+-      install4jConfigXml.'**'.codeSigning.each { codeSigning ->
+-        codeSigning.'@macEnabled' = "false"
+-      }
+-      install4jConfigXml.'**'.windows.each { windows ->
+-        windows.'@runPostProcessor' = "false"
+-      }
+-    }
+-
+-    // turn off checksum creation for LOCAL channel
+-    def e = install4jConfigXml.application[0]
+-    if (CHANNEL == "LOCAL") {
+-      e.'@createChecksums' = "false"
+-    } else {
+-      e.'@createChecksums' = "true"
+-    }
+-
+-    // put file association actions where placeholder action is
+-    def install4jFileAssociationsText = install4jFileAssociationsFile.text
+-    def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
+-    install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
+-      if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
+-        def parent = a.parent()
+-        parent.remove(a)
+-        fileAssociationActions.each { faa ->
+-            parent.append(faa)
+-        }
+-        // don't need to continue in .any loop once replacements have been made
+-        return true
+-      }
+-    }
+-
+-    // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
+-    // NB we're deleting the /other/ one!
+-    // Also remove the examples subdir from non-release versions
+-    def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
+-    // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
+-    if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
+-      customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
+-    } else {
+-      // remove the examples subdir from Full File Set
+-      def files = install4jConfigXml.files[0]
+-      def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
+-      def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
+-      def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
+-      def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
+-      dirEntry.parent().remove(dirEntry)
+-    }
+-    install4jConfigXml.'**'.action.any { a ->
+-      if (a.'@customizedId' == customizedIdToDelete) {
+-        def parent = a.parent()
+-        parent.remove(a)
+-        return true
+-      }
+-    }
+-
+-    // write install4j file
+-    install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
+-  }
+-}
+-
+-
+-clean {
+-  doFirst {
+-    delete install4jConfFile
+-  }
+-}
+-
+-
+-task installers(type: com.install4j.gradle.Install4jTask) {
+-  group = "distribution"
+-  description = "Create the install4j installers"
+-  dependsOn getdown
+-  dependsOn copyInstall4jTemplate
+-
+-  projectFile = install4jConfFile
+-
+-  // create an md5 for the input files to use as version for install4j conf file
+-  def digest = MessageDigest.getInstance("MD5")
+-  digest.update(
+-    (file("${install4jDir}/${install4j_template}").text + 
+-    file("${install4jDir}/${install4j_info_plist_file_associations}").text +
+-    file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
+-  def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
+-  if (filesMd5.length() >= 8) {
+-    filesMd5 = filesMd5.substring(0,8)
+-  }
+-  def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
+-  // make install4jBuildDir relative to jalviewDir
+-  def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
+-
+-  variables = [
+-    'JALVIEW_NAME': jalview_name,
+-    'JALVIEW_APPLICATION_NAME': install4jApplicationName,
+-    'JALVIEW_DIR': "../..",
+-    'OSX_KEYSTORE': OSX_KEYSTORE,
+-    'OSX_APPLEID': OSX_APPLEID,
+-    'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
+-    'JSIGN_SH': JSIGN_SH,
+-    'JRE_DIR': getdown_app_dir_java,
+-    'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
+-    'JALVIEW_VERSION': JALVIEW_VERSION,
+-    'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
+-    'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
+-    'JAVA_VERSION': JAVA_VERSION,
+-    'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
+-    'VERSION': JALVIEW_VERSION,
+-    'MACOS_JAVA_VM_DIR': macosJavaVMDir,
+-    'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
+-    'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
+-    'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
+-    'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
+-    'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
+-    'COPYRIGHT_MESSAGE': install4j_copyright_message,
+-    'BUNDLE_ID': install4jBundleId,
+-    'INTERNAL_ID': install4jInternalId,
+-    'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
+-    'MACOS_DMG_DS_STORE': install4jDMGDSStore,
+-    'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
+-    'WRAPPER_LINK': getdownWrapperLink,
+-    'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
+-    'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
+-    'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
+-    'INSTALLER_NAME': install4jInstallerName,
+-    'INSTALL4J_UTILS_DIR': install4j_utils_dir,
+-    'GETDOWN_WEBSITE_DIR': getdown_website_dir,
+-    'GETDOWN_FILES_DIR': getdown_files_dir,
+-    'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
+-    'GETDOWN_DIST_DIR': getdownAppDistDir,
+-    'GETDOWN_ALT_DIR': getdown_app_dir_alt,
+-    'GETDOWN_INSTALL_DIR': getdown_install_dir,
+-    'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
+-    'BUILD_DIR': install4jBuildDir,
+-    'APPLICATION_CATEGORIES': install4j_application_categories,
+-    'APPLICATION_FOLDER': install4jApplicationFolder,
+-    'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
+-    'EXECUTABLE_NAME': install4jExecutableName,
+-    'EXTRA_SCHEME': install4jExtraScheme,
+-    'MAC_ICONS_FILE': install4jMacIconsFile,
+-    'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
+-    'PNG_ICON_FILE': install4jPngIconFile,
+-    'BACKGROUND': install4jBackground,
+-
+-  ]
+-
+-  //println("INSTALL4J VARIABLES:")
+-  //variables.each{k,v->println("${k}=${v}")}
+-
+-  destination = "${jalviewDir}/${install4jBuildDir}"
+-  buildSelected = true
+-
+-  if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
+-    faster = true
+-    disableSigning = true
+-    disableNotarization = true
+-  }
+-
+-  if (OSX_KEYPASS) {
+-    macKeystorePassword = OSX_KEYPASS
+-  } 
+-  
+-  if (OSX_ALTOOLPASS) {
+-    appleIdPassword = OSX_ALTOOLPASS
+-    disableNotarization = false
+-  } else {
+-    disableNotarization = true
+-  }
+-
+-  doFirst {
+-    println("Using projectFile "+projectFile)
+-    if (!disableNotarization) { println("Will notarize OSX App DMG") }
+-  }
+-  //verbose=true
+-
+-  inputs.dir(getdownWebsiteDir)
+-  inputs.file(install4jConfFile)
+-  inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
+-  inputs.dir(macosJavaVMDir)
+-  inputs.dir(windowsJavaVMDir)
+-  outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
+-}
+-
+-
+-spotless {
+-  java {
+-    eclipse().configFile(eclipse_codestyle_file)
+-  }
+-}
+-
+-
+-task sourceDist(type: Tar) {
+-  group "distribution"
+-  description "Create a source .tar.gz file for distribution"
+-
+-  dependsOn createBuildProperties
+-  dependsOn convertMdFiles
+-
+-  def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
+-  def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
+-  archiveFileName = outputFileName
+-  
+-  compression Compression.GZIP
+-  
+-  into project.name
+-
+-  def EXCLUDE_FILES=[
+-    "build/*",
+-    "bin/*",
+-    "test-output/",
+-    "test-reports",
+-    "tests",
+-    "clover*/*",
+-    ".*",
+-    "benchmarking/*",
+-    "**/.*",
+-    "*.class",
+-    "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
+-    "*locales/**",
+-    "utils/InstallAnywhere",
+-    "**/*.log",
+-  ] 
+-  def PROCESS_FILES=[
+-    "AUTHORS",
+-    "CITATION",
+-    "FEATURETODO",
+-    "JAVA-11-README",
+-    "FEATURETODO",
+-    "LICENSE",
+-    "**/README",
+-    "RELEASE",
+-    "THIRDPARTYLIBS",
+-    "TESTNG",
+-    "build.gradle",
+-    "gradle.properties",
+-    "**/*.java",
+-    "**/*.html",
+-    "**/*.xml",
+-    "**/*.gradle",
+-    "**/*.groovy",
+-    "**/*.properties",
+-    "**/*.perl",
+-    "**/*.sh",
+-  ]
+-  def INCLUDE_FILES=[
+-    ".settings/org.eclipse.jdt.core.jalview.prefs",
+-  ]
+-
+-  from(jalviewDir) {
+-    exclude (EXCLUDE_FILES)
+-    include (PROCESS_FILES)
+-    filter(ReplaceTokens,
+-      beginToken: '$$',
+-      endToken: '$$',
+-      tokens: [
+-        'Version-Rel': JALVIEW_VERSION,
+-        'Year-Rel': getDate("yyyy")
+-      ]
+-    )
+-  }
+-  from(jalviewDir) {
+-    exclude (EXCLUDE_FILES)
+-    exclude (PROCESS_FILES)
+-    exclude ("appletlib")
+-    exclude ("**/*locales")
+-    exclude ("*locales/**")
+-    exclude ("utils/InstallAnywhere")
+-
+-    exclude (getdown_files_dir)
+-    exclude (getdown_website_dir)
+-
+-    // exluding these as not using jars as modules yet
+-    exclude ("${j11modDir}/**/*.jar")
+-  }
+-  from(jalviewDir) {
+-    include(INCLUDE_FILES)
+-  }
+-//  from (jalviewDir) {
+-//    // explicit includes for stuff that seemed to not get included
+-//    include(fileTree("test/**/*."))
+-//    exclude(EXCLUDE_FILES)
+-//    exclude(PROCESS_FILES)
+-//  }
+-
+-  from(file(buildProperties).getParent()) {
+-    include(file(buildProperties).getName())
+-    rename(file(buildProperties).getName(), "build_properties")
+-    filter({ line ->
+-      line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
+-    })
+-  }
+-
+-}
+-
+-
+-task helppages {
+-  dependsOn copyHelp
+-  dependsOn pubhtmlhelp
+-  
+-  inputs.dir("${helpBuildDir}/${help_dir}")
+-  outputs.dir("${buildDir}/distributions/${help_dir}")
+-}
+-
+-
+-task j2sSetHeadlessBuild {
+-  doFirst {
+-    IN_ECLIPSE = false
+-  }
+-}
+-
+-
+-task jalviewjsEnableAltFileProperty(type: WriteProperties) {
+-  group "jalviewjs"
+-  description "Enable the alternative J2S Config file for headless build"
+-
+-  outputFile = jalviewjsJ2sSettingsFileName
+-  def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
+-  def j2sProps = new Properties()
+-  if (j2sPropsFile.exists()) {
+-    try {
+-      def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
+-      j2sProps.load(j2sPropsFileFIS)
+-      j2sPropsFileFIS.close()
+-
+-      j2sProps.each { prop, val ->
+-        property(prop, val)
+-      }
+-    } catch (Exception e) {
+-      println("Exception reading ${jalviewjsJ2sSettingsFileName}")
+-      e.printStackTrace()
+-    }
+-  }
+-  if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
+-    property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
+-  }
+-}
+-
+-
+-task jalviewjsSetEclipseWorkspace {
+-  def propKey = "jalviewjs_eclipse_workspace"
+-  def propVal = null
+-  if (project.hasProperty(propKey)) {
+-    propVal = project.getProperty(propKey)
+-    if (propVal.startsWith("~/")) {
+-      propVal = System.getProperty("user.home") + propVal.substring(1)
+-    }
+-  }
+-  def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
+-  def propsFile = file(propsFileName)
+-  def eclipseWsDir = propVal
+-  def props = new Properties()
+-
+-  def writeProps = true
+-  if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
+-    def ins = new FileInputStream(propsFileName)
+-    props.load(ins)
+-    ins.close()
+-    if (props.getProperty(propKey, null) != null) {
+-      eclipseWsDir = props.getProperty(propKey)
+-      writeProps = false
+-    }
+-  }
+-
+-  if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
+-    def tempDir = File.createTempDir()
+-    eclipseWsDir = tempDir.getAbsolutePath()
+-    writeProps = true
+-  }
+-  eclipseWorkspace = file(eclipseWsDir)
+-
+-  doFirst {
+-    // do not run a headless transpile when we claim to be in Eclipse
+-    if (IN_ECLIPSE) {
+-      println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-      throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
+-    } else {
+-      println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-    }
+-
+-    if (writeProps) {
+-      props.setProperty(propKey, eclipseWsDir)
+-      propsFile.parentFile.mkdirs()
+-      def bytes = new ByteArrayOutputStream()
+-      props.store(bytes, null)
+-      def propertiesString = bytes.toString()
+-      propsFile.text = propertiesString
+-      print("NEW ")
+-    } else {
+-      print("EXISTING ")
+-    }
+-
+-    println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
+-  }
+-
+-  //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
+-  outputs.file(propsFileName)
+-  outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
+-}
+-
+-
+-task jalviewjsEclipsePaths {
+-  def eclipseProduct
+-
+-  def eclipseRoot = jalviewjs_eclipse_root
+-  if (eclipseRoot.startsWith("~/")) {
+-    eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
+-  }
+-  if (OperatingSystem.current().isMacOsX()) {
+-    eclipseRoot += "/Eclipse.app"
+-    eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
+-    eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
+-  } else if (OperatingSystem.current().isWindows()) { // check these paths!!
+-    if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
+-      eclipseRoot += "/eclipse"
+-    }
+-    eclipseBinary = "${eclipseRoot}/eclipse.exe"
+-    eclipseProduct = "${eclipseRoot}/.eclipseproduct"
+-  } else { // linux or unix
+-    if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
+-      eclipseRoot += "/eclipse"
+-println("eclipseDir exists")
+-    }
+-    eclipseBinary = "${eclipseRoot}/eclipse"
+-    eclipseProduct = "${eclipseRoot}/.eclipseproduct"
+-  }
+-
+-  eclipseVersion = "4.13" // default
+-  def assumedVersion = true
+-  if (file(eclipseProduct).exists()) {
+-    def fis = new FileInputStream(eclipseProduct)
+-    def props = new Properties()
+-    props.load(fis)
+-    eclipseVersion = props.getProperty("version")
+-    fis.close()
+-    assumedVersion = false
+-  }
+-  
+-  def propKey = "eclipse_debug"
+-  eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
+-
+-  doFirst {
+-    // do not run a headless transpile when we claim to be in Eclipse
+-    if (IN_ECLIPSE) {
+-      println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-      throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
+-    } else {
+-      println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-    }
+-
+-    if (!assumedVersion) {
+-      println("ECLIPSE VERSION=${eclipseVersion}")
+-    }
+-  }
+-}
+-
+-
+-task printProperties {
+-  group "Debug"
+-  description "Output to console all System.properties"
+-  doFirst {
+-    System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
+-  }
+-}
+-
+-
+-task eclipseSetup {
+-  dependsOn eclipseProject
+-  dependsOn eclipseClasspath
+-  dependsOn eclipseJdt
+-}
+-
+-
+-// this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
+-task jalviewjsEclipseCopyDropins(type: Copy) {
+-  dependsOn jalviewjsEclipsePaths
+-
+-  def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
+-  inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
+-  def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
+-
+-  from inputFiles
+-  into outputDir
+-}
+-
+-
+-// this eclipse -clean doesn't actually work
+-task jalviewjsCleanEclipse(type: Exec) {
+-  dependsOn eclipseSetup
+-  dependsOn jalviewjsEclipsePaths
+-  dependsOn jalviewjsEclipseCopyDropins
+-
+-  executable(eclipseBinary)
+-  args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
+-  if (eclipseDebug) {
+-    args += "-debug"
+-  }
+-  args += "-l"
+-
+-  def inputString = """exit
+-y
+-"""
+-  def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
+-  standardInput = inputByteStream
+-}
+-
+-/* not really working yet
+-jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
+-*/
+-
+-
+-task jalviewjsTransferUnzipSwingJs {
+-  def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
+-
+-  doLast {
+-    copy {
+-      from zipTree(file_zip)
+-      into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
+-    }
+-  }
+-
+-  inputs.file file_zip
+-  outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
+-}
+-
+-
+-task jalviewjsTransferUnzipLib {
+-  def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
+-
+-  doLast {
+-    zipFiles.each { file_zip -> 
+-      copy {
+-        from zipTree(file_zip)
+-        into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
+-      }
+-    }
+-  }
+-
+-  inputs.files zipFiles
+-  outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
+-}
+-
+-
+-task jalviewjsTransferUnzipAllLibs {
+-  dependsOn jalviewjsTransferUnzipSwingJs
+-  dependsOn jalviewjsTransferUnzipLib
+-}
+-
+-
+-task jalviewjsCreateJ2sSettings(type: WriteProperties) {
+-  group "JalviewJS"
+-  description "Create the alternative j2s file from the j2s.* properties"
+-
+-  jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
+-  def siteDirProperty = "j2s.site.directory"
+-  def setSiteDir = false
+-  jalviewjsJ2sProps.each { prop, val ->
+-    if (val != null) {
+-      if (prop == siteDirProperty) {
+-        if (!(val.startsWith('/') || val.startsWith("file://") )) {
+-          val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
+-        }
+-        setSiteDir = true
+-      }
+-      property(prop,val)
+-    }
+-    if (!setSiteDir) { // default site location, don't override specifically set property
+-      property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
+-    }
+-  }
+-  outputFile = jalviewjsJ2sAltSettingsFileName
+-
+-  if (! IN_ECLIPSE) {
+-    inputs.properties(jalviewjsJ2sProps)
+-    outputs.file(jalviewjsJ2sAltSettingsFileName)
+-  }
+-}
+-
+-
+-task jalviewjsEclipseSetup {
+-  dependsOn jalviewjsEclipseCopyDropins
+-  dependsOn jalviewjsSetEclipseWorkspace
+-  dependsOn jalviewjsCreateJ2sSettings
+-}
+-
+-
+-task jalviewjsSyncAllLibs (type: Sync) {
+-  dependsOn jalviewjsTransferUnzipAllLibs
+-  def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
+-  inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
+-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
+-
+-  from inputFiles
+-  into outputDir
+-  def outputFiles = []
+-  rename { filename ->
+-    outputFiles += "${outputDir}/${filename}"
+-    null
+-  }
+-  preserve {
+-    include "**"
+-  }
+-  outputs.files outputFiles
+-  inputs.files inputFiles
+-}
+-
+-
+-task jalviewjsSyncResources (type: Sync) {
+-  dependsOn buildResources
+-
+-  def inputFiles = fileTree(dir: resourcesBuildDir)
+-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
+-
+-  from inputFiles
+-  into outputDir
+-  def outputFiles = []
+-  rename { filename ->
+-    outputFiles += "${outputDir}/${filename}"
+-    null
+-  }
+-  preserve {
+-    include "**"
+-  }
+-  outputs.files outputFiles
+-  inputs.files inputFiles
+-}
+-
+-
+-task jalviewjsSyncSiteResources (type: Sync) {
+-  def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
+-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
+-
+-  from inputFiles
+-  into outputDir
+-  def outputFiles = []
+-  rename { filename ->
+-    outputFiles += "${outputDir}/${filename}"
+-    null
+-  }
+-  preserve {
+-    include "**"
+-  }
+-  outputs.files outputFiles
+-  inputs.files inputFiles
+-}
+-
+-
+-task jalviewjsSyncBuildProperties (type: Sync) {
+-  dependsOn createBuildProperties
+-  def inputFiles = [file(buildProperties)]
+-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
+-
+-  from inputFiles
+-  into outputDir
+-  def outputFiles = []
+-  rename { filename ->
+-    outputFiles += "${outputDir}/${filename}"
+-    null
+-  }
+-  preserve {
+-    include "**"
+-  }
+-  outputs.files outputFiles
+-  inputs.files inputFiles
+-}
+-
+-
+-task jalviewjsProjectImport(type: Exec) {
+-  dependsOn eclipseSetup
+-  dependsOn jalviewjsEclipsePaths
+-  dependsOn jalviewjsEclipseSetup
+-
+-  doFirst {
+-    // do not run a headless import when we claim to be in Eclipse
+-    if (IN_ECLIPSE) {
+-      println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-      throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
+-    } else {
+-      println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-    }
+-  }
+-  //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
+-  def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
+-  executable(eclipseBinary)
+-  args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
+-  if (eclipseDebug) {
+-    args += "-debug"
+-  }
+-  args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
+-  if (!IN_ECLIPSE) {
+-    args += [ "-D${j2sHeadlessBuildProperty}=true" ]
+-    args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
+-  }
+-
+-  inputs.file("${jalviewDir}/.project")
+-  outputs.upToDateWhen { 
+-    file(projdir).exists()
+-  }
+-}
+-
+-
+-task jalviewjsTranspile(type: Exec) {
+-  dependsOn jalviewjsEclipseSetup 
+-  dependsOn jalviewjsProjectImport
+-  dependsOn jalviewjsEclipsePaths
+-  if (!IN_ECLIPSE) {
+-    dependsOn jalviewjsEnableAltFileProperty
+-  }
+-
+-  doFirst {
+-    // do not run a headless transpile when we claim to be in Eclipse
+-    if (IN_ECLIPSE) {
+-      println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-      throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
+-    } else {
+-      println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
+-    }
+-  }
+-
+-  executable(eclipseBinary)
+-  args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
+-  if (eclipseDebug) {
+-    args += "-debug"
+-  }
+-  args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
+-  if (!IN_ECLIPSE) {
+-    args += [ "-D${j2sHeadlessBuildProperty}=true" ]
+-    args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
+-  }
+-
+-  def stdout
+-  def stderr
+-  doFirst {
+-    stdout = new ByteArrayOutputStream()
+-    stderr = new ByteArrayOutputStream()
+-
+-    def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
+-    def logOutFile = file(logOutFileName)
+-    logOutFile.createNewFile()
+-    logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
+-BINARY: ${eclipseBinary}
+-VERSION: ${eclipseVersion}
+-WORKSPACE: ${eclipseWorkspace}
+-DEBUG: ${eclipseDebug}
+-----
+-"""
+-    def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
+-    // combine stdout and stderr
+-    def logErrFOS = logOutFOS
+-
+-    if (jalviewjs_j2s_to_console.equals("true")) {
+-      standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-        new org.apache.tools.ant.util.TeeOutputStream(
+-          logOutFOS,
+-          stdout),
+-        System.out)
+-      errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-        new org.apache.tools.ant.util.TeeOutputStream(
+-          logErrFOS,
+-          stderr),
+-        System.err)
+-    } else {
+-      standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-        logOutFOS,
+-        stdout)
+-      errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-        logErrFOS,
+-        stderr)
+-    }
+-  }
+-
+-  doLast {
+-    if (stdout.toString().contains("Error processing ")) {
+-      // j2s did not complete transpile
+-      //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
+-      if (jalviewjs_ignore_transpile_errors.equals("true")) {
+-        println("IGNORING TRANSPILE ERRORS")
+-        println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
+-      } else {
+-        throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
+-      }
+-    }
+-  }
+-
+-  inputs.dir("${jalviewDir}/${sourceDir}")
+-  outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
+-  outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
+-}
+-
+-
+-def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
+-
+-  def stdout = new ByteArrayOutputStream()
+-  def stderr = new ByteArrayOutputStream()
+-
+-  def coreFile = file(jsfile)
+-  def msg = ""
+-  msg = "Creating core for ${name}...\nGenerating ${jsfile}"
+-  println(msg)
+-  logOutFile.createNewFile()
+-  logOutFile.append(msg+"\n")
+-
+-  def coreTop = file(prefixFile)
+-  def coreBottom = file(suffixFile)
+-  coreFile.getParentFile().mkdirs()
+-  coreFile.createNewFile()
+-  coreFile.write( coreTop.getText("UTF-8") )
+-  list.each {
+-    f ->
+-    if (f.exists()) {
+-      def t = f.getText("UTF-8")
+-      t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
+-      coreFile.append( t )
+-    } else {
+-      msg = "...file '"+f.getPath()+"' does not exist, skipping"
+-      println(msg)
+-      logOutFile.append(msg+"\n")
+-    }
+-  }
+-  coreFile.append( coreBottom.getText("UTF-8") )
+-
+-  msg = "Generating ${zjsfile}"
+-  println(msg)
+-  logOutFile.append(msg+"\n")
+-  def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
+-  def logErrFOS = logOutFOS
+-
+-  javaexec {
+-    classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
+-    main = "com.google.javascript.jscomp.CommandLineRunner"
+-    jvmArgs = [ "-Dfile.encoding=UTF-8" ]
+-    args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
+-    maxHeapSize = "2g"
+-
+-    msg = "\nRunning '"+commandLine.join(' ')+"'\n"
+-    println(msg)
+-    logOutFile.append(msg+"\n")
+-
+-    if (logOutConsole) {
+-      standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-        new org.apache.tools.ant.util.TeeOutputStream(
+-          logOutFOS,
+-          stdout),
+-        standardOutput)
+-        errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-          new org.apache.tools.ant.util.TeeOutputStream(
+-            logErrFOS,
+-            stderr),
+-          errorOutput)
+-    } else {
+-      standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-        logOutFOS,
+-        stdout)
+-        errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
+-          logErrFOS,
+-          stderr)
+-    }
+-  }
+-  msg = "--"
+-  println(msg)
+-  logOutFile.append(msg+"\n")
+-}
+-
+-
+-task jalviewjsBuildAllCores {
+-  group "JalviewJS"
+-  description "Build the core js lib closures listed in the classlists dir"
+-  dependsOn jalviewjsTranspile
+-  dependsOn jalviewjsTransferUnzipSwingJs
+-
+-  def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
+-  def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
+-  def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
+-  def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
+-  def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
+-  def prefixFile = "${jsDir}/core/coretop2.js"
+-  def suffixFile = "${jsDir}/core/corebottom2.js"
+-
+-  inputs.file prefixFile
+-  inputs.file suffixFile
+-
+-  def classlistFiles = []
+-  // add the classlists found int the jalviewjs_classlists_dir
+-  fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
+-    file ->
+-    def name = file.getName() - ".txt"
+-    classlistFiles += [
+-      'file': file,
+-      'name': name
+-    ]
+-  }
+-
+-  // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
+-  //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
+-  classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
+-
+-  jalviewjsCoreClasslists = []
+-
+-  classlistFiles.each {
+-    hash ->
+-
+-    def file = hash['file']
+-    if (! file.exists()) {
+-      //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
+-      return false // this is a "continue" in groovy .each closure
+-    }
+-    def name = hash['name']
+-    if (name == null) {
+-      name = file.getName() - ".txt"
+-    }
+-
+-    def filelist = []
+-    file.eachLine {
+-      line ->
+-        filelist += line
+-    }
+-    def list = fileTree(dir: j2sDir, includes: filelist)
+-
+-    def jsfile = "${outputDir}/core${name}.js"
+-    def zjsfile = "${outputDir}/core${name}.z.js"
+-
+-    jalviewjsCoreClasslists += [
+-      'jsfile': jsfile,
+-      'zjsfile': zjsfile,
+-      'list': list,
+-      'name': name
+-    ]
+-
+-    inputs.file(file)
+-    inputs.files(list)
+-    outputs.file(jsfile)
+-    outputs.file(zjsfile)
+-  }
+-  
+-  // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
+-  def stevesoftClasslistName = "_stevesoft"
+-  def stevesoftClasslist = [
+-    'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
+-    'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
+-    'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
+-    'name': stevesoftClasslistName
+-  ]
+-  jalviewjsCoreClasslists += stevesoftClasslist
+-  inputs.files(stevesoftClasslist['list'])
+-  outputs.file(stevesoftClasslist['jsfile'])
+-  outputs.file(stevesoftClasslist['zjsfile'])
+-
+-  // _all core
+-  def allClasslistName = "_all"
+-  def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
+-  allJsFiles += fileTree(
+-    dir: libJ2sDir,
+-    include: "**/*.js",
+-    excludes: [
+-      // these exlusions are files that the closure-compiler produces errors for. Should fix them
+-      "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
+-      "**/org/jmol/export/JSExporter.js"
+-    ]
+-  )
+-  allJsFiles += fileTree(
+-    dir: swingJ2sDir,
+-    include: "**/*.js",
+-    excludes: [
+-      // these exlusions are files that the closure-compiler produces errors for. Should fix them
+-      "**/sun/misc/Unsafe.js",
+-      "**/swingjs/jquery/jquery-editable-select.js",
+-      "**/swingjs/jquery/j2sComboBox.js",
+-      "**/sun/misc/FloatingDecimal.js"
+-    ]
+-  )
+-  def allClasslist = [
+-    'jsfile': "${outputDir}/core${allClasslistName}.js",
+-    'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
+-    'list': allJsFiles,
+-    'name': allClasslistName
+-  ]
+-  // not including this version of "all" core at the moment
+-  //jalviewjsCoreClasslists += allClasslist
+-  inputs.files(allClasslist['list'])
+-  outputs.file(allClasslist['jsfile'])
+-  outputs.file(allClasslist['zjsfile'])
+-
+-  doFirst {
+-    def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
+-    logOutFile.getParentFile().mkdirs()
+-    logOutFile.createNewFile()
+-    logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
+-
+-    jalviewjsCoreClasslists.each {
+-      jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
+-    }
+-  }
+-
+-}
+-
+-
+-def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
+-  copy {
+-    from inputFile
+-    into file(outputFile).getParentFile()
+-    rename { filename ->
+-      if (filename.equals(inputFile.getName())) {
+-        return file(outputFile).getName()
+-      }
+-      return null
+-    }
+-    filter(ReplaceTokens,
+-      beginToken: '_',
+-      endToken: '_',
+-      tokens: [
+-        'MAIN': '"'+main_class+'"',
+-        'CODE': "null",
+-        'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
+-        'COREKEY': jalviewjs_core_key,
+-        'CORENAME': coreName
+-      ]
+-    )
+-  }
+-}
+-
+-
+-task jalviewjsPublishCoreTemplates {
+-  dependsOn jalviewjsBuildAllCores
+-  def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
+-  def inputFile = file(inputFileName)
+-  def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
+-
+-  def outputFiles = []
+-  jalviewjsCoreClasslists.each { cl ->
+-    def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
+-    cl['outputfile'] = outputFile
+-    outputFiles += outputFile
+-  }
+-
+-  doFirst {
+-    jalviewjsCoreClasslists.each { cl ->
+-      jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
+-    }
+-  }
+-  inputs.file(inputFile)
+-  outputs.files(outputFiles)
+-}
+-
+-
+-task jalviewjsSyncCore (type: Sync) {
+-  dependsOn jalviewjsBuildAllCores
+-  dependsOn jalviewjsPublishCoreTemplates
+-  def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
+-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
+-
+-  from inputFiles
+-  into outputDir
+-  def outputFiles = []
+-  rename { filename ->
+-    outputFiles += "${outputDir}/${filename}"
+-    null
+-  }
+-  preserve {
+-    include "**"
+-  }
+-  outputs.files outputFiles
+-  inputs.files inputFiles
+-}
+-
+-
+-// this Copy version of TransferSiteJs will delete anything else in the target dir
+-task jalviewjsCopyTransferSiteJs(type: Copy) {
+-  dependsOn jalviewjsTranspile
+-  from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
+-  into "${jalviewDir}/${jalviewjsSiteDir}"
+-}
+-
+-
+-// this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
+-task jalviewjsSyncTransferSiteJs(type: Sync) {
+-  from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
+-  include "**/*.*"
+-  into "${jalviewDir}/${jalviewjsSiteDir}"
+-  preserve {
+-    include "**"
+-  }
+-}
+-
+-
+-jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
+-jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
+-jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
+-jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
+-
+-jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
+-jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
+-jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
+-jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
+-
+-
+-task jalviewjsPrepareSite {
+-  group "JalviewJS"
+-  description "Prepares the website folder including unzipping files and copying resources"
+-  dependsOn jalviewjsSyncAllLibs
+-  dependsOn jalviewjsSyncResources
+-  dependsOn jalviewjsSyncSiteResources
+-  dependsOn jalviewjsSyncBuildProperties
+-  dependsOn jalviewjsSyncCore
+-}
+-
+-
+-task jalviewjsBuildSite {
+-  group "JalviewJS"
+-  description "Builds the whole website including transpiled code"
+-  dependsOn jalviewjsCopyTransferSiteJs
+-  dependsOn jalviewjsPrepareSite
+-}
+-
+-
+-task cleanJalviewjsTransferSite {
+-  doFirst {
+-    delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
+-    delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
+-    delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
+-    delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
+-  }
+-}
+-
+-
+-task cleanJalviewjsSite {
+-  dependsOn cleanJalviewjsTransferSite
+-  doFirst {
+-    delete "${jalviewDir}/${jalviewjsSiteDir}"
+-  }
+-}
+-
+-
+-task jalviewjsSiteTar(type: Tar) {
+-  group "JalviewJS"
+-  description "Creates a tar.gz file for the website"
+-  dependsOn jalviewjsBuildSite
+-  def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
+-  archiveFileName = outputFilename
+-
+-  compression Compression.GZIP
+-
+-  from "${jalviewDir}/${jalviewjsSiteDir}"
+-  into jalviewjs_site_dir // this is inside the tar file
+-
+-  inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
+-}
+-
+-
+-task jalviewjsServer {
+-  group "JalviewJS"
+-  def filename = "jalviewjsTest.html"
+-  description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
+-  def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
+-  doLast {
+-
+-    def factory
+-    try {
+-      def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
+-      factory = f.newInstance()
+-    } catch (ClassNotFoundException e) {
+-      throw new GradleException("Unable to create SimpleHttpFileServerFactory")
+-    }
+-    def port = Integer.valueOf(jalviewjs_server_port)
+-    def start = port
+-    def running = false
+-    def url
+-    def jalviewjsServer
+-    while(port < start+1000 && !running) {
+-      try {
+-        def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
+-        jalviewjsServer = factory.start(doc_root, port)
+-        running = true
+-        url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
+-        println("SERVER STARTED with document root ${doc_root}.")
+-        println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
+-        println("For debug: "+url+"?j2sdebug")
+-        println("For verbose: "+url+"?j2sverbose")
+-      } catch (Exception e) {
+-        port++;
+-      }
+-    }
+-    def htmlText = """
+-      <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
+-      <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
+-      <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
+-      """
+-    jalviewjsCoreClasslists.each { cl ->
+-      def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
+-      htmlText += """
+-      <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
+-      """
+-      println("For core ${cl.name}: "+urlcore)
+-    }
+-
+-    file(htmlFile).text = htmlText
+-  }
+-
+-  outputs.file(htmlFile)
+-  outputs.upToDateWhen({false})
+-}
+-
+-
+-task cleanJalviewjsAll {
+-  group "JalviewJS"
+-  description "Delete all configuration and build artifacts to do with JalviewJS build"
+-  dependsOn cleanJalviewjsSite
+-  dependsOn jalviewjsEclipsePaths
+-  
+-  doFirst {
+-    delete "${jalviewDir}/${jalviewjsBuildDir}"
+-    delete "${jalviewDir}/${eclipse_bin_dir}"
+-    if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
+-      delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
+-    }
+-    delete jalviewjsJ2sAltSettingsFileName
+-  }
+-
+-  outputs.upToDateWhen( { false } )
+-}
+-
+-
+-task jalviewjsIDE_checkJ2sPlugin {
+-  group "00 JalviewJS in Eclipse"
+-  description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
+-
+-  doFirst {
+-    def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
+-    def j2sPluginFile = file(j2sPlugin)
+-    def eclipseHome = System.properties["eclipse.home.location"]
+-    if (eclipseHome == null || ! IN_ECLIPSE) {
+-      throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
+-    }
+-    def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
+-    def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
+-    if (altPluginsDir != null && file(altPluginsDir).exists()) {
+-      eclipseJ2sPluginDirs += altPluginsDir
+-    }
+-    def foundPlugin = false
+-    def j2sPluginFileName = j2sPluginFile.getName()
+-    def eclipseJ2sPlugin
+-    def eclipseJ2sPluginFile
+-    eclipseJ2sPluginDirs.any { dir ->
+-      eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
+-      eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
+-      if (eclipseJ2sPluginFile.exists()) {
+-        foundPlugin = true
+-        return true
+-      }
+-    }
+-    if (!foundPlugin) {
+-      def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
+-      System.err.println(msg)
+-      throw new StopExecutionException(msg)
+-    }
+-
+-    def digest = MessageDigest.getInstance("MD5")
+-
+-    digest.update(j2sPluginFile.text.bytes)
+-    def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
+-
+-    digest.update(eclipseJ2sPluginFile.text.bytes)
+-    def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
+-     
+-    if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
+-      def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
+-      System.err.println(msg)
+-      throw new StopExecutionException(msg)
+-    } else {
+-      def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
+-      println(msg)
+-    }
+-  }
+-}
+-
+-task jalviewjsIDE_copyJ2sPlugin {
+-  group "00 JalviewJS in Eclipse"
+-  description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
+-
+-  doFirst {
+-    def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
+-    def j2sPluginFile = file(j2sPlugin)
+-    def eclipseHome = System.properties["eclipse.home.location"]
+-    if (eclipseHome == null || ! IN_ECLIPSE) {
+-      throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
+-    }
+-    def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
+-    def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
+-    def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
+-    System.err.println(msg)
+-    copy {
+-      from j2sPlugin
+-      eclipseJ2sPluginFile.getParentFile().mkdirs()
+-      into eclipseJ2sPluginFile.getParent()
+-    }
+-  }
+-}
+-
+-
+-task jalviewjsIDE_j2sFile {
+-  group "00 JalviewJS in Eclipse"
+-  description "Creates the .j2s file"
+-  dependsOn jalviewjsCreateJ2sSettings
+-}
+-
+-
+-task jalviewjsIDE_SyncCore {
+-  group "00 JalviewJS in Eclipse"
+-  description "Build the core js lib closures listed in the classlists dir and publish core html from template"
+-  dependsOn jalviewjsSyncCore
+-}
+-
+-
+-task jalviewjsIDE_SyncSiteAll {
+-  dependsOn jalviewjsSyncAllLibs
+-  dependsOn jalviewjsSyncResources
+-  dependsOn jalviewjsSyncSiteResources
+-  dependsOn jalviewjsSyncBuildProperties
+-}
+-
+-
+-cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
+-
+-
+-task jalviewjsIDE_PrepareSite {
+-  group "00 JalviewJS in Eclipse"
+-  description "Sync libs and resources to site dir, but not closure cores"
+-
+-  dependsOn jalviewjsIDE_SyncSiteAll
+-  //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
+-}
+-
+-
+-task jalviewjsIDE_AssembleSite {
+-  group "00 JalviewJS in Eclipse"
+-  description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
+-  dependsOn jalviewjsPrepareSite
+-}
+-
+-
+-task jalviewjsIDE_SiteClean {
+-  group "00 JalviewJS in Eclipse"
+-  description "Deletes the Eclipse transpiled site"
+-  dependsOn cleanJalviewjsSite
+-}
+-
+-
+-task jalviewjsIDE_Server {
+-  group "00 JalviewJS in Eclipse"
+-  description "Starts a webserver on localhost to test the website"
+-  dependsOn jalviewjsServer
+-}
+-
+-
+-// buildship runs this at import or gradle refresh
+-task eclipseSynchronizationTask {
+-  //dependsOn eclipseSetup
+-  dependsOn createBuildProperties
+-  if (J2S_ENABLED) {
+-    dependsOn jalviewjsIDE_j2sFile
+-    dependsOn jalviewjsIDE_checkJ2sPlugin
+-    dependsOn jalviewjsIDE_PrepareSite
+-  }
+-}
+-
+-
+-// buildship runs this at build time or project refresh
+-task eclipseAutoBuildTask {
+-  //dependsOn jalviewjsIDE_checkJ2sPlugin
+-  //dependsOn jalviewjsIDE_PrepareSite
++  outputs.file("${outputDir}/${archiveFileName}")
+ }
+-
+-task jalviewjs {
+-  group "JalviewJS"
+-  description "Build the site"
+-  dependsOn jalviewjsBuildSite
+-}
diff --git a/utils/debian/debian/icons/128x128/apps/jalview-icon.png b/utils/debian/debian/icons/128x128/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..83a15fb
Binary files /dev/null and b/utils/debian/debian/icons/128x128/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/icons/16x16/apps/jalview-icon.png b/utils/debian/debian/icons/16x16/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..120bbf8
Binary files /dev/null and b/utils/debian/debian/icons/16x16/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/icons/16x16/mimetypes/x-jalview-file.png b/utils/debian/debian/icons/16x16/mimetypes/x-jalview-file.png
new file mode 100644 (file)
index 0000000..af2b2c3
Binary files /dev/null and b/utils/debian/debian/icons/16x16/mimetypes/x-jalview-file.png differ
diff --git a/utils/debian/debian/icons/22x22/mimetypes/x-jalview-file.png b/utils/debian/debian/icons/22x22/mimetypes/x-jalview-file.png
new file mode 100644 (file)
index 0000000..f5ac4ba
Binary files /dev/null and b/utils/debian/debian/icons/22x22/mimetypes/x-jalview-file.png differ
diff --git a/utils/debian/debian/icons/24x24/mimetypes/x-jalview-file.png b/utils/debian/debian/icons/24x24/mimetypes/x-jalview-file.png
new file mode 100644 (file)
index 0000000..7d9b615
Binary files /dev/null and b/utils/debian/debian/icons/24x24/mimetypes/x-jalview-file.png differ
diff --git a/utils/debian/debian/icons/256x256/apps/jalview-icon.png b/utils/debian/debian/icons/256x256/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..2dc68b0
Binary files /dev/null and b/utils/debian/debian/icons/256x256/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/icons/32x32/apps/jalview-icon.png b/utils/debian/debian/icons/32x32/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..8f8c3f6
Binary files /dev/null and b/utils/debian/debian/icons/32x32/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/icons/32x32/mimetypes/x-jalview-file.png b/utils/debian/debian/icons/32x32/mimetypes/x-jalview-file.png
new file mode 100644 (file)
index 0000000..1a6eb7c
Binary files /dev/null and b/utils/debian/debian/icons/32x32/mimetypes/x-jalview-file.png differ
diff --git a/utils/debian/debian/icons/48x48/apps/jalview-icon.png b/utils/debian/debian/icons/48x48/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..b4837fa
Binary files /dev/null and b/utils/debian/debian/icons/48x48/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/icons/48x48/mimetypes/x-jalview-file.png b/utils/debian/debian/icons/48x48/mimetypes/x-jalview-file.png
new file mode 100644 (file)
index 0000000..bf482ec
Binary files /dev/null and b/utils/debian/debian/icons/48x48/mimetypes/x-jalview-file.png differ
diff --git a/utils/debian/debian/icons/512x512/apps/jalview-icon.png b/utils/debian/debian/icons/512x512/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..41b845b
Binary files /dev/null and b/utils/debian/debian/icons/512x512/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/icons/512x512/mimetypes/x-jalview-file.png b/utils/debian/debian/icons/512x512/mimetypes/x-jalview-file.png
new file mode 100644 (file)
index 0000000..38edb48
Binary files /dev/null and b/utils/debian/debian/icons/512x512/mimetypes/x-jalview-file.png differ
diff --git a/utils/debian/debian/icons/64x64/apps/jalview-icon.png b/utils/debian/debian/icons/64x64/apps/jalview-icon.png
new file mode 100644 (file)
index 0000000..2490a8d
Binary files /dev/null and b/utils/debian/debian/icons/64x64/apps/jalview-icon.png differ
diff --git a/utils/debian/debian/jalview-file.png b/utils/debian/debian/jalview-file.png
deleted file mode 100644 (file)
index 1d98699..0000000
Binary files a/utils/debian/debian/jalview-file.png and /dev/null differ
index 181fbed..757682c 100644 (file)
 
   <mime-type type="application/x-jalview+xml+zip">
     <comment>Jalview File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.jvp" weight="100"/>
   </mime-type>
 
   <mime-type type="chemical/x-cif">
     <comment>CIF File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.cif" weight="40"/>
   </mime-type>
 
   <mime-type type="chemical/x-mmcif">
     <comment>mmCIF File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.mcif" weight="40"/>
     <glob pattern="*.mmcif" weight="40"/>
   </mime-type>
 
   <mime-type type="chemical/x-pdb">
     <comment>PDB File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.pdb" weight="40"/>
     <glob pattern="*.ent" weight="40"/>
   </mime-type>
 
   <mime-type type="application/x-amsa+txt">
     <comment>AMSA File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.amsa" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-jalview-annotations+text">
     <comment>Jalview Annotations File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.annotations" weight="100"/>
     <glob pattern="*.jvannotations" weight="100"/>
   </mime-type>
 
   <mime-type type="application/x-jalview-biojson+json">
     <comment>BioJSON File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.biojson" weight="100"/>
   </mime-type>
 
   <mime-type type="application/x-blc+txt">
     <comment>BLC File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.blc" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-clustal+txt">
     <comment>Clustal File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.aln" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-fasta+txt">
     <comment>Fasta File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.fa" weight="90"/>
     <glob pattern="*.fasta" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-jalview-features+text">
     <comment>Jalview Features File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.features" weight="100"/>
     <glob pattern="*.jvfeatures" weight="100"/>
   </mime-type>
 
   <mime-type type="application/x-gff2+txt">
     <comment>Generic Features Format v2 File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.gff2" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-gff3+txt">
     <comment>Generic Features Format v3 File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.gff3" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-jalview-jnet+text">
     <comment>JnetFile File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.concise" weight="100"/>
     <glob pattern="*.jnet" weight="100"/>
   </mime-type>
 
   <mime-type type="application/x-msf+txt">
     <comment>MSF File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.msf" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-pfam+txt">
     <comment>PFAM File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.pfam" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-phylip+txt">
     <comment>PHYLIP File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.phy" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-pileup+txt">
     <comment>PileUp File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.pileup" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-pir+txt">
     <comment>PIR File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.pir" weight="90"/>
   </mime-type>
 
   <mime-type type="application/rnaml+xml">
     <comment>RNAML File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.rnaml" weight="90"/>
   </mime-type>
 
   <mime-type type="application/x-jalview-scorematrix+text">
     <comment>Substitution Matrix File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.mat" weight="100"/>
   </mime-type>
 
   <mime-type type="application/x-stockholm+txt">
     <comment>Stockholm File</comment>
-    <icon name="jalview-file"/>
+    <generic-icon name="x-jalview-file"/>
     <glob pattern="*.sto" weight="90"/>
     <glob pattern="*.stk" weight="90"/>
   </mime-type>
index d4cc896..7cf0afb 100644 (file)
@@ -6,7 +6,7 @@ Comment=Multiple Sequence Alignment Editor
 Icon=jalview-icon
 Type=Application
 TryExec=jalview
-Exec=jalview -open %u
+Exec=jalview %u
 Terminal=false
 Categories=Science;Biology;
 Keywords=alignment;sequence;
diff --git a/utils/debian/debian/wrappers/jalview b/utils/debian/debian/wrappers/jalview
new file mode 100755 (executable)
index 0000000..4823bee
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -e
+ARG1=$1
+
+# copy the debian default settings if no user jalview settings file exist
+if [ -n "${HOME}" -a \! -e ${HOME}/.jalview_properties ]; then
+  /bin/cp /etc/jalview_properties ${HOME}/.jalview_properties
+fi
+
+# check to see if $1 is set and is not start of other cli set args
+OPEN=""
+if [ -n "$ARG1" -a "$ARG1" = "${ARG1#-}" ]; then
+  # first argument exists and does not start with a "-"
+  OPEN="-open"
+fi
+  
+java -jar /usr/share/java/jalview.jar $OPEN "$@"
diff --git a/utils/debian/debian_build.gradle b/utils/debian/debian_build.gradle
new file mode 100644 (file)
index 0000000..a0e8cd9
--- /dev/null
@@ -0,0 +1,514 @@
+/* Convention for properties.  Read from gradle.properties, use lower_case_underlines for property names.
+ * For properties set within build.gradle, use camelCaseNoSpace.
+ */
+import org.apache.tools.ant.filters.ReplaceTokens
+
+plugins {
+  id 'java'
+  id 'application'
+}
+
+// in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
+def string(Object o) {
+  return o == null ? "" : o.toString()
+}
+
+def overrideProperties(String propsFileName, boolean output = false) {
+  if (propsFileName == null) {
+    return
+  }
+  def propsFile = file(propsFileName)
+  if (propsFile != null && propsFile.exists()) {
+    println("Using properties from file '${propsFileName}'")
+    try {
+      def p = new Properties()
+      def localPropsFIS = new FileInputStream(propsFile)
+      p.load(localPropsFIS)
+      localPropsFIS.close()
+      p.each {
+        key, val -> 
+          def oldval
+          if (project.hasProperty(key)) {
+            oldval = project.findProperty(key)
+            project.setProperty(key, val)
+            if (output) {
+              println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
+            }
+          } else {
+            ext.setProperty(key, val)
+            if (output) {
+              println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
+            }
+          }
+      }
+    } catch (Exception e) {
+      println("Exception reading local.properties")
+      e.printStackTrace()
+    }
+  }
+}
+
+project.ext {
+  jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
+  jalviewDirRelativePath = jalviewDir
+
+  propertiesChannelName = "release"
+  channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
+  channelGradleProperties = string("${channelDir}/channel_gradle.properties")
+  overrideProperties(channelGradleProperties, false)
+  
+  ////  
+  // Import releaseProps from the RELEASE file
+  // or a file specified via JALVIEW_RELEASE_FILE if defined
+  // Expect jalview.version and target release branch in jalview.release        
+  def releaseProps = new Properties();
+  def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
+  def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
+  try {
+    (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream { 
+     releaseProps.load(it)
+    }
+  } catch (Exception fileLoadError) {
+    throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
+  }
+  ////
+  // Set JALVIEW_VERSION if it is not already set
+  if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
+    JALVIEW_VERSION = releaseProps.get("jalview.version")
+  }
+
+  // essentials
+  bareSourceDir = string(source_dir)
+  sourceDir = string("${jalviewDir}/${bareSourceDir}")
+  resourceDir = string("${jalviewDir}/${resource_dir}")
+  bareTestSourceDir = string(test_source_dir)
+  testDir = string("${jalviewDir}/${bareTestSourceDir}")
+
+  classesDir = string("${jalviewDir}/${classes_dir}")
+
+  useClover = false
+
+  resourceClassesDir = classesDir
+
+  testSourceDir = testDir
+  testClassesDir = "${jalviewDir}/${test_output_dir}"
+
+  buildProperties = string("${classesDir}/${build_properties_file}")
+  getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
+
+  install4jApplicationName = "${jalview_name}"
+  
+  println("Using a ${CHANNEL} profile.")
+
+  additional_compiler_args = []
+  // configure classpath/args for j8/j11 compilation
+  if (JAVA_VERSION.equals("1.8")) {
+    JAVA_INTEGER_VERSION = string("8")
+    //libDir = j8libDir
+    libDir = j11libDir
+    libDistDir = j8libDir
+    compile_source_compatibility = 1.8
+    compile_target_compatibility = 1.8
+  } else if (JAVA_VERSION.equals("11")) {
+    JAVA_INTEGER_VERSION = string("11")
+    libDir = j11libDir
+    libDistDir = j11libDir
+    compile_source_compatibility = 11
+    compile_target_compatibility = 11
+  } else {
+    throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
+  }
+
+  resourceBuildDir = string("${buildDir}/resources")
+  resourcesBuildDir = string("${resourceBuildDir}/resources_build")
+  helpBuildDir = string("${resourceBuildDir}/help_build")
+  docBuildDir = string("${resourceBuildDir}/doc_build")
+
+  if (buildProperties == null) {
+    buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
+  }
+  buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
+  helpParentDir = string("${jalviewDir}/${help_parent_dir}")
+  helpSourceDir = string("${helpParentDir}/${help_dir}")
+  helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
+
+  // ENDEXT
+}
+
+
+sourceSets {
+  main {
+    java {
+      srcDirs sourceDir
+      outputDir = file(classesDir)
+    }
+
+    resources {
+      srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
+    }
+
+    compileClasspath = files(sourceSets.main.java.outputDir)
+    compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
+
+
+    compileClasspath = files(sourceSets.main.java.outputDir)
+    compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
+
+    runtimeClasspath = compileClasspath
+    runtimeClasspath += files(sourceSets.main.resources.srcDirs)
+  }
+
+  test {
+    java {
+      srcDirs testSourceDir
+      outputDir = file(testClassesDir)
+    }
+
+    resources {
+      srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
+    }
+
+    compileClasspath = files( sourceSets.test.java.outputDir )
+    compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
+    compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
+
+    runtimeClasspath = compileClasspath
+    runtimeClasspath += files(sourceSets.test.resources.srcDirs)
+  }
+ /*  test {
+    java {
+      srcDirs testSourceDir
+      outputDir = file(testClassesDir)
+    }
+
+    resources {
+      srcDirs = sourceSets.main.resources.srcDirs
+    }
+
+    compileClasspath = files( sourceSets.test.java.outputDir )
+    compileClasspath += sourceSets.main.compileClasspath
+    compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**   REMOVE_THIS_GAP  /*.jar"])
+
+    runtimeClasspath = compileClasspath
+  }
+*/
+}
+
+
+compileJava {
+  sourceCompatibility = compile_source_compatibility
+  targetCompatibility = compile_target_compatibility
+  options.compilerArgs = additional_compiler_args
+  doFirst {
+    print ("Setting target compatibility to "+compile_target_compatibility+"\n")
+  }
+}
+
+
+compileTestJava {
+  doFirst {
+    sourceCompatibility = compile_source_compatibility
+    targetCompatibility = compile_target_compatibility
+    options.compilerArgs = additional_compiler_args
+    print ("Setting target compatibility to "+targetCompatibility+"\n")
+  }
+}
+
+
+clean {
+  doFirst {
+    delete sourceSets.main.java.outputDir
+  }
+}
+
+
+cleanTest {
+  doFirst {
+    delete sourceSets.test.java.outputDir
+  }
+}
+
+
+// format is a string like date.format("dd MMMM yyyy")
+def getDate(format) {
+  def date = new Date()
+  return date.format(format)
+}
+
+
+task copyDocs(type: Copy) {
+  def inputDir = "${jalviewDir}/${doc_dir}"
+  def outputDir = "${docBuildDir}/${doc_dir}"
+  from(inputDir) {
+    include('**/*.txt')
+    include('**/*.md')
+    include('**/*.html')
+    include('**/*.xml')
+    filter(ReplaceTokens,
+      beginToken: '$$',
+      endToken: '$$',
+      tokens: [
+        'Version-Rel': JALVIEW_VERSION,
+        'Year-Rel': getDate("yyyy")
+      ]
+    )
+  }
+  from(inputDir) {
+    exclude('**/*.txt')
+    exclude('**/*.md')
+    exclude('**/*.html')
+    exclude('**/*.xml')
+  }
+  into outputDir
+
+  inputs.dir(inputDir)
+  outputs.dir(outputDir)
+}
+
+
+task copyHelp(type: Copy) {
+  def inputDir = helpSourceDir
+  def outputDir = "${helpBuildDir}/${help_dir}"
+  from(inputDir) {
+    include('**/*.txt')
+    include('**/*.md')
+    include('**/*.html')
+    include('**/*.hs')
+    include('**/*.xml')
+    include('**/*.jhm')
+    filter(ReplaceTokens,
+      beginToken: '$$',
+      endToken: '$$',
+      tokens: [
+        'Version-Rel': JALVIEW_VERSION,
+        'Year-Rel': getDate("yyyy")
+      ]
+    )
+  }
+  from(inputDir) {
+    exclude('**/*.txt')
+    exclude('**/*.md')
+    exclude('**/*.html')
+    exclude('**/*.hs')
+    exclude('**/*.xml')
+    exclude('**/*.jhm')
+  }
+  into outputDir
+
+  inputs.dir(inputDir)
+  outputs.files(helpFile)
+  outputs.dir(outputDir)
+}
+
+
+task copyResources(type: Copy) {
+  group = "build"
+  description = "Copy (and make text substitutions in) the resources dir to the build area"
+
+  def inputDir = resourceDir
+  def outputDir = resourcesBuildDir
+  from(inputDir) {
+    include('**/*.txt')
+    include('**/*.md')
+    include('**/*.html')
+    include('**/*.xml')
+    filter(ReplaceTokens,
+      beginToken: '$$',
+      endToken: '$$',
+      tokens: [
+        'Version-Rel': JALVIEW_VERSION,
+        'Year-Rel': getDate("yyyy")
+      ]
+    )
+  }
+  from(inputDir) {
+    exclude('**/*.txt')
+    exclude('**/*.md')
+    exclude('**/*.html')
+    exclude('**/*.xml')
+  }
+  into outputDir
+
+  inputs.dir(inputDir)
+  outputs.dir(outputDir)
+}
+
+task copyChannelResources(type: Copy) {
+  dependsOn copyResources
+  group = "build"
+  description = "Copy the channel resources dir to the build resources area"
+
+  def inputDir = "${channelDir}/${resource_dir}"
+  def outputDir = resourcesBuildDir
+  from inputDir
+  into outputDir
+
+  inputs.dir(inputDir)
+  outputs.dir(outputDir)
+}
+
+task createBuildProperties(type: Copy) {
+  // using the build_properties already included in the source tarball
+  def inputFile = "build_properties"
+  def outputFile = buildProperties
+  from inputFile
+  into file(outputFile).getParent()
+  rename(file(inputFile).getName(), file(outputFile).getName())
+
+  inputs.file(inputFile)
+  outputs.file(outputFile)
+}
+
+
+task buildIndices(type: JavaExec) {
+  dependsOn copyHelp
+  classpath = sourceSets.main.compileClasspath
+  main = "com.sun.java.help.search.Indexer"
+  workingDir = "${helpBuildDir}/${help_dir}"
+  def argDir = "html"
+  args = [ argDir ]
+  inputs.dir("${workingDir}/${argDir}")
+
+  outputs.dir("${classesDir}/doc")
+  outputs.dir("${classesDir}/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 buildResources {
+  dependsOn copyResources
+  dependsOn copyChannelResources
+  dependsOn createBuildProperties
+}
+
+task prepare {
+  dependsOn buildResources
+  dependsOn copyDocs
+  dependsOn copyHelp
+  dependsOn buildIndices
+}
+
+
+compileJava.dependsOn prepare
+run.dependsOn compileJava
+//run.dependsOn prepare
+
+
+//testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
+test {
+  dependsOn prepare
+  dependsOn compileJava //?
+
+  useTestNG() {
+    includeGroups testng_groups
+    excludeGroups testng_excluded_groups
+    preserveOrder true
+    useDefaultListeners=true
+  }
+
+  maxHeapSize = "1024m"
+
+  workingDir = jalviewDir
+  //systemProperties 'clover.jar' System.properties.clover.jar
+  def testLaf = project.findProperty("test_laf")
+  if (testLaf != null) {
+    println("Setting Test LaF to '${testLaf}'")
+    systemProperty "laf", testLaf
+  }
+  def testHiDPIScale = project.findProperty("test_HiDPIScale")
+  if (testHiDPIScale != null) {
+    println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
+    systemProperty "sun.java2d.uiScale", testHiDPIScale
+  }
+  sourceCompatibility = compile_source_compatibility
+  targetCompatibility = compile_target_compatibility
+  jvmArgs += additional_compiler_args
+
+  doFirst {
+  }
+}
+
+
+task compileLinkCheck(type: JavaCompile) {
+  options.fork = true
+  classpath = files("${jalviewDir}/${utils_dir}")
+  destinationDir = file("${jalviewDir}/${utils_dir}")
+  source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
+
+  inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
+  inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
+  outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
+  outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
+}
+
+
+task linkCheck(type: JavaExec) {
+  dependsOn prepare
+  dependsOn compileLinkCheck
+
+  def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
+  classpath = files("${jalviewDir}/${utils_dir}")
+  main = "HelpLinksChecker"
+  workingDir = jalviewDir
+  args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
+
+  def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
+  standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
+    outFOS,
+    System.out)
+  errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
+    outFOS,
+    System.err)
+
+  inputs.dir(helpBuildDir)
+  outputs.file(helpLinksCheckerOutFile)
+}
+
+
+// import the pubhtmlhelp target
+ant.properties.basedir = "${jalviewDir}"
+ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
+ant.importBuild "${utils_dir}/publishHelp.xml"
+
+
+task cleanPackageDir(type: Delete) {
+  doFirst {
+    delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
+  }
+}
+
+
+jar {
+  dependsOn prepare
+  dependsOn linkCheck
+
+  manifest {
+    attributes "Main-Class": main_class,
+    "Permissions": "all-permissions",
+    "Application-Name": install4jApplicationName,
+    "Codebase": application_codebase,
+    "Implementation-Version": JALVIEW_VERSION
+  }
+
+  def outputDir = "${jalviewDir}/${package_dir}"
+  destinationDirectory = file(outputDir)
+  archiveFileName = rootProject.name+".jar"
+
+  exclude "cache*/**"
+  exclude "*.jar"
+  exclude "*.jar.*"
+  exclude "**/*.jar"
+  exclude "**/*.jar.*"
+
+  inputs.dir(sourceSets.main.java.outputDir)
+  sourceSets.main.resources.srcDirs.each{ dir ->
+    inputs.dir(dir)
+  }
+
+  outputs.file("${outputDir}/${archiveFileName}")
+}
+
diff --git a/utils/debian/etc/jalview_properties b/utils/debian/etc/jalview_properties
new file mode 100644 (file)
index 0000000..0275ae3
--- /dev/null
@@ -0,0 +1,60 @@
+# global template for ~/.jalview_properties for debian systems
+# 
+# this file is copied into a user's home directory by 
+# the jalview wrapper script when no .jalview_properties file
+# exists. 
+#
+# changes to this file will not affect the jalview configuration
+# for existing users (at least not at the time of writing)
+
+# Configure the automatic display of the Jalview Example Project for new users
+# default is true
+# SHOW_STARTUP_FILE=false
+
+# Location of the file to be loaded in on startup if SHOW_STARTUP_FILE is true
+# default is https://www.jalview.org/examples/exampleFile_2_7.jvp
+# STARTUP_FILE=https://www.jalview.org/examples/exampleFile_2_7.jvp
+
+# 
+# Disable Jalview's connections to various web services
+#
+
+# Connection: https://www.jalview.org/services/identifiers 
+# uncomment to stop jalview retrieving a list of URL templates for
+# biological databases originally provided by identifiers.org
+#
+# NOIDENTIFIERSSERVICE=true
+
+# Connection: https://www.jalview.org/feeds/desktop/rss
+# uncomment to stop Jalview checking the www.jalview.org news feed
+# NONEWS=true
+
+# Connection: https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json
+# uncomment to disable download of the latest 'BioJS' HTML export template
+# NOHTMLTEMPLATES=true
+
+# Uncomment to disable pings to google analytics 
+# these provide record of launch statistics for the Jalview project
+#
+# default is to prompt user on launch. 
+# Allowed values are 'true', 'false' or undefined
+# USAGESTATS=false
+
+# Uncomment to disable jalview's retrieval of https://www.jalview.org/cgi-bin/questionnaire.pl
+# this service is used to make Jalview users aware 
+# of any community questionnaires currently active on www.jalview.org 
+# Allowed values are true/false. Default is true.
+# NOQUESTIONNAIRES=true
+
+# Uncomment to disable jalview's retrieval of https://www.jalview.org/webstart/jalview.jnlp
+# this document contains the version number of the latest release
+# and used to notify the user if they should consider upgrading their installation.
+# Allowed values are true/false. Default is true.
+# VERSION_CHECK=false
+
+# Uncomment to prevent jalview automatically contacting
+# https://www.compbio.dundee.ac.uk/jabaws/ to discover web services
+# When disabled, users can still initiate service discovery via a button 
+# in the 'Web Services' menu.
+# Allowed values are true or false. Default is true.
+# SHOW_JWS2_SERVICES=false 
\ No newline at end of file
index 5136d0b..003423c 100644 (file)
@@ -1,6 +1,6 @@
   <mime-type type="$$MIMETYPE$$">
     <comment>$$NAME$$ File</comment>
-    <icon name="$$ICONFILE$$"/>
+    <generic-icon name="$$ICONFILE$$"/>
 $$    <glob pattern="*.EXTENSIONS" weight="$$PRIORITY$$0"/>
 $$  </mime-type>
 
index 56fc037..15e1ea1 100755 (executable)
@@ -141,7 +141,7 @@ for my $shortname (@ordered) {
   $MimeType .= $mimetype;
 
   my $iconfile = $a->{iconfile};
-  $iconfile = "jalview-file" unless $iconfile;
+  $iconfile = "x-jalview-file" unless $iconfile;
 
   my $primary = (! grep($_ eq $shortname, @non_primary));
   my $primarystring = $primary?"true":"false";
@@ -233,7 +233,7 @@ Comment=Multiple Sequence Alignment Editor
 Icon=jalview-icon
 Type=Application
 TryExec=jalview
-Exec=jalview -open %u
+Exec=jalview %u
 Terminal=false
 Categories=Science;Biology;
 Keywords=alignment;sequence;
index c488d80..cf8634a 100755 (executable)
 ### and
 ### ./tgz/jre-VERSION-OS-ARCH.tgz
 ### which is an archive of the _contents_ of ./jre-VERSION-OS-ARCH/jre/ and used by install4j for the installer
+### bs 2021-10-26
+### Edited to use adoptium domain to gain access to Java 17 (LTS) versions.
 
-BASE=https://api.adoptopenjdk.net/v3/binary/latest
+BASE=https://api.adoptium.net/v3/binary/latest
 RELEASE_TYPE=ga
 JVM_IMPL=hotspot
 HEAP_SIZE=normal
-VENDOR=adoptopenjdk
+VENDOR=eclipse
 IMAGE_TYPE=jdk
 
 RM=/bin/rm
@@ -34,40 +36,38 @@ unzip-strip() (
   fi && rmdir "$temp"/* "$temp"
 )
 
-for FEATURE_VERSION in 8 11 12 13; do
-  for OS in mac; do
-  #for OS in linux mac windows; do
-    for ARCH in x64; do
-    #for ARCH in aarch64 arm x32 x64; do
-      NAME="${IMAGE_TYPE}-${FEATURE_VERSION}-${OS}-${ARCH}"
-      TARFILE="${NAME}.tgz"
-      echo "* Downloading ${TARFILE}"
-      URL="${BASE}/${FEATURE_VERSION}/${RELEASE_TYPE}/${OS}/${ARCH}/${IMAGE_TYPE}/${JVM_IMPL}/${HEAP_SIZE}/${VENDOR}"
-      wget -q -O "${TARFILE}" "${URL}"
-      if [ "$?" != 0 ]; then
-        echo "- No ${IMAGE_TYPE}-${FEATURE_VERSION} download for ${OS}-${ARCH} '${URL}'"
-        $RM -f "${TARFILE}"
-        continue;
-      fi
-      echo "Unpacking ${TARFILE}"
-      JREDIR="${NAME}/${IMAGE_TYPE}"
-      [ x$NAME != x -a -e "${JREDIR}" ] && $RM -rf "${JREDIR}"
-      mkdir -p "${JREDIR}"
-      if [ x$OS = xwindows ]; then
-        echo "using unzip"
-        unzip-strip "${TARFILE}" "${JREDIR}"
-        RET=$?
-      else
-        echo "using tar"
-        tar --strip-components=1 -C "${JREDIR}" -zxf "${TARFILE}"
-        RET=$?
-      fi
-      if [ "$RET" != 0 ]; then
-        echo "Error unpacking ${TARFILE}"
-        exit 1
-      fi
-      $RM "${TARFILE}"
-    done
+for FEATURE_VERSION in 8 11 17; do
+  for OS_ARCH in mac:x64 mac:aarch64 windows:x64 linux:x64 linux:arm linux:aarch64; do
+    OS=${OS_ARCH%:*}
+    ARCH=${OS_ARCH#*:}
+    NAME="${IMAGE_TYPE}-${FEATURE_VERSION}-${OS}-${ARCH}"
+    TARFILE="${NAME}.tgz"
+    echo "* Downloading ${TARFILE}"
+    URL="${BASE}/${FEATURE_VERSION}/${RELEASE_TYPE}/${OS}/${ARCH}/${IMAGE_TYPE}/${JVM_IMPL}/${HEAP_SIZE}/${VENDOR}"
+    wget -q -O "${TARFILE}" "${URL}"
+    if [ "$?" != 0 ]; then
+      echo "- No ${IMAGE_TYPE}-${FEATURE_VERSION} download for ${OS}-${ARCH} '${URL}'"
+      $RM -f "${TARFILE}"
+      continue;
+    fi
+    echo "Unpacking ${TARFILE}"
+    JREDIR="${NAME}/${IMAGE_TYPE}"
+    [ x$NAME != x -a -e "${JREDIR}" ] && $RM -rf "${JREDIR}"
+    mkdir -p "${JREDIR}"
+    if [ x$OS = xwindows ]; then
+      echo "using unzip"
+      unzip-strip "${TARFILE}" "${JREDIR}"
+      RET=$?
+    else
+      echo "using tar"
+      tar --strip-components=1 -C "${JREDIR}" -zxf "${TARFILE}"
+      RET=$?
+    fi
+    if [ "$RET" != 0 ]; then
+      echo "Error unpacking ${TARFILE}"
+      exit 1
+    fi
+    $RM "${TARFILE}"
   done
 done
 
index 89ed8fc..8029e82 100755 (executable)
 ### and
 ### ./tgz/jre-VERSION-OS-ARCH.tgz
 ### which is an archive of the _contents_ of ./jre-VERSION-OS-ARCH/jre/ and used by install4j for the installer
+### bs 2021-10-26
+### Edited to use adoptium domain to gain access to Java 17 (LTS) versions.
 
-BASE=https://api.adoptopenjdk.net/v3/binary/latest
+BASE=https://api.adoptium.net/v3/binary/latest
 RELEASE_TYPE=ga
 JVM_IMPL=hotspot
 HEAP_SIZE=normal
-VENDOR=adoptopenjdk
+VENDOR=eclipse
 IMAGE_TYPE=jre
 TAR=tar
 ZIP=zip
@@ -41,71 +43,74 @@ unzip-strip() (
   fi && rmdir "$temp"/* "$temp"
 )
 
-for FEATURE_VERSION in 8 11; do
-  for OS in linux mac windows; do
-    for ARCH in x64 x32 arm; do
-      #for ARCH in aarch64 arm x32 x64; do
-      NAME="${IMAGE_TYPE}-${FEATURE_VERSION}-${OS}-${ARCH}"
-      TARFILE="${NAME}.tgz"
-      echo "* Downloading ${TARFILE}"
-      URL="${BASE}/${FEATURE_VERSION}/${RELEASE_TYPE}/${OS}/${ARCH}/${IMAGE_TYPE}/${JVM_IMPL}/${HEAP_SIZE}/${VENDOR}"
-      wget -q -O "${TARFILE}" "${URL}"
-      if [ "$?" != 0 ]; then
-        echo "- No ${IMAGE_TYPE}-${FEATURE_VERSION} download for ${OS}-${ARCH} '${URL}'"
-        $RM -f "${TARFILE}"
-        continue;
-      fi
-      echo "Unpacking ${TARFILE}"
-      JREDIR="${NAME}/${IMAGE_TYPE}"
-      [ x$NAME != x -a -e "${JREDIR}" ] && $RM -rf "${JREDIR}"
-      mkdir -p "${JREDIR}"
-      if [ x$OS = xwindows ]; then
-        echo "using unzip"
-        unzip-strip "${TARFILE}" "${JREDIR}"
+for FEATURE_VERSION in 8 11 17; do
+  for OS_ARCH in mac:x64 mac:aarch64 windows:x64 linux:x64 linux:arm linux:aarch64; do
+    OS=${OS_ARCH%:*}
+    ARCH=${OS_ARCH#*:}
+    NAME="${IMAGE_TYPE}-${FEATURE_VERSION}-${OS}-${ARCH}"
+    TARFILE="${NAME}.tgz"
+    echo "* Downloading ${TARFILE}"
+    URL="${BASE}/${FEATURE_VERSION}/${RELEASE_TYPE}/${OS}/${ARCH}/${IMAGE_TYPE}/${JVM_IMPL}/${HEAP_SIZE}/${VENDOR}"
+    wget -q -O "${TARFILE}" "${URL}"
+    if [ "$?" != 0 ]; then
+      echo "- No ${IMAGE_TYPE}-${FEATURE_VERSION} download for ${OS}-${ARCH} '${URL}'"
+      $RM -f "${TARFILE}"
+      continue;
+    fi
+    echo "Unpacking ${TARFILE}"
+    JREDIR="${NAME}/${IMAGE_TYPE}"
+    [ x$NAME != x -a -e "${JREDIR}" ] && $RM -rf "${JREDIR}"
+    mkdir -p "${JREDIR}"
+    if [ x$OS = xwindows ]; then
+      echo "using unzip"
+      unzip-strip "${TARFILE}" "${JREDIR}"
+      RET=$?
+    else
+      echo "using tar"
+      if [ x$OS = xmac -a x$STRIP_MAC_APP_BUNDLING = xtrue ]; then
+        $TAR --strip-components=3 -C "${JREDIR}" -zxf "${TARFILE}" "*/Contents/Home"
         RET=$?
       else
-        echo "using tar"
-        if [ x$OS = xmac -a x$STRIP_MAC_APP_BUNDLING = xtrue ]; then
-          $TAR --strip-components=3 -C "${JREDIR}" -zxf "${TARFILE}" "*/Contents/Home"
-          RET=$?
-        else
-          $TAR --strip-components=1 -C "${JREDIR}" -zxf "${TARFILE}"
-          RET=$?
-        fi
-      fi
-      if [ "$RET" != 0 ]; then
-        echo "Error unpacking ${TARFILE}"
-        exit 1
-      fi
-      $RM "${TARFILE}"
-      if [ \! -z "$CREATE_ARCHIVES" ]; then
-        for CREATEARCHIVE in ${CREATE_ARCHIVES}; do
-          ARCHIVEDIR=$CREATEARCHIVE
-          case $CREATEARCHIVE in
-            zip)
-              EXT=${CREATEARCHIVE}
-              echo "Creating ${NAME}.${EXT} for getdown updates"
-              [ \! -d ${ARCHIVEDIR} ] && mkdir -p "${ARCHIVEDIR}"
-              ABSARCHIVEDIR="${PWD}/$ARCHIVEDIR"
-              ZIPFILE="${ABSARCHIVEDIR}/${NAME}.${CREATEARCHIVE}"
-              [ -e "${ZIPFILE}" ] && $RM "${ZIPFILE}"
-              cd ${NAME}
-              $ZIP -X -r "${ZIPFILE}" "${IMAGE_TYPE}"
-              cd -
-              ;;
-            tgz)
-              EXT=tar.gz
-              echo "Creating ${NAME}.${EXT} for install4j bundling"
-              [ \! -d ${ARCHIVEDIR} ] && mkdir -p "${ARCHIVEDIR}"
-              $TAR -C "${JREDIR}" -zcf "${ARCHIVEDIR}/${NAME}.${EXT}" .
-              ;;
-            *)
-              echo "Archiving as '${CREATEARCHIVE}' file not supported"
-              ;;
-          esac
-        done
+        $TAR --strip-components=1 -C "${JREDIR}" -zxf "${TARFILE}"
+        RET=$?
       fi
-    done
+    fi
+    if [ "$RET" != 0 ]; then
+      echo "Error unpacking ${TARFILE}"
+      exit 1
+    fi
+    $RM "${TARFILE}"
+    if [ \! -z "$CREATE_ARCHIVES" ]; then
+      for CREATEARCHIVE in ${CREATE_ARCHIVES}; do
+        ARCHIVEDIR=$CREATEARCHIVE
+        case $CREATEARCHIVE in
+          zip)
+            EXT=${CREATEARCHIVE}
+            echo "Creating ${NAME}.${EXT} for getdown updates"
+            [ \! -d ${ARCHIVEDIR} ] && mkdir -p "${ARCHIVEDIR}"
+            ABSARCHIVEDIR="${PWD}/$ARCHIVEDIR"
+            ZIPFILE="${ABSARCHIVEDIR}/${NAME}.${CREATEARCHIVE}"
+            [ -e "${ZIPFILE}" ] && $RM "${ZIPFILE}"
+            cd ${NAME}
+            $ZIP -X -r "${ZIPFILE}" "${IMAGE_TYPE}"
+            cd -
+            ;;
+          tgz)
+            EXT=tar.gz
+            echo "Creating ${NAME}.${EXT} for install4j bundling"
+            [ \! -d ${ARCHIVEDIR} ] && mkdir -p "${ARCHIVEDIR}"
+            $TAR -C "${JREDIR}" -zcf "${ARCHIVEDIR}/${NAME}.${EXT}" .
+            # make symbolic link with _ instead of - for install4j9
+            NEWNAME=${NAME//-/_}
+            echo "Linking from ${NEWNAME}.${EXT} for install4j9"
+            ln -s "${NAME}.${EXT}" "${ARCHIVEDIR}/${NEWNAME}.${EXT}"
+            ;;
+          *)
+            echo "Archiving as '${CREATEARCHIVE}' file not supported"
+            ;;
+        esac
+      done
+    fi
   done
 done
 
index f281469..31a4afa 100755 (executable)
@@ -39,7 +39,7 @@ my $add_associations = {
   annotations => {shortname=>"annotations",name=>"Jalview Annotations",extensions=>["annotations","jvannotations"]},
   mmcif => {shortname=>"mmcif",name=>"CIF",extensions=>["cif"]},
   mmcif2 => {shortname=>"mmcif2",name=>"mmCIF",extensions=>["mcif","mmcif"]},
-  jvl => {shortname=>"jvl",name=>"Jalview Launch",extensions=>["jvl"],iconfile=>"Jalview-Launch"},
+  jvl => {shortname=>"jvl",name=>"Jalview Launch",extensions=>["jvl"],iconfile=>"jvl_file"},
   jnet => {shortname=>"jnet",name=>"JnetFile",extensions=>["concise","jnet"]},
   scorematrix => {shortname=>"scorematrix",name=>"Substitution Matrix",extensions=>["mat"]},
 };
index fac86a3..0b927a8 100644 (file)
@@ -28,7 +28,7 @@
 <key>CFBundleTypeName</key>
 <string>Jalview Launch File</string>
 <key>CFBundleTypeIconFile</key>
-<string>Jalview-Launch.icns</string>
+<string>jvl_file.icns</string>
 <key>CFBundleTypeRole</key>
 <string>Editor</string>
 <key>CFBundleTypeMIMETypes</key>
 <dict>
 <key>CFBundleTypeExtensions</key>
 <array>
+<string>txt</string>
+</array>
+<key>CFBundleTypeName</key>
+<string>ENA Flatfile File</string>
+<key>CFBundleTypeIconFile</key>
+<string>Jalview-File.icns</string>
+<key>CFBundleTypeRole</key>
+<string>Editor</string>
+<key>CFBundleTypeMIMETypes</key>
+<array>
+<string>application/x-embl+txt</string>
+</array>
+<key>LSIsAppleDefaultForType</key>
+<true/>
+</dict>
+
+<dict>
+<key>CFBundleTypeExtensions</key>
+<array>
 <string>fa</string>
 <string>fasta</string>
 </array>
 <dict>
 <key>CFBundleTypeExtensions</key>
 <array>
+<string>gb</string>
+<string>gbk</string>
+</array>
+<key>CFBundleTypeName</key>
+<string>GenBank Flatfile File</string>
+<key>CFBundleTypeIconFile</key>
+<string>Jalview-File.icns</string>
+<key>CFBundleTypeRole</key>
+<string>Editor</string>
+<key>CFBundleTypeMIMETypes</key>
+<array>
+<string>application/x-genbank+txt</string>
+</array>
+<key>LSIsAppleDefaultForType</key>
+<true/>
+</dict>
+
+<dict>
+<key>CFBundleTypeExtensions</key>
+<array>
 <string>gff2</string>
 </array>
 <key>CFBundleTypeName</key>
index b14d32a..b995078 100644 (file)
@@ -18,7 +18,7 @@
                     <serializedBean>
                       <property name="description" type="string">Jalview File</property>
                       <property name="extension" type="string">jvp</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     <serializedBean>
                       <property name="description" type="string">Jalview Launch File</property>
                       <property name="extension" type="string">jvl</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
-                          <string>Jalview-Launch.icns</string>
+                          <string>jvl_file.icns</string>
                         </object>
                       </property>
                       <property name="macRole" type="enum" class="com.install4j.runtime.beans.actions.desktop.MacAssociationRole" value="EDITOR" />
                       <property name="unix" type="boolean" value="true" />
                       <property name="unixIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
-                          <string>Jalview-Launch.png</string>
+                          <string>jvl_file.png</string>
                         </object>
                       </property>
                       <property name="unixMimeType" type="string">application/x-jalview-jvl+text</property>
                       <property name="windowsIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
-                          <string>Jalview-Launch.ico</string>
+                          <string>jvl_file.ico</string>
                         </object>
                       </property>
                     </serializedBean>
                     <serializedBean>
                       <property name="description" type="string">CIF File</property>
                       <property name="extension" type="string">cif</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="mmCIF (.mcif, .mmcif) progress bar 13" id="10010" customizedId="mmCIF-mcif,mmcif-10010-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="mmCIF (.mcif, .mmcif) progress bar 12" id="10010" customizedId="mmCIF-mcif,mmcif-10010-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="13" />
+                      <property name="percentValue" type="int" value="12" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">mmCIF File</property>
                       <property name="extension" type="string">mcif,mmcif</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="PDB (.ent, .pdb) progress bar 17" id="10013" customizedId="PDB-ent,pdb-10013-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PDB (.ent, .pdb) progress bar 16" id="10013" customizedId="PDB-ent,pdb-10013-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="17" />
+                      <property name="percentValue" type="int" value="16" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">PDB File</property>
                       <property name="extension" type="string">ent,pdb</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="AMSA (.amsa) progress bar 21" id="10016" customizedId="AMSA-amsa-10016-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="AMSA (.amsa) progress bar 20" id="10016" customizedId="AMSA-amsa-10016-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="21" />
+                      <property name="percentValue" type="int" value="20" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">AMSA File</property>
                       <property name="extension" type="string">amsa</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Annotations (.annotations, .jvannotations) progress bar 26" id="10019" customizedId="Jalview Annotations-annotations,jvannotations-10019-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Annotations (.annotations, .jvannotations) progress bar 24" id="10019" customizedId="Jalview Annotations-annotations,jvannotations-10019-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="26" />
+                      <property name="percentValue" type="int" value="24" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">Jalview Annotations File</property>
                       <property name="extension" type="string">annotations,jvannotations</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="BioJSON (.biojson) progress bar 30" id="10022" customizedId="BioJSON-biojson-10022-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="BioJSON (.biojson) progress bar 28" id="10022" customizedId="BioJSON-biojson-10022-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="30" />
+                      <property name="percentValue" type="int" value="28" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">BioJSON File</property>
                       <property name="extension" type="string">biojson</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="BLC (.blc) progress bar 34" id="10025" customizedId="BLC-blc-10025-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="BLC (.blc) progress bar 32" id="10025" customizedId="BLC-blc-10025-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="34" />
+                      <property name="percentValue" type="int" value="32" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">BLC File</property>
                       <property name="extension" type="string">blc</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                     </serializedBean>
                   </action>
 
-                  <action name="Clustal (.aln) progress bar 39" id="10028" customizedId="Clustal-aln-10028-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Clustal (.aln) progress bar 36" id="10028" customizedId="Clustal-aln-10028-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="39" />
+                      <property name="percentValue" type="int" value="36" />
                     </serializedBean>
                   </action>
 
                     <serializedBean>
                       <property name="description" type="string">Clustal File</property>
                       <property name="extension" type="string">aln</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                   </action>
 <!-- END -->
 
+<!-- ENA Flatfile (.txt) BEGIN -->
+                  <action name="ENA Flatfile (.txt) message" id="10030" customizedId="ENA Flatfile-txt-10030-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                    <serializedBean>
+                      <property name="detailMessage" type="string">ENA Flatfile (.txt)</property>
+                      <property name="statusMessage" type="string">Creating file associations...</property>
+                      <property name="useDetail" type="boolean" value="true" />
+                      <property name="useStatus" type="boolean" value="true" />
+                    </serializedBean>
+                  </action>
+
+                  <action name="ENA Flatfile (.txt) progress bar 40" id="10031" customizedId="ENA Flatfile-txt-10031-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                    <serializedBean>
+                      <property name="percentValue" type="int" value="40" />
+                    </serializedBean>
+                  </action>
+
+                  <action name="ENA Flatfile (.txt) file association" id="10032" customizedId="ENA Flatfile-txt-10032-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .txt file association">
+                    <serializedBean>
+                      <property name="description" type="string">ENA Flatfile File</property>
+                      <property name="extension" type="string">txt</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
+                      <property name="macIconFile">
+                        <object class="com.install4j.api.beans.ExternalFile">
+                          <string>Jalview-File.icns</string>
+                        </object>
+                      </property>
+                      <property name="macRole" type="enum" class="com.install4j.runtime.beans.actions.desktop.MacAssociationRole" value="EDITOR" />
+                      <property name="restartFinder" type="boolean" value="true" />
+                      <property name="selected" type="boolean" value="true" />
+                      <property name="unix" type="boolean" value="true" />
+                      <property name="unixIconFile">
+                        <object class="com.install4j.api.beans.ExternalFile">
+                          <string>Jalview-File.png</string>
+                        </object>
+                      </property>
+                      <property name="unixMimeType" type="string">application/x-embl+txt</property>
+                      <property name="windowsIconFile">
+                        <object class="com.install4j.api.beans.ExternalFile">
+                          <string>Jalview-File.ico</string>
+                        </object>
+                      </property>
+                    </serializedBean>
+                  </action>
+<!-- END -->
+
 <!-- Fasta (.fa, .fasta) BEGIN -->
-                  <action name="Fasta (.fa, .fasta) message" id="10030" customizedId="Fasta-fa,fasta-10030-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Fasta (.fa, .fasta) message" id="10033" customizedId="Fasta-fa,fasta-10033-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">Fasta (.fa, .fasta)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="Fasta (.fa, .fasta) progress bar 43" id="10031" customizedId="Fasta-fa,fasta-10031-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Fasta (.fa, .fasta) progress bar 44" id="10034" customizedId="Fasta-fa,fasta-10034-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="43" />
+                      <property name="percentValue" type="int" value="44" />
                     </serializedBean>
                   </action>
 
-                  <action name="Fasta (.fa, .fasta) file association" id="10032" customizedId="Fasta-fa,fasta-10032-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .fa,fasta file association">
+                  <action name="Fasta (.fa, .fasta) file association" id="10035" customizedId="Fasta-fa,fasta-10035-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .fa,fasta file association">
                     <serializedBean>
                       <property name="description" type="string">Fasta File</property>
                       <property name="extension" type="string">fa,fasta</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- Jalview Features (.features, .jvfeatures) BEGIN -->
-                  <action name="Jalview Features (.features, .jvfeatures) message" id="10033" customizedId="Jalview Features-features,jvfeatures-10033-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Features (.features, .jvfeatures) message" id="10036" customizedId="Jalview Features-features,jvfeatures-10036-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">Jalview Features (.features, .jvfeatures)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Features (.features, .jvfeatures) progress bar 47" id="10034" customizedId="Jalview Features-features,jvfeatures-10034-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Features (.features, .jvfeatures) progress bar 48" id="10037" customizedId="Jalview Features-features,jvfeatures-10037-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="47" />
+                      <property name="percentValue" type="int" value="48" />
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Features (.features, .jvfeatures) file association" id="10035" customizedId="Jalview Features-features,jvfeatures-10035-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .features,jvfeatures file association">
+                  <action name="Jalview Features (.features, .jvfeatures) file association" id="10038" customizedId="Jalview Features-features,jvfeatures-10038-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .features,jvfeatures file association">
                     <serializedBean>
                       <property name="description" type="string">Jalview Features File</property>
                       <property name="extension" type="string">features,jvfeatures</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
                   </action>
 <!-- END -->
 
+<!-- GenBank Flatfile (.gb, .gbk) BEGIN -->
+                  <action name="GenBank Flatfile (.gb, .gbk) message" id="10039" customizedId="GenBank Flatfile-gb,gbk-10039-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                    <serializedBean>
+                      <property name="detailMessage" type="string">GenBank Flatfile (.gb, .gbk)</property>
+                      <property name="statusMessage" type="string">Creating file associations...</property>
+                      <property name="useDetail" type="boolean" value="true" />
+                      <property name="useStatus" type="boolean" value="true" />
+                    </serializedBean>
+                  </action>
+
+                  <action name="GenBank Flatfile (.gb, .gbk) progress bar 52" id="10040" customizedId="GenBank Flatfile-gb,gbk-10040-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                    <serializedBean>
+                      <property name="percentValue" type="int" value="52" />
+                    </serializedBean>
+                  </action>
+
+                  <action name="GenBank Flatfile (.gb, .gbk) file association" id="10041" customizedId="GenBank Flatfile-gb,gbk-10041-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .gb,gbk file association">
+                    <serializedBean>
+                      <property name="description" type="string">GenBank Flatfile File</property>
+                      <property name="extension" type="string">gb,gbk</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
+                      <property name="macIconFile">
+                        <object class="com.install4j.api.beans.ExternalFile">
+                          <string>Jalview-File.icns</string>
+                        </object>
+                      </property>
+                      <property name="macRole" type="enum" class="com.install4j.runtime.beans.actions.desktop.MacAssociationRole" value="EDITOR" />
+                      <property name="restartFinder" type="boolean" value="true" />
+                      <property name="selected" type="boolean" value="true" />
+                      <property name="unix" type="boolean" value="true" />
+                      <property name="unixIconFile">
+                        <object class="com.install4j.api.beans.ExternalFile">
+                          <string>Jalview-File.png</string>
+                        </object>
+                      </property>
+                      <property name="unixMimeType" type="string">application/x-genbank+txt</property>
+                      <property name="windowsIconFile">
+                        <object class="com.install4j.api.beans.ExternalFile">
+                          <string>Jalview-File.ico</string>
+                        </object>
+                      </property>
+                    </serializedBean>
+                  </action>
+<!-- END -->
+
 <!-- Generic Features Format v2 (.gff2) BEGIN -->
-                  <action name="Generic Features Format v2 (.gff2) message" id="10036" customizedId="Generic Features Format v2-gff2-10036-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Generic Features Format v2 (.gff2) message" id="10042" customizedId="Generic Features Format v2-gff2-10042-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">Generic Features Format v2 (.gff2)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="Generic Features Format v2 (.gff2) progress bar 52" id="10037" customizedId="Generic Features Format v2-gff2-10037-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Generic Features Format v2 (.gff2) progress bar 56" id="10043" customizedId="Generic Features Format v2-gff2-10043-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="52" />
+                      <property name="percentValue" type="int" value="56" />
                     </serializedBean>
                   </action>
 
-                  <action name="Generic Features Format v2 (.gff2) file association" id="10038" customizedId="Generic Features Format v2-gff2-10038-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .gff2 file association">
+                  <action name="Generic Features Format v2 (.gff2) file association" id="10044" customizedId="Generic Features Format v2-gff2-10044-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .gff2 file association">
                     <serializedBean>
                       <property name="description" type="string">Generic Features Format v2 File</property>
                       <property name="extension" type="string">gff2</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- Generic Features Format v3 (.gff3) BEGIN -->
-                  <action name="Generic Features Format v3 (.gff3) message" id="10039" customizedId="Generic Features Format v3-gff3-10039-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Generic Features Format v3 (.gff3) message" id="10045" customizedId="Generic Features Format v3-gff3-10045-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">Generic Features Format v3 (.gff3)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="Generic Features Format v3 (.gff3) progress bar 56" id="10040" customizedId="Generic Features Format v3-gff3-10040-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Generic Features Format v3 (.gff3) progress bar 60" id="10046" customizedId="Generic Features Format v3-gff3-10046-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="56" />
+                      <property name="percentValue" type="int" value="60" />
                     </serializedBean>
                   </action>
 
-                  <action name="Generic Features Format v3 (.gff3) file association" id="10041" customizedId="Generic Features Format v3-gff3-10041-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .gff3 file association">
+                  <action name="Generic Features Format v3 (.gff3) file association" id="10047" customizedId="Generic Features Format v3-gff3-10047-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .gff3 file association">
                     <serializedBean>
                       <property name="description" type="string">Generic Features Format v3 File</property>
                       <property name="extension" type="string">gff3</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- JnetFile (.concise, .jnet) BEGIN -->
-                  <action name="JnetFile (.concise, .jnet) message" id="10042" customizedId="JnetFile-concise,jnet-10042-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="JnetFile (.concise, .jnet) message" id="10048" customizedId="JnetFile-concise,jnet-10048-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">JnetFile (.concise, .jnet)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="JnetFile (.concise, .jnet) progress bar 60" id="10043" customizedId="JnetFile-concise,jnet-10043-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="JnetFile (.concise, .jnet) progress bar 64" id="10049" customizedId="JnetFile-concise,jnet-10049-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="60" />
+                      <property name="percentValue" type="int" value="64" />
                     </serializedBean>
                   </action>
 
-                  <action name="JnetFile (.concise, .jnet) file association" id="10044" customizedId="JnetFile-concise,jnet-10044-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .concise,jnet file association">
+                  <action name="JnetFile (.concise, .jnet) file association" id="10050" customizedId="JnetFile-concise,jnet-10050-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .concise,jnet file association">
                     <serializedBean>
                       <property name="description" type="string">JnetFile File</property>
                       <property name="extension" type="string">concise,jnet</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- MSF (.msf) BEGIN -->
-                  <action name="MSF (.msf) message" id="10045" customizedId="MSF-msf-10045-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="MSF (.msf) message" id="10051" customizedId="MSF-msf-10051-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">MSF (.msf)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="MSF (.msf) progress bar 65" id="10046" customizedId="MSF-msf-10046-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="MSF (.msf) progress bar 68" id="10052" customizedId="MSF-msf-10052-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="65" />
+                      <property name="percentValue" type="int" value="68" />
                     </serializedBean>
                   </action>
 
-                  <action name="MSF (.msf) file association" id="10047" customizedId="MSF-msf-10047-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .msf file association">
+                  <action name="MSF (.msf) file association" id="10053" customizedId="MSF-msf-10053-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .msf file association">
                     <serializedBean>
                       <property name="description" type="string">MSF File</property>
                       <property name="extension" type="string">msf</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- PFAM (.pfam) BEGIN -->
-                  <action name="PFAM (.pfam) message" id="10048" customizedId="PFAM-pfam-10048-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PFAM (.pfam) message" id="10054" customizedId="PFAM-pfam-10054-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">PFAM (.pfam)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="PFAM (.pfam) progress bar 69" id="10049" customizedId="PFAM-pfam-10049-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PFAM (.pfam) progress bar 72" id="10055" customizedId="PFAM-pfam-10055-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="69" />
+                      <property name="percentValue" type="int" value="72" />
                     </serializedBean>
                   </action>
 
-                  <action name="PFAM (.pfam) file association" id="10050" customizedId="PFAM-pfam-10050-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .pfam file association">
+                  <action name="PFAM (.pfam) file association" id="10056" customizedId="PFAM-pfam-10056-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .pfam file association">
                     <serializedBean>
                       <property name="description" type="string">PFAM File</property>
                       <property name="extension" type="string">pfam</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- PHYLIP (.phy) BEGIN -->
-                  <action name="PHYLIP (.phy) message" id="10051" customizedId="PHYLIP-phy-10051-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PHYLIP (.phy) message" id="10057" customizedId="PHYLIP-phy-10057-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">PHYLIP (.phy)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="PHYLIP (.phy) progress bar 73" id="10052" customizedId="PHYLIP-phy-10052-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PHYLIP (.phy) progress bar 76" id="10058" customizedId="PHYLIP-phy-10058-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="73" />
+                      <property name="percentValue" type="int" value="76" />
                     </serializedBean>
                   </action>
 
-                  <action name="PHYLIP (.phy) file association" id="10053" customizedId="PHYLIP-phy-10053-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .phy file association">
+                  <action name="PHYLIP (.phy) file association" id="10059" customizedId="PHYLIP-phy-10059-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .phy file association">
                     <serializedBean>
                       <property name="description" type="string">PHYLIP File</property>
                       <property name="extension" type="string">phy</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- PileUp (.pileup) BEGIN -->
-                  <action name="PileUp (.pileup) message" id="10054" customizedId="PileUp-pileup-10054-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PileUp (.pileup) message" id="10060" customizedId="PileUp-pileup-10060-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">PileUp (.pileup)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="PileUp (.pileup) progress bar 78" id="10055" customizedId="PileUp-pileup-10055-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PileUp (.pileup) progress bar 80" id="10061" customizedId="PileUp-pileup-10061-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="78" />
+                      <property name="percentValue" type="int" value="80" />
                     </serializedBean>
                   </action>
 
-                  <action name="PileUp (.pileup) file association" id="10056" customizedId="PileUp-pileup-10056-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .pileup file association">
+                  <action name="PileUp (.pileup) file association" id="10062" customizedId="PileUp-pileup-10062-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .pileup file association">
                     <serializedBean>
                       <property name="description" type="string">PileUp File</property>
                       <property name="extension" type="string">pileup</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- PIR (.pir) BEGIN -->
-                  <action name="PIR (.pir) message" id="10057" customizedId="PIR-pir-10057-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PIR (.pir) message" id="10063" customizedId="PIR-pir-10063-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">PIR (.pir)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="PIR (.pir) progress bar 82" id="10058" customizedId="PIR-pir-10058-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PIR (.pir) progress bar 84" id="10064" customizedId="PIR-pir-10064-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="82" />
+                      <property name="percentValue" type="int" value="84" />
                     </serializedBean>
                   </action>
 
-                  <action name="PIR (.pir) file association" id="10059" customizedId="PIR-pir-10059-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .pir file association">
+                  <action name="PIR (.pir) file association" id="10065" customizedId="PIR-pir-10065-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .pir file association">
                     <serializedBean>
                       <property name="description" type="string">PIR File</property>
                       <property name="extension" type="string">pir</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- RNAML (.rnaml) BEGIN -->
-                  <action name="RNAML (.rnaml) message" id="10060" customizedId="RNAML-rnaml-10060-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="RNAML (.rnaml) message" id="10066" customizedId="RNAML-rnaml-10066-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">RNAML (.rnaml)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="RNAML (.rnaml) progress bar 86" id="10061" customizedId="RNAML-rnaml-10061-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="RNAML (.rnaml) progress bar 88" id="10067" customizedId="RNAML-rnaml-10067-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="86" />
+                      <property name="percentValue" type="int" value="88" />
                     </serializedBean>
                   </action>
 
-                  <action name="RNAML (.rnaml) file association" id="10062" customizedId="RNAML-rnaml-10062-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .rnaml file association">
+                  <action name="RNAML (.rnaml) file association" id="10068" customizedId="RNAML-rnaml-10068-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .rnaml file association">
                     <serializedBean>
                       <property name="description" type="string">RNAML File</property>
                       <property name="extension" type="string">rnaml</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- Substitution Matrix (.mat) BEGIN -->
-                  <action name="Substitution Matrix (.mat) message" id="10063" customizedId="Substitution Matrix-mat-10063-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Substitution Matrix (.mat) message" id="10069" customizedId="Substitution Matrix-mat-10069-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">Substitution Matrix (.mat)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="Substitution Matrix (.mat) progress bar 91" id="10064" customizedId="Substitution Matrix-mat-10064-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Substitution Matrix (.mat) progress bar 92" id="10070" customizedId="Substitution Matrix-mat-10070-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="91" />
+                      <property name="percentValue" type="int" value="92" />
                     </serializedBean>
                   </action>
 
-                  <action name="Substitution Matrix (.mat) file association" id="10065" customizedId="Substitution Matrix-mat-10065-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .mat file association">
+                  <action name="Substitution Matrix (.mat) file association" id="10071" customizedId="Substitution Matrix-mat-10071-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .mat file association">
                     <serializedBean>
                       <property name="description" type="string">Substitution Matrix File</property>
                       <property name="extension" type="string">mat</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
 <!-- END -->
 
 <!-- Stockholm (.stk, .sto) BEGIN -->
-                  <action name="Stockholm (.stk, .sto) message" id="10066" customizedId="Stockholm-stk,sto-10066-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Stockholm (.stk, .sto) message" id="10072" customizedId="Stockholm-stk,sto-10072-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
                       <property name="detailMessage" type="string">Stockholm (.stk, .sto)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                     </serializedBean>
                   </action>
 
-                  <action name="Stockholm (.stk, .sto) progress bar 95" id="10067" customizedId="Stockholm-stk,sto-10067-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Stockholm (.stk, .sto) progress bar 96" id="10073" customizedId="Stockholm-stk,sto-10073-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="95" />
+                      <property name="percentValue" type="int" value="96" />
                     </serializedBean>
                   </action>
 
-                  <action name="Stockholm (.stk, .sto) file association" id="10068" customizedId="Stockholm-stk,sto-10068-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .stk,sto file association">
+                  <action name="Stockholm (.stk, .sto) file association" id="10074" customizedId="Stockholm-stk,sto-10074-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .stk,sto file association">
                     <serializedBean>
                       <property name="description" type="string">Stockholm File</property>
                       <property name="extension" type="string">stk,sto</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.icns</string>
index 5a311f1..c8e94a1 100644 (file)
@@ -18,7 +18,7 @@
                     <serializedBean>
                       <property name="description" type="string">$$NAME$$ File</property>
                       <property name="extension" type="string">$$EXTENSION$$</property>
-                      <property name="launcherId" type="string">737</property>
+                      <property name="launcherId" type="string">JALVIEW</property>
                       <property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>$$ICONFILE$$.icns</string>
index a14900c..e4e2193 100644 (file)
     </components>
   </files>
   <launchers>
-    <launcher name="Jalview Launcher" id="737" menuName="${compiler:JALVIEW_APPLICATION_NAME}" icnsFile="${compiler:JALVIEW_DIR}/${compiler:MAC_ICONS_FILE}" customMacBundleIdentifier="true" macBundleIdentifier="${compiler:BUNDLE_ID}" fileset="734" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:JALVIEW_APPLICATION_NAME}">
+    <launcher name="Jalview Launcher" id="737" customizedId="JALVIEW" menuName="${compiler:JALVIEW_APPLICATION_NAME}" icnsFile="${compiler:JALVIEW_DIR}/${compiler:MAC_ICONS_FILE}" customMacBundleIdentifier="true" macBundleIdentifier="${compiler:BUNDLE_ID}" fileset="734" useCustomMacosExecutableName="true" customMacosExecutableName="${compiler:JALVIEW_APPLICATION_NAME}">
       <executable name="${compiler:EXECUTABLE_NAME}" iconSet="true" iconFile="${compiler:JALVIEW_DIR}/${compiler:WINDOWS_ICONS_FILE}" redirectStdout="true" executableMode="gui" changeWorkingDirectory="false" singleInstance="true" checkConsoleParameter="true">
         <versionInfo include="true" fileDescription="${compiler:sys.fullName}" legalCopyright="${compiler:COPYRIGHT_MESSAGE}" internalName="${compiler:INTERNAL_ID}" productName="${compiler:sys.fullName}" />
       </executable>
@@ -533,19 +533,19 @@ return console.askOkCancel(message, true);
               </group>
               <action id="2350" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                 <serializedBean>
-                  <property name="launcherId" type="string">737</property>
+                  <property name="launcherId" type="string">JALVIEW</property>
                   <property name="scheme" type="string">jalview</property>
                 </serializedBean>
               </action>
               <action id="2450" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                 <serializedBean>
-                  <property name="launcherId" type="string">737</property>
+                  <property name="launcherId" type="string">JALVIEW</property>
                   <property name="scheme" type="string">jalviews</property>
                 </serializedBean>
               </action>
               <action id="2641" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                 <serializedBean>
-                  <property name="launcherId" type="string">737</property>
+                  <property name="launcherId" type="string">JALVIEW</property>
                   <property name="scheme" type="string">${compiler:EXTRA_SCHEME}</property>
                 </serializedBean>
               </action>
@@ -1287,7 +1287,7 @@ return console.askYesNo(message, true);
         <file name=".background/jalview_dmg_background.png" file="${compiler:JALVIEW_DIR}/${compiler:MACOS_DMG_BG_IMAGE}" />
         <file name=".DS_Store" file="${compiler:JALVIEW_DIR}/${compiler:MACOS_DMG_DS_STORE}" />
         <file name="${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/Resources/Jalview-File.icns" file="${compiler:JALVIEW_DIR}/${compiler:INSTALL4J_UTILS_DIR}/Jalview-File.icns" />
-        <file name="${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/Resources/Jalview-Launch.icns" file="${compiler:JALVIEW_DIR}/${compiler:INSTALL4J_UTILS_DIR}/Jalview-Launch.icns" />
+        <file name="${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/Resources/jvl_file.icns" file="${compiler:JALVIEW_DIR}/${compiler:INSTALL4J_UTILS_DIR}/jvl_file.icns" />
         <symlink name="${compiler:JALVIEW_APPLICATION_NAME}.app/Contents/MacOS/${compiler:WRAPPER_LINK}" target="../Resources/app/${compiler:WRAPPER_SCRIPT_BIN_DIR}/${compiler:BASH_WRAPPER_SCRIPT}" />
       </topLevelFiles>
     </macosArchive>
diff --git a/utils/install4j/jvl_file.icns b/utils/install4j/jvl_file.icns
new file mode 100644 (file)
index 0000000..8230feb
Binary files /dev/null and b/utils/install4j/jvl_file.icns differ
diff --git a/utils/install4j/jvl_file.ico b/utils/install4j/jvl_file.ico
new file mode 100644 (file)
index 0000000..8811bc2
Binary files /dev/null and b/utils/install4j/jvl_file.ico differ
diff --git a/utils/install4j/jvl_file.png b/utils/install4j/jvl_file.png
new file mode 100644 (file)
index 0000000..56e9eae
Binary files /dev/null and b/utils/install4j/jvl_file.png differ
diff --git a/utils/install4j/jvl_file.svg b/utils/install4j/jvl_file.svg
new file mode 100644 (file)
index 0000000..c6e01be
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 85.33334 85.333347"
+   enable-background="new 0 0 595.238 595.238"
+   xml:space="preserve"
+   sodipodi:docname="jvl_file.svg"
+   width="85.333344"
+   height="85.333344"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="2152"
+   inkscape:window-height="1410"
+   id="namedview11"
+   showgrid="false"
+   fit-margin-top="0"
+   fit-margin-left="0"
+   fit-margin-right="0"
+   fit-margin-bottom="0"
+   inkscape:zoom="2.7754382"
+   inkscape:cx="42.666672"
+   inkscape:cy="42.515809"
+   inkscape:window-x="0"
+   inkscape:window-y="0"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Layer_1" />
+  <metadata
+   id="metadata41">
+    <rdf:RDF>
+      <cc:Work
+   rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+   rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+   id="defs39">
+    
+    
+    
+    
+    
+    
+  </defs>
+  <g
+   id="g4756"
+   transform="translate(4.0769397e-6,-0.15086052)"><rect
+     style="fill:#0084a9;stroke-width:1"
+     id="rect2"
+     height="20.911402"
+     width="20.91173"
+     y="32.353989"
+     x="32.057495" /><path
+     inkscape:connector-curvature="0"
+     id="polygon4"
+     d="M 0,0.30172379 0.00572055,53.26261 H 10.525655 V 10.821168 H 68.897858 L 58.376942,0.30172379 Z"
+     style="fill:#ad208e;stroke-width:1" /><path
+     inkscape:connector-curvature="0"
+     id="polygon6"
+     d="m 26.699622,26.995298 h 31.67732 L 68.897858,16.921076 H 16.62115 v 36.329112 h 10.078472 z"
+     style="fill:#f78e1e;stroke-width:1" /><polygon
+     transform="matrix(0.16344439,0,0,0.16344439,-6.339681,-5.9678396)"
+     style="fill:#009ddc;stroke-width:6.11828899"
+     id="polygon8"
+     points="137.861,494.236 202.225,558.595 560.882,558.607 560.848,234.574 496.501,234.574 496.501,494.26 " /><polygon
+     transform="matrix(0.16344439,0,0,0.16344439,-6.339681,-5.9678396)"
+     style="fill:#c1d82f;stroke-width:6.11828899"
+     id="polygon10"
+     points="457.329,234.646 395.688,234.646 395.688,395.282 38.904,395.282 100.535,456.929 457.329,456.929 " /><path
+     inkscape:connector-curvature="0"
+     style="fill:none;stroke:#000000;stroke-width:0.1"
+     id="path32"
+     d="M 0.43525241,58.050222" /></g>
+</svg>
\ No newline at end of file
index ae01fe1..fd38213 100644 (file)
-
-com/stevesoft/pat/Any.js
-com/stevesoft/pat/Bracket.js
-com/stevesoft/pat/Branch.js
-com/stevesoft/pat/CaseMgr.js
-com/stevesoft/pat/DotMulti.js
-com/stevesoft/pat/End.js
-com/stevesoft/pat/FastBracket.js
-com/stevesoft/pat/FastChar.js
-com/stevesoft/pat/FastMulti.js
-com/stevesoft/pat/NUnicodeAlpha.js
-com/stevesoft/pat/NUnicodeCurrency.js
-com/stevesoft/pat/NUnicodeDigit.js
-com/stevesoft/pat/NUnicodeMath.js
-com/stevesoft/pat/NUnicodePunct.js
-com/stevesoft/pat/NUnicodeW.js
-com/stevesoft/pat/NUnicodeWhite.js
-com/stevesoft/pat/NoPattern.js
-com/stevesoft/pat/NullPattern.js
-com/stevesoft/pat/Or.js
-com/stevesoft/pat/OrMark.js
-com/stevesoft/pat/Pattern.js
-com/stevesoft/pat/PatternSub.js
-com/stevesoft/pat/Pthings.js
-com/stevesoft/pat/Range.js
-com/stevesoft/pat/RegHolder.js
-com/stevesoft/pat/RegOpt.js
-com/stevesoft/pat/RegRes.js
-com/stevesoft/pat/Regex.js
-com/stevesoft/pat/ReplaceRule.js
-com/stevesoft/pat/Replacer.js
-com/stevesoft/pat/Rthings.js
-com/stevesoft/pat/Skip.js
-com/stevesoft/pat/StrPos.js
-com/stevesoft/pat/StringLike.js
-com/stevesoft/pat/StringRule.js
-com/stevesoft/pat/SubMark.js
-com/stevesoft/pat/UniValidator.js
-com/stevesoft/pat/UnicodeAlpha.js
-com/stevesoft/pat/UnicodeCurrency.js
-com/stevesoft/pat/UnicodeDigit.js
-com/stevesoft/pat/UnicodeLower.js
-com/stevesoft/pat/UnicodeMath.js
-com/stevesoft/pat/UnicodePunct.js
-com/stevesoft/pat/UnicodeUpper.js
-com/stevesoft/pat/UnicodeW.js
-com/stevesoft/pat/UnicodeWhite.js
-com/stevesoft/pat/Validator.js
-com/stevesoft/pat/oneChar.js
-com/stevesoft/pat/parsePerl.js
-com/stevesoft/pat/patInf.js
-com/stevesoft/pat/patInt.js
-com/stevesoft/pat/wrap/StringWrap.js
+com/stevesoft/pat/Boundary.js
+com/stevesoft/pat/Start.js
 intervalstore/api/IntervalI.js
 intervalstore/api/IntervalStoreI.js
 intervalstore/impl/BinarySearcher.js
 intervalstore/impl/IntervalStore.js
 intervalstore/impl/NCList.js
 intervalstore/impl/NCNode.js
-jalview/analysis/AAFrequency.js
-jalview/analysis/AlignSeq.js
-jalview/analysis/AlignmentAnnotationUtils.js
-jalview/analysis/AlignmentUtils.js
-jalview/analysis/AnnotationSorter.js
-jalview/analysis/AverageDistanceTree.js
-jalview/analysis/Conservation.js
-jalview/analysis/CrossRef.js
-jalview/analysis/GeneticCodeI.js
-jalview/analysis/GeneticCodes.js
-jalview/analysis/Grouping.js
-jalview/analysis/NJTree.js
-jalview/analysis/SeqsetUtils.js
-jalview/analysis/SequenceIdMatcher.js
-jalview/analysis/TreeBuilder.js
-jalview/analysis/TreeModel.js
-jalview/analysis/scoremodels/DistanceScoreModel.js
-jalview/analysis/scoremodels/FeatureDistanceModel.js
-jalview/analysis/scoremodels/PIDModel.js
-jalview/analysis/scoremodels/ScoreMatrix.js
-jalview/analysis/scoremodels/ScoreModels.js
-jalview/analysis/scoremodels/SimilarityParams.js
-jalview/analysis/scoremodels/SimilarityScoreModel.js
-jalview/api/AlignCalcManagerI.js
-jalview/api/AlignCalcWorkerI.js
-jalview/api/AlignViewControllerGuiI.js
-jalview/api/AlignViewControllerI.js
-jalview/api/AlignViewportI.js
-jalview/api/AlignmentColsCollectionI.js
-jalview/api/AlignmentRowsCollectionI.js
-jalview/api/AlignmentViewPanel.js
-jalview/api/BuildDetailsI.js
-jalview/api/DBRefEntryI.js
-jalview/api/FeatureColourI.js
-jalview/api/FeatureRenderer.js
-jalview/api/FeatureSettingsControllerI.js
-jalview/api/FeatureSettingsModelI.js
-jalview/api/FeaturesDisplayedI.js
-jalview/api/OOMHandlerI.js
-jalview/api/RendererListenerI.js
-jalview/api/SequenceRenderer.js
-jalview/api/SequenceStructureBinding.js
-jalview/api/StructureSelectionManagerProvider.js
-jalview/api/ViewStyleI.js
-jalview/api/analysis/PairwiseScoreModelI.js
-jalview/api/analysis/ScoreModelI.js
-jalview/api/analysis/SimilarityParamsI.js
-jalview/api/structures/JalviewStructureDisplayI.js
-jalview/bin/ArgsParser.js
-jalview/bin/BuildDetails.js
-jalview/bin/Cache.js
-jalview/bin/Jalview.js
-jalview/controller/AlignViewController.js
-jalview/datamodel/ASequence.js
-jalview/datamodel/ASequenceI.js
-jalview/datamodel/Alignment.js
-jalview/datamodel/AlignmentAnnotation.js
-jalview/datamodel/AlignmentI.js
-jalview/datamodel/AlignmentView.js
-jalview/datamodel/AnnotatedCollectionI.js
-jalview/datamodel/Annotation.js
-jalview/datamodel/BinaryNode.js
-jalview/datamodel/CigarArray.js
-jalview/datamodel/CigarBase.js
-jalview/datamodel/CigarSimple.js
-jalview/datamodel/ColumnSelection.js
-jalview/datamodel/ContiguousI.js
-jalview/datamodel/DBRefEntry.js
-jalview/datamodel/DBRefSource.js
-jalview/datamodel/GraphLine.js
-jalview/datamodel/HiddenColumns.js
-jalview/datamodel/HiddenColumnsCursor.js
-jalview/datamodel/HiddenCursorPosition.js
-jalview/datamodel/HiddenSequences.js
-jalview/datamodel/Mapping.js
-jalview/datamodel/PDBEntry.js
-jalview/datamodel/Profile.js
-jalview/datamodel/ProfileI.js
-jalview/datamodel/Profiles.js
-jalview/datamodel/ProfilesI.js
-jalview/datamodel/Range.js
-jalview/datamodel/RangeElementsIterator.js
-jalview/datamodel/RangeIterator.js
-jalview/datamodel/ResidueCount.js
-jalview/datamodel/SearchResultMatchI.js
-jalview/datamodel/SearchResults.js
-jalview/datamodel/SearchResultsI.js
-jalview/datamodel/SeqCigar.js
-jalview/datamodel/Sequence.js
-jalview/datamodel/SequenceCollectionI.js
-jalview/datamodel/SequenceCursor.js
-jalview/datamodel/SequenceFeature.js
-jalview/datamodel/SequenceGroup.js
-jalview/datamodel/SequenceI.js
-jalview/datamodel/SequenceNode.js
-jalview/datamodel/StartRegionIterator.js
-jalview/datamodel/StructureViewerModel.js
-jalview/datamodel/VisibleColsCollection.js
-jalview/datamodel/VisibleContigsIterator.js
-jalview/datamodel/VisibleRowsCollection.js
-jalview/datamodel/VisibleRowsIterator.js
-jalview/datamodel/features/FeatureAttributes.js
-jalview/datamodel/features/FeatureLocationI.js
-jalview/datamodel/features/FeatureMatcherSet.js
-jalview/datamodel/features/FeatureMatcherSetI.js
-jalview/datamodel/features/FeatureSources.js
-jalview/datamodel/features/FeatureStore.js
-jalview/datamodel/features/SequenceFeatures.js
-jalview/datamodel/features/SequenceFeaturesI.js
-jalview/ext/ensembl/EnsemblData.js
-jalview/ext/ensembl/EnsemblGene.js
-jalview/ext/ensembl/EnsemblGenomes.js
-jalview/ext/ensembl/EnsemblRestClient.js
-jalview/ext/ensembl/EnsemblSeqProxy.js
-jalview/ext/ensembl/EnsemblSequenceFetcher.js
-jalview/ext/jmol/JalviewJmolBinding.js
-jalview/ext/jmol/JmolCommands.js
-jalview/ext/jmol/JmolParser.js
-jalview/fts/api/FTSData.js
-jalview/fts/api/FTSDataColumnI.js
-jalview/fts/api/FTSRestClientI.js
-jalview/fts/api/GFTSPanelI.js
-jalview/fts/core/DecimalFormatTableCellRenderer.js
-jalview/fts/core/FTSDataColumnPreferences.js
-jalview/fts/core/FTSRestClient.js
-jalview/fts/core/FTSRestRequest.js
-jalview/fts/core/FTSRestResponse.js
-jalview/fts/core/GFTSPanel.js
-jalview/fts/service/pdb/PDBFTSPanel.js
-jalview/fts/service/pdb/PDBFTSRestClient.js
-jalview/fts/service/uniprot/UniProtFTSRestClient.js
-jalview/fts/service/uniprot/UniprotFTSPanel.js
-jalview/gui/AlignFrame.js
-jalview/gui/AlignViewport.js
-jalview/gui/AlignmentPanel.js
-jalview/gui/AnnotationColumnChooser.js
-jalview/gui/AnnotationLabels.js
-jalview/gui/AnnotationPanel.js
-jalview/gui/AnnotationRowFilter.js
-jalview/gui/AppJmol.js
-jalview/gui/AppJmolBinding.js
-jalview/gui/CalculationChooser.js
-jalview/gui/ColourMenuHelper.js
-jalview/gui/ComboBoxTooltipRenderer.js
-jalview/gui/Desktop.js
-jalview/gui/FeatureRenderer.js
-jalview/gui/FeatureSettings.js
-jalview/gui/FeatureTypeSettings.js
-jalview/gui/FontChooser.js
-jalview/gui/IProgressIndicator.js
-jalview/gui/IdCanvas.js
-jalview/gui/IdPanel.js
-jalview/gui/IdwidthAdjuster.js
-jalview/gui/JalviewBooleanRadioButtons.js
-jalview/gui/JalviewChangeSupport.js
-jalview/gui/JalviewColourChooser.js
-jalview/gui/JalviewDialog.js
-jalview/gui/JvSwingUtils.js
-jalview/gui/OverviewCanvas.js
-jalview/gui/OverviewPanel.js
-jalview/gui/PaintRefresher.js
-jalview/gui/PopupMenu.js
-jalview/gui/Preferences.js
-jalview/gui/ProgressBar.js
-jalview/gui/ProgressPanel.js
-jalview/gui/ScalePanel.js
-jalview/gui/SeqCanvas.js
-jalview/gui/SeqPanel.js
-jalview/gui/SequenceFetcher.js
-jalview/gui/SequenceRenderer.js
-jalview/gui/SliderPanel.js
-jalview/gui/StructureChooser.js
-jalview/gui/StructureViewer.js
-jalview/gui/StructureViewerBase.js
-jalview/gui/TreeCanvas.js
-jalview/gui/TreePanel.js
-jalview/gui/ViewSelectionMenu.js
-jalview/io/AlignFile.js
-jalview/io/AlignmentFileReaderI.js
-jalview/io/AlignmentFileWriterI.js
-jalview/io/AnnotationFile.js
-jalview/io/AppletFormatAdapter.js
-jalview/io/DataSourceType.js
-jalview/io/FastaFile.js
-jalview/io/FileFormat.js
-jalview/io/FileFormatI.js
-jalview/io/FileFormats.js
-jalview/io/FileLoader.js
-jalview/io/FileParse.js
-jalview/io/FormatAdapter.js
-jalview/io/IdentifyFile.js
-jalview/io/JPredFile.js
-jalview/io/JalviewFileChooser.js
-jalview/io/JalviewFileFilter.js
-jalview/io/JalviewFileView.js
-jalview/io/JnetAnnotationMaker.js
-jalview/io/NewickFile.js
-jalview/io/PDBFeatureSettings.js
-jalview/io/PIRFile.js
-jalview/io/ScoreMatrixFile.js
-jalview/io/SequenceAnnotationReport.js
-jalview/io/StructureFile.js
-jalview/io/TCoffeeScoreFile.js
-jalview/io/cache/JvCacheableInputBox.js
-jalview/javascript/json/JSON.js
-jalview/javascript/log4j/ConsoleAppender.js
-jalview/javascript/log4j/Layout.js
-jalview/javascript/log4j/Level.js
-jalview/javascript/log4j/Logger.js
-jalview/javascript/log4j/Priority.js
-jalview/javascript/log4j/SimpleLayout.js
-jalview/javascript/log4j/spi/OptionHandler.js
-jalview/javascript/web/Client.js
-jalview/javascript/web/ClientResponse.js
-jalview/javascript/web/WebResource.js
-jalview/jbgui/BackupFilesPresetEntry.js
-jalview/jbgui/GAlignFrame.js
-jalview/jbgui/GAlignmentPanel.js
-jalview/jbgui/GDesktop.js
-jalview/jbgui/GFontChooser.js
-jalview/jbgui/GPreferences.js
-jalview/jbgui/GSliderPanel.js
-jalview/jbgui/GStructureChooser.js
-jalview/jbgui/GStructureViewer.js
-jalview/jbgui/GTreePanel.js
-jalview/jbgui/IntKeyStringValueEntry.js
-jalview/math/Matrix.js
-jalview/math/MatrixI.js
-jalview/project/Jalview2XML.js
-jalview/renderer/AnnotationRenderer.js
-jalview/renderer/AwtRenderPanelI.js
-jalview/renderer/OverviewRenderer.js
-jalview/renderer/OverviewResColourFinder.js
-jalview/renderer/ResidueColourFinder.js
-jalview/renderer/ResidueShader.js
-jalview/renderer/ResidueShaderI.js
-jalview/renderer/ScaleRenderer.js
-jalview/renderer/seqfeatures/FeatureColourFinder.js
-jalview/renderer/seqfeatures/FeatureRenderer.js
-jalview/schemes/Blosum62ColourScheme.js
-jalview/schemes/BuriedColourScheme.js
-jalview/schemes/ClustalxColourScheme.js
-jalview/schemes/ColourSchemeI.js
-jalview/schemes/ColourSchemeProperty.js
-jalview/schemes/ColourSchemes.js
-jalview/schemes/Consensus.js
-jalview/schemes/FeatureColour.js
-jalview/schemes/FeatureSettingsAdapter.js
-jalview/schemes/HelixColourScheme.js
-jalview/schemes/HydrophobicColourScheme.js
-jalview/schemes/IdColourScheme.js
-jalview/schemes/JalviewColourScheme.js
-jalview/schemes/NucleotideColourScheme.js
-jalview/schemes/PIDColourScheme.js
-jalview/schemes/PurinePyrimidineColourScheme.js
-jalview/schemes/RNAHelicesColour.js
-jalview/schemes/ResidueColourScheme.js
-jalview/schemes/ResidueProperties.js
-jalview/schemes/ScoreColourScheme.js
-jalview/schemes/StrandColourScheme.js
-jalview/schemes/TCoffeeColourScheme.js
-jalview/schemes/TaylorColourScheme.js
-jalview/schemes/TurnColourScheme.js
-jalview/schemes/ZappoColourScheme.js
-jalview/structure/AtomSpec.js
-jalview/structure/CommandListener.js
-jalview/structure/SelectionListener.js
-jalview/structure/SelectionSource.js
-jalview/structure/SequenceListener.js
-jalview/structure/StructureImportSettings.js
-jalview/structure/StructureListener.js
-jalview/structure/StructureMapping.js
-jalview/structure/StructureMappingcommandSet.js
-jalview/structure/StructureSelectionManager.js
-jalview/structure/VamsasSource.js
-jalview/structures/models/AAStructureBindingModel.js
-jalview/structures/models/SequenceStructureBindingModel.js
-jalview/urls/CustomUrlProvider.js
-jalview/urls/IdOrgSettings.js
-jalview/urls/IdentifiersUrlProvider.js
-jalview/urls/UrlLinkDisplay.js
-jalview/urls/UrlLinkTableModel.js
-jalview/urls/UrlProvider.js
-jalview/urls/UrlProviderImpl.js
-jalview/urls/api/UrlProviderFactoryI.js
-jalview/urls/api/UrlProviderI.js
-jalview/urls/desktop/DesktopUrlProviderFactory.js
-jalview/util/CaseInsensitiveString.js
-jalview/util/ColorUtils.js
-jalview/util/Comparison.js
-jalview/util/DBRefUtils.js
-jalview/util/Format.js
-jalview/util/LinkedIdentityHashSet.js
-jalview/util/MapList.js
-jalview/util/MessageManager.js
-jalview/util/Platform.js
-jalview/util/QuickSort.js
-jalview/util/SetUtils.js
-jalview/util/StringUtils.js
-jalview/util/UrlLink.js
-jalview/util/dialogrunner/DialogRunnerI.js
-jalview/util/jarInputStreamProvider.js
-jalview/viewmodel/AlignmentViewport.js
-jalview/viewmodel/OverviewDimensions.js
-jalview/viewmodel/OverviewDimensionsHideHidden.js
-jalview/viewmodel/ViewportListenerI.js
-jalview/viewmodel/ViewportProperties.js
-jalview/viewmodel/ViewportRanges.js
-jalview/viewmodel/annotationfilter/AnnotationFilterParameter.js
-jalview/viewmodel/seqfeatures/FeatureRendererModel.js
-jalview/viewmodel/seqfeatures/FeatureRendererSettings.js
-jalview/viewmodel/seqfeatures/FeaturesDisplayed.js
-jalview/viewmodel/styles/ViewStyle.js
-jalview/workers/AlignCalcManager.js
-jalview/workers/AlignCalcWorker.js
-jalview/workers/ComplementConsensusThread.js
-jalview/workers/ConsensusThread.js
-jalview/workers/ConservationThread.js
-jalview/workers/StrucConsensusThread.js
-jalview/ws/SequenceFetcher.js
-jalview/ws/dbsources/EbiFileRetrievedProxy.js
-jalview/ws/dbsources/EmblCdsSource.js
-jalview/ws/dbsources/EmblSource.js
-jalview/ws/dbsources/EmblXmlSource.js
-jalview/ws/dbsources/Pdb.js
-jalview/ws/dbsources/Pfam.js
-jalview/ws/dbsources/PfamFull.js
-jalview/ws/dbsources/PfamSeed.js
-jalview/ws/dbsources/Rfam.js
-jalview/ws/dbsources/RfamSeed.js
-jalview/ws/dbsources/Uniprot.js
-jalview/ws/dbsources/Xfam.js
-jalview/ws/ebi/EBIFetchClient.js
-jalview/ws/seqfetcher/ASequenceFetcher.js
-jalview/ws/seqfetcher/DbSourceProxy.js
-jalview/ws/seqfetcher/DbSourceProxyImpl.js
-jalview/ws/sifts/SiftsSettings.js
-jalview/xml/binding/jalview/Annotation.js
-jalview/xml/binding/jalview/AnnotationElement.js
-jalview/xml/binding/jalview/Feature.js
-jalview/xml/binding/jalview/JalviewModel.js
-jalview/xml/binding/jalview/ObjectFactory.js
-jalview/xml/binding/jalview/Pdbentry.js
-jalview/xml/binding/jalview/Sequence.js
-jalview/xml/binding/jalview/SequenceSet.js
-jalview/xml/binding/jalview/SequenceType.js
-jalview/xml/binding/jalview/VAMSAS.js
-jalview/xml/binding/jalview/WebServiceParameterSet.js
-jalview/xml/binding/uniprot/CitationType.js
-jalview/xml/binding/uniprot/CommentType.js
-jalview/xml/binding/uniprot/ConsortiumType.js
-jalview/xml/binding/uniprot/DbReferenceType.js
-jalview/xml/binding/uniprot/Entry.js
-jalview/xml/binding/uniprot/EventType.js
-jalview/xml/binding/uniprot/EvidenceType.js
-jalview/xml/binding/uniprot/EvidencedStringType.js
-jalview/xml/binding/uniprot/FeatureType.js
-jalview/xml/binding/uniprot/GeneNameType.js
-jalview/xml/binding/uniprot/GeneType.js
-jalview/xml/binding/uniprot/IsoformType.js
-jalview/xml/binding/uniprot/KeywordType.js
-jalview/xml/binding/uniprot/LocationType.js
-jalview/xml/binding/uniprot/NameListType.js
-jalview/xml/binding/uniprot/OrganismNameType.js
-jalview/xml/binding/uniprot/OrganismType.js
-jalview/xml/binding/uniprot/PersonType.js
-jalview/xml/binding/uniprot/PositionType.js
-jalview/xml/binding/uniprot/PropertyType.js
-jalview/xml/binding/uniprot/ProteinExistenceType.js
-jalview/xml/binding/uniprot/ProteinType.js
-jalview/xml/binding/uniprot/ReferenceType.js
-jalview/xml/binding/uniprot/SequenceType.js
-jalview/xml/binding/uniprot/SourceDataType.js
-jalview/xml/binding/uniprot/SourceType.js
-jalview/xml/binding/uniprot/SubcellularLocationType.js
-jalview/xml/binding/uniprot/Uniprot.js
+jalview/bin/JalviewTaskbar.js
+jalview/datamodel/AlignedCodonFrame.js
+jalview/ext/ensembl/EnsemblFeatures.js
+jalview/ext/ensembl/EnsemblLookup.js
+jalview/ext/ensembl/EnsemblSymbol.js
+jalview/ext/ensembl/EnsemblXref.js
+jalview/ext/ensembl/Species.js
+jalview/fts/api/StructureFTSRestClientI.js
+jalview/fts/service/threedbeacons/TDBeaconsFTSRestClient.js
+jalview/gui/APQHandlers.js
+jalview/gui/CrossRefAction.js
+jalview/gui/CutAndPasteTransfer.js
+jalview/gui/JvOptionPane.js
+jalview/gui/SplashScreen.js
+jalview/gui/structurechooser/PDBStructureChooserQuerySource.js
+jalview/gui/structurechooser/StructureChooserQuerySource.js
+jalview/gui/structurechooser/TDBResultAnalyser.js
+jalview/gui/structurechooser/ThreeDBStructureChooserQuerySource.js
+jalview/io/gff/SequenceOntologyFactory.js
+jalview/io/gff/SequenceOntologyI.js
+jalview/io/gff/SequenceOntologyLite.js
+jalview/jbgui/FilterOption.js
+jalview/jbgui/GCutAndPasteTransfer.js
+jalview/structure/AtomSpecModel.js
+jalview/structure/StructureCommand.js
+jalview/structure/StructureCommandI.js
+jalview/structure/StructureCommandsBase.js
+jalview/structure/StructureCommandsI.js
+jalview/util/ChannelProperties.js
+jalview/util/HttpUtils.js
+jalview/util/IntRangeComparator.js
+jalview/util/JSONUtils.js
+jalview/util/ShortcutKeyMaskExWrapper.js
+jalview/util/ShortcutKeyMaskExWrapper8.js
+jalview/util/ShortcutKeyMaskExWrapperI.js
+jalview/ws/SequenceFetcherFactory.js
+jalview/ws/dbsources/EBIAlfaFold.js
+jalview/ws/dbsources/EmblFlatfileSource.js
+jalview/ws/utils/UrlDownloadClient.js
+jalview/xml/binding/uniprot/InteractantType.js
+jalview/xml/binding/uniprot/MoleculeType.js
+jalview/xml/binding/uniprot/ReactionType.js
+java/applet/AppletContext.js
+java/applet/AppletStub.js
+java/applet/JSApplet.js
+java/awt/AWTEvent.js
+java/awt/AWTEventMulticaster.js
 java/awt/AWTKeyStroke.js
+java/awt/ActiveEvent.js
+java/awt/Adjustable.js
 java/awt/AlphaComposite.js
+java/awt/BasicStroke.js
+java/awt/BorderLayout.js
 java/awt/CardLayout.js
+java/awt/Color.js
+java/awt/Component.js
+java/awt/ComponentOrientation.js
 java/awt/Composite.js
+java/awt/Container.js
 java/awt/ContainerOrderFocusTraversalPolicy.js
+java/awt/Cursor.js
 java/awt/DefaultFocusTraversalPolicy.js
 java/awt/DefaultKeyboardFocusManager.js
+java/awt/Desktop.js
+java/awt/Dialog.js
+java/awt/Dimension.js
+java/awt/EventDispatchThread.js
+java/awt/EventFilter.js
+java/awt/EventQueue.js
+java/awt/EventQueueItem.js
+java/awt/FlowLayout.js
 java/awt/FocusTraversalPolicy.js
+java/awt/Font.js
+java/awt/FontMetrics.js
+java/awt/GraphicsCallback.js
+java/awt/GraphicsConfiguration.js
+java/awt/GraphicsDevice.js
+java/awt/GraphicsEnvironment.js
 java/awt/GridBagConstraints.js
 java/awt/GridBagLayout.js
 java/awt/GridBagLayoutInfo.js
 java/awt/GridLayout.js
 java/awt/Image.js
+java/awt/Insets.js
+java/awt/ItemSelectable.js
+java/awt/JSComponent.js
+java/awt/JSDialog.js
+java/awt/JSFrame.js
+java/awt/JSPanel.js
 java/awt/KeyEventDispatcher.js
 java/awt/KeyEventPostProcessor.js
 java/awt/KeyboardFocusManager.js
+java/awt/LayoutManager.js
+java/awt/LayoutManager2.js
+java/awt/LightweightDispatcher.js
+java/awt/Paint.js
+java/awt/Point.js
+java/awt/Queue.js
+java/awt/Rectangle.js
+java/awt/RenderingHints.js
 java/awt/SentEvent.js
+java/awt/Shape.js
+java/awt/Stroke.js
+java/awt/Taskbar.js
 java/awt/TextComponent.js
+java/awt/Toolkit.js
+java/awt/Transparency.js
 java/awt/VKCollection.js
+java/awt/Window.js
+java/awt/color/ColorSpace.js
 java/awt/datatransfer/ClipboardOwner.js
-java/awt/datatransfer/DataFlavor.js
 java/awt/datatransfer/FlavorMap.js
 java/awt/datatransfer/FlavorTable.js
-java/awt/datatransfer/MimeType.js
-java/awt/datatransfer/MimeTypeParameterList.js
 java/awt/datatransfer/SystemFlavorMap.js
-java/awt/datatransfer/Transferable.js
 java/awt/dnd/DropTarget.js
 java/awt/dnd/DropTargetContext.js
-java/awt/dnd/DropTargetDropEvent.js
-java/awt/dnd/DropTargetEvent.js
 java/awt/dnd/DropTargetListener.js
-java/awt/dnd/peer/DropTargetContextPeer.js
 java/awt/dnd/peer/DropTargetPeer.js
+java/awt/event/AWTEventListener.js
 java/awt/event/ActionEvent.js
+java/awt/event/ActionListener.js
+java/awt/event/AdjustmentEvent.js
+java/awt/event/AdjustmentListener.js
 java/awt/event/ComponentAdapter.js
+java/awt/event/ComponentEvent.js
+java/awt/event/ComponentListener.js
 java/awt/event/ContainerEvent.js
+java/awt/event/ContainerListener.js
 java/awt/event/FocusAdapter.js
+java/awt/event/FocusEvent.js
+java/awt/event/FocusListener.js
+java/awt/event/HierarchyBoundsListener.js
+java/awt/event/HierarchyEvent.js
+java/awt/event/HierarchyListener.js
+java/awt/event/InputEvent.js
+java/awt/event/InputMethodListener.js
+java/awt/event/InvocationEvent.js
+java/awt/event/ItemEvent.js
+java/awt/event/ItemListener.js
 java/awt/event/KeyAdapter.js
 java/awt/event/KeyEvent.js
+java/awt/event/KeyListener.js
 java/awt/event/MouseAdapter.js
+java/awt/event/MouseEvent.js
+java/awt/event/MouseListener.js
 java/awt/event/MouseMotionAdapter.js
+java/awt/event/MouseMotionListener.js
 java/awt/event/MouseWheelEvent.js
+java/awt/event/MouseWheelListener.js
+java/awt/event/TextListener.js
+java/awt/event/WindowAdapter.js
+java/awt/event/WindowEvent.js
+java/awt/event/WindowFocusListener.js
+java/awt/event/WindowListener.js
+java/awt/event/WindowStateListener.js
+java/awt/font/FontRenderContext.js
 java/awt/font/TextAttribute.js
+java/awt/geom/AffineTransform.js
+java/awt/geom/Dimension2D.js
 java/awt/geom/Path2D.js
 java/awt/geom/PathIterator.js
+java/awt/geom/Point2D.js
 java/awt/geom/RectIterator.js
+java/awt/geom/Rectangle2D.js
+java/awt/geom/RectangularShape.js
 java/awt/image/BufferedImage.js
 java/awt/image/ColorModel.js
 java/awt/image/DataBuffer.js
 java/awt/image/DataBufferInt.js
 java/awt/image/DirectColorModel.js
 java/awt/image/ImageConsumer.js
+java/awt/image/ImageObserver.js
 java/awt/image/ImageProducer.js
 java/awt/image/PackedColorModel.js
 java/awt/image/PixelGrabber.js
@@ -494,15 +186,26 @@ java/awt/image/RenderedImage.js
 java/awt/image/SampleModel.js
 java/awt/image/SinglePixelPackedSampleModel.js
 java/awt/image/WritableRaster.js
+java/awt/peer/ComponentPeer.js
+java/awt/peer/ContainerPeer.js
 java/awt/peer/DialogPeer.js
+java/awt/peer/FramePeer.js
 java/awt/peer/KeyboardFocusManagerPeer.js
+java/awt/peer/LightweightPeer.js
+java/awt/peer/WindowPeer.js
 java/awt/print/Printable.js
+java/beans/ChangeListenerMap.js
+java/beans/PropertyChangeEvent.js
+java/beans/PropertyChangeListener.js
+java/beans/PropertyChangeSupport.js
 java/io/BufferedInputStream.js
 java/io/BufferedReader.js
 java/io/BufferedWriter.js
 java/io/ByteArrayInputStream.js
 java/io/ByteArrayOutputStream.js
 java/io/Closeable.js
+java/io/DataInput.js
+java/io/DataInputStream.js
 java/io/File.js
 java/io/FileDescriptor.js
 java/io/FileInputStream.js
@@ -518,41 +221,44 @@ java/io/ObjectStreamField.js
 java/io/OutputStream.js
 java/io/OutputStreamWriter.js
 java/io/PrintStream.js
-java/io/PrintWriter.js
-java/io/PushbackInputStream.js
 java/io/Reader.js
 java/io/StringReader.js
 java/io/StringWriter.js
 java/io/Writer.js
+java/lang/AbstractStringBuilder.js
 java/lang/AutoCloseable.js
+java/lang/Class.js
+java/lang/Enum.js
 java/lang/Iterable.js
 java/lang/Readable.js
 java/lang/Runtime.js
+java/lang/StringBuffer.js
 java/lang/StringBuilder.js
+java/lang/Thread.js
+java/lang/ThreadGroup.js
+java/lang/ThreadLocal.js
+java/lang/ref/ReferenceQueue.js
+java/lang/reflect/AccessibleObject.js
+java/lang/reflect/AnnotatedElement.js
 java/lang/reflect/Constructor.js
 java/lang/reflect/Method.js
 java/math/BigDecimal.js
 java/math/BigInteger.js
 java/math/MathContext.js
 java/math/RoundingMode.js
+java/net/ContentHandler.js
 java/net/HttpURLConnection.js
-java/net/HttpsURLConnection.js
 java/net/URI.js
+java/net/URL.js
 java/net/URLConnection.js
-java/net/URLDecoder.js
 java/net/URLStreamHandler.js
-java/nio/Bits.js
-java/nio/Buffer.js
-java/nio/ByteBuffer.js
-java/nio/ByteOrder.js
-java/nio/CharBuffer.js
-java/nio/HeapByteBuffer.js
-java/nio/HeapCharBuffer.js
-java/nio/charset/Charset.js
-java/nio/charset/CharsetDecoder.js
-java/nio/charset/CoderResult.js
-java/nio/charset/CodingErrorAction.js
-java/security/AccessControlContext.js
+java/net/URLStreamHandlerFactory.js
+java/net/UnknownHostException.js
+java/nio/file/FileSystem.js
+java/nio/file/FileSystems.js
+java/nio/file/Path.js
+java/nio/file/Watchable.js
+java/nio/file/spi/FileSystemProvider.js
 java/security/AccessController.js
 java/security/PrivilegedAction.js
 java/security/PrivilegedExceptionAction.js
@@ -568,26 +274,46 @@ java/text/Format.js
 java/text/MessageFormat.js
 java/text/NumberFormat.js
 java/text/SimpleDateFormat.js
+java/text/spi/BreakIteratorProvider.js
+java/text/spi/CollatorProvider.js
+java/text/spi/DateFormatProvider.js
+java/text/spi/DateFormatSymbolsProvider.js
+java/text/spi/DecimalFormatSymbolsProvider.js
+java/text/spi/NumberFormatProvider.js
+java/util/AbstractCollection.js
+java/util/AbstractList.js
+java/util/AbstractMap.js
 java/util/AbstractQueue.js
 java/util/AbstractSequentialList.js
+java/util/AbstractSet.js
 java/util/ArrayDeque.js
+java/util/ArrayList.js
+java/util/Arrays.js
 java/util/BitSet.js
 java/util/Calendar.js
 java/util/Collection.js
+java/util/Collections.js
 java/util/ComparableTimSort.js
 java/util/Comparator.js
 java/util/Deque.js
+java/util/Dictionary.js
 java/util/DualPivotQuicksort.js
 java/util/Enumeration.js
+java/util/EventListener.js
+java/util/EventObject.js
 java/util/Formatter.js
 java/util/GregorianCalendar.js
+java/util/HashMap.js
+java/util/HashSet.js
+java/util/Hashtable.js
+java/util/IdentityHashMap.js
 java/util/Iterator.js
 java/util/LinkedHashMap.js
 java/util/LinkedHashSet.js
 java/util/LinkedList.js
 java/util/List.js
 java/util/ListIterator.js
-java/util/ListResourceBundle.js
+java/util/Locale.js
 java/util/Map.js
 java/util/NavigableMap.js
 java/util/NavigableSet.js
@@ -595,16 +321,22 @@ java/util/Objects.js
 java/util/Properties.js
 java/util/PropertyResourceBundle.js
 java/util/Queue.js
+java/util/Random.js
 java/util/RandomAccess.js
+java/util/RandomAccessSubList.js
 java/util/ResourceBundle.js
+java/util/ServiceLoader.js
 java/util/Set.js
 java/util/SortedMap.js
 java/util/SortedSet.js
+java/util/Stack.js
 java/util/StringTokenizer.js
+java/util/SubList.js
 java/util/TimSort.js
 java/util/TimeZone.js
 java/util/TreeMap.js
 java/util/TreeSet.js
+java/util/Vector.js
 java/util/WeakHashMap.js
 java/util/concurrent/AbstractExecutorService.js
 java/util/concurrent/BlockingQueue.js
@@ -619,7 +351,6 @@ java/util/concurrent/Semaphore.js
 java/util/concurrent/ThreadFactory.js
 java/util/concurrent/ThreadPoolExecutor.js
 java/util/concurrent/TimeUnit.js
-java/util/concurrent/atomic/AtomicBoolean.js
 java/util/concurrent/atomic/AtomicInteger.js
 java/util/concurrent/locks/AbstractOwnableSynchronizer.js
 java/util/concurrent/locks/AbstractQueuedSynchronizer.js
@@ -628,14 +359,16 @@ java/util/concurrent/locks/Lock.js
 java/util/concurrent/locks/ReadWriteLock.js
 java/util/concurrent/locks/ReentrantLock.js
 java/util/concurrent/locks/ReentrantReadWriteLock.js
-java/util/function/Function.js
 java/util/jar/JarEntry.js
 java/util/jar/JarInputStream.js
-java/util/logging/Level.js
-java/util/logging/Logger.js
 java/util/regex/MatchResult.js
 java/util/regex/Matcher.js
 java/util/regex/Pattern.js
+java/util/spi/CalendarDataProvider.js
+java/util/spi/CurrencyNameProvider.js
+java/util/spi/LocaleNameProvider.js
+java/util/spi/LocaleServiceProvider.js
+java/util/spi/TimeZoneNameProvider.js
 java/util/zip/CRC32.js
 java/util/zip/Inflater.js
 java/util/zip/InflaterInputStream.js
@@ -647,17 +380,20 @@ javajs/api/GenericCifDataParser.js
 javajs/api/GenericLineReader.js
 javajs/api/GenericOutputChannel.js
 javajs/api/JSONEncodable.js
-javajs/awt/Font.js
-javajs/awt/FontManager.js
 javajs/util/A4.js
+javajs/util/AU.js
+javajs/util/AjaxURLConnection.js
 javajs/util/AjaxURLStreamHandler.js
+javajs/util/AjaxURLStreamHandlerFactory.js
 javajs/util/BS.js
 javajs/util/Base64.js
 javajs/util/CU.js
 javajs/util/CifDataParser.js
 javajs/util/DF.js
 javajs/util/Encoding.js
+javajs/util/JSThread.js
 javajs/util/LimitedLineReader.js
+javajs/util/Lst.js
 javajs/util/M3.js
 javajs/util/M34.js
 javajs/util/M4.js
@@ -665,96 +401,141 @@ javajs/util/OC.js
 javajs/util/P3.js
 javajs/util/P3i.js
 javajs/util/P4.js
+javajs/util/PT.js
 javajs/util/Rdr.js
 javajs/util/SB.js
 javajs/util/T3.js
 javajs/util/T3i.js
 javajs/util/T4.js
 javajs/util/V3.js
+javax/net/ssl/HttpsURLConnection.js
 javax/swing/AbstractAction.js
-javax/swing/AbstractCellEditor.js
-javax/swing/AbstractSpinnerModel.js
+javax/swing/AbstractButton.js
+javax/swing/AbstractListModel.js
 javax/swing/Action.js
+javax/swing/ActionMap.js
+javax/swing/AncestorNotifier.js
+javax/swing/ArrayTable.js
 javax/swing/Autoscroller.js
-javax/swing/CellEditor.js
+javax/swing/BorderFactory.js
+javax/swing/BoundedRangeModel.js
+javax/swing/BoxLayout.js
+javax/swing/ButtonGroup.js
+javax/swing/ButtonModel.js
 javax/swing/CellRendererPane.js
-javax/swing/ColorChooserDialog.js
+javax/swing/ClientPropertyKey.js
+javax/swing/ComboBoxEditor.js
+javax/swing/ComboBoxModel.js
 javax/swing/ComponentInputMap.js
-javax/swing/DefaultCellEditor.js
+javax/swing/DefaultBoundedRangeModel.js
+javax/swing/DefaultButtonModel.js
+javax/swing/DefaultComboBoxModel.js
 javax/swing/DefaultDesktopManager.js
 javax/swing/DefaultListCellRenderer.js
 javax/swing/DefaultListSelectionModel.js
 javax/swing/DefaultRowSorter.js
+javax/swing/DefaultSingleSelectionModel.js
 javax/swing/DesktopManager.js
 javax/swing/DropMode.js
+javax/swing/FocusManager.js
 javax/swing/Icon.js
 javax/swing/ImageIcon.js
 javax/swing/InputMap.js
-javax/swing/JColorChooser.js
+javax/swing/InternalFrameFocusTraversalPolicy.js
+javax/swing/JApplet.js
+javax/swing/JButton.js
+javax/swing/JCheckBox.js
+javax/swing/JCheckBoxMenuItem.js
+javax/swing/JComboBox.js
+javax/swing/JComponent.js
 javax/swing/JDesktopPane.js
 javax/swing/JDialog.js
-javax/swing/JFileChooser.js
-javax/swing/JFormattedTextField.js
+javax/swing/JFrame.js
 javax/swing/JInternalFrame.js
+javax/swing/JLabel.js
+javax/swing/JLayeredPane.js
 javax/swing/JList.js
+javax/swing/JMenu.js
+javax/swing/JMenuBar.js
+javax/swing/JMenuItem.js
 javax/swing/JOptionPane.js
+javax/swing/JPanel.js
+javax/swing/JPopupMenu.js
 javax/swing/JProgressBar.js
-javax/swing/JRadioButton.js
+javax/swing/JRadioButtonMenuItem.js
+javax/swing/JRootPane.js
+javax/swing/JScrollBar.js
 javax/swing/JScrollPane.js
-javax/swing/JSlider.js
-javax/swing/JSpinner.js
+javax/swing/JSeparator.js
 javax/swing/JTabbedPane.js
 javax/swing/JTable.js
 javax/swing/JTextArea.js
 javax/swing/JTextField.js
+javax/swing/JToggleButton.js
 javax/swing/JToolTip.js
 javax/swing/JViewport.js
 javax/swing/JWindow.js
 javax/swing/KeyStroke.js
+javax/swing/KeyboardManager.js
+javax/swing/LayoutComparator.js
+javax/swing/LayoutFocusTraversalPolicy.js
 javax/swing/ListCellRenderer.js
+javax/swing/ListModel.js
 javax/swing/ListSelectionModel.js
+javax/swing/LookAndFeel.js
+javax/swing/MenuElement.js
 javax/swing/MenuSelectionManager.js
+javax/swing/MutableComboBoxModel.js
 javax/swing/Popup.js
 javax/swing/PopupFactory.js
-javax/swing/RowFilter.js
+javax/swing/RepaintManager.js
+javax/swing/RootPaneContainer.js
 javax/swing/RowSorter.js
 javax/swing/ScrollPaneConstants.js
 javax/swing/ScrollPaneLayout.js
 javax/swing/Scrollable.js
+javax/swing/SingleSelectionModel.js
+javax/swing/SizeRequirements.js
 javax/swing/SortOrder.js
-javax/swing/SpinnerModel.js
-javax/swing/SpinnerNumberModel.js
-javax/swing/Spring.js
-javax/swing/SpringLayout.js
+javax/swing/SortingFocusTraversalPolicy.js
+javax/swing/SwingConstants.js
+javax/swing/SwingContainerOrderFocusTraversalPolicy.js
+javax/swing/SwingDefaultFocusTraversalPolicy.js
+javax/swing/SwingPaintEventDispatcher.js
+javax/swing/SwingUtilities.js
 javax/swing/Timer.js
 javax/swing/ToolTipManager.js
+javax/swing/TransferHandler.js
+javax/swing/UIDefaults.js
+javax/swing/UIManager.js
 javax/swing/ViewportLayout.js
+javax/swing/WindowConstants.js
+javax/swing/border/AbstractBorder.js
+javax/swing/border/BevelBorder.js
+javax/swing/border/Border.js
 javax/swing/border/CompoundBorder.js
+javax/swing/border/EmptyBorder.js
+javax/swing/border/EtchedBorder.js
 javax/swing/border/LineBorder.js
-javax/swing/border/MatteBorder.js
-javax/swing/border/TitledBorder.js
-javax/swing/colorchooser/AbstractColorChooserPanel.js
-javax/swing/colorchooser/CenterLayout.js
-javax/swing/colorchooser/ColorChooserComponentFactory.js
-javax/swing/colorchooser/ColorSelectionModel.js
-javax/swing/colorchooser/DefaultColorSelectionModel.js
-javax/swing/colorchooser/DefaultPreviewPanel.js
-javax/swing/colorchooser/DefaultRGBChooserPanel.js
-javax/swing/colorchooser/DefaultSwatchChooserPanel.js
-javax/swing/colorchooser/MainSwatchPanel.js
-javax/swing/colorchooser/RecentSwatchPanel.js
-javax/swing/colorchooser/SmartGridLayout.js
-javax/swing/colorchooser/SwatchPanel.js
+javax/swing/event/AncestorEvent.js
+javax/swing/event/AncestorListener.js
 javax/swing/event/CaretEvent.js
 javax/swing/event/CaretListener.js
 javax/swing/event/CellEditorListener.js
+javax/swing/event/ChangeEvent.js
+javax/swing/event/ChangeListener.js
 javax/swing/event/DocumentEvent.js
 javax/swing/event/DocumentListener.js
+javax/swing/event/EventListenerList.js
+javax/swing/event/HyperlinkListener.js
 javax/swing/event/InternalFrameAdapter.js
 javax/swing/event/InternalFrameEvent.js
 javax/swing/event/InternalFrameListener.js
+javax/swing/event/ListDataEvent.js
+javax/swing/event/ListDataListener.js
 javax/swing/event/ListSelectionEvent.js
 javax/swing/event/ListSelectionListener.js
+javax/swing/event/MenuEvent.js
 javax/swing/event/MenuKeyListener.js
 javax/swing/event/MenuListener.js
 javax/swing/event/MouseInputListener.js
@@ -767,17 +548,23 @@ javax/swing/event/TableModelEvent.js
 javax/swing/event/TableModelListener.js
 javax/swing/event/UndoableEditEvent.js
 javax/swing/event/UndoableEditListener.js
-javax/swing/filechooser/FileFilter.js
-javax/swing/filechooser/FileView.js
+javax/swing/plaf/ActionMapUIResource.js
+javax/swing/plaf/BorderUIResource.js
+javax/swing/plaf/ColorUIResource.js
 javax/swing/plaf/ComponentInputMapUIResource.js
+javax/swing/plaf/ComponentUI.js
+javax/swing/plaf/DimensionUIResource.js
+javax/swing/plaf/FontUIResource.js
 javax/swing/plaf/InputMapUIResource.js
+javax/swing/plaf/InsetsUIResource.js
+javax/swing/plaf/UIResource.js
 javax/swing/plaf/basic/BasicBorders.js
+javax/swing/plaf/basic/BasicGraphicsUtils.js
 javax/swing/table/AbstractTableModel.js
 javax/swing/table/DefaultTableCellRenderer.js
 javax/swing/table/DefaultTableColumnModel.js
 javax/swing/table/DefaultTableModel.js
 javax/swing/table/JTableHeader.js
-javax/swing/table/TableCellEditor.js
 javax/swing/table/TableCellRenderer.js
 javax/swing/table/TableColumn.js
 javax/swing/table/TableColumnModel.js
@@ -785,21 +572,18 @@ javax/swing/table/TableModel.js
 javax/swing/table/TableRowSorter.js
 javax/swing/text/AbstractDocument.js
 javax/swing/text/AttributeSet.js
+javax/swing/text/BoxView.js
 javax/swing/text/Caret.js
+javax/swing/text/CompositeView.js
 javax/swing/text/DefaultCaret.js
 javax/swing/text/DefaultEditorKit.js
-javax/swing/text/DefaultFormatter.js
-javax/swing/text/DefaultFormatterFactory.js
 javax/swing/text/Document.js
-javax/swing/text/DocumentFilter.js
 javax/swing/text/EditorKit.js
 javax/swing/text/Element.js
 javax/swing/text/GapContent.js
 javax/swing/text/GapVector.js
-javax/swing/text/InternationalFormatter.js
 javax/swing/text/JTextComponent.js
 javax/swing/text/MutableAttributeSet.js
-javax/swing/text/NumberFormatter.js
 javax/swing/text/PlainDocument.js
 javax/swing/text/PlainView.js
 javax/swing/text/Position.js
@@ -813,7 +597,7 @@ javax/swing/text/TabExpander.js
 javax/swing/text/TextAction.js
 javax/swing/text/Utilities.js
 javax/swing/text/View.js
-javax/swing/tree/TreeCellEditor.js
+javax/swing/text/WrappedPlainView.js
 javax/swing/tree/TreeNode.js
 javax/swing/undo/AbstractUndoableEdit.js
 javax/swing/undo/CompoundEdit.js
@@ -831,15 +615,11 @@ javax/xml/bind/annotation/adapters/CollapsedStringAdapter.js
 javax/xml/bind/annotation/adapters/XmlAdapter.js
 javax/xml/bind/helpers/AbstractUnmarshallerImpl.js
 javax/xml/bind/helpers/DefaultValidationEventHandler.js
-javax/xml/datatype/DatatypeFactory.js
 javax/xml/datatype/XMLGregorianCalendar.js
 javax/xml/namespace/QName.js
 javax/xml/stream/XMLInputFactory.js
+javax/xml/stream/XMLStreamConstants.js
 javax/xml/stream/XMLStreamReader.js
-mc_view/Atom.js
-mc_view/Bond.js
-mc_view/PDBChain.js
-mc_view/Residue.js
 net/miginfocom/layout/AC.js
 net/miginfocom/layout/AnimSpec.js
 net/miginfocom/layout/BoundSize.js
@@ -858,7 +638,6 @@ net/miginfocom/layout/UnitValue.js
 net/miginfocom/swing/MigLayout.js
 net/miginfocom/swing/SwingComponentWrapper.js
 net/miginfocom/swing/SwingContainerWrapper.js
-org/apache/xerces/jaxp/datatype/DatatypeFactoryImpl.js
 org/apache/xerces/jaxp/datatype/XMLGregorianCalendarImpl.js
 org/jmol/adapter/readers/cif/CifReader.js
 org/jmol/adapter/readers/cif/MMCifReader.js
@@ -874,9 +653,9 @@ org/jmol/adapter/smarter/Resolver.js
 org/jmol/adapter/smarter/SmarterJmolAdapter.js
 org/jmol/adapter/smarter/Structure.js
 org/jmol/adapter/smarter/StructureIterator.js
-org/jmol/adapter/smarter/XtalSymmetry.js
 org/jmol/api/AtomIndexIterator.js
 org/jmol/api/EventManager.js
+org/jmol/api/FontManager.js
 org/jmol/api/GenericFileInterface.js
 org/jmol/api/GenericMouseInterface.js
 org/jmol/api/GenericPlatform.js
@@ -886,9 +665,9 @@ org/jmol/api/JmolAdapterAtomIterator.js
 org/jmol/api/JmolAdapterBondIterator.js
 org/jmol/api/JmolAdapterStructureIterator.js
 org/jmol/api/JmolCallbackListener.js
+org/jmol/api/JmolFilesReaderInterface.js
 org/jmol/api/JmolGraphicsInterface.js
 org/jmol/api/JmolMeasurementClient.js
-org/jmol/api/JmolPropertyManager.js
 org/jmol/api/JmolRendererInterface.js
 org/jmol/api/JmolRepaintManager.js
 org/jmol/api/JmolScriptEvaluator.js
@@ -920,6 +699,8 @@ org/jmol/c/PAL.js
 org/jmol/c/STER.js
 org/jmol/c/STR.js
 org/jmol/c/VDW.js
+org/jmol/dssx/Bridge.js
+org/jmol/dssx/DSSP.js
 org/jmol/g3d/CylinderRenderer.js
 org/jmol/g3d/G3DRenderer.js
 org/jmol/g3d/Graphics3D.js
@@ -936,6 +717,7 @@ org/jmol/i18n/GT.js
 org/jmol/i18n/Language.js
 org/jmol/i18n/Resource.js
 org/jmol/io/FileReader.js
+org/jmol/io/FilesReader.js
 org/jmol/modelset/Atom.js
 org/jmol/modelset/AtomCollection.js
 org/jmol/modelset/AtomIteratorWithinModel.js
@@ -945,9 +727,11 @@ org/jmol/modelset/BondIterator.js
 org/jmol/modelset/BondIteratorSelected.js
 org/jmol/modelset/Chain.js
 org/jmol/modelset/Group.js
+org/jmol/modelset/HBond.js
 org/jmol/modelset/LabelToken.js
 org/jmol/modelset/Measurement.js
 org/jmol/modelset/MeasurementData.js
+org/jmol/modelset/MeasurementPending.js
 org/jmol/modelset/Model.js
 org/jmol/modelset/ModelLoader.js
 org/jmol/modelset/ModelSet.js
@@ -965,12 +749,9 @@ org/jmol/modelsetbio/BioPolymer.js
 org/jmol/modelsetbio/BioResolver.js
 org/jmol/modelsetbio/Helix.js
 org/jmol/modelsetbio/Monomer.js
-org/jmol/modelsetbio/NucleicMonomer.js
-org/jmol/modelsetbio/NucleicPolymer.js
-org/jmol/modelsetbio/PhosphorusMonomer.js
-org/jmol/modelsetbio/PhosphorusPolymer.js
 org/jmol/modelsetbio/ProteinStructure.js
 org/jmol/modelsetbio/Sheet.js
+org/jmol/modelsetbio/Turn.js
 org/jmol/render/BallsRenderer.js
 org/jmol/render/BbcageRenderer.js
 org/jmol/render/CageRenderer.js
@@ -1000,6 +781,7 @@ org/jmol/script/ScriptFunction.js
 org/jmol/script/ScriptManager.js
 org/jmol/script/ScriptMathProcessor.js
 org/jmol/script/ScriptParam.js
+org/jmol/script/ScriptQueueThread.js
 org/jmol/script/ScriptTokenParser.js
 org/jmol/script/T.js
 org/jmol/scriptext/CmdExt.js
@@ -1008,6 +790,7 @@ org/jmol/scriptext/ScriptExt.js
 org/jmol/shape/AtomShape.js
 org/jmol/shape/Balls.js
 org/jmol/shape/Bbcage.js
+org/jmol/shape/Echo.js
 org/jmol/shape/FontLineShape.js
 org/jmol/shape/Frank.js
 org/jmol/shape/Hover.js
@@ -1027,6 +810,7 @@ org/jmol/symmetry/SymmetryInfo.js
 org/jmol/symmetry/UnitCell.js
 org/jmol/thread/HoverWatcherThread.js
 org/jmol/thread/JmolThread.js
+org/jmol/thread/TimeoutThread.js
 org/jmol/util/BSUtil.js
 org/jmol/util/BoxInfo.js
 org/jmol/util/C.js
@@ -1036,6 +820,7 @@ org/jmol/util/DefaultLogger.js
 org/jmol/util/Edge.js
 org/jmol/util/Elements.js
 org/jmol/util/Escape.js
+org/jmol/util/Font.js
 org/jmol/util/GData.js
 org/jmol/util/Geodesic.js
 org/jmol/util/Int2IntHash.js
@@ -1063,7 +848,6 @@ org/jmol/viewer/JC.js
 org/jmol/viewer/ModelManager.js
 org/jmol/viewer/MotionPoint.js
 org/jmol/viewer/MouseState.js
-org/jmol/viewer/PropertyManager.js
 org/jmol/viewer/SelectionManager.js
 org/jmol/viewer/ShapeManager.js
 org/jmol/viewer/StateManager.js
@@ -1072,6 +856,7 @@ org/jmol/viewer/TransformManager.js
 org/jmol/viewer/Viewer.js
 org/jmol/viewer/binding/Binding.js
 org/jmol/viewer/binding/JmolBinding.js
+org/json/simple/parser/ParseException.js
 org/xml/sax/AttributeList.js
 org/xml/sax/Attributes.js
 org/xml/sax/ContentHandler.js
@@ -1079,11 +864,18 @@ org/xml/sax/InputSource.js
 org/xml/sax/Parser.js
 org/xml/sax/XMLReader.js
 org/xml/sax/ext/Attributes2.js
-sun/awt/AWTAccessor.js
+sun/awt/AWTAutoShutdown.js
+sun/awt/AppContext.js
 sun/awt/CausedFocusEvent.js
+sun/awt/ComponentFactory.js
 sun/awt/EventQueueItem.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
+sun/awt/MostRecentKeyValue.js
+sun/awt/MostRecentThreadAppContext.js
+sun/awt/PaintEventDispatcher.js
+sun/awt/PostEventQueue.js
+sun/awt/RequestFocusController.js
 sun/awt/SunGraphicsCallback.js
+sun/awt/SunToolkit.js
 sun/awt/image/DataStealer.js
 sun/awt/image/IntegerComponentRaster.js
 sun/awt/image/IntegerInterleavedRaster.js
@@ -1094,20 +886,18 @@ sun/font/EAttribute.js
 sun/font/FontDesignMetrics.js
 sun/java2d/StateTrackable.js
 sun/java2d/StateTrackableDelegate.js
-sun/nio/cs/ArrayDecoder.js
-sun/nio/cs/HistoricallyNamedCharset.js
-sun/nio/cs/StandardCharsets.js
-sun/nio/cs/ThreadLocalCoders.js
-sun/nio/cs/UTF_8.js
-sun/nio/cs/Unicode.js
+sun/net/www/MessageHeader.js
 sun/swing/DefaultLookup.js
 sun/swing/StringUIClientPropertyKey.js
+sun/swing/SwingLazyValue.js
 sun/swing/SwingUtilities2.js
 sun/swing/UIAction.js
 sun/swing/UIClientPropertyKey.js
 sun/swing/table/DefaultTableCellHeaderRenderer.js
 sun/text/resources/FormatData.js
-sun/text/resources/FormatData_en.js
+sun/text/resources/en/FormatData_en.js
+sun/text/resources/en/FormatData_en_GB.js
+sun/text/resources/en/FormatData_en_US.js
 sun/util/calendar/AbstractCalendar.js
 sun/util/calendar/BaseCalendar.js
 sun/util/calendar/CalendarDate.js
@@ -1115,22 +905,56 @@ sun/util/calendar/CalendarSystem.js
 sun/util/calendar/CalendarUtils.js
 sun/util/calendar/Gregorian.js
 sun/util/calendar/ZoneInfo.js
+sun/util/calendar/ZoneInfoFile.js
+sun/util/locale/BaseLocale.js
+sun/util/locale/LanguageTag.js
+sun/util/locale/LocaleUtils.js
+sun/util/locale/provider/AuxLocaleProviderAdapter.js
+sun/util/locale/provider/AvailableLanguageTags.js
+sun/util/locale/provider/CalendarDataProviderImpl.js
+sun/util/locale/provider/CalendarDataUtility.js
+sun/util/locale/provider/CalendarProviderImpl.js
+sun/util/locale/provider/DateFormatProviderImpl.js
+sun/util/locale/provider/JRELocaleProviderAdapter.js
+sun/util/locale/provider/LocaleDataMetaInfo.js
+sun/util/locale/provider/LocaleProviderAdapter.js
+sun/util/locale/provider/LocaleResources.js
+sun/util/locale/provider/LocaleServiceProviderPool.js
+sun/util/locale/provider/ResourceBundleBasedAdapter.js
+sun/util/locale/provider/SPILocaleProviderAdapter.js
 sun/util/resources/LocaleData.js
-swingjs/JSAbstractDocument.js
-swingjs/JSCharSet.js
-swingjs/JSDnD.js
-swingjs/JSDocumentEvent.js
+sun/util/resources/ParallelListResourceBundle.js
+sun/util/spi/CalendarProvider.js
+swingjs/JSApp.js
+swingjs/JSAppletThread.js
+swingjs/JSAppletViewer.js
+swingjs/JSDummyApplet.js
+swingjs/JSFileSystem.js
 swingjs/JSFocusPeer.js
-swingjs/JSGraphicsCompositor.js
+swingjs/JSFontMetrics.js
+swingjs/JSFrameViewer.js
+swingjs/JSGraphics2D.js
+swingjs/JSGraphicsConfiguration.js
+swingjs/JSGraphicsEnvironment.js
 swingjs/JSImage.js
 swingjs/JSImagekit.js
 swingjs/JSKeyEvent.js
 swingjs/JSMenuManager.js
-swingjs/JSPlainDocument.js
-swingjs/JSTempFile.js
+swingjs/JSMouse.js
+swingjs/JSScreenDevice.js
+swingjs/JSThreadGroup.js
+swingjs/JSToolkit.js
+swingjs/JSUtil.js
 swingjs/a2s/A2SContainer.js
 swingjs/a2s/Dialog.js
-swingjs/api/JSMinimalAbstractDocument.js
+swingjs/api/Interface.js
+swingjs/api/JSUtilI.js
+swingjs/api/js/DOMNode.js
+swingjs/api/js/HTML5Canvas.js
+swingjs/api/js/HTML5CanvasContext2D.js
+swingjs/api/js/JSFunction.js
+swingjs/api/js/JSInterface.js
+swingjs/jquery/JQueryUI.js
 swingjs/json/JSON.js
 swingjs/jzlib/Adler32.js
 swingjs/jzlib/CRC32.js
@@ -1142,42 +966,66 @@ swingjs/jzlib/Inflate.js
 swingjs/jzlib/Inflater.js
 swingjs/jzlib/InflaterInputStream.js
 swingjs/jzlib/ZStream.js
-swingjs/plaf/BasicArrowButton.js
+swingjs/plaf/BasicComboBoxEditor.js
+swingjs/plaf/BasicComboBoxRenderer.js
 swingjs/plaf/BasicHTML.js
+swingjs/plaf/ButtonListener.js
 swingjs/plaf/CellHolder.js
-swingjs/plaf/CenterLayout.js
+swingjs/plaf/DefaultMenuLayout.js
+swingjs/plaf/HTML5LookAndFeel.js
 swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSColorChooserUI.js
+swingjs/plaf/JSButtonUI.js
+swingjs/plaf/JSCheckBoxMenuItemUI.js
+swingjs/plaf/JSCheckBoxUI.js
+swingjs/plaf/JSComboBoxUI.js
+swingjs/plaf/JSComboPopupList.js
+swingjs/plaf/JSComponentUI.js
 swingjs/plaf/JSDesktopIconUI.js
 swingjs/plaf/JSDesktopPaneUI.js
 swingjs/plaf/JSDialogUI.js
-swingjs/plaf/JSFormattedTextFieldUI.js
+swingjs/plaf/JSEventHandler.js
+swingjs/plaf/JSFrameUI.js
 swingjs/plaf/JSGraphicsUtils.js
 swingjs/plaf/JSInternalFrameUI.js
+swingjs/plaf/JSLabelUI.js
+swingjs/plaf/JSLayeredPaneUI.js
+swingjs/plaf/JSLightweightUI.js
 swingjs/plaf/JSListUI.js
+swingjs/plaf/JSMenuBarUI.js
+swingjs/plaf/JSMenuItemUI.js
+swingjs/plaf/JSMenuUI.js
+swingjs/plaf/JSOptionPaneUI.js
+swingjs/plaf/JSPanelUI.js
+swingjs/plaf/JSPopupMenuSeparatorUI.js
+swingjs/plaf/JSPopupMenuUI.js
 swingjs/plaf/JSPopupUI.js
 swingjs/plaf/JSProgressBarUI.js
+swingjs/plaf/JSRadioButtonMenuItemUI.js
+swingjs/plaf/JSRadioButtonUI.js
+swingjs/plaf/JSRootPaneUI.js
+swingjs/plaf/JSScrollBarUI.js
 swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSpinnerUI.js
+swingjs/plaf/JSSeparatorUI.js
+swingjs/plaf/JSSliderUI.js
 swingjs/plaf/JSTabbedPaneUI.js
 swingjs/plaf/JSTableHeaderUI.js
 swingjs/plaf/JSTableUI.js
 swingjs/plaf/JSTextAreaUI.js
 swingjs/plaf/JSTextFieldUI.js
 swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
 swingjs/plaf/JSToolTipUI.js
 swingjs/plaf/JSViewportUI.js
+swingjs/plaf/JSWindowUI.js
+swingjs/plaf/LazyActionMap.js
+swingjs/plaf/Resizer.js
 swingjs/plaf/TextListener.js
 swingjs/xml/JSJAXBClass.js
 swingjs/xml/JSJAXBContext.js
 swingjs/xml/JSJAXBContextFactory.js
-swingjs/xml/JSJAXBDatatypeFactory.js
 swingjs/xml/JSJAXBField.js
 swingjs/xml/JSJAXBUnmarshaller.js
 swingjs/xml/JSSAXAttributes.js
 swingjs/xml/JSSAXParser.js
 swingjs/xml/JSXMLGregorianCalendarImpl.js
 swingjs/xml/JSXMLInputFactory.js
-swingjs/xml/JSXMLStreamReader.jscom/stevesoft/pat/Any.js
-swingjs/xml/JSXMLStreamReader.jscom/stevesoft/pat/Boundary.js
+swingjs/xml/JSXMLStreamReader.js
index 94bd28e..65732a4 100644 (file)
Binary files a/utils/jalviewjs/libjs/jmol-app.zip and b/utils/jalviewjs/libjs/jmol-app.zip differ
diff --git a/utils/mk_jalview_icons.sh b/utils/mk_jalview_icons.sh
new file mode 100755 (executable)
index 0000000..4a2768e
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+FILENAME512=$1
+BASENAME=${FILENAME512%-512.png}
+
+usage () {
+  echo "$(basename "$0") <LOGO_NAME>-512.png"
+}
+
+[ "$1" = "-h" ] && usage && exit 0
+[ -r "$FILENAME512" ] || ( usage && echo "'${FILENAME512}' must exist and be readable" && exit 1 )
+[ "$BASENAME" = "$FILENAME512" ] && usage && echo "Must have '-512.png' at end of filename" && exit 2
+
+set -e
+
+SIZES="16 32 38 48 64 128 256"
+declare -a ICOFILES=()
+declare -a ICNSFILES=()
+for n in $SIZES
+do
+  NEWFILE="${BASENAME}-${n}.png"
+  [ -e "{$NEWFILE}" ] && continue
+  convert -geometry "${n}x${n}" "${BASENAME}-512.png" "${NEWFILE}"
+  [ "${n}" != 38 ] && ICOFILES=( "${ICOFILES[@]}" "${NEWFILE}" )
+  [ "${n}" != 64 ] && [ "${n}" != 38 ] && ICNSFILES=( "${ICNSFILES[@]}" "${NEWFILE}" )
+done
+
+# make the .ico
+ICOFILE="${BASENAME}.ico"
+echo "Creating ${ICOFILE}"
+convert "${ICOFILES[@]}" "${ICOFILE}"
+
+# make the .icns
+ICNSFILE="${BASENAME}.icns"
+echo "Creating ${ICNSFILE}"
+png2icns "${ICNSFILE}" "${ICNSFILES[@]}"
+
+# make the rotatable icon
+ROTATABLEFILE="rotatable_${BASENAME}-38.png"
+convert "${BASENAME}-38.png" -gravity center -background white -extent 60x60 "${ROTATABLEFILE}"
+
+exit 0