Merge branch 'develop' into trialMerge
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 25 Nov 2016 14:21:34 +0000 (14:21 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 25 Nov 2016 14:21:34 +0000 (14:21 +0000)
Conflicts:
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AppletJmol.java
src/jalview/appletgui/AppletJmolBinding.java
src/jalview/appletgui/ExtJmol.java
src/jalview/datamodel/PDBEntry.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/JalviewChimeraBindingModel.java
src/jalview/gui/StructureChooser.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/BioJsHTMLOutput.java
src/jalview/io/HTMLOutput.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/StructureFile.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/ws/dbsources/Pdb.java
src/jalview/ws/dbsources/Xfam.java
test/MCview/PDBfileTest.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/ext/jmol/JmolVsJalviewPDBParserEndToEndTest.java
test/jalview/gui/AlignViewportTest.java
test/jalview/io/FeaturesFileTest.java
test/jalview/io/Jalview2xmlTests.java
test/jalview/io/PfamFormatInputTest.java
test/jalview/io/gff/ExonerateHelperTest.java
test/jalview/structure/Mapping.java
test/jalview/structures/models/AAStructureBindingModelTest.java

514 files changed:
.classpath
AUTHORS
CITATION [new file with mode: 0644]
RELEASE
THIRDPARTYLIBS
appletlib/JmolApplet-14.2.14_2015.06.11.jar [deleted file]
appletlib/JmolApplet-14.6.4_2016.10.26.jar [new file with mode: 0644]
build.xml
examples/appletDeployment.html
examples/applets.html
examples/biojson-doc/index.html
examples/biojson-doc/tests/test.html
examples/embedded.html
examples/embeddedWJmol.html
examples/exampleFeatures.txt
examples/exampleFile.jar
examples/exampleFile_2_3.jar
examples/exampleFile_2_7.jar
examples/example_biojs.html
examples/ferredoxin.nw
examples/formComplete.html
examples/groovy/featureCounter.groovy
examples/index.html
examples/javascript/facebox-1.3.js [new file with mode: 0644]
examples/javascriptLaunch.html
examples/linkedapplets_ng.html
examples/plantfdx.fa
examples/plantfdx.features
examples/testdata/jal-2005.fa [new file with mode: 0644]
examples/testdata/jal-2005.jvf [new file with mode: 0644]
examples/testdata/localstruct.pdb [new file with mode: 0644]
examples/testdata/test.html
examples/uniref50.fa
examples/uniref50_mz.fa
help/help.jhm
help/helpTOC.xml
help/html/calculations/consensus.html
help/html/calculations/conservation.html
help/html/calculations/pca.html
help/html/calculations/redundancy.html
help/html/calculations/referenceseq.html
help/html/calculations/scorematrices.html
help/html/calculations/sorting.html
help/html/calculations/structureconsensus.html
help/html/calculations/tree.html
help/html/calculations/treeviewer.html
help/html/colourSchemes/abovePID.html
help/html/colourSchemes/annotationColouring.html
help/html/colourSchemes/conservation.html
help/html/colourSchemes/index.html
help/html/colourSchemes/rnahelicesColouring.html
help/html/editing/index.html
help/html/features/annotation.html
help/html/features/annotationsFormat.html
help/html/features/bioJsonFormat.html
help/html/features/chimera.html
help/html/features/clarguments.html
help/html/features/columnFilterByAnnotation.html
help/html/features/commandline.html
help/html/features/creatinFeatures.html
help/html/features/dasfeatures.html
help/html/features/dassettings.html
help/html/features/editingFeatures.html
help/html/features/ensemblsequencefetcher.html [new file with mode: 0644]
help/html/features/featuresFormat.html
help/html/features/featuresettings.html
help/html/features/groovy.html
help/html/features/hiddenRegions.html
help/html/features/jmol.html
help/html/features/mmcif.html
help/html/features/multipleViews.html
help/html/features/pdbseqfetcher.png
help/html/features/pdbsequencefetcher.html
help/html/features/pdbviewer.html
help/html/features/preferences.html
help/html/features/search.html
help/html/features/selectfetchdb.gif
help/html/features/seqfeatures.html
help/html/features/seqfetch.html
help/html/features/seqmappings.html
help/html/features/siftsmapping.html
help/html/features/splitView.html
help/html/features/structurechooser.html
help/html/features/uniprotqueryfields.html
help/html/features/uniprotsequencefetcher.html
help/html/features/varna.html
help/html/features/viewingpdbs.html
help/html/features/xsspannotation.html
help/html/groovy/featureCounter.html [new file with mode: 0644]
help/html/index.html
help/html/io/export.html
help/html/io/exportseqreport.html
help/html/io/fileformats.html
help/html/io/index.html
help/html/io/modellerpir.html
help/html/io/tcoffeescores.html
help/html/keys.html
help/html/memory.html
help/html/menus/alignmentMenu.html
help/html/menus/alwannotation.html
help/html/menus/alwannotationpanel.html
help/html/menus/alwcalculate.html
help/html/menus/alwedit.html
help/html/menus/alwfile.html
help/html/menus/alwformat.html
help/html/menus/alwselect.html
help/html/menus/desktopMenu.html
help/html/menus/index.html
help/html/menus/popupMenu.html
help/html/menus/wsmenu.html
help/html/misc/aaproperties.html
help/html/na/index.html
help/html/privacy.html
help/html/releases.html
help/html/vamsas/index.html
help/html/webServices/AACon.html
help/html/webServices/JABAWS.html
help/html/webServices/RNAalifold.html
help/html/webServices/dbreffetcher.html
help/html/webServices/index.html
help/html/webServices/jnet.html
help/html/webServices/msaclient.html
help/html/webServices/newsreader.html
help/html/webServices/proteinDisorder.html
help/html/webServices/shmr.html
help/html/webServices/urllinks.html
help/html/webServices/webServicesParams.html
help/html/webServices/webServicesPrefs.html
help/html/whatsNew.html
lib/Jmol-14.2.14_2015.06.11.jar [deleted file]
lib/Jmol-14.6.4_2016.10.26.jar [new file with mode: 0644]
nbproject/project.properties
resources/authors.props
resources/embl_mapping.xml
resources/fts/pdb_data_columns.txt
resources/lang/Messages.properties
resources/lang/Messages_es.properties
resources/uniprot_mapping.xml
src/MCview/AppletPDBCanvas.java
src/MCview/Atom.java
src/MCview/PDBCanvas.java
src/MCview/PDBChain.java
src/MCview/PDBViewer.java
src/MCview/PDBfile.java
src/ext/edu/ucsf/rbvi/strucviz2/ChimUtils.java
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraModel.java
src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java
src/ext/edu/ucsf/rbvi/strucviz2/StructureSettings.java
src/ext/edu/ucsf/rbvi/strucviz2/port/ListenerThreads.java
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/AlignSeq.java
src/jalview/analysis/AlignmentSorter.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/Conservation.java
src/jalview/analysis/CrossRef.java
src/jalview/analysis/Dna.java
src/jalview/analysis/Finder.java
src/jalview/analysis/NJTree.java
src/jalview/analysis/Rna.java
src/jalview/analysis/SeqsetUtils.java
src/jalview/analysis/StructureFrequency.java
src/jalview/api/AlignViewControllerI.java
src/jalview/api/AlignViewportI.java
src/jalview/api/DBRefEntryI.java
src/jalview/api/FeatureColourI.java
src/jalview/api/FeatureRenderer.java
src/jalview/api/FeaturesSourceI.java
src/jalview/api/SiftsClientI.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationRowFilter.java
src/jalview/appletgui/AppletJmol.java
src/jalview/appletgui/AppletJmolBinding.java
src/jalview/appletgui/ExtJmol.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/Finder.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/SliderPanel.java
src/jalview/appletgui/TreeCanvas.java
src/jalview/bin/ArgsParser.java
src/jalview/bin/Cache.java
src/jalview/bin/Jalview.java
src/jalview/bin/JalviewLite.java
src/jalview/commands/TrimRegionCommand.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/AlignedCodonFrame.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/DBRefEntry.java
src/jalview/datamodel/DBRefSource.java
src/jalview/datamodel/HiddenSequences.java
src/jalview/datamodel/MappingType.java
src/jalview/datamodel/PDBEntry.java
src/jalview/datamodel/Profile.java [new file with mode: 0644]
src/jalview/datamodel/ProfileI.java [new file with mode: 0644]
src/jalview/datamodel/Profiles.java [new file with mode: 0644]
src/jalview/datamodel/ProfilesI.java [new file with mode: 0644]
src/jalview/datamodel/ResidueCount.java [new file with mode: 0644]
src/jalview/datamodel/SearchResultMatchI.java [new file with mode: 0644]
src/jalview/datamodel/SearchResults.java
src/jalview/datamodel/SearchResultsI.java [new file with mode: 0644]
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceFeature.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/xdb/embl/EmblEntry.java
src/jalview/datamodel/xdb/embl/EmblFile.java
src/jalview/ext/android/ContainerHelpers.java [new file with mode: 0644]
src/jalview/ext/android/SparseIntArray.java [new file with mode: 0644]
src/jalview/ext/android/SparseShortArray.java [new file with mode: 0644]
src/jalview/ext/ensembl/EnsemblCdna.java
src/jalview/ext/ensembl/EnsemblCds.java
src/jalview/ext/ensembl/EnsemblFeatures.java
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblGenome.java
src/jalview/ext/ensembl/EnsemblGenomes.java
src/jalview/ext/ensembl/EnsemblInfo.java
src/jalview/ext/ensembl/EnsemblLookup.java
src/jalview/ext/ensembl/EnsemblProtein.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/ext/ensembl/EnsemblSequenceFetcher.java
src/jalview/ext/ensembl/EnsemblSymbol.java
src/jalview/ext/ensembl/EnsemblXref.java
src/jalview/ext/ensembl/Species.java
src/jalview/ext/htsjdk/HtsContigDb.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/ext/so/SequenceOntology.java
src/jalview/fts/api/FTSRestClientI.java
src/jalview/fts/core/DecimalFormatTableCellRenderer.java
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/pdb/PDBFTSPanel.java
src/jalview/fts/service/pdb/PDBFTSRestClient.java
src/jalview/fts/service/uniprot/UniProtFTSRestClient.java
src/jalview/fts/service/uniprot/UniprotFTSPanel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationColourChooser.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/AnnotationExporter.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/AnnotationRowFilter.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/CrossRefAction.java [new file with mode: 0644]
src/jalview/gui/CutAndPasteHtmlTransfer.java
src/jalview/gui/CutAndPasteTransfer.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/Finder.java
src/jalview/gui/Help.java
src/jalview/gui/IdPanel.java
src/jalview/gui/JDatabaseTree.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/Jalview2XML_V1.java
src/jalview/gui/JalviewChimeraBindingModel.java
src/jalview/gui/JalviewDialog.java
src/jalview/gui/OptsAndParamsPage.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/SliderPanel.java
src/jalview/gui/SplitFrame.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewer.java
src/jalview/gui/StructureViewerBase.java
src/jalview/gui/TreeCanvas.java
src/jalview/gui/VamsasApplication.java
src/jalview/io/AnnotationFile.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/BioJsHTMLOutput.java
src/jalview/io/FastaFile.java
src/jalview/io/FeaturesFile.java
src/jalview/io/FileFormat.java
src/jalview/io/HTMLOutput.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/io/JalviewFileView.java
src/jalview/io/JnetAnnotationMaker.java
src/jalview/io/MSFfile.java
src/jalview/io/PDBFeatureSettings.java
src/jalview/io/PfamFile.java
src/jalview/io/SequenceAnnotationReport.java
src/jalview/io/StockholmFile.java
src/jalview/io/StructureFile.java
src/jalview/io/gff/ExonerateHelper.java
src/jalview/io/gff/Gff2Helper.java
src/jalview/io/gff/Gff3Helper.java
src/jalview/io/gff/GffConstants.java
src/jalview/io/gff/GffHelperBase.java
src/jalview/io/gff/GffHelperFactory.java
src/jalview/io/gff/GffHelperI.java
src/jalview/io/gff/InterProScanHelper.java
src/jalview/io/gff/SequenceOntologyFactory.java
src/jalview/io/gff/SequenceOntologyI.java
src/jalview/io/gff/SequenceOntologyLite.java
src/jalview/io/packed/JalviewDataset.java
src/jalview/io/vamsas/DatastoreRegistry.java
src/jalview/io/vamsas/Tree.java
src/jalview/javascript/JSFunctionExec.java
src/jalview/javascript/MouseOverStructureListener.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GCutAndPasteHtmlTransfer.java
src/jalview/jbgui/GCutAndPasteTransfer.java
src/jalview/jbgui/GSequenceLink.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/renderer/ScaleRenderer.java
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/schemes/Blosum62ColourScheme.java
src/jalview/schemes/ColourSchemeI.java
src/jalview/schemes/FeatureColour.java
src/jalview/schemes/FeatureSettingsAdapter.java
src/jalview/schemes/FollowerColourScheme.java
src/jalview/schemes/PIDColourScheme.java
src/jalview/schemes/ResidueColourScheme.java
src/jalview/schemes/ResidueProperties.java
src/jalview/schemes/TCoffeeColourScheme.java
src/jalview/structure/SequenceListener.java
src/jalview/structure/StructureImportSettings.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/util/ArrayUtils.java
src/jalview/util/CaseInsensitiveString.java [new file with mode: 0644]
src/jalview/util/ColorUtils.java
src/jalview/util/Comparison.java
src/jalview/util/DBRefUtils.java
src/jalview/util/DnaUtils.java
src/jalview/util/Format.java
src/jalview/util/HttpUtils.java
src/jalview/util/ImageMaker.java
src/jalview/util/LinkedIdentityHashSet.java [new file with mode: 0644]
src/jalview/util/MapList.java
src/jalview/util/MappingUtils.java
src/jalview/util/Platform.java
src/jalview/util/QuickSort.java
src/jalview/util/SparseCount.java [new file with mode: 0644]
src/jalview/util/StringUtils.java
src/jalview/util/UrlConstants.java [new file with mode: 0644]
src/jalview/util/UrlLink.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
src/jalview/workers/AlignCalcWorker.java
src/jalview/workers/AlignmentAnnotationFactory.java
src/jalview/workers/AnnotationProviderI.java
src/jalview/workers/ColumnCounterWorker.java
src/jalview/workers/ComplementConsensusThread.java
src/jalview/workers/ConsensusThread.java
src/jalview/workers/ConservationThread.java
src/jalview/workers/FeatureCounterI.java
src/jalview/ws/DBRefFetcher.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/SequenceFetcherFactory.java
src/jalview/ws/dbsources/EmblXmlSource.java
src/jalview/ws/dbsources/Pdb.java
src/jalview/ws/dbsources/Pfam.java
src/jalview/ws/dbsources/PfamFull.java
src/jalview/ws/dbsources/PfamSeed.java
src/jalview/ws/dbsources/RfamFull.java
src/jalview/ws/dbsources/RfamSeed.java
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/jws1/MsaWSThread.java
src/jalview/ws/jws1/SeqSearchWSClient.java
src/jalview/ws/jws2/MsaWSClient.java
src/jalview/ws/seqfetcher/ASequenceFetcher.java
src/jalview/ws/sifts/MappingOutputPojo.java
src/jalview/ws/sifts/SiftsClient.java
src/jalview/ws/sifts/SiftsException.java
src/jalview/ws/sifts/SiftsSettings.java
test/MCview/PDBfileTest.java
test/jalview/analysis/AAFrequencyTest.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/ConservationTest.java [new file with mode: 0644]
test/jalview/analysis/CrossRefTest.java
test/jalview/analysis/DnaTest.java
test/jalview/analysis/FinderTest.java [new file with mode: 0644]
test/jalview/analysis/GroupingTest.java
test/jalview/analysis/RnaTest.java
test/jalview/analysis/SequenceIdMatcherTest.java
test/jalview/analysis/scoremodels/FeatureScoreModelTest.java
test/jalview/bin/ArgsParserTest.java
test/jalview/bin/CacheTest.java
test/jalview/bin/CommandLineOperations.java
test/jalview/commands/EditCommandTest.java
test/jalview/controller/AlignViewControllerTest.java
test/jalview/datamodel/AlignedCodonFrameTest.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/DBRefEntryTest.java
test/jalview/datamodel/HiddenSequencesTest.java
test/jalview/datamodel/MappingTypeTest.java
test/jalview/datamodel/MatchTest.java
test/jalview/datamodel/PDBEntryTest.java
test/jalview/datamodel/ResidueCountTest.java [new file with mode: 0644]
test/jalview/datamodel/SearchResultsTest.java
test/jalview/datamodel/SeqCigarTest.java
test/jalview/datamodel/SequenceFeatureTest.java
test/jalview/datamodel/SequenceTest.java
test/jalview/datamodel/xdb/embl/EmblEntryTest.java
test/jalview/datamodel/xdb/embl/EmblTestHelper.java
test/jalview/ext/android/SparseIntArrayTest.java [new file with mode: 0644]
test/jalview/ext/android/SparseShortArrayTest.java [new file with mode: 0644]
test/jalview/ext/ensembl/EnsemblCdnaTest.java
test/jalview/ext/ensembl/EnsemblCdsTest.java
test/jalview/ext/ensembl/EnsemblGeneTest.java
test/jalview/ext/ensembl/EnsemblGenomeTest.java
test/jalview/ext/ensembl/EnsemblProteinTest.java
test/jalview/ext/ensembl/EnsemblRestClientTest.java
test/jalview/ext/ensembl/EnsemblSeqProxyAdapter.java
test/jalview/ext/ensembl/EnsemblSeqProxyTest.java
test/jalview/ext/ensembl/EnsemblXrefTest.java
test/jalview/ext/htsjdk/TestHtsContigDb.java
test/jalview/ext/jmol/JmolCommandsTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/ext/jmol/JmolVsJalviewPDBParserEndToEndTest.java
test/jalview/ext/so/SequenceOntologyTest.java
test/jalview/fts/core/FTSRestClientTest.java
test/jalview/fts/service/pdb/PDBFTSRestClientTest.java
test/jalview/gui/AlignFrameTest.java
test/jalview/gui/AlignViewportTest.java
test/jalview/gui/AnnotationChooserTest.java
test/jalview/gui/AppVarnaTest.java
test/jalview/gui/JAL1353bugdemo.java
test/jalview/gui/MouseEventDemo.java [new file with mode: 0644]
test/jalview/gui/PopupMenuTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/gui/StructureViewerTest.java [new file with mode: 0644]
test/jalview/io/3ucu.cif [new file with mode: 0644]
test/jalview/io/AnnotatedPDBFileInputTest.java
test/jalview/io/AnnotationFileIOTest.java
test/jalview/io/BioJsHTMLOutputTest.java
test/jalview/io/CrossRef2xmlTests.java [new file with mode: 0644]
test/jalview/io/FeaturesFileTest.java
test/jalview/io/FormatAdapterTest.java
test/jalview/io/JSONFileTest.java
test/jalview/io/Jalview2xmlBase.java [new file with mode: 0644]
test/jalview/io/Jalview2xmlTests.java
test/jalview/io/NewickFileTests.java
test/jalview/io/PfamFormatInputTest.java
test/jalview/io/SequenceAnnotationReportTest.java
test/jalview/io/StockholmFileTest.java
test/jalview/io/gff/ExonerateHelperTest.java
test/jalview/io/gff/Gff3HelperTest.java
test/jalview/io/gff/GffHelperBaseTest.java
test/jalview/io/gff/GffHelperFactoryTest.java
test/jalview/io/gff/GffTests.java
test/jalview/io/gff/InterProScanHelperTest.java
test/jalview/io/testProps_nodas.jvprops [new file with mode: 0644]
test/jalview/schemes/DnaCodonTests.java
test/jalview/schemes/FeatureColourTest.java
test/jalview/schemes/ResidueColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/ResiduePropertiesTest.java
test/jalview/schemes/UserColourSchemeTest.java
test/jalview/structure/Mapping.java
test/jalview/structure/StructureSelectionManagerTest.java
test/jalview/structures/models/AAStructureBindingModelTest.java
test/jalview/util/ArrayUtilsTest.java
test/jalview/util/CaseInsensitiveStringTest.java [new file with mode: 0644]
test/jalview/util/ColorUtilsTest.java
test/jalview/util/ComparisonTest.java
test/jalview/util/DBRefUtilsTest.java
test/jalview/util/DnaUtilsTest.java
test/jalview/util/FormatTest.java [new file with mode: 0644]
test/jalview/util/MapListTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/util/PlatformTest.java [new file with mode: 0644]
test/jalview/util/QuickSortTest.java
test/jalview/util/SparseCountTest.java [new file with mode: 0644]
test/jalview/util/UrlLinkTest.java [new file with mode: 0644]
test/jalview/workers/AlignCalcManagerTest.java
test/jalview/ws/PDBSequenceFetcherTest.java
test/jalview/ws/SequenceFetcherTest.java
test/jalview/ws/dbsources/UniprotTest.java
test/jalview/ws/ebi/EBIFetchClientTest.java
test/jalview/ws/jabaws/DisorderAnnotExportImport.java
test/jalview/ws/jabaws/RNAStructExportImport.java
test/jalview/ws/seqfetcher/DbRefFetcherTest.java
test/jalview/ws/sifts/SiftsClientTest.java
utils/BufferedLineReader.java [new file with mode: 0644]
utils/HelpLinksChecker.java
utils/InstallAnywhere/Jalview.iap_xml
utils/JettyExamplesDir.java
utils/MessageBundleChecker.java
utils/checkstyle/checkstyle.xml
utils/checkstyle/import-control.xml
utils/getJavaVersion.java
utils/help2Website.java

index 6583992..8aef745 100644 (file)
@@ -64,7 +64,7 @@
        <classpathentry kind="lib" path="lib/jetty-http-9.2.10.v20150310.jar"/>
        <classpathentry kind="lib" path="lib/jetty-io-9.2.10.v20150310.jar"/>
        <classpathentry kind="lib" path="lib/java-json.jar"/>
-       <classpathentry kind="lib" path="lib/Jmol-14.2.14_2015.06.11.jar"/>
+       <classpathentry kind="lib" path="lib/Jmol-14.6.4_2016.10.26.jar"/>
        <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
        <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
        <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
diff --git a/AUTHORS b/AUTHORS
index 30db2a1..1bfc734 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,15 +7,16 @@ or might otherwise be considered author of Jalview.
 The people listed below are 'The Jalview Authors', who collectively
 own the copyright to the Jalview source code and permit it to be released under GPL.
 
-This is the authoritative list. It was correct on 4th June 2014.
+This is the authoritative list. It was correct on 23rd November 2016.
 If you are releasing a version of Jalview, please make sure any
 statement of authorship in the GUI reflects the list shown here.
 In particular, check the resources/authors.props file ! 
 
 Jim Procter
-Andrew Waterhouse
 Mungo Carstairs
 Tochukwu 'Charles' Ofoegbu
+Kira Mourao
+Andrew Waterhouse
 Jan Engelhardt
 Lauren Lui
 Anne Menard
diff --git a/CITATION b/CITATION
new file mode 100644 (file)
index 0000000..9b06f7c
--- /dev/null
+++ b/CITATION
@@ -0,0 +1,5 @@
+If you use Jalview in your work, please cite the Jalview 2 paper in Bioinformatics:
+
+Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M., Barton, G.J (2009),
+"Jalview version 2: A Multiple Sequence Alignment and Analysis Workbench,"
+Bioinformatics 25 (9) 1189-1191 doi: 10.1093/bioinformatics/btp033 
diff --git a/RELEASE b/RELEASE
index 6cd9254..9bc5817 100644 (file)
--- a/RELEASE
+++ b/RELEASE
@@ -1,2 +1,2 @@
-jalview.release=Release_2_9_0b1_Branch
-jalview.version=2.9.0b2
+jalview.release=releases/Release_2_10_1_Branch
+jalview.version=2.10.1
index caaa7f9..e0be904 100644 (file)
@@ -6,11 +6,14 @@ A number of sources have also been adapted for incorporation into Jalview's sour
 
 ext.edu.ucsf.rbvi.strucviz2 includes sources originally developed by Scooter Morris and Nadezhda Doncheva for the Cytoscape StructureViz2 plugin. It is released under the Berkley license and we hereby acknowledge its original copyright is held by the UCSF Computer Graphics Laboratory
  and the software was developed with support by the NIH National Center for Research Resources, grant P41-RR01081. 
+ jalview.ext.android includes code taken from the Android Open Source Project (https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/util).
+ The Apache 2.0 Licence (http://www.apache.org/licenses/LICENSE-2.0) is acknowledged in the source code.
 
-Licencing information for each library is given below:
+Licensing information for each library is given below:
 
 JGoogleAnalytics_0.3.jar       APL 2.0 License - http://code.google.com/p/jgoogleanalytics/
-Jmol-14.2.14_2015.06.11.jar    GPL/LGPLv2 http://sourceforge.net/projects/jmol/files/
+Jmol-14.6.4_2016.10.26.jar     GPL/LGPLv2 http://sourceforge.net/projects/jmol/files/
 VARNAv3-93.jar GPL licenced software by K�vin Darty, Alain Denise and Yann Ponty. http://varna.lri.fr
 activation.jar 
 apache-mime4j-0.6.jar
@@ -46,7 +49,11 @@ jfreesvg-2.1.jar : GPL v3 licensed library from the JFree suite: http://www.jfre
 
 quaqua: v.8.0 (latest stable) by Randel S Hofer. LGPL and BSD Modified license: downloaded from http://www.randelshofer.ch/quaqua/ 
 
-lib/htsjdk-1.120-SNAPSHOT.jar: built from maven master at https://github.com/samtools/htsjdk MIT License to Broad Institute
+lib/htsjdk-1.120-SNAPSHOT.jar: (currently not required for 2.10) built from maven master at https://github.com/samtools/htsjdk MIT License to Broad Institute
+
+lib/biojava-core-4.1.0.jar LGPLv2.1 - latest license at https://github.com/biojava/biojava/blob/master/LICENSE
+
+lib/biojava-ontology-4.1.0.jar LGPLv2.1 - latest license at https://github.com/biojava/biojava/blob/master/LICENSE
 
 
 Additional dependencies
@@ -54,7 +61,5 @@ Additional dependencies
 examples/javascript/deployJava.js : http://java.com/js/deployJava.js
 examples/javascript/jquery*.js : BSD license
 examples/javascript/jshashtable-2.1.js : Apache License
-
-Tools not bundled with Jalview source
-jbake (http://jbake.org MIT license) was used to build the JalviewLite examples pages found in the examples directory.
+examples/javascript/facebox-1.3.js : MTI License - http://www.opensource.org/licenses/mit-license.php
 
diff --git a/appletlib/JmolApplet-14.2.14_2015.06.11.jar b/appletlib/JmolApplet-14.2.14_2015.06.11.jar
deleted file mode 100644 (file)
index 5d6338c..0000000
Binary files a/appletlib/JmolApplet-14.2.14_2015.06.11.jar and /dev/null differ
diff --git a/appletlib/JmolApplet-14.6.4_2016.10.26.jar b/appletlib/JmolApplet-14.6.4_2016.10.26.jar
new file mode 100644 (file)
index 0000000..e5c312c
Binary files /dev/null and b/appletlib/JmolApplet-14.6.4_2016.10.26.jar differ
index a8b8928..e86aa2b 100755 (executable)
--- a/build.xml
+++ b/build.xml
     <property name="packageDir" value="dist" />
     <property name="outputJar" value="jalview.jar" />
     <!-- Jalview Applet JMol Jar Dependency -->
-    <property name="jmolJar" value="JmolApplet-14.2.14_2015.06.11.jar" />
+    <property name="jmolJar" value="JmolApplet-14.6.4_2016.10.26.jar" />
     <property name="varnaJar" value="VARNAv3-93.jar" />
     <property name="jsoup" value="jsoup-1.8.1.jar" />
     <property name="jsonSimple" value="json_simple-1.1.jar" />
   </axis-wsdl2java>
 </target>
 
-<target name="makedist" depends="build, buildPropertiesFile, buildindices">
+<target name="makedist" depends="build, buildPropertiesFile, linkcheck, buildindices">
   <!-- make the package jar if not already existing -->
   <mkdir dir="${packageDir}" />
   <!-- clean dir if it already existed -->
 
 <target name="compileApplet" depends="init,clean">
   <mkdir dir="${outputDir}" />
-  <javac source="${javac.source}" target="${javac.target}" srcdir="${sourceDir}" destdir="${outputDir}" debug="${javac.debug}" classpathref="jalviewlite.deps" includes="jalview/appletgui/**" excludes="ext/**,gui/**,jbgui/**,MCview/**,org/**,vamsas/**,jalview/ext/rbvi/**,jalview/ext/paradise/**,jalview/ext/ensembl/**,jalview/ext/so" />
+  <javac source="${javac.source}" target="${javac.target}" srcdir="${sourceDir}" destdir="${outputDir}" debug="${javac.debug}" classpathref="jalviewlite.deps" includes="jalview/appletgui/**" excludes="ext/**,gui/**,jbgui/**,MCview/**,org/**,vamsas/**,jalview/ext/rbvi/**,jalview/ext/paradise/**,jalview/ext/ensembl/**,jalview/ext/so/**" />
 </target>
 
 <target name="packageApplet" depends="compileApplet, buildPropertiesFile">
     <pathelement location="appletlib/${jsoup}" />
     <pathelement location="appletlib/${jsonSimple}" />
     <pathelement location="appletlib/${javaJson}" />
-       <fileset dir="${java.home}/lib">
-        <include name="plugin.jar" />
+    <fileset dir="${java.home}/lib">
+      <include name="plugin.jar" />
     </fileset>
   </path>
   <taskdef resource="proguard/ant/task.properties" classpath="utils/proguard.jar" />
 
   <proguard verbose="true" >
-    <injar file="in.jar" />    
-    <outjar file="${jalviewLiteJar}" />    
-    <libraryjar refid="obfuscateDeps.path" />    
+    <injar file="in.jar" />
+    <outjar file="${jalviewLiteJar}" />
+    <libraryjar refid="obfuscateDeps.path" />
     <dontwarn />
     <keep access="public" type="class" name="jalview.bin.JalviewLite">
       <field access="public" />
       <constructor/>
       <method name="*"/>
     </keep>
-   
+
     <keep access="public" type="class" name="MCview.PDBfile">
       <field access="public" />
       <method access="public" />
       <method access="public" />
       <constructor access="public" />
     </keep>
-    
+
     <keep access="public" type="class" name="jalview.ext.jmol.JmolParser">
       <field access="public" />
       <method access="public" />
       <constructor access="public" />
     </keep>
-    
-    
+
+
     <!--      -libraryjars "${obfuscateDeps}"
       -injars      in.jar
       -outjars     jalviewApplet.jar
 </target>
 <target name="sourcedist" description="create jalview source distribution" depends="init">
   <delete file="${source.dist.name}" />
-  <tar destfile="${source.dist.name}" compression="gzip">
-    <tarfileset dir="./" prefix="jalview" preserveLeadingSlashes="true">
+  <!-- temporary copy of source to update timestamps -->
+  <copy todir="_sourcedist">
+    <fileset dir=".">
+      <exclude name=".*" />
+      <exclude name="**/.*" />
+      <exclude name="*.class" />
+      <exclude name="**/*.class" />
       <include name="LICENSE" />
       <include name="README" />
       <include name="build.xml" />
       <include name="utils/**/*" />
       <include name="${docDir}/**/*" />
       <include name="examples/**/*" />
+    </fileset>
+  </copy>
+
+  <tstamp prefix="build">
+    <format property="year" pattern="yyyy" />
+  </tstamp>
+  <!-- each replacetoken CDATA body must be on one line - 
+       otherwise the pattern doesn't match -->
+  <replace value="${JALVIEW_VERSION}">
+    <replacetoken><![CDATA[$$Version-Rel$$]]></replacetoken>
+    <fileset dir="_sourcedist">
+      <include name="**/*" />
+    </fileset>
+  </replace>
+  <replace dir="_sourcedist" value="${build.year}">
+    <replacetoken><![CDATA[$$Year-Rel$$]]></replacetoken>
+    <fileset dir="_sourcedist">
+      <include name="**/*" />
+    </fileset>
+  </replace>
+
+  <tar destfile="${source.dist.name}" compression="gzip">
+    <tarfileset dir="_sourcedist/" prefix="jalview" preserveLeadingSlashes="true">
     </tarfileset>
   </tar>
+
+  <delete dir="_sourcedist" />
 </target>
 <target name="prepubapplet_1" depends="makeApplet">
   <copy todir="${packageDir}/examples">
     </packageset>
   </javadoc>
 </target>
+<target name="linkcheck" depends="init,prepare">
+  <javac srcdir="utils" destdir="utils" includes="HelpLinksChecker.java"/>
+  <java fork="true" dir="${helpDir}" classpath="utils" classname="HelpLinksChecker" failonerror="true">
+    <arg file="${helpDir}"/>
+    <arg value="-nointernet"/>
+  </java>
+</target>
 </project>
index 7fcca00..7b4daee 100644 (file)
@@ -33,7 +33,7 @@
     <td>Main Jalview Applet Jar</td>
   </tr>
   <tr>
-    <td><a href="http://www.jalview.org/builds/develop/examples/JmolApplet-14.2.14_2015.06.11.jar">JmolApplet-14.2.14_2015.06.11.jar</a> </td>
+    <td><a href="http://www.jalview.org/builds/develop/examples/JmolApplet-14.6.4_2016.10.26.jar">JmolApplet-14.6.4_2016.10.26.jar</a> </td>
     <td>Jmol Applet Jar</td>
   </tr>
   <tr>
@@ -48,7 +48,7 @@
 
 <p>To run Jalview applet in your web page download the Jars listed above. The snippet below shows a minimal code for embedding Jalview applet into a web page.    
 <pre><code>
-&lt;applet code="jalview.bin.JalviewLite" width="756" height="560" archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar"&gt;
+&lt;applet code="jalview.bin.JalviewLite" width="756" height="560" archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar"&gt;
        &lt;param name="permissions" value="sandbox" /&gt;
        &lt;param name="file" value="plantfdx.fa" /&gt;
        &lt;param name="features" value="plantfdx.features" /&gt;
index 1f65565..d997f14 100644 (file)
@@ -41,7 +41,7 @@ Try out JalviewLite by pressing one of the buttons below.
       <td width="10%" valign="center">
       <applet
        code="jalview.bin.JalviewLite" width="140" height="35"
-       archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">  
+       archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">  
        <param name="permissions" value="sandbox"/>
        <param name="file" value="uniref50.fa"/>
        <param name="treeFile" value="ferredoxin.nw"/>
@@ -64,7 +64,7 @@ Try out JalviewLite by pressing one of the buttons below.
     <tr>
       <td width="10%" valign="center"><applet
    code="jalview.bin.JalviewLite" width="140" height="35"
-   archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="file" value="uniref50.fa"/>
 <param name="features" value="exampleFeatures.txt"/>
@@ -89,7 +89,7 @@ Try out JalviewLite by pressing one of the buttons below.
     <tr>
       <td width="10%" valign="center"><applet
    code="jalview.bin.JalviewLite" width="140" height="35"
-   archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="file" value="uniref50.fa"/>
 <param name="showFullId" value="false"/>
@@ -116,7 +116,7 @@ Try out JalviewLite by pressing one of the buttons below.
     <tr>
       <td width="10%" valign="center"><applet
    code="jalview.bin.JalviewLite" width="140" height="35"
-   archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="file" value="jpred_msa.fasta"/>
 <param name="jnetfile" value="jpred_msa.seq.concise"/>
@@ -147,7 +147,7 @@ Try out JalviewLite by pressing one of the buttons below.
     <tr>
       <td width="10%" valign="center"><applet
    code="jalview.bin.JalviewLite" width="140" height="35"
-   archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="file" value="RF00031_folded.stk"/>
 <param name="showFullId" value="false"/>
@@ -171,7 +171,7 @@ Try out JalviewLite by pressing one of the buttons below.
       <td width="10%" valign="center">
 <applet
    code="jalview.bin.JalviewLite" width="140" height="35"
-   archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="file2" value="estrogenReceptorCdna_frag.fa"/>
 <param name="file" value="estrogenReceptorProtein_frag.fa"/>
index ba607f4..e0e5741 100755 (executable)
@@ -1,4 +1,24 @@
 <!DOCTYPE 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.
+ -->
 <html>
 <head>
     <title>BioJSON Format Documentation</title>
@@ -358,4 +378,4 @@ This page describes the data available in BioJSON format, the main content secti
 </html>
 
 
\ No newline at end of file
index 2cbbd50..c6bebd6 100755 (executable)
@@ -1,3 +1,23 @@
+<!--
+ * 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.
+ -->
 <!DOCTYPE html>
 <html>
 <head>
index 0d5ddf3..0cea17d 100644 (file)
@@ -40,7 +40,7 @@
   <a href="view-source:http://www.jalview.org/builds/develop/examples/embedded.html" target="_blank">View the source code for this example here</a> (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/embedded.html">this page</a> and viewing the page source manually).<p>
   <applet
    code="jalview.bin.JalviewLite" width="756" height="560"
-   archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="file" value="plantfdx.fa"/>
 <param name="features" value="plantfdx.features"/>
index 1ecff58..6fdcc07 100644 (file)
@@ -1,5 +1,25 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML+RDFa 1.1//EN">
-<html lang="en" dir="ltr" version="HTML+RDFa 1.1"
+<!--
+ * 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.
+ -->
+ <html lang="en" dir="ltr" version="HTML+RDFa 1.1"
        xmlns:content="http://purl.org/rss/1.0/modules/content/"
        xmlns:dc="http://purl.org/dc/terms/"
        xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:og="http://ogp.me/ns#"
@@ -191,7 +211,7 @@ jQuery.extend(Drupal.settings, {"basePath":"\/","pathPrefix":"","ajaxPageState":
 <script language="JavaScript">
 // instead of this, we use a custom JmolApplet spec
 // jmolInitialize('jmol');
-jmolInitialize("","JmolApplet-14.2.14_2015.06.11.jar");
+jmolInitialize("","JmolApplet-14.6.4_2016.10.26.jar");
 </script>
 <script>
  var loglevel=1;
@@ -222,7 +242,7 @@ jmolInitialize("","JmolApplet-14.2.14_2015.06.11.jar");
  var _jvA=new Object();
  _jvA.attributes = {
   code : 'jalview.bin.JalviewLite',
-  archive : 'jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar',
+  archive : 'jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar',
   width : '500',
   height : '350',
   mayscript : 'True',
@@ -275,7 +295,7 @@ jmolInitialize("","JmolApplet-14.2.14_2015.06.11.jar");
 </div>
 <div>
 <applet
-   code="jalview.bin.JalviewLite" width="500" height="350" id="jvA" mayscript="mayscript" archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   code="jalview.bin.JalviewLite" width="500" height="350" id="jvA" mayscript="mayscript" archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="permissions" value="sandbox"/>
 <param name="java_arguments" value="-Xmx256m"/>
 <param name="externalstructureviewer" value="true"/>
index c0098a9..2de9817 100755 (executable)
@@ -79,12 +79,12 @@ Iron-sulfur (2Fe-2S)        FER_BRANA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_BRANA       -1      77      77      METAL
 <html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_8</a></html>     FER_BRANA       -1      8       83      Pfam
 Ferredoxin_fold Status: True Positive  FER_BRANA       -1      2       96      Cath
-Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      91      91      METAL
-Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      96      96      METAL
-Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      99      99      METAL
-Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      129     129     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER2_ARATH      -1      60      135     Pfam
-Ferredoxin_fold Status: True Positive  FER2_ARATH      -1      50      145     Cath
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      91      91      METAL
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      96      96      METAL
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      99      99      METAL
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      129     129     METAL
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER1_ARATH      -1      60      135     Pfam
+Ferredoxin_fold Status: True Positive  FER1_ARATH      -1      50      145     Cath
 <html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_11</a></html>   Q93Z60_ARATH    -1      60      118     Pfam
 Ferredoxin_fold Status: True Positive  Q93Z60_ARATH    -1      52      118     Cath
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      91      91      METAL
@@ -127,13 +127,13 @@ STARTGROUP        netphos
 <html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P00221&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 112_11</a></html>     FER1_SPIOL      -1      112     112     PHOSPHORYLATION (S)
 <html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P00221&amp;service=NetPhos-2.0">PHOSPHORYLATION (T) 139_13</a></html>     FER1_SPIOL      -1      139     139     PHOSPHORYLATION (T)
 <html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P00221&amp;service=NetPhos-2.0">PHOSPHORYLATION (Y) 73_7</a></html>       FER1_SPIOL      -1      73      73      PHOSPHORYLATION (Y)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 19_1</a></html>   FER1_ARATH      -1      19      19      PHOSPHORYLATION (S)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 24_2</a></html>   FER1_ARATH      -1      24      24      PHOSPHORYLATION (S)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 90_9</a></html>   FER1_ARATH      -1      90      90      PHOSPHORYLATION (S)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 107_10</a></html> FER1_ARATH      -1      107     107     PHOSPHORYLATION (S)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 114_11</a></html> FER1_ARATH      -1      114     114     PHOSPHORYLATION (S)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (T) 141_14</a></html> FER1_ARATH      -1      141     141     PHOSPHORYLATION (T)
-<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER1_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (Y) 75_7</a></html>   FER1_ARATH      -1      75      75      PHOSPHORYLATION (Y)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 19_1</a></html>   FER2_ARATH      -1      19      19      PHOSPHORYLATION (S)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 24_2</a></html>   FER2_ARATH      -1      24      24      PHOSPHORYLATION (S)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 90_9</a></html>   FER2_ARATH      -1      90      90      PHOSPHORYLATION (S)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 107_10</a></html> FER2_ARATH      -1      107     107     PHOSPHORYLATION (S)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 114_11</a></html> FER2_ARATH      -1      114     114     PHOSPHORYLATION (S)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (T) 141_14</a></html> FER2_ARATH      -1      141     141     PHOSPHORYLATION (T)
+<html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=FER2_ARATH&amp;service=NetPhos-2.0">PHOSPHORYLATION (Y) 75_7</a></html>   FER2_ARATH      -1      75      75      PHOSPHORYLATION (Y)
 <html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P00227&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 38_3</a></html>       FER_BRANA       -1      38      38      PHOSPHORYLATION (S)
 <html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P00227&amp;service=NetPhos-2.0">PHOSPHORYLATION (S) 62_6</a></html>       FER_BRANA       -1      62      62      PHOSPHORYLATION (S)
 <html>High confidence server. Only hits with scores over 0.8 are reported. <a href="http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P00227&amp;service=NetPhos-2.0">PHOSPHORYLATION (T) 89_8</a></html>       FER_BRANA       -1      89      89      PHOSPHORYLATION (T)
index 3231974..2f9000d 100755 (executable)
Binary files a/examples/exampleFile.jar and b/examples/exampleFile.jar differ
index adf707e..1a8bef0 100644 (file)
Binary files a/examples/exampleFile_2_3.jar and b/examples/exampleFile_2_3.jar differ
index 0b70e66..7cd9d77 100644 (file)
Binary files a/examples/exampleFile_2_7.jar and b/examples/exampleFile_2_7.jar differ
index b6f7bec..6738672 100644 (file)
@@ -1,4 +1,24 @@
 <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.
+ -->
 <header><title>BioJS viewer</title></header>
 
 <body>
index 0b949de..89ea348 100755 (executable)
@@ -1 +1 @@
-(((FER_BRANA:128.0,FER3_RAPSA:128.0):50.75,FER_CAPAA:178.75):121.94443,(Q93Z60_ARATH:271.45456,((O80429_MAIZE:183.0,FER1_MAIZE:183.0):30.5,((Q7XA98_TRIPR:90.0,FER1_PEA:90.0):83.32143,(((FER2_ARATH:64.0,FER1_ARATH:64.0):94.375,(FER1_SPIOL:124.5,FER1_MESCR:124.5):33.875):6.4166718,((Q93XJ9_SOLTU:33.5,FER1_SOLLC:33.5):49.0,FER_CAPAN:82.5):82.29167):8.529755):40.178574):57.95456):29.239868);
+(((FER_BRANA:128.0,FER3_RAPSA:128.0):50.75,FER_CAPAA:178.75):121.94443,(Q93Z60_ARATH:271.45456,((O80429_MAIZE:183.0,FER1_MAIZE:183.0):30.5,((Q7XA98_TRIPR:90.0,FER1_PEA:90.0):83.32143,(((FER1_ARATH:64.0,FER2_ARATH:64.0):94.375,(FER1_SPIOL:124.5,FER1_MESCR:124.5):33.875):6.4166718,((Q93XJ9_SOLTU:33.5,FER1_SOLLC:33.5):49.0,FER_CAPAN:82.5):82.29167):8.529755):40.178574):57.95456):29.239868);
index 9e89990..65a3a45 100644 (file)
@@ -36,7 +36,7 @@ instance on the page.</p>
   <a href="view-source:http://www.jalview.org/builds/develop/examples/formComplete.html" target="_blank">View the source here to see how it has been done</a>  (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/formComplete.html">this page</a> and viewing the page source manually).<br/>
 <a name="api">View the full <a href="javascript:doSubmit('jalviewLiteJs')">JalviewLite API documentation</a>.</a>
 <applet code="jalview.bin.JalviewLite" width="0" height="0"
-       archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar" name="Jalview">
+       archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar" name="Jalview">
   
   <param name="file" value="plantfdx.fa"/>
   <param name="features" value="plantfdx.features"/>
index a16d8bb..9059dd0 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * 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.
+ */
 import jalview.workers.FeatureCounterI;
 import jalview.workers.AlignmentAnnotationFactory;
 
index 46df4eb..37edb8e 100644 (file)
@@ -1,5 +1,25 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML+RDFa 1.1//EN">
-<html lang="en" dir="ltr" version="HTML+RDFa 1.1"
+<!--
+ * 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.
+ -->
+ <html lang="en" dir="ltr" version="HTML+RDFa 1.1"
        xmlns:content="http://purl.org/rss/1.0/modules/content/"
        xmlns:dc="http://purl.org/dc/terms/"
        xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:og="http://ogp.me/ns#"
diff --git a/examples/javascript/facebox-1.3.js b/examples/javascript/facebox-1.3.js
new file mode 100644 (file)
index 0000000..ad45310
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Facebox (for jQuery)
+ * version: 1.2 (05/05/2008)
+ * @requires jQuery v1.2 or later
+ *
+ * Examples at http://famspam.com/facebox/
+ *
+ * Licensed under the MIT:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
+ *
+ * Usage:
+ *
+ *  jQuery(document).ready(function() {
+ *    jQuery('a[rel*=facebox]').facebox()
+ *  })
+ *
+ *  <a href="#terms" rel="facebox">Terms</a>
+ *    Loads the #terms div in the box
+ *
+ *  <a href="terms.html" rel="facebox">Terms</a>
+ *    Loads the terms.html page in the box
+ *
+ *  <a href="terms.png" rel="facebox">Terms</a>
+ *    Loads the terms.png image in the box
+ *
+ *
+ *  You can also use it programmatically:
+ *
+ *    jQuery.facebox('some html')
+ *    jQuery.facebox('some html', 'my-groovy-style')
+ *
+ *  The above will open a facebox with "some html" as the content.
+ *
+ *    jQuery.facebox(function($) {
+ *      $.get('blah.html', function(data) { $.facebox(data) })
+ *    })
+ *
+ *  The above will show a loading screen before the passed function is called,
+ *  allowing for a better ajaxy experience.
+ *
+ *  The facebox function can also display an ajax page, an image, or the contents of a div:
+ *
+ *    jQuery.facebox({ ajax: 'remote.html' })
+ *    jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')
+ *    jQuery.facebox({ image: 'stairs.jpg' })
+ *    jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')
+ *    jQuery.facebox({ div: '#box' })
+ *    jQuery.facebox({ div: '#box' }, 'my-groovy-style')
+ *
+ *  Want to close the facebox?  Trigger the 'close.facebox' document event:
+ *
+ *    jQuery(document).trigger('close.facebox')
+ *
+ *  Facebox also has a bunch of other hooks:
+ *
+ *    loading.facebox
+ *    beforeReveal.facebox
+ *    reveal.facebox (aliased as 'afterReveal.facebox')
+ *    init.facebox
+ *    afterClose.facebox
+ *
+ *  Simply bind a function to any of these hooks:
+ *
+ *   $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
+ *
+ */
+(function($) {
+  $.facebox = function(data, klass) {
+    $.facebox.loading()
+
+    if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)
+    else if (data.image) fillFaceboxFromImage(data.image, klass)
+    else if (data.div) fillFaceboxFromHref(data.div, klass)
+    else if ($.isFunction(data)) data.call($)
+    else $.facebox.reveal(data, klass)
+  }
+
+  /*
+   * Public, $.facebox methods
+   */
+
+  $.extend($.facebox, {
+    settings: {
+      opacity      : 0.2,
+      overlay      : true,
+      loadingImage : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/loading.gif',
+      closeImage   : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/cancel.png',
+      imageTypes   : [ 'png', 'jpg', 'jpeg', 'gif' ],
+      faceboxHtml  : '\
+    <div id="facebox" style="display:none;"> \
+      <div class="popup"> \
+        <div class="content"> \
+        </div> \
+        <a href="#" class="close"><img src="https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/cancel.png" title="close" class="close_image" /></a> \
+      </div> \
+    </div>'
+    },
+
+    loading: function() {
+      init()
+      if ($('#facebox .loading').length == 1) return true
+      showOverlay()
+
+      $('#facebox .content').empty()
+      $('#facebox .body').children().hide().end().
+        append('<div class="loading"><img src="'+$.facebox.settings.loadingImage+'"/></div>')
+
+      $('#facebox').css({
+        top:   getPageScroll()[1] + (getPageHeight() / 10),
+        left:  $(window).width() / 2 - 205
+      }).show()
+
+      $(document).bind('keydown.facebox', function(e) {
+        if (e.keyCode == 27) $.facebox.close()
+        return true
+      })
+      $(document).trigger('loading.facebox')
+    },
+
+    reveal: function(data, klass) {
+      $(document).trigger('beforeReveal.facebox')
+      if (klass) $('#facebox .content').addClass(klass)
+      $('#facebox .content').append('<pre><code>'+JSON.stringify(JSON.parse(data),null,4)+'</pre></code>')
+      $('#facebox .loading').remove()
+      $('#facebox .body').children().fadeIn('normal')
+      $('#facebox').css('left', $(window).width() / 2 - ($('#facebox .popup').width() / 2))
+      $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')
+    },
+
+    close: function() {
+      $(document).trigger('close.facebox')
+      return false
+    }
+  })
+
+  /*
+   * Public, $.fn methods
+   */
+
+  $.fn.facebox = function(settings) {
+    if ($(this).length == 0) return
+
+    init(settings)
+
+    function clickHandler() {
+      $.facebox.loading(true)
+
+      // support for rel="facebox.inline_popup" syntax, to add a class
+      // also supports deprecated "facebox[.inline_popup]" syntax
+      var klass = this.rel.match(/facebox\[?\.(\w+)\]?/)
+      if (klass) klass = klass[1]
+
+      fillFaceboxFromHref(this.href, klass)
+      return false
+    }
+
+    return this.bind('click.facebox', clickHandler)
+  }
+
+  /*
+   * Private methods
+   */
+
+  // called one time to setup facebox on this page
+  function init(settings) {
+    if ($.facebox.settings.inited) return true
+    else $.facebox.settings.inited = true
+
+    $(document).trigger('init.facebox')
+    makeCompatible()
+
+    var imageTypes = $.facebox.settings.imageTypes.join('|')
+    $.facebox.settings.imageTypesRegexp = new RegExp('\.(' + imageTypes + ')$', 'i')
+
+    if (settings) $.extend($.facebox.settings, settings)
+    $('body').append($.facebox.settings.faceboxHtml)
+
+    var preload = [ new Image(), new Image() ]
+    preload[0].src = $.facebox.settings.closeImage
+    preload[1].src = $.facebox.settings.loadingImage
+
+    $('#facebox').find('.b:first, .bl').each(function() {
+      preload.push(new Image())
+      preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1')
+    })
+
+    $('#facebox .close').click($.facebox.close)
+    $('#facebox .close_image').attr('src', $.facebox.settings.closeImage)
+  }
+
+  // getPageScroll() by quirksmode.com
+  function getPageScroll() {
+    var xScroll, yScroll;
+    if (self.pageYOffset) {
+      yScroll = self.pageYOffset;
+      xScroll = self.pageXOffset;
+    } else if (document.documentElement && document.documentElement.scrollTop) {        // Explorer 6 Strict
+      yScroll = document.documentElement.scrollTop;
+      xScroll = document.documentElement.scrollLeft;
+    } else if (document.body) {// all other Explorers
+      yScroll = document.body.scrollTop;
+      xScroll = document.body.scrollLeft;
+    }
+    return new Array(xScroll,yScroll)
+  }
+
+  // Adapted from getPageSize() by quirksmode.com
+  function getPageHeight() {
+    var windowHeight
+    if (self.innerHeight) {    // all except Explorer
+      windowHeight = self.innerHeight;
+    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
+      windowHeight = document.documentElement.clientHeight;
+    } else if (document.body) { // other Explorers
+      windowHeight = document.body.clientHeight;
+    }
+    return windowHeight
+  }
+
+  // Backwards compatibility
+  function makeCompatible() {
+    var $s = $.facebox.settings
+
+    $s.loadingImage = $s.loading_image || $s.loadingImage
+    $s.closeImage = $s.close_image || $s.closeImage
+    $s.imageTypes = $s.image_types || $s.imageTypes
+    $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml
+  }
+
+  // Figures out what you want to display and displays it
+  // formats are:
+  //     div: #id
+  //   image: blah.extension
+  //    ajax: anything else
+  function fillFaceboxFromHref(href, klass) {
+    // div
+    if (href.match(/#/)) {
+      var url    = window.location.href.split('#')[0]
+      var target = href.replace(url,'')
+      if (target == '#') return
+      $.facebox.reveal($(target).html(), klass)
+
+    // image
+    } else if (href.match($.facebox.settings.imageTypesRegexp)) {
+      fillFaceboxFromImage(href, klass)
+    // ajax
+    } else {
+      fillFaceboxFromAjax(href, klass)
+    }
+  }
+
+  function fillFaceboxFromImage(href, klass) {
+    var image = new Image()
+    image.onload = function() {
+      $.facebox.reveal('<div class="image"><img src="' + image.src + '" /></div>', klass)
+    }
+    image.src = href
+  }
+
+  function fillFaceboxFromAjax(href, klass) {
+    $.get(href, function(data) { $.facebox.reveal(data, klass) })
+  }
+
+  function skipOverlay() {
+    return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null
+  }
+
+  function showOverlay() {
+    if (skipOverlay()) return
+
+    if ($('#facebox_overlay').length == 0)
+      $("body").append('<div id="facebox_overlay" class="facebox_hide"></div>')
+
+    $('#facebox_overlay').hide().addClass("facebox_overlayBG")
+      .css('opacity', $.facebox.settings.opacity)
+      .click(function() { $(document).trigger('close.facebox') })
+      .fadeIn(200)
+    return false
+  }
+
+  function hideOverlay() {
+    if (skipOverlay()) return
+
+    $('#facebox_overlay').fadeOut(200, function(){
+      $("#facebox_overlay").removeClass("facebox_overlayBG")
+      $("#facebox_overlay").addClass("facebox_hide")
+      $("#facebox_overlay").remove()
+    })
+
+    return false
+  }
+
+  /*
+   * Bindings
+   */
+
+  $(document).bind('close.facebox', function() {
+    $(document).unbind('keydown.facebox')
+    $('#facebox').fadeOut(function() {
+      $('#facebox .content').removeClass().addClass('content')
+      $('#facebox .loading').remove()
+      $(document).trigger('afterClose.facebox')
+    })
+    hideOverlay()
+  })
+
+})(jQuery);
index 35b1d81..38f80b7 100644 (file)
@@ -110,7 +110,7 @@ function startJalview(aligURL,title,alwvar) {
 </SCRIPT>
   <form name="Form1">
 <applet name="JalviewLite"  code="jalview.bin.JalviewLite"
-archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar" width="0" height="0">
+archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar" width="0" height="0">
 <param name="debug" value="true"/>
 <param name="showbutton" value="false"/>
 </applet>
index 5890515..8ddfd2f 100644 (file)
@@ -38,7 +38,7 @@
 
 
 <applet
-   code="jalview.bin.JalviewLite" width="800" height="300" id="jvapp" mayscript="True" scriptable="True" archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   code="jalview.bin.JalviewLite" width="800" height="300" id="jvapp" mayscript="True" scriptable="True" archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="oninit" value="lJvApp"/>
 <param name="automaticScrolling" value="true"/>
 <param name="file" value="plantfdx.fa"/>
@@ -61,7 +61,7 @@
 
 
 <applet
-   code="jalview.bin.JalviewLite" width="800" height="300" id="jvfollower" mayscript="True" scriptable="True" archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_simple-1.1.jar">
+   code="jalview.bin.JalviewLite" width="800" height="300" id="jvfollower" mayscript="True" scriptable="True" archive="jalviewApplet.jar,JmolApplet-14.6.4_2016.10.26.jar,java-json.jar,json_simple-1.1.jar">
 <param name="oninit" value="lJvFollow"/>
 <param name="file" value="plantfdx.fa"/>
 <param name="annotations" value="plantfdx.annotations"/>
index 1412a5a..80d7133 100644 (file)
@@ -34,7 +34,7 @@ IETHKEEELTA-
 ----------------------------------------------------------ATYKVKFITPEGEQ
 EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDDQIAEGFVLTCAAYPTSDVT
 IETHREEDMV--
->FER1_ARATH/1-148
+>FER2_ARATH/1-148
 ----MASTALSSAIVGTSFIRRSPAPISLRSLPSANT-QSLFGLKS-GTARGGRVTAMATYKVKFITPEGEL
 EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDEQIGEGFVLTCAAYPTSDVT
 IETHKEEDIV--
@@ -42,7 +42,7 @@ IETHKEEDIV--
 ----------------------------------------------------------ATYKVKFITPEGEQ
 EVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDVT
 IETHKEEELV--
->FER2_ARATH/1-148
+>FER1_ARATH/1-148
 ----MASTALSSAIVSTSFLRRQQTPISLRSLPFANT-QSLFGLKS-STARGGRVTAMATYKVKFITPEGEQ
 EVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDVV
 IETHKEEAIM--
index 872dadc..6a2e058 100644 (file)
@@ -78,23 +78,23 @@ Iron-sulfur (2Fe-2S)        FER3_RAPSA      -1      77      77      METAL
 R -> K         FER3_RAPSA      -1      91      91      VARIANT
 M -> V         FER3_RAPSA      -1      95      95      VARIANT
 <html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER3_RAPSA      -1      8       83      Pfam
-Chloroplast    FER1_ARATH      -1      1       52      TRANSIT
-Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      91      91      METAL
-Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      96      96      METAL
-Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      99      99      METAL
-Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      129     129     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_ARATH      -1      60      135     Pfam
-Iron-sulfur (2Fe-2S)   FER_BRANA       -1      39      39      METAL
-Iron-sulfur (2Fe-2S)   FER_BRANA       -1      44      44      METAL
-Iron-sulfur (2Fe-2S)   FER_BRANA       -1      47      47      METAL
-Iron-sulfur (2Fe-2S)   FER_BRANA       -1      77      77      METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER_BRANA       -1      8       83      Pfam
 Chloroplast    FER2_ARATH      -1      1       52      TRANSIT
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER2_ARATH      -1      129     129     METAL
 <html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER2_ARATH      -1      60      135     Pfam
+Iron-sulfur (2Fe-2S)   FER_BRANA       -1      39      39      METAL
+Iron-sulfur (2Fe-2S)   FER_BRANA       -1      44      44      METAL
+Iron-sulfur (2Fe-2S)   FER_BRANA       -1      47      47      METAL
+Iron-sulfur (2Fe-2S)   FER_BRANA       -1      77      77      METAL
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER_BRANA       -1      8       83      Pfam
+Chloroplast    FER1_ARATH      -1      1       52      TRANSIT
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      91      91      METAL
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      96      96      METAL
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      99      99      METAL
+Iron-sulfur (2Fe-2S)   FER1_ARATH      -1      129     129     METAL
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_ARATH      -1      60      135     Pfam
 <html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_118</a></html>     Q93Z60_ARATH    -1      60      118     Pfam
 Chloroplast    FER1_MAIZE      -1      1       52      TRANSIT
 STRAND FER1_MAIZE      -1      57      59      STRAND
diff --git a/examples/testdata/jal-2005.fa b/examples/testdata/jal-2005.fa
new file mode 100644 (file)
index 0000000..cc58469
--- /dev/null
@@ -0,0 +1,16 @@
+>a
+QQQ
+>b
+QQQ
+>c
+QQQ
+>d
+QQQ
+>e
+QQQ
+>f
+QQQ
+>g
+QQQ
+>h
+QQQ
diff --git a/examples/testdata/jal-2005.jvf b/examples/testdata/jal-2005.jvf
new file mode 100644 (file)
index 0000000..8f37849
--- /dev/null
@@ -0,0 +1,11 @@
+feature_1      8c25cd
+
+STARTGROUP     Jalview
+feature_1      a       -1      1       1       feature_1       0.4
+feature_1      a       -1      2       2       feature_1       0.6
+feature_1      b       -1      1       1       feature_1       0.8
+feature_1      b       -1      2       2       feature_1       1.0
+feature_1      c       -1      1       1       feature_1       1.5
+feature_1      d       -1      1       1       feature_1       2.0
+feature_1      e       -1      1       1       feature_1       3.0
+ENDGROUP       Jalview
diff --git a/examples/testdata/localstruct.pdb b/examples/testdata/localstruct.pdb
new file mode 100644 (file)
index 0000000..bdf13db
--- /dev/null
@@ -0,0 +1,51 @@
+ATOM   7013  N   ALA A 650     -32.039 -14.559  -3.977  1.00 97.16           N  
+ATOM   7014  CA  ALA A 650     -33.253 -15.372  -3.971  1.00101.29           C  
+ATOM   7015  C   ALA A 650     -32.928 -16.865  -4.014  1.00102.48           C  
+ATOM   7016  O   ALA A 650     -33.833 -17.704  -4.075  1.00102.31           O  
+ATOM   7017  CB  ALA A 650     -34.168 -14.987  -5.138  1.00 94.98           C  
+ATOM   7018  N   MET A 651     -31.636 -17.186  -3.978  1.00 98.86           N  
+ATOM   7019  CA  MET A 651     -31.164 -18.568  -4.040  1.00 95.81           C  
+ATOM   7020  C   MET A 651     -29.680 -18.618  -3.678  1.00 95.69           C  
+ATOM   7021  O   MET A 651     -28.847 -18.030  -4.367  1.00 93.27           O  
+ATOM   7022  CB  MET A 651     -31.414 -19.157  -5.435  1.00 94.70           C  
+ATOM   7023  CG  MET A 651     -31.097 -18.189  -6.581  1.00 93.74           C  
+ATOM   7024  SD  MET A 651     -31.780 -18.651  -8.198  1.00 87.88           S  
+ATOM   7025  CE  MET A 651     -30.854 -20.142  -8.594  1.00 81.80           C  
+ATOM   7026  N   LYS A 652     -29.355 -19.313  -2.589  1.00 95.36           N  
+ATOM   7027  CA  LYS A 652     -27.982 -19.355  -2.075  1.00 88.97           C  
+ATOM   7028  C   LYS A 652     -27.021 -20.133  -2.984  1.00 89.03           C  
+ATOM   7029  O   LYS A 652     -27.393 -21.143  -3.592  1.00 90.36           O  
+ATOM   7030  CB  LYS A 652     -27.953 -19.930  -0.656  1.00 85.99           C  
+ATOM   7031  N   ARG A 653     -25.784 -19.655  -3.070  1.00 83.57           N  
+ATOM   7032  CA  ARG A 653     -24.765 -20.305  -3.888  1.00 82.09           C  
+ATOM   7033  C   ARG A 653     -23.704 -20.963  -3.017  1.00 79.82           C  
+ATOM   7034  O   ARG A 653     -23.327 -20.431  -1.977  1.00 79.58           O  
+ATOM   7035  CB  ARG A 653     -24.115 -19.291  -4.831  1.00 84.10           C  
+ATOM   7036  CG  ARG A 653     -23.554 -18.068  -4.129  1.00 82.91           C  
+ATOM   7037  CD  ARG A 653     -23.098 -17.010  -5.124  1.00 84.28           C  
+ATOM   7038  NE  ARG A 653     -23.064 -15.675  -4.527  1.00 83.48           N  
+ATOM   7039  CZ  ARG A 653     -21.959 -15.047  -4.134  1.00 82.34           C  
+ATOM   7040  NH1 ARG A 653     -20.770 -15.621  -4.277  1.00 80.52           N  
+ATOM   7041  NH2 ARG A 653     -22.045 -13.836  -3.602  1.00 84.76           N  
+ATOM   7042  N   ARG A 654     -23.219 -22.122  -3.446  1.00 83.16           N  
+ATOM   7043  CA  ARG A 654     -22.263 -22.882  -2.647  1.00 84.47           C  
+ATOM   7044  C   ARG A 654     -20.845 -22.831  -3.207  1.00 82.72           C  
+ATOM   7045  O   ARG A 654     -20.611 -22.306  -4.294  1.00 84.47           O  
+ATOM   7046  CB  ARG A 654     -22.720 -24.337  -2.500  1.00 86.90           C  
+ATOM   7047  CG  ARG A 654     -22.700 -25.156  -3.785  1.00 90.62           C  
+ATOM   7048  CD  ARG A 654     -21.792 -26.372  -3.625  1.00 94.56           C  
+ATOM   7049  NE  ARG A 654     -22.296 -27.559  -4.313  1.00100.64           N  
+ATOM   7050  CZ  ARG A 654     -21.755 -28.770  -4.203  1.00101.77           C  
+ATOM   7051  NH1 ARG A 654     -20.690 -28.949  -3.433  1.00 99.43           N  
+ATOM   7052  NH2 ARG A 654     -22.277 -29.803  -4.858  1.00103.21           N  
+ATOM   7053  N   ARG A 655     -19.901 -23.377  -2.452  1.00 80.06           N  
+ATOM   7054  CA  ARG A 655     -18.522 -23.461  -2.899  1.00 81.57           C  
+ATOM   7055  C   ARG A 655     -18.393 -24.576  -3.925  1.00 85.28           C  
+ATOM   7056  O   ARG A 655     -19.120 -25.567  -3.865  1.00 87.19           O  
+ATOM   7057  CB  ARG A 655     -17.617 -23.772  -1.718  1.00 83.19           C  
+ATOM   7058  CG  ARG A 655     -17.720 -25.217  -1.265  1.00 86.49           C  
+ATOM   7059  CD  ARG A 655     -17.099 -25.402   0.093  1.00 85.01           C  
+ATOM   7060  NE  ARG A 655     -15.880 -24.617   0.223  1.00 85.24           N  
+ATOM   7061  CZ  ARG A 655     -15.123 -24.608   1.310  1.00 87.53           C  
+ATOM   7062  NH1 ARG A 655     -15.465 -25.351   2.354  1.00 87.44           N  
+ATOM   7063  NH2 ARG A 655     -14.028 -23.864   1.350  1.00 89.64           N  
index 1e41232..12be42e 100644 (file)
@@ -1,4 +1,24 @@
 <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.
+ -->
 <input type="hidden" name="seqData" id="seqData" value='{"seqs":[{"name":"FER_CAPAA/1-97","start":1,"svid":"1.0","end":97,"id":"4362914","seq":"-----------------------------------------------------------ASYKVKLITPDGPIEFDCPDDVYILDQAEEAGHDLPYSCRAGSCSSCAGKIAGGAVDQTDGNFLDDDQLEEGWVLTCVAYPQSDVTIETHKEAELVG-","order":1},{"name":"FER_CAPAN/1-144","start":1,"svid":"1.0","end":144,"id":"87519910","seq":"MA------SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALFGLKS-A--NGGKVTCMASYKVKLITPDGPIEFDCPDNVYILDQAEEAGHDLPYSCRAGSCSSCAGKIAGGAVDQTDGNFLDDDQLEEGWVLTCVAYPQSDVTIETHKEAELVG-","order":2},{"name":"FER1_SOLLC/1-144","start":1,"svid":"1.0","end":144,"id":"706449716","seq":"MA------SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMASYKVKLITPEGPIEFECPDDVYILDQAEEEGHDLPYSCRAGSCSSCAGKVTAGSVDQSDGNFLDEDQEAAGFVLTCVAYPKGDVTIETHKEEELTA-","order":3},{"name":"Q93XJ9_SOLTU/1-144","start":1,"svid":"1.0","end":144,"id":"1704607829","seq":"MA------SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMASYKVKLITPDGPIEFECPDDVYILDQAEEEGHDLPYSCRAGSCSSCAGKVTAGTVDQSDGKFLDDDQEAAGFVLTCVAYPKCDVTIETHKEEELTA-","order":4},{"name":"FER1_PEA/1-149","start":1,"svid":"1.0","end":149,"id":"1901660614","seq":"MATT---PALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFLGLKT-SLKRGDLAVAMASYKVKLVTPDGTQEFECPSDVYILDHAEEVGIDLPYSCRAGSCSSCAGKVVGGEVDQSDGSFLDDEQIEAGFVLTCVAYPTSDVVIETHKEEDLTA-","order":5},{"name":"Q7XA98_TRIPR/1-152","start":1,"svid":"1.0","end":152,"id":"1329985289","seq":"MATT---PALYGTAVSTSFMRRQPVPMSV-ATTTTTKAFPSGFGLKSVSTKRGDLAVAMATYKVKLITPEGPQEFDCPDDVYILDHAEEVGIELPYSCRAGSCSSCAGKVVNGNVNQEDGSFLDDEQIEGGWVLTCVAFPTSDVTIETHKEEELTA-","order":6},{"name":"FER1_MESCR/1-148","start":1,"svid":"1.0","end":148,"id":"966876644","seq":"MAAT--TAALSGATMSTAFAPK--TPPMTAALPTNVGR--ALFGLKS-SASR-GRVTAMAAYKVTLVTPEGKQELECPDDVYILDAAEEAGIDLPYSCRAGSCSSCAGKVTSGSVNQDDGSFLDDDQIKEGWVLTCVAYPTGDVTIETHKEEELTA-","order":7},{"name":"FER1_SPIOL/1-147","start":1,"svid":"1.0","end":147,"id":"235809389","seq":"MAAT--TTTMMG--MATTFVPKPQAPPMMAALPSNTGR--SLFGLKT-GSR--GGRMTMAAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLDDDQIDEGWVLTCAAYPVSDVTIETHKEEELTA-","order":8},{"name":"FER3_RAPSA/1-96","start":1,"svid":"1.0","end":96,"id":"924845395","seq":"-----------------------------------------------------------ATYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDDQIAEGFVLTCAAYPTSDVTIETHREEDMV--","order":9},{"name":"FER1_ARATH/1-148","start":1,"svid":"1.0","end":148,"id":"1472020737","seq":"MAST----ALSSAIVGTSFIRRSPAPISLRSLPSANTQ--SLFGLKS-GTARGGRVTAMATYKVKFITPEGELEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDEQIGEGFVLTCAAYPTSDVTIETHKEEDIV--","order":10},{"name":"FER_BRANA/1-96","start":1,"svid":"1.0","end":96,"id":"1690335343","seq":"-----------------------------------------------------------ATYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDVTIETHKEEELV--","order":11},{"name":"FER2_ARATH/1-148","start":1,"svid":"1.0","end":148,"id":"467823576","seq":"MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMATYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDVVIETHKEEAIM--","order":12},{"name":"Q93Z60_ARATH/1-118","start":1,"svid":"1.0","end":118,"id":"752877418","seq":"MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMATYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD--------------------------------","order":13},{"name":"FER1_MAIZE/1-150","start":1,"svid":"1.0","end":150,"id":"299304633","seq":"MATVLGSPRAPAFFFSSSSLRAAPAPTAV--ALPAAKV--GIMGRSA-SSRR--RLRAQATYNVKLITPEGEVELQVPDDVYILDQAEEDGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSYLDDGQIADGWVLTCHAYPTSDVVIETHKEEELTGA","order":14},{"name":"O80429_MAIZE/1-140","start":1,"svid":"1.0","end":140,"id":"1991448556","seq":"MAAT---------ALSMSILR---APPPCFSSPLRLRV--AVAKPLA-APMRRQLLRAQATYNVKLITPEGEVELQVPDDVYILDFAEEEGIDLPFSCRAGSCSSCAGKVVSGSVDQSDQSFLNDNQVADGWVLTCAAYPTSDVVIETHKEDDLL--","order":15},{"name":"1A70|/1-97","start":1,"svid":"1.0","end":97,"id":"2114395721","seq":"-----------------------------------------------------------AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLDDDQIDEGWVLTCAAYPVSDVTIETHKKEELTA","order":16}],"appSettings":{"globalColorScheme":"foo","webStartUrl":"www.jalview.org/services/launchApp","application":"Jalview","hiddenSeqs":"2114395721","showSeqFeatures":"false","version":"2.9"},"seqGroups":[{"displayText":true,"startRes":59,"groupName":"ferredoxin","endRes":124,"colourText":false,"seqsHash":["1472020737","299304633","966876644","1901660614","706449716","235809389","467823576","924845395","1690335343","4362914","87519910","752877418","1329985289","1991448556","1704607829"],"svid":"1.0","showNonconserved":false,"colourScheme":"Zappo","displayBoxes":true}],"alignAnnotation":[{"svid":"1.0","annotations":[{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"1","value":1,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"2","value":2,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"3","value":3,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"4","value":4,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"5","value":5,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"6","value":6,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"H"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"7","value":7,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"9","value":9,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"E"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"}],"description":"New description","label":"Secondary Structure"},{"svid":"1.0","annotations":[{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"description":"Fe","displayCharacter":"Fe","value":0,"secondaryStructure":" "},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"},{"displayCharacter":"","value":0,"secondaryStructure":"\u0000"}],"description":"New description","label":"Iron Sulphur Contacts"}],"svid":"1.0","seqFeatures":[{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:   1  1a70 ","xStart":59,"xEnd":60,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:   2  1a70 ","xStart":60,"xEnd":61,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:   3  1a70 ","xStart":61,"xEnd":62,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:   4  1a70 ","xStart":62,"xEnd":63,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:   5  1a70 ","xStart":63,"xEnd":64,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:   6  1a70 ","xStart":64,"xEnd":65,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:   7  1a70 ","xStart":65,"xEnd":66,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:   8  1a70 ","xStart":66,"xEnd":67,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:   9  1a70 ","xStart":67,"xEnd":68,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:  10  1a70 ","xStart":68,"xEnd":69,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:  11  1a70 ","xStart":69,"xEnd":70,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:  12  1a70 ","xStart":70,"xEnd":71,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASN:  13  1a70 ","xStart":71,"xEnd":72,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:  14  1a70 ","xStart":72,"xEnd":73,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  15  1a70 ","xStart":73,"xEnd":74,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PHE:  16  1a70 ","xStart":74,"xEnd":75,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:  17  1a70 ","xStart":75,"xEnd":76,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:  18  1a70 ","xStart":76,"xEnd":77,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:  19  1a70 ","xStart":77,"xEnd":78,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  20  1a70 ","xStart":78,"xEnd":79,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  21  1a70 ","xStart":79,"xEnd":80,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:  22  1a70 ","xStart":80,"xEnd":81,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:  23  1a70 ","xStart":81,"xEnd":82,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:  24  1a70 ","xStart":82,"xEnd":83,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  25  1a70 ","xStart":83,"xEnd":84,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  26  1a70 ","xStart":84,"xEnd":85,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  27  1a70 ","xStart":85,"xEnd":86,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  28  1a70 ","xStart":86,"xEnd":87,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  29  1a70 ","xStart":87,"xEnd":88,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  30  1a70 ","xStart":88,"xEnd":89,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  31  1a70 ","xStart":89,"xEnd":90,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:  32  1a70 ","xStart":90,"xEnd":91,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:  33  1a70 ","xStart":91,"xEnd":92,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  34  1a70 ","xStart":92,"xEnd":93,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  35  1a70 ","xStart":93,"xEnd":94,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:  36  1a70 ","xStart":94,"xEnd":95,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:  37  1a70 ","xStart":95,"xEnd":96,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  38  1a70 ","xStart":96,"xEnd":97,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:  39  1a70 ","xStart":97,"xEnd":98,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ARG:  40  1a70 ","xStart":98,"xEnd":99,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  41  1a70 ","xStart":99,"xEnd":100,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:  42  1a70 ","xStart":100,"xEnd":101,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  43  1a70 ","xStart":101,"xEnd":102,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:  44  1a70 ","xStart":102,"xEnd":103,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  45  1a70 ","xStart":103,"xEnd":104,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  46  1a70 ","xStart":104,"xEnd":105,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:  47  1a70 ","xStart":105,"xEnd":106,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  48  1a70 ","xStart":106,"xEnd":107,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:  49  1a70 ","xStart":107,"xEnd":108,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:  50  1a70 ","xStart":108,"xEnd":109,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  51  1a70 ","xStart":109,"xEnd":110,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:  52  1a70 ","xStart":110,"xEnd":111,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:  53  1a70 ","xStart":111,"xEnd":112,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:  54  1a70 ","xStart":112,"xEnd":113,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  55  1a70 ","xStart":113,"xEnd":114,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  56  1a70 ","xStart":114,"xEnd":115,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASN:  57  1a70 ","xStart":115,"xEnd":116,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:  58  1a70 ","xStart":116,"xEnd":117,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  59  1a70 ","xStart":117,"xEnd":118,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  60  1a70 ","xStart":118,"xEnd":119,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:  61  1a70 ","xStart":119,"xEnd":120,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  62  1a70 ","xStart":120,"xEnd":121,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PHE:  63  1a70 ","xStart":121,"xEnd":122,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  64  1a70 ","xStart":122,"xEnd":123,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  65  1a70 ","xStart":123,"xEnd":124,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  66  1a70 ","xStart":124,"xEnd":125,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  67  1a70 ","xStart":125,"xEnd":126,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:  68  1a70 ","xStart":126,"xEnd":127,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:  69  1a70 ","xStart":127,"xEnd":128,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  70  1a70 ","xStart":128,"xEnd":129,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  71  1a70 ","xStart":129,"xEnd":130,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:  72  1a70 ","xStart":130,"xEnd":131,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TRP:  73  1a70 ","xStart":131,"xEnd":132,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:  74  1a70 ","xStart":132,"xEnd":133,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  75  1a70 ","xStart":133,"xEnd":134,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:  76  1a70 ","xStart":134,"xEnd":135,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:  77  1a70 ","xStart":135,"xEnd":136,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  78  1a70 ","xStart":136,"xEnd":137,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  79  1a70 ","xStart":137,"xEnd":138,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:  80  1a70 ","xStart":138,"xEnd":139,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:  81  1a70 ","xStart":139,"xEnd":140,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:  82  1a70 ","xStart":140,"xEnd":141,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:  83  1a70 ","xStart":141,"xEnd":142,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:  84  1a70 ","xStart":142,"xEnd":143,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:  85  1a70 ","xStart":143,"xEnd":144,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:  86  1a70 ","xStart":144,"xEnd":145,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:  87  1a70 ","xStart":145,"xEnd":146,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  88  1a70 ","xStart":146,"xEnd":147,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:  89  1a70 ","xStart":147,"xEnd":148,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"HIS:  90  1a70 ","xStart":148,"xEnd":149,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:  91  1a70 ","xStart":149,"xEnd":150,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  93  1a70 ","xStart":151,"xEnd":152,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:  94  1a70 ","xStart":152,"xEnd":153,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:  95  1a70 ","xStart":153,"xEnd":154,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:  96  1a70 ","xStart":154,"xEnd":155,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:  97  1a70 ","xStart":155,"xEnd":156,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:1 1a70 ","xStart":59,"xEnd":60,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:2 1a70 ","xStart":60,"xEnd":61,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:3 1a70 ","xStart":61,"xEnd":62,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:4 1a70 ","xStart":62,"xEnd":63,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:5 1a70 ","xStart":63,"xEnd":64,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:6 1a70 ","xStart":64,"xEnd":65,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:7 1a70 ","xStart":65,"xEnd":66,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:8 1a70 ","xStart":66,"xEnd":67,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:9 1a70 ","xStart":67,"xEnd":68,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:10 1a70 ","xStart":68,"xEnd":69,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:11 1a70 ","xStart":69,"xEnd":70,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:12 1a70 ","xStart":70,"xEnd":71,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASN:13 1a70 ","xStart":71,"xEnd":72,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:14 1a70 ","xStart":72,"xEnd":73,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:15 1a70 ","xStart":73,"xEnd":74,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PHE:16 1a70 ","xStart":74,"xEnd":75,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:17 1a70 ","xStart":75,"xEnd":76,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:18 1a70 ","xStart":76,"xEnd":77,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:19 1a70 ","xStart":77,"xEnd":78,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:20 1a70 ","xStart":78,"xEnd":79,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:21 1a70 ","xStart":79,"xEnd":80,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:22 1a70 ","xStart":80,"xEnd":81,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:23 1a70 ","xStart":81,"xEnd":82,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:24 1a70 ","xStart":82,"xEnd":83,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:25 1a70 ","xStart":83,"xEnd":84,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:26 1a70 ","xStart":84,"xEnd":85,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:27 1a70 ","xStart":85,"xEnd":86,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:28 1a70 ","xStart":86,"xEnd":87,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:29 1a70 ","xStart":87,"xEnd":88,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:30 1a70 ","xStart":88,"xEnd":89,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:31 1a70 ","xStart":89,"xEnd":90,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:32 1a70 ","xStart":90,"xEnd":91,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:33 1a70 ","xStart":91,"xEnd":92,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:34 1a70 ","xStart":92,"xEnd":93,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:35 1a70 ","xStart":93,"xEnd":94,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:36 1a70 ","xStart":94,"xEnd":95,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:37 1a70 ","xStart":95,"xEnd":96,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:38 1a70 ","xStart":96,"xEnd":97,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:39 1a70 ","xStart":97,"xEnd":98,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ARG:40 1a70 ","xStart":98,"xEnd":99,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:41 1a70 ","xStart":99,"xEnd":100,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:42 1a70 ","xStart":100,"xEnd":101,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:43 1a70 ","xStart":101,"xEnd":102,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:44 1a70 ","xStart":102,"xEnd":103,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:45 1a70 ","xStart":103,"xEnd":104,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:46 1a70 ","xStart":104,"xEnd":105,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:47 1a70 ","xStart":105,"xEnd":106,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:48 1a70 ","xStart":106,"xEnd":107,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:49 1a70 ","xStart":107,"xEnd":108,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:50 1a70 ","xStart":108,"xEnd":109,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:51 1a70 ","xStart":109,"xEnd":110,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:52 1a70 ","xStart":110,"xEnd":111,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:53 1a70 ","xStart":111,"xEnd":112,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:54 1a70 ","xStart":112,"xEnd":113,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:55 1a70 ","xStart":113,"xEnd":114,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:56 1a70 ","xStart":114,"xEnd":115,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASN:57 1a70 ","xStart":115,"xEnd":116,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:58 1a70 ","xStart":116,"xEnd":117,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:59 1a70 ","xStart":117,"xEnd":118,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:60 1a70 ","xStart":118,"xEnd":119,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:61 1a70 ","xStart":119,"xEnd":120,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:62 1a70 ","xStart":120,"xEnd":121,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PHE:63 1a70 ","xStart":121,"xEnd":122,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:64 1a70 ","xStart":122,"xEnd":123,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:65 1a70 ","xStart":123,"xEnd":124,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:66 1a70 ","xStart":124,"xEnd":125,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:67 1a70 ","xStart":125,"xEnd":126,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:68 1a70 ","xStart":126,"xEnd":127,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:69 1a70 ","xStart":127,"xEnd":128,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:70 1a70 ","xStart":128,"xEnd":129,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:71 1a70 ","xStart":129,"xEnd":130,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:72 1a70 ","xStart":130,"xEnd":131,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TRP:73 1a70 ","xStart":131,"xEnd":132,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:74 1a70 ","xStart":132,"xEnd":133,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:75 1a70 ","xStart":133,"xEnd":134,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:76 1a70 ","xStart":134,"xEnd":135,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:77 1a70 ","xStart":135,"xEnd":136,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:78 1a70 ","xStart":136,"xEnd":137,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:79 1a70 ","xStart":137,"xEnd":138,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:80 1a70 ","xStart":138,"xEnd":139,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:81 1a70 ","xStart":139,"xEnd":140,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:82 1a70 ","xStart":140,"xEnd":141,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:83 1a70 ","xStart":141,"xEnd":142,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:84 1a70 ","xStart":142,"xEnd":143,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:85 1a70 ","xStart":143,"xEnd":144,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:86 1a70 ","xStart":144,"xEnd":145,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:87 1a70 ","xStart":145,"xEnd":146,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:88 1a70 ","xStart":146,"xEnd":147,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:89 1a70 ","xStart":147,"xEnd":148,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"HIS:90 1a70 ","xStart":148,"xEnd":149,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:91 1a70 ","xStart":149,"xEnd":150,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:93 1a70 ","xStart":151,"xEnd":152,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:94 1a70 ","xStart":152,"xEnd":153,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:95 1a70 ","xStart":153,"xEnd":154,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:96 1a70 ","xStart":154,"xEnd":155,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"235809389","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:97 1a70 ","xStart":155,"xEnd":156,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:   1  1a70 ","xStart":59,"xEnd":60,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:   2  1a70 ","xStart":60,"xEnd":61,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"TYR:   3  1a70 ","xStart":61,"xEnd":62,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LYS:   4  1a70 ","xStart":62,"xEnd":63,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:   5  1a70 ","xStart":63,"xEnd":64,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:   6  1a70 ","xStart":64,"xEnd":65,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:   7  1a70 ","xStart":65,"xEnd":66,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:   8  1a70 ","xStart":66,"xEnd":67,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:   9  1a70 ","xStart":67,"xEnd":68,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"PRO:  10  1a70 ","xStart":68,"xEnd":69,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:  11  1a70 ","xStart":69,"xEnd":70,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLY:  12  1a70 ","xStart":70,"xEnd":71,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASN:  13  1a70 ","xStart":71,"xEnd":72,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:  14  1a70 ","xStart":72,"xEnd":73,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  15  1a70 ","xStart":73,"xEnd":74,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"PHE:  16  1a70 ","xStart":74,"xEnd":75,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLN:  17  1a70 ","xStart":75,"xEnd":76,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"CYS:  18  1a70 ","xStart":76,"xEnd":77,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"PRO:  19  1a70 ","xStart":77,"xEnd":78,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  20  1a70 ","xStart":78,"xEnd":79,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  21  1a70 ","xStart":79,"xEnd":80,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:  22  1a70 ","xStart":80,"xEnd":81,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"TYR:  23  1a70 ","xStart":81,"xEnd":82,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ILE:  24  1a70 ","xStart":82,"xEnd":83,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  25  1a70 ","xStart":83,"xEnd":84,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  26  1a70 ","xStart":84,"xEnd":85,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  27  1a70 ","xStart":85,"xEnd":86,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  28  1a70 ","xStart":86,"xEnd":87,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  29  1a70 ","xStart":87,"xEnd":88,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  30  1a70 ","xStart":88,"xEnd":89,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  31  1a70 ","xStart":89,"xEnd":90,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLY:  32  1a70 ","xStart":90,"xEnd":91,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ILE:  33  1a70 ","xStart":91,"xEnd":92,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  34  1a70 ","xStart":92,"xEnd":93,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  35  1a70 ","xStart":93,"xEnd":94,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"PRO:  36  1a70 ","xStart":94,"xEnd":95,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"TYR:  37  1a70 ","xStart":95,"xEnd":96,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  38  1a70 ","xStart":96,"xEnd":97,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"CYS:  39  1a70 ","xStart":97,"xEnd":98,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ARG:  40  1a70 ","xStart":98,"xEnd":99,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  41  1a70 ","xStart":99,"xEnd":100,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLY:  42  1a70 ","xStart":100,"xEnd":101,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  43  1a70 ","xStart":101,"xEnd":102,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"CYS:  44  1a70 ","xStart":102,"xEnd":103,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  45  1a70 ","xStart":103,"xEnd":104,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  46  1a70 ","xStart":104,"xEnd":105,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"CYS:  47  1a70 ","xStart":105,"xEnd":106,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  48  1a70 ","xStart":106,"xEnd":107,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLY:  49  1a70 ","xStart":107,"xEnd":108,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LYS:  50  1a70 ","xStart":108,"xEnd":109,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  51  1a70 ","xStart":109,"xEnd":110,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LYS:  52  1a70 ","xStart":110,"xEnd":111,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:  53  1a70 ","xStart":111,"xEnd":112,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLY:  54  1a70 ","xStart":112,"xEnd":113,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  55  1a70 ","xStart":113,"xEnd":114,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  56  1a70 ","xStart":114,"xEnd":115,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASN:  57  1a70 ","xStart":115,"xEnd":116,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLN:  58  1a70 ","xStart":116,"xEnd":117,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  59  1a70 ","xStart":117,"xEnd":118,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  60  1a70 ","xStart":118,"xEnd":119,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLN:  61  1a70 ","xStart":119,"xEnd":120,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  62  1a70 ","xStart":120,"xEnd":121,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"PHE:  63  1a70 ","xStart":121,"xEnd":122,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  64  1a70 ","xStart":122,"xEnd":123,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  65  1a70 ","xStart":123,"xEnd":124,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  66  1a70 ","xStart":124,"xEnd":125,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  67  1a70 ","xStart":125,"xEnd":126,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLN:  68  1a70 ","xStart":126,"xEnd":127,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ILE:  69  1a70 ","xStart":127,"xEnd":128,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  70  1a70 ","xStart":128,"xEnd":129,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  71  1a70 ","xStart":129,"xEnd":130,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLY:  72  1a70 ","xStart":130,"xEnd":131,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"TRP:  73  1a70 ","xStart":131,"xEnd":132,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:  74  1a70 ","xStart":132,"xEnd":133,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  75  1a70 ","xStart":133,"xEnd":134,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:  76  1a70 ","xStart":134,"xEnd":135,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"CYS:  77  1a70 ","xStart":135,"xEnd":136,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  78  1a70 ","xStart":136,"xEnd":137,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  79  1a70 ","xStart":137,"xEnd":138,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"TYR:  80  1a70 ","xStart":138,"xEnd":139,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"PRO:  81  1a70 ","xStart":139,"xEnd":140,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:  82  1a70 ","xStart":140,"xEnd":141,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"SER:  83  1a70 ","xStart":141,"xEnd":142,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ASP:  84  1a70 ","xStart":142,"xEnd":143,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"VAL:  85  1a70 ","xStart":143,"xEnd":144,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:  86  1a70 ","xStart":144,"xEnd":145,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ILE:  87  1a70 ","xStart":145,"xEnd":146,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  88  1a70 ","xStart":146,"xEnd":147,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:  89  1a70 ","xStart":147,"xEnd":148,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"HIS:  90  1a70 ","xStart":148,"xEnd":149,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LYS:  91  1a70 ","xStart":149,"xEnd":150,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LYS:  92  1a70 ","xStart":150,"xEnd":151,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  93  1a70 ","xStart":151,"xEnd":152,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"GLU:  94  1a70 ","xStart":152,"xEnd":153,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"LEU:  95  1a70 ","xStart":153,"xEnd":154,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"THR:  96  1a70 ","xStart":154,"xEnd":155,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":""},"svid":"1.0","description":"ALA:  97  1a70 ","xStart":155,"xEnd":156,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:1 1a70 ","xStart":59,"xEnd":60,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:2 1a70 ","xStart":60,"xEnd":61,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:3 1a70 ","xStart":61,"xEnd":62,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:4 1a70 ","xStart":62,"xEnd":63,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:5 1a70 ","xStart":63,"xEnd":64,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:6 1a70 ","xStart":64,"xEnd":65,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:7 1a70 ","xStart":65,"xEnd":66,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:8 1a70 ","xStart":66,"xEnd":67,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:9 1a70 ","xStart":67,"xEnd":68,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:10 1a70 ","xStart":68,"xEnd":69,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:11 1a70 ","xStart":69,"xEnd":70,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:12 1a70 ","xStart":70,"xEnd":71,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASN:13 1a70 ","xStart":71,"xEnd":72,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:14 1a70 ","xStart":72,"xEnd":73,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:15 1a70 ","xStart":73,"xEnd":74,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PHE:16 1a70 ","xStart":74,"xEnd":75,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:17 1a70 ","xStart":75,"xEnd":76,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:18 1a70 ","xStart":76,"xEnd":77,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:19 1a70 ","xStart":77,"xEnd":78,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:20 1a70 ","xStart":78,"xEnd":79,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:21 1a70 ","xStart":79,"xEnd":80,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:22 1a70 ","xStart":80,"xEnd":81,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:23 1a70 ","xStart":81,"xEnd":82,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:24 1a70 ","xStart":82,"xEnd":83,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:25 1a70 ","xStart":83,"xEnd":84,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:26 1a70 ","xStart":84,"xEnd":85,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:27 1a70 ","xStart":85,"xEnd":86,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:28 1a70 ","xStart":86,"xEnd":87,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:29 1a70 ","xStart":87,"xEnd":88,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:30 1a70 ","xStart":88,"xEnd":89,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:31 1a70 ","xStart":89,"xEnd":90,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:32 1a70 ","xStart":90,"xEnd":91,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:33 1a70 ","xStart":91,"xEnd":92,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:34 1a70 ","xStart":92,"xEnd":93,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:35 1a70 ","xStart":93,"xEnd":94,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:36 1a70 ","xStart":94,"xEnd":95,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:37 1a70 ","xStart":95,"xEnd":96,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:38 1a70 ","xStart":96,"xEnd":97,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:39 1a70 ","xStart":97,"xEnd":98,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ARG:40 1a70 ","xStart":98,"xEnd":99,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:41 1a70 ","xStart":99,"xEnd":100,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:42 1a70 ","xStart":100,"xEnd":101,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:43 1a70 ","xStart":101,"xEnd":102,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:44 1a70 ","xStart":102,"xEnd":103,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:45 1a70 ","xStart":103,"xEnd":104,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:46 1a70 ","xStart":104,"xEnd":105,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:47 1a70 ","xStart":105,"xEnd":106,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:48 1a70 ","xStart":106,"xEnd":107,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:49 1a70 ","xStart":107,"xEnd":108,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:50 1a70 ","xStart":108,"xEnd":109,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:51 1a70 ","xStart":109,"xEnd":110,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:52 1a70 ","xStart":110,"xEnd":111,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:53 1a70 ","xStart":111,"xEnd":112,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:54 1a70 ","xStart":112,"xEnd":113,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:55 1a70 ","xStart":113,"xEnd":114,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:56 1a70 ","xStart":114,"xEnd":115,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASN:57 1a70 ","xStart":115,"xEnd":116,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:58 1a70 ","xStart":116,"xEnd":117,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:59 1a70 ","xStart":117,"xEnd":118,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:60 1a70 ","xStart":118,"xEnd":119,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:61 1a70 ","xStart":119,"xEnd":120,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:62 1a70 ","xStart":120,"xEnd":121,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PHE:63 1a70 ","xStart":121,"xEnd":122,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:64 1a70 ","xStart":122,"xEnd":123,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:65 1a70 ","xStart":123,"xEnd":124,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:66 1a70 ","xStart":124,"xEnd":125,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:67 1a70 ","xStart":125,"xEnd":126,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLN:68 1a70 ","xStart":126,"xEnd":127,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:69 1a70 ","xStart":127,"xEnd":128,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:70 1a70 ","xStart":128,"xEnd":129,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:71 1a70 ","xStart":129,"xEnd":130,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLY:72 1a70 ","xStart":130,"xEnd":131,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TRP:73 1a70 ","xStart":131,"xEnd":132,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:74 1a70 ","xStart":132,"xEnd":133,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:75 1a70 ","xStart":133,"xEnd":134,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:76 1a70 ","xStart":134,"xEnd":135,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"CYS:77 1a70 ","xStart":135,"xEnd":136,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:78 1a70 ","xStart":136,"xEnd":137,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:79 1a70 ","xStart":137,"xEnd":138,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"TYR:80 1a70 ","xStart":138,"xEnd":139,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"PRO:81 1a70 ","xStart":139,"xEnd":140,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:82 1a70 ","xStart":140,"xEnd":141,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"SER:83 1a70 ","xStart":141,"xEnd":142,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ASP:84 1a70 ","xStart":142,"xEnd":143,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"VAL:85 1a70 ","xStart":143,"xEnd":144,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:86 1a70 ","xStart":144,"xEnd":145,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ILE:87 1a70 ","xStart":145,"xEnd":146,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:88 1a70 ","xStart":146,"xEnd":147,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:89 1a70 ","xStart":147,"xEnd":148,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"HIS:90 1a70 ","xStart":148,"xEnd":149,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:91 1a70 ","xStart":149,"xEnd":150,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LYS:92 1a70 ","xStart":150,"xEnd":151,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:93 1a70 ","xStart":151,"xEnd":152,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"GLU:94 1a70 ","xStart":152,"xEnd":153,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"LEU:95 1a70 ","xStart":153,"xEnd":154,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"THR:96 1a70 ","xStart":154,"xEnd":155,"type":"RESNUM"},{"fillColor":"#ffffff","score":0,"sequenceRef":"2114395721","featureGroup":"1a70","otherDetails":{"status":"IEA:jalview"},"svid":"1.0","description":"ALA:97 1a70 ","xStart":155,"xEnd":156,"type":"RESNUM"}]}'>
 <style type="text/css"> div.parent{ width:100%;<!-- overflow: auto; -->}
 div.titlex{ width:11%; float: left; }
index 72c062d..6e6c670 100755 (executable)
@@ -34,7 +34,7 @@ TIETHKEEELTA-
 -----------------------------------------------------------ATYKVKFITPEGE
 QEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDDQIAEGFVLTCAAYPTSDV
 TIETHREEDMV--
->FER1_ARATH Ferredoxin-1, chloroplast precursor
+>FER2_ARATH Ferredoxin-2, chloroplast precursor
 MAST----ALSSAIVGTSFIRRSPAPISLRSLPSANTQ--SLFGLKS-GTARGGRVTAMATYKVKFITPEGE
 LEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDDEQIGEGFVLTCAAYPTSDV
 TIETHKEEDIV--
@@ -42,7 +42,7 @@ TIETHKEEDIV--
 -----------------------------------------------------------ATYKVKFITPEGE
 QEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDDDQIAEGFVLTCAAYPTSDV
 TIETHKEEELV--
->FER2_ARATH Ferredoxin-2, chloroplast precursor
+>FER1_ARATH Ferredoxin-1, chloroplast precursor
 MAST----ALSSAIVSTSFLRRQQTPISLRSLPFANTQ--SLFGLKS-STARGGRVTAMATYKVKFITPEGE
 QEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDDEQMSEGYVLTCVAYPTSDV
 VIETHKEEAIM--
index 9974fc7..725d210 100644 (file)
@@ -18,11 +18,11 @@ AAYKVTLVTPEGKQELECPDDVYILDAAEEAGIDLPYSCRAGSCSSCAGKVTSGSVNQDDGSFLDD
 AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLDD
 >FER3_RAPSA/1-66 Ferredoxin, leaf L-A
 ATYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDD
->FER1_ARATH/53-118 Ferredoxin-1, chloroplast precursor
+>FER2_ARATH/53-118 Ferredoxin-1, chloroplast precursor
 ATYKVKFITPEGELEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGSVDQSDQSFLDD
 >FER_BRANA/1-66 Ferredoxin
 ATYKVKFITPEGEQEVECDDDVYVLDAAEEAGIDLPYSCRAGSCSSCAGKVVSGFVDQSDESFLDD
->FER2_ARATH/53-118 Ferredoxin-2, chloroplast precursor
+>FER1_ARATH/53-118 Ferredoxin-2, chloroplast precursor
 ATYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD
 >Q93Z60_ARATH/53-118 At1g10960/T19D16_12
 ATYKVKFITPEGEQEVECEEDVYVLDAAEEAGLDLPYSCRAGSCSSCAGKVVSGSIDQSDQSFLDD
index ce98085..e034fc2 100755 (executable)
@@ -22,7 +22,7 @@
    <mapID target="home" url="html/index.html" />
    
    <mapID target="new" url="html/whatsNew.html"/>
-   <mapID target="release" url="html/releases.html#Jalview.2.9"/>
+   <mapID target="release" url="html/releases.html#Jalview.2.10.1"/>
    <mapID target="alannotation" url="html/features/annotation.html"/>
    <mapID target="keys" url="html/keys.html"/>
    <mapID target="newkeys" url="html/features/newkeystrokes.html"/>
    
    <mapID target="memory" url="html/memory.html" />
    <mapID target="groovy" url="html/features/groovy.html" />
+   <mapID target="groovy.featurecounter" url="html/groovy/featureCounter.html" />
    <mapID target="privacy" url="html/privacy.html" />
    <mapID target="vamsas" url="html/vamsas/index.html"/>
    <mapID target="aminoAcids" url="html/misc/aminoAcids.html" />
    
    <mapID target="biojson" url="html/features/bioJsonFormat.html" />
    <mapID target="pdbfetcher" url="html/features/pdbsequencefetcher.html" />
+   <mapID target="siftsmapping" url="html/features/siftsmapping.html" />
    <mapID target="pdbchooser" url="html/features/structurechooser.html" />
    <mapID target="selectcolbyannot" url="html/features/columnFilterByAnnotation.html" />
    <mapID target="biojsmsa" url="html/features/biojsmsa.html" />
    
+   <mapID target="ensemblfetch" url="html/features/ensemblsequencefetcher.html" />
+   
+   <mapID target="uniprotfetcher" url="html/features/uniprotsequencefetcher.html" />
+   
    <mapID target="backIcon" url="icons/back.png" />
    <mapID target="forwardIcon" url="icons/forward.png" />
    <mapID target="homeIcon" url="icons/Home.png" />
index fe8e1a9..3a6b0b3 100755 (executable)
 <!-- DO NOT WRAP THESE LINES - help2Website relies on each item being on one line! -->
        <tocitem text="Jalview Documentation" target="home" expand="true">
                        <tocitem text="What's new" target="new" expand="true">
-                               <tocitem text="Split Frame View" target="splitframe" />
-                               <tocitem text="PDB Sequence Fetcher" target="pdbfetcher" />
-                               <tocitem text="PDB Structure Chooser" target="pdbchooser" />
-                               <tocitem text="Chimera Viewer" target="chimera" />
-                               <tocitem text="Select Columns by Annotation" target="selectcolbyannot" />
                                <tocitem text="Latest Release Notes" target="release"/>
                </tocitem>
                
                        <tocitem text="By RNA Helices" target="colours.rnahelices" />
                </tocitem>
                
-               <tocitem text="Calculations" target="calculations" expand="false">
+               <tocitem text="Calculations" expand="false">
                        <tocitem text="Sorting alignments" target="sorting" />
                        <tocitem text="Calculating trees" target="trees" />
                        <tocitem text="Principal Component Analysis" target="pca" />
                        <tocitem text="PDB Sequence Fetcher" target="pdbfetcher" />
                        <tocitem text="PDB Structure Chooser" target="pdbchooser" />
                        <tocitem text="Jmol Viewer" target="pdbjmol" />
-                       <tocitem text="Chimera Viewer" target="chimera" />
-                       <tocitem text="Simple PDB Viewer" target="pdbmcviewer" />
+                       <tocitem text="Chimera Viewer" target="chimera" />                      
                </tocitem>
                <tocitem text="Viewing RNA structures" target="varna" expand="false"/>
                <tocitem text="VAMSAS Data Exchange" target="vamsas">
                </tocitem>
                <tocitem text="Preferences" target="preferences" />
                <tocitem text="Memory Settings" target="memory" expand="false"/>
+               <tocitem text="Scripting with Groovy" target="groovy">
+                       <tocitem text="Groovy Feature Counter example" target="groovy.featurecounter"/>
+               </tocitem>
                <tocitem text="Command Line" target="commandline" expand="false">
                        <tocitem text="Command Line Arguments" target="clarguments" />
-                       <tocitem text="Groovy Shell" target="groovy" />
                </tocitem>
                <tocitem text="Privacy" target="privacy" />
        </tocitem>
index c870887..c1b276d 100644 (file)
@@ -43,7 +43,7 @@
     entry from the consensus annotation label to copy the alignment's
     consensus sequence to the clipboard.
   <p>
-    <strong>Sequence logo</strong>
+    <a name="logo"><strong>Sequence logo</strong></a>
   </p>
   By clicking on the label you can also activate the sequence logo. It
   indicates the relative amount of residues per column which can be
   <strong>Normalise Consensus Logo</strong> to scale all columns of the
   logo to the same height.
 
-    <p>
-    <strong>Group Consensus</strong><br>
-    If sequence groups have been defined, then selecting option 'Group Consensus' in the <a href="../menus/alwannotation.html">Annotations menu</a> will 
-    result in Consensus being calculated for each group, as well as the alignment as a whole.
+  <p>
+    <strong>Group Consensus</strong><br> If sequence groups have
+    been defined, then selecting option 'Group Consensus' in the <a
+      href="../menus/alwannotation.html">Annotations menu</a> will
+    result in Consensus being calculated for each group, as well as the
+    alignment as a whole.
   </p>
   <p>
     <strong>cDNA Consensus</strong>
index 9cb8ce1..4535525 100755 (executable)
@@ -40,8 +40,8 @@
     <b>9</b> No. 6 (745-756)).
   </ul>
   <em><a
-    href="http://www.compbio.dundee.ac.uk/papers/amas/amas3d.html"
-  >View an HTML version of the paper</a></em>
+    href="http://www.compbio.dundee.ac.uk/papers/amas/amas3d.html">View
+      an HTML version of the paper</a></em>
   </p>
   <p>
     Conservation is measured as a numerical index reflecting the
     <strong>Colouring an alignment by conservation</strong><br>
     Conservation scores can be used to colour an alignment. This is
     explained further in the help page for <a
-      href="../colourSchemes/conservation.html"
-    >conservation colouring</a>.
+      href="../colourSchemes/conservation.html">conservation
+      colouring</a>.
   </p>
   <p>
-    <strong>Group conservation</strong><br>
-    If sequence groups have been defined, then selecting option 'Group Conservation' in the <a href="../menus/alwannotation.html">Annotations menu</a> will 
-    result in Conservation being calculated for each group, as well as the alignment as a whole.
+    <strong>Group conservation</strong><br> If sequence groups have
+    been defined, then selecting option 'Group Conservation' in the <a
+      href="../menus/alwannotation.html">Annotations menu</a> will
+    result in Conservation being calculated for each group, as well as
+    the alignment as a whole.
   </p>
 </body>
 </html>
index 071a2b5..c38d9ac 100755 (executable)
     pair of sequences - computed with one of the available score
     matrices, such as <a href="scorematrices.html#blosum62">BLOSUM62</a>,
     <a href="scorematrices.html#pam250">PAM250</a>, or the <a
-      href="scorematrices.html#simplenucleotide"
-    >simple single nucleotide substitution matrix</a>. The options
-    available for calculation are given in the <strong><em>Change
+      href="scorematrices.html#simplenucleotide">simple single
+      nucleotide substitution matrix</a>. The options available for
+    calculation are given in the <strong><em>Change
         Parameters</em></strong> menu.
   </p>
   <p>
-    <em>PCA Calculation modes</em><br /> The default Jalview calculation
-    mode (indicated when <em><strong>Jalview PCA
-        Calculation</strong></em> is ticked in the <strong><em>Change
+    <em>PCA Calculation modes</em><br /> The default Jalview
+    calculation mode (indicated when <em><strong>Jalview
+        PCA Calculation</strong></em> is ticked in the <strong><em>Change
         Parameters</em></strong> menu) is to perform a PCA on a matrix where elements
     in the upper diagonal give the sum of scores for mutating in one
     direction, and the lower diagonal is the sum of scores for mutating
     gives an asymmetric matrix, and a different PCA to a matrix produced
     with the method described in the paper by G. Casari, C. Sander and
     A. Valencia. Structural Biology volume 2, no. 2, February 1995 (<a
-      href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=7749921"
-    >pubmed</a>) and implemented at the SeqSpace server at the EBI. This
-    method preconditions the matrix by multiplying it with its
-    transpose, and can be employed in the PCA viewer by unchecking the <strong><em>Jalview
+      href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=pubmed&dopt=Abstract&list_uids=7749921">pubmed</a>)
+    and implemented at the SeqSpace server at the EBI. This method
+    preconditions the matrix by multiplying it with its transpose, and
+    can be employed in the PCA viewer by unchecking the <strong><em>Jalview
         PCA Calculation</em></strong> option in the <strong><em>Change
         Parameters</em></strong> menu.
   </p>
index 94cbc65..5b1badb 100755 (executable)
     menu or pressing <strong>'CONTROL+D'</strong> brings up a dialog box
     asking you to select a threshold. If the percentage identity between
     the aligned positions of any two sequences in the visible alignment
-    exceeds this value, the shorter sequence is discarded.<br>
-    <em>Note:</em> The redundancy calculation is done when the dialog
-    box is opened. For large numbers of sequences this can take a long
-    time as all pairs have to be compared.
+    exceeds this value, the shorter sequence is discarded.<br> <em>Note:</em>
+    The redundancy calculation is done when the dialog box is opened.
+    For large numbers of sequences this can take a long time as all
+    pairs have to be compared.
   </p>
 </body>
 </html>
index 03d24a5..a79541b 100644 (file)
   <p>
     <strong>Reference Sequence Alignment Views</strong>
   </p>
+  <p>Many alignment analysis tasks concern a query, or reference
+    sequence. For instance, when searching for sequences from other
+    organisms that are similar to a newly sequenced gene, or when
+    searching for structurally similar sequences for use in homology
+    modelling.</p>
   <p>
-    The reference sequence for an alignment is indicated by its ID being
-    shown in bold. When a reference sequence has been defined, the <strong>Format&#8594;Show
-      unconserved</strong> option highlights mutations with respect to the
-    reference sequence, rather than the alignment's consensus sequence.
+    <strong>What happens when a reference sequence is defined ?</strong>
   </p>
+  <p>The reference sequence for an alignment is indicated by its ID
+    being shown in bold. In addition:</p>
+  <ul>
+    <li><strong>Reference sequence numbering</strong>. Instead of
+      column numbers, the alignment ruler shows the reference sequence
+      positions at each column. At each tick mark, either the reference
+      sequence symbol and position is given, or the column number when a
+      gap is present at that position in the reference sequence.</li>
+    <li><strong>Format&#8594;Show unconserved</strong> highlights
+      mutations with respect to the reference sequence, rather than the
+      alignment's consensus sequence.</li>
+  </ul>
   <p>
+    <strong>Defining the reference sequence</strong>
+  </p>
+  <p>Each alignment view can have its own reference sequence.</p>
   <ul>
-    <li>Jalview automatically assigns a reference sequence when <a
-      href="../webServices/jnet.html"
-    >JPred4</a> predictions are imported.
-    </li>
-    <li><strong>Assigning a reference sequence</strong><br /> A
-      sequence can be marked as the reference sequence by right-clicking
-      on it's ID to open the popup menu, and selecting the "<strong>(Sequence
-        ID)&#8594;Mark as Reference</strong>" entry."</li>
+    <li><strong>Manually assigning a reference sequence</strong><br />
+      A sequence can be marked as the reference sequence by
+      right-clicking on its ID to open the popup menu, and selecting the
+      "<strong>(Sequence ID)&#8594;Mark as Reference</strong>" entry.</li>
+    <li><strong>Defining a reference when importing
+        annotation</strong><br />Jalview automatically assigns a reference
+      sequence when importing analysis results, such as those returned
+      from <a href="../webServices/jnet.html">JPred4</a> . A reference
+      sequence can also be assigned via the <a
+      href="../features/annotationsFormat.html#refsandviews">SET_REF</a>
+      command in an alignment annotation file.</li>
   </ul>
   <p>
     <em>Reference sequence based alignment visualisation was
-      introduced in Jalview 2.9.</em>
+      introduced in Jalview 2.9, and support for storage and retrieval
+      of reference sequence views in 2.10.</em>
   </p>
 </html>
index f6bffb0..5fbbc19 100644 (file)
@@ -33,7 +33,8 @@
       matrix, and (since 2.8.1) is available for Tree and PCA
       calculations.</li>
     <li><a href="#simplenucleotide">Simple Nucleotide
-        Substitution</a> is a (fairly) arbitrary DNA/RNA substitution matrix.</li>
+        Substitution</a> is a (fairly) arbitrary DNA/RNA substitution
+      matrix.</li>
     <!--  <li><a href="#conservation">Conservation Matrices</a> A range of matrices for distinguishing amino-acids by physicochemical property conservation.
 </li> -->
   </ul>
     <strong><a name="pam250">PAM250</a></strong><br /> <em><strong>P</strong>ercentage
       <strong>A</strong>ccepted <strong>M</strong>utation matrix. PAM250
       estimates substitutions after 250% of sites have changed (each
-      site can be mutated multple times).<br /> Jalview 2.8.1 introduced
-      support for PAM250 based <a href="../calculations/pca.html">PCA</a>
-      and <a href="../calculations/tree.html">tree</a> calculations.</em>
+      site can be mutated multple times).<br /> Jalview 2.8.1
+      introduced support for PAM250 based <a
+      href="../calculations/pca.html">PCA</a> and <a
+      href="../calculations/tree.html">tree</a> calculations.</em>
   <table border="1">
     <tr>
       <td></td>
   </table>
   <strong><em>This nucleotide matrix was introduced in
       Jalview 2.8. If you'd like to improve it - please take a look at <a
-      href="http://issues.jalview.org/browse/JAL-1027"
-    >Issue JAL-1027 - introduce a nucleotide substitution matrix that
+      href="http://issues.jalview.org/browse/JAL-1027">Issue
+        JAL-1027 - introduce a nucleotide substitution matrix that
         supports RNA/DNA and ambiguity codes</a>
   </em></strong>
   </p>
index 8c017a9..aeb461a 100755 (executable)
       </p>
       <p>
         This menu appears if the alignment contains any <a
-          href="../features/annotationsFormat.html"
-        >sequence associated alignment annotation</a> with associated
-        score values. Each entry is the label for a distinct group of
-        sequence associated annotation scores which can be used for
-        sorting.
+          href="../features/annotationsFormat.html">sequence
+          associated alignment annotation</a> with associated score values.
+        Each entry is the label for a distinct group of sequence
+        associated annotation scores which can be used for sorting.
       </p>
   </ul>
   <p>
+    <strong>Sorting according to sequence features</strong><br />
+    Additional sort operations for alignments containing sequence
+    features are provided in the <strong><a
+      href="../features/featuresettings.html#sortbyfeature">Feature
+        Settings</a></strong> dialog, opened via <strong>View&#8594;Feature
+      Settings...</strong>
+  <p>
     <strong>Reversing the Order</strong>
   </p>
   <p>Selecting any item from the Sort menu will sort sequences in an
     ascending order according to the property defining the sort. If the
     same sort is re-applied, the sequences will be sorted in the inverse
-    order. In the case of trees and alignment orderings, Jalview will
-    remember your last choice for sorting the alignment and only apply
-    the inverse ordering if you select the same tree or alignment
-    ordering item again.</p>
+    order. In both cases, for sequences which are equivalent under the
+    sort operation, their order will be preserved (since version 2.10).
+    In the case of trees and alignment orderings, Jalview will remember
+    your last choice for sorting the alignment and only apply the
+    inverse ordering if you select the same tree or alignment ordering
+    item again.</p>
 
 </body>
 </html>
index 7325439..fd47dc0 100755 (executable)
     <strong>Alignment RNA Structure Consensus Annotation</strong>
   </p>
 
+  <p>The RNA structure consensus displayed below the alignment gives
+    the percentage of valid base pairs per column for the first
+    secondary structure annotation shown on the annotation panel. These
+    values are shown as a histogram labeled &quot;StrucConsensus&quot;,
+    where a symbol below each bar indicates whether the majority of base
+    pairs are:
+  <ul>
+    <li>'(' - Watson-Crick (C:G, A:U/T)</li>
+    <li>'[' - Non-canonical (a.ka. wobble) (G:U/T)</li>
+    <li>'{' - Invalid (a.k.a. tertiary) (the rest)</li>
+  </ul>
+  <p>Mousing over the column gives the fraction of pairs classified
+    as Watson-Crick, Canonical or Invalid.</p>
+
   <p>
-    The RNA structure consensus displayed below the alignment is the
-    percentage of valid base pairs per column. It is calculated in
-    relation to a secondary structure and just paired columns are
-    calculated. The canonical Watson-Crick base pairings (A-T/U, G-C)
-    and the wobble base pair (G-T/U) are regarded as valid pairings.<br>
-    The amount of valid base pairs is indicated by the profile in the
-    Alignment Annotation row.<br> By default this calculation
-    includes gaps in columns. You can choose to ignore gaps in the
-    calculation by right clicking on the label &quot;StrConsensus&quot;
-    to the left of the structure consensus bar chart.<br>
+    By default this calculation includes gaps in columns. You can choose
+    to ignore gaps in the calculation by right clicking on the label
+    &quot;StrucConsensus&quot; to the left of the structure consensus
+    bar chart.<br>
   <p>
-    <strong>Structure logo</strong>
-  </p>
-  By clicking on the label you can also activate the structure logo. It
-  is very similar to a sequence logo but counts the numbers of base
-  pairs. There are two residues per column, the actual column and the
-  interacting base. The opening bracket is always the one on the left
-  side.
-  <br> Like sequence logos the relative amount of a specific base
-  pair can be estimated by its size in the logo. The tool tip of a
-  column gives the exact numbers for all occurring valid base pairs.
+    <strong>RNA Structure logo</strong><br /> Right-clicking on the
+    label allows you to enable the structure logo. It is very similar to
+    a sequence logo but instead shows the distribution of base pairs.
+    There are two residues per column, the actual column and the
+    interacting base. The opening bracket is always the one on the left
+    side. <br> Like <a href="consensus.html#logo">sequence
+      logos</a>, the relative amount of a specific base pair can be
+    estimated by its size in the logo, and this can be made more obvious
+    by <em>normalising</em> the logo (enabled via the popup menu). When
+    the logo is displayed, the tool tip for a column gives the exact
+    percentages for all base pairs at that position.
   </p>
 </body>
 </html>
index 7a8271e..59736ca 100755 (executable)
     Trees are calculated on either the complete alignment, or just the
     currently selected group of sequences, using the functions in the <strong>Calculate&#8594;Calculate
       tree</strong> submenu. Once calculated, trees are displayed in a new <a
-      href="../calculations/treeviewer.html"
-    >tree viewing window</a>. There are four different calculations, using
-    one of two distance measures and constructing the tree from one of
-    two algorithms :
+      href="../calculations/treeviewer.html">tree viewing
+      window</a>. There are four different calculations, using one of two
+    distance measures and constructing the tree from one of two
+    algorithms :
   </p>
   <p>
     <strong>Distance Measures</strong>
@@ -56,8 +56,8 @@
       scores for the residue pairs at each aligned position.
       <ul>
         <li>For details about each model, see the <a
-          href="scorematrices.html"
-        >list of built-in score matrices</a>.
+          href="scorematrices.html">list of built-in score
+            matrices</a>.
         </li>
       </ul></li>
     <li><strong>Sequence Feature Similarity</strong><br>Trees
   </ul>
   <p>
     A newly calculated tree will be displayed in a new <a
-      href="../calculations/treeviewer.html"
-    >tree viewing window</a>. In addition, a new entry with the same tree
-    viewer window name will be added in the Sort menu so that the
-    alignment can be reordered to reflect the ordering of the leafs of
-    the tree. If the tree was calculated on a selected region of the
-    alignment, then the title of the tree view will reflect this.
+      href="../calculations/treeviewer.html">tree viewing
+      window</a>. In addition, a new entry with the same tree viewer window
+    name will be added in the Sort menu so that the alignment can be
+    reordered to reflect the ordering of the leafs of the tree. If the
+    tree was calculated on a selected region of the alignment, then the
+    title of the tree view will reflect this.
   </p>
 
   <p>
     phylogenetic trees, which can cope with large numbers of sequences,
     use better distance methods and can perform bootstrapping. Jalview
     can read <a
-      href="http://evolution.genetics.washington.edu/phylip/newick_doc.html"
-    >Newick</a> format tree files using the 'Load Associated Tree' entry
-    of the alignment's File menu. Sequences in the alignment will be
+      href="http://evolution.genetics.washington.edu/phylip/newick_doc.html">Newick</a>
+    format tree files using the 'Load Associated Tree' entry of the
+    alignment's File menu. Sequences in the alignment will be
     automatically associated to nodes in the tree, by matching Sequence
     IDs to the tree's leaf names.
   </p>
index b45f8fe..3d6245e 100755 (executable)
   </p>
   <p>
     The tree viewing window is opened when a tree has been <a
-      href="tree.html"
-    >calculated from an alignment</a>, or imported via a file or web
-    service. It includes <a href="#menus">menus</a> for controlling
-    layout and file and figure creation, and enables various selection
-    and colouring operations on the associated sequences in the
-    alignment.
+      href="tree.html">calculated from an alignment</a>, or
+    imported via a file or web service. It includes <a href="#menus">menus</a>
+    for controlling layout and file and figure creation, and enables
+    various selection and colouring operations on the associated
+    sequences in the alignment.
   </p>
   <p>
     <strong><em>Selecting Sequence Leaf Nodes</em></strong><br>
     tree is rendered and labeled:
   <ul>
     <li><strong>Fit to Window</strong>
-    <p>The tree layout will be scaled to fit in the display window.
-        You may need to reduce the font size to minimise the leaf label
-        overlap when this option is selected.</p></li>
+      <p>The tree layout will be scaled to fit in the display
+        window. You may need to reduce the font size to minimise the
+        leaf label overlap when this option is selected.</p></li>
     <li><strong>Font Size ...</strong><em>n</em>
-    <p>
+      <p>
         Brings up a dialog box to set the font size for the leaf names.
         <em>n</em> is the current font size.
       </p></li>
     <li><strong>Show Distances</strong>
-    <p>Labels each branch or leaf with its associated branch length.</p></li>
+      <p>Labels each branch or leaf with its associated branch
+        length.</p></li>
     <li><strong>Show Bootstrap values</strong>
-    <p>Labels each branch or leaf with its associated bootstrap
+      <p>Labels each branch or leaf with its associated bootstrap
         value.</p></li>
     <li><strong>Mark unlinked leaves</strong>
-    <p>Toggles the display of a '*' at the beginning of a leaf label
-        to indicate that there is no sequence corresponding to that leaf
-        in the associated alignment.</p></li>
+      <p>Toggles the display of a '*' at the beginning of a leaf
+        label to indicate that there is no sequence corresponding to
+        that leaf in the associated alignment.</p></li>
     <li><strong>Sort Alignment By Tree</strong>
       <p>
         Sorts any associated alignment views using the current tree. (<em>Only
     <li><strong>Associate Leaves with ...</strong>
       <p>
         Only visible when there are <a
-          href="../features/multipleviews.html"
-        >multiple views</a> of the same alignment to show and edit which
-        alignment views are associated with the leaves of the displayed
-        tree.
+          href="../features/multipleViews.html">multiple
+          views</a> of the same alignment to show and edit which alignment
+        views are associated with the leaves of the displayed tree.
       </p>
   </ul>
   </p>
index 614764b..8adacc9 100755 (executable)
@@ -35,10 +35,10 @@ td {
     <strong>Colouring above a percentage identity threshold</strong>
   </p>
   <p>Selecting this option causes the colour scheme to be applied to
-    only those residues that occur in that column more than a certain
-    percentage of the time. For instance selecting the threshold to be
-    100 will only colour those columns with 100 % identity. This
-    threshold option can be applied to the Zappo, Taylor, Hydrophobicity
-    and User colour schemes.</p>
+    only those residues that occur in that column at least a certain
+    percentage of the time. For instance, selecting the threshold to be
+    100 will only colour those columns with 100% identity, and selecting 50 will shade residues appearing in least 50% of the rows (or sequences) in each column.</p>
+   <p>The percentage calculation may include or exclude gaps in the column, depending on the option selected for the <a href="../calculations/consensus.html">consensus calculation</a>.</p>
+   <p>With a threshold of 0, colouring is unchanged.</p>
 </body>
 </html>
index 30b6396..2272503 100755 (executable)
   </div>
   <ul>
     <li>Select which annotation to base the colouring scheme on
-      using the top left selection box.<br />If the <strong>Per-sequence
-        only</strong> tick box is not greyed out, then ticking it will limit the
-      available annotation rows to just those that are sequence
-      associated (e.g. T-COFFEE scores and <a
-      href="../webServices/proteinDisorder.html"
-    >protein disorder predictions</a>), which will colour each sequence
-      according to its own per-residue scores.<br /> <em>Per-sequence
-        associated annotation colouring was introduced in Jalview 2.8</em>
+      using the top left selection box. Sequence associated alignment
+      annotation are shown with the seuqence's name appended.<br />If
+      the <strong>Per-sequence only</strong> tick box is not greyed out,
+      then ticking it will limit the list of available annotation rows
+      to just the labels for those that are sequence associated.
+      Annotation rows on each sequence with the same label (e.g.
+      T-COFFEE scores and <a href="../webServices/proteinDisorder.html">protein
+        disorder predictions</a>) will then be used to colour its
+      corresponding positions in the alignment.<br /> <em>Per-sequence
+        associated annotation colouring is currently only available in
+        the Desktop.</em>
     </li>
     <li>If the &quot;Use Original Colours&quot; box is selected,
       the colouring scheme will use the colouring scheme present on the
@@ -74,9 +77,9 @@
         <li>Press the &quot;Defaults&quot; button to reset the
           minimum and maximum colours to their default settings (these
           are configured in the applet's parameters or the <a
-          href="../features/preferences.html"
-        >application's user preferences</a>.).<br /> <em>Default min
-            and max colours were introduced in Jalview 2.7</em>
+          href="../features/preferences.html">application's
+            user preferences</a>.).<br /> <em>Default min and max
+            colours were introduced in Jalview 2.7</em>
       </ul>
     </li>
 
index 19d276e..88ef6ba 100755 (executable)
@@ -33,9 +33,9 @@
     alignment analysis (Livingstone C.D. and Barton G.J. (1993), Protein
     Sequence Alignments: A Strategy for the Hierarchical Analysis of
     Residue Conservation.CABIOS Vol. 9 No. 6 (745-756)). See the <a
-      href="../calculations/conservation.html"
-    >conservation calculation</a> help page for a more thorough
-    explanation of the calculation.
+      href="../calculations/conservation.html">conservation
+      calculation</a> help page for a more thorough explanation of the
+    calculation.
   </p>
   <p>For an already coloured alignment, the conservation index at
     each alignment position is used to modify the shading intensity of
   <p>
     Conservation can be calculated over all sequences in an alignment,
     or just within specific groups (such as those defined by <a
-      href="../calculations/tree.html"
-    >phylogenetic tree partitioning</a>). The option 'apply to all groups'
-    controls whether the contrast slider value will be applied to the
-    indices for the currently selected group, or all groups defined over
-    the alignment.
+      href="../calculations/tree.html">phylogenetic tree
+      partitioning</a>). The option 'apply to all groups' controls whether
+    the contrast slider value will be applied to the indices for the
+    currently selected group, or all groups defined over the alignment.
   </p>
 </body>
 </html>
index 3f01bdf..7664101 100755 (executable)
@@ -49,8 +49,7 @@ td {
     the background colour.</p>
   <p>
     The <strong>&quot;Colour&#8594;<a
-      href="../colourSchemes/textcolour.html"
-    >Colour Text...</a>&quot;
+      href="../colourSchemes/textcolour.html">Colour Text...</a>&quot;
     </strong> entry opens a dialog box to set a different text colour for light
     and dark background, and the intensity threshold for transition
     between them.
index a7d0898..9b9d41a 100644 (file)
     on its helices. The helices are determined from the secondary
     structure line in the Stockholm file (#GC SS_cons) written in WUSS
     notation that specifies base pairing. See <a
-      href="http://en.wikipedia.org/wiki/Stockholm_format"
-    > Wikipedia</a> or <a
-      href="http://jalview-rnasupport.blogspot.com/2010/06/parsing-wuss-notation-of-rna-secondary.html"
-    > Jalview RNA Support Blog</a> for more information about Stockholm
+      href="http://en.wikipedia.org/wiki/Stockholm_format">
+      Wikipedia</a> or <a
+      href="http://jalview-rnasupport.blogspot.com/2010/06/parsing-wuss-notation-of-rna-secondary.html">
+      Jalview RNA Support Blog</a> for more information about Stockholm
     files and WUSS notation.
   </p>
   Select &quot;Colour&quot;
index 5d83d00..fd8c5a3 100755 (executable)
     clicking the left mouse button and pressing a combination of either
     shift and control (or the alt, option or apple key on Macs) and
     dragging the mouse. Pressing <em>F2</em> toggles the alternative <a
-      href="../features/cursorMode.html"
-    >'Cursor mode'</a> keyboard editing facility, where the space bar and
-    delete keys add and remove gaps at the current editing position. The
-    key strokes for both these modes are summarised in the <a
-      href="../keys.html"
-    >keystrokes table</a>.
+      href="../features/cursorMode.html">'Cursor mode'</a> keyboard
+    editing facility, where the space bar and delete keys add and remove
+    gaps at the current editing position. The key strokes for both these
+    modes are summarised in the <a href="../keys.html">keystrokes
+      table</a>.
   </p>
   <p>
     <strong>Tip:</strong> For large alignments, deselect &quot;Calculate
@@ -50,9 +49,8 @@
     right to insert gaps and remove gaps.<br> If the current
     selection is a group over all sequences in the alignment, or a group
     over some sequences or all columns in the alignment, then hold down
-    either &quot;Control&quot; key (or the &quot;Alt;&quot; on OSX if
-    &quot;Control&quot; does not work) and drag the residue left or
-    right to edit all sequences in the defined group at once.
+    &quot;Control&quot; key (&quot;Cmd&quot; key on OSX) and drag the residue 
+    left or right to edit all sequences in the defined group at once.
   </p>
   <p>
     <em>Copy/paste/cut/delete</em> - any sequences which are in the
index 7e52c46..b63d20b 100755 (executable)
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
-<head><title>Alignment Annotation</title></head>
+<head>
+<title>Alignment Annotation</title>
+</head>
 <body>
-<p><strong>Alignment Annotation</strong></p>
+  <p>
+    <strong>Alignment Annotation</strong>
+  </p>
 
-<p>In addition to the definition of groups and sequence features,
-  Jalview can display symbols and graphs under the columns of an
-  alignment, and allow you to mark particular columns of an alignment and add symbols and text 
-  in the annotation area shown below the alignment (which may be hidden if <strong>View&#8594;Show 
-  Annotation</strong> is not ticked). Any displayed annotation row can be hidden (using the pop-up 
-  menu obtained by right-clicking the label), or re-ordered by dragging the label to a new 
-  position with the left mouse button.</p>
-<p>
-Web services can also add annotation to an alignment (see the <a
-href="../webServices/jnet.html">JNet</a> and <a
-href="../webServices/proteinDisorder.html">Disorder</a> protein
-structure prediction services), and as of Jalview 2.08 quantitative
-and symbolic annotations can be added to an alignment via an <a
-href="annotationsFormat.html">Annotations File</a> dragged into the
-alignment window or loaded from the alignment's file menu.
-</p>
-<p><a name="seqannots"/><strong>Sequence Reference Annotation</strong>
-</p>
-<p>
-               Sequence reference annotation is created from 3D structure
-               data, and from the results of sequence based prediction of
-               <a href="../webServices/jnet.html">secondary structure</a> and <a
-                       href="../webServices/proteinDisorder.html">disordered region</a>
-               prediction methods. 
-</p>
-<p><strong>Sequence Group Annotation</strong>
-</p>
-<p>
-       If sequence groups are defined, <a href="../calculations/conservation.html">Conservation</a>
-        and <a href="../calculations/consensus.html">Consensus</a> annotation can be enabled
-       for each group from the <a href="../menus/alwannotation.html">Annotations menu</a>, or can
-       be imported from a Jalview <a href="annotationsFormat.html">Annotations file</a>.
-</p>
-<p><strong>Sequence Selection from Annotation</strong>
-</p>
-<p>
-    Sequences associated with sequence (or sequence group) annotations can be selected by
-    double-clicking the annotation label with these key combinations:
-    <ul>
-    <li>double-click - Select associated sequences (replaces current selection)</li>
-    <li>shift double-click - add  sequences to selection</li>
-    <li>Ctrl (Mac CMD) double-click - toggles inclusion of associated sequences in the current selection</li>
-    </ul>
-    Note this also works in combination with manual sequence selection in the alignment.
-<p><strong>Interactive Alignment Annotation</strong></p>
-<p>
-Annotation rows are added using the <strong>Annotation Label</strong>
-menu, which is obtained by clicking anywhere on the annotation row labels
-area (below the sequence ID area).
-</p>
-<ul>
-  <li><strong>Add New Row</strong><br>
-    <em>Adds a new, named annotation row (a dialog box will pop up for you to 
-    enter the label for the new row). </em> </li>
-  <li><strong>Edit Label/Description</strong><br>
-    <em>This opens a dialog where you can change the name (displayed label), or the description
-    (as shown on the label tooltip) of the clicked annotation. </em> </li>
-  <li><strong>Hide This Row</strong><br>
-    <em>Hides the annotation row whose label was clicked in order to bring up 
-    the menu.</em> </li>
-  <li><strong>Hide All <em>&lt;label&gt;</em></strong><br>
-    <em>Hides all annotation rows whose label matches the one clicked. 
-    (This option is only shown for annotations that relate to individual sequences, 
-    not for whole alignment annotations. Since Jalview 2.8.2.)</em> </li>
-  <li><strong>Delete This Row</strong><br>
-    <em>Deletes the annotation row whose label was clicked in order to bring up 
-    the menu.</em> </li>
-  <li><strong>Show All Hidden Rows</strong><br>
-    <em>Shows all hidden annotation rows.</em> </li>
-          <li><strong>Export Annotation</strong> <em>(Application only)</em><br>
-       <em>Annotations can be saved to file or output to a text window in either the 
-        Jalview annotations format or as a spreadsheet style set of comma separated values (CSV). </em> </li>
-      <li><strong>Show Values in Text Box</strong> <em>(applet only)</em><br>
-        <em>Opens a text box with a list of comma-separated values corresponding 
-        to the annotation (numerical or otherwise) at each position in the row. 
-        This is useful to export alignment quality measurements for further analysis.</em> 
-      </li>
-      <li><strong>Scale Label To Column</strong><em>(introduced in 2.5)</em><br>
-      <em>Selecting this toggles whether column labels will be shrunk to fit within each column, or displayed using the view's standard font size.</em></li>
-</ul>
-<p>
-<strong>Editing Label and secondary structure Annotation</strong></p>
-<p>
-Use the <strong>left mouse button</strong> to select a position along the row that are to
-be annotated - these regions will be coloured red. <strong>Control</strong> and <strong>shift</strong> in combination
-with the left-click will select more than one position, or a range of
-positions on the alignment.
-</p>
-<p>Once the desired position has been selected, use the <strong>right mouse
-button</strong> to open the <strong>annotation menu</strong>:</p>
-<ul>
-<li>Helix<br><em>Mark selected positions with a helix glyph (a red
-oval), and optional text label (see below). A
-dialog box will open for you to enter the text. Consecutive ovals
-will be rendered as an unbroken red line.</em>
-</li>
-<li>Sheet<br><em>Mark selected positions with a sheet glyph (a green
-arrow oriented from left to right), and optional text label (see
-below). A dialog box will open for you to enter the text. Consecutive
-arrows will be joined together to form a single green arrow.</em>
-</li>
-<li><a name="rna">RNA Helix</a> (only shown when working with nucleotide sequences)<br>
-<em>Mark selected positions as participating in a base pair
-either upstream or downstream. When the dialog box opens, enter a
-'(' to indicate these bases pair with columns upstream (to right),
-and ')' to indicate this region pairs with bases to the left of the
-highlighted columns.<br />If any brackets do not match up, then an
-orange square will highlight the first position where a bracket was
-found not to match.
-</em>
-</li>
-<li>Label<br><em>Set the text label at the selected positions. A
-dialog box will open for you to enter the text.  If
-more than one consecutive position is marked with the same label, only
-the first position's label will be rendered.</em>
-</li>
-<li>Colour<br><em>Changes the colour of the annotation text label.</em>
-</li>
-<li>Remove Annotation<br><em>Blanks any annotation at the selected positions on
-the row. Note: <strong>This cannot be undone</strong></em>
-</li>
-</ul>
-<p>
-User defined annotation is stored and retrieved using <a
-href="../features/jalarchive.html">Jalview Archives</a>.
-</p>
-<p><em>Current Limitations</em></p>
-<p>As of version 2.5, the Jalview user interface does not support the 
-creation and editing of quantitative annotation (histograms and line graphs), or 
-to create annotation associated with a specific sequence. It is also incapable of
-annotation grouping or changing the style of existing annotation (to change between line or bar charts, or to make multiple line graphs). These annotation capabilities are only possible by the import of an 
-<a href="annotationsFormat.html">Annotation file</a>.<br>
-</p>
+  <p>
+    In addition to the definition of groups and sequence features,
+    Jalview can display symbols and graphs under the columns of an
+    alignment. These annotation tracks are displayed in the annotation
+    area below the alignment. The annotation area's visibility is
+    controlled with the <strong>View&#8594;Show Annotation</strong>
+    option.
+  </p>
+  <p>
+    <strong>Types of annotation</strong>
+  <ul>
+    <li><a name="seqannots"><strong>Sequence
+          associated annotation.</strong></a><br />Data displayed on sequence
+      annotation rows are associated with the positions of a sequence.
+      Often this is 'Reference annotation' such as secondary structure
+      information derived from 3D structure data, or from the results of
+      sequence based prediction of <a href="../webServices/jnet.html">secondary
+        structure</a> and <a href="../webServices/proteinDisorder.html">disorder</a>.
+      If reference annotation is available for a the currently selected
+      sequences, it can be shown by selecting the <strong>Add
+        Reference Annotation</strong> option in the sequence or selection popup
+      menu.</li>
+    <li><strong>Group associated annotation.</strong><br />Data can
+      be associated with groups defined on the alignment. If sequence
+      groups are defined, <a href="../calculations/conservation.html">Conservation</a>
+      and <a href="../calculations/consensus.html">Consensus</a>
+      annotation can be enabled for each group from the <a
+      href="../menus/alwannotation.html">Annotations menu</a>, or can be
+      imported from a Jalview <a href="annotationsFormat.html">Annotations
+        file</a>.</li>
+    <li><strong>Alignment associated annotation.</strong><br />Annotation
+      rows associated with columns on the alignment are simply
+      'alignment annotation'. Controls allow you to <a href="#iaannot">interactively
+        create alignment annotation</a> to add labels and symbols to
+      alignment columns. Jalview's consensus, conservation and quality
+      calculations also create histogram and sequence logo annotations
+      on the alignment.</li>
+  </ul>
+  <p>
+    <strong>Importing and exporting annotation</strong><br />
+    Annotations on an alignment view are saved in Jalview project files.
+    You can also load <a href="annotationsFormat.html">Annotations
+      Files</a> in order to add any kind of quantitative and symbolic
+    annotations to an alignment. To see an example, use the <strong>Export
+      Features/Annotation</strong> option from an alignment window's File menu.
+  </p>
+  <p>
+    <strong>Layout and display controls</strong><br /> Individual and
+    groups of annotation rows can be shown or hidden using the pop-up
+    menu obtained by right-clicking the label. You can also reorder them
+    by dragging the label to a new position with the left mouse button.
+    The <strong>Annotations</strong> menu provides settings controlling
+    the ordering and display of sequence, group and alignment associated
+    annotation. The <strong>Colour by annotation</strong> option in the
+    colour menu allows annotation to be used to <a
+      href="../colourSchemes/annotationColouring.html">shade the
+      alignment</a>. Annotations can also be used to <a
+      href="../features/columnFilterByAnnotation.html">select or
+      hide columns</a> via the dialog opened from the <strong>Selection</strong>
+    menu.
+  </p>
+  <p>
+    <strong>Sequence Highlighting and Selection from Annotation</strong>
+  </p>
+  <p>
+    A <strong>single click</strong> on the label of an annotation row
+    associated with sequences and sequence groups will cause the
+    associated sequences to be highlighted in the alignment view. <strong>Double
+      clicking</strong> the label will select the associated sequences, replacing
+    any existing selection. Like with other kinds of selection, <strong>shift
+      double-click</strong> will add associated sequences, and <strong>Ctrl
+      (Mac CMD) double-click</strong> will toggle inclusion of associated
+    sequences in the selection.
+  <p>
+    <strong>Interactive Alignment Annotation</strong>
+  </p>
+  <p>
+    <a name="iaannot"> Annotation rows</a> are added using the <strong>Annotation
+      Label</strong> menu, which is obtained by clicking anywhere on the
+    annotation row labels area (below the sequence ID area).
+  </p>
+  <ul>
+    <li><strong>Add New Row</strong><br> <em>Adds a new,
+        named annotation row (a dialog box will pop up for you to enter
+        the label for the new row). </em></li>
+    <li><strong>Edit Label/Description</strong><br> <em>This
+        opens a dialog where you can change the name (displayed label),
+        or the description (as shown on the label tooltip) of the
+        clicked annotation. </em></li>
+    <li><strong>Hide This Row</strong><br> <em>Hides the
+        annotation row whose label was clicked in order to bring up the
+        menu.</em></li>
+    <li><strong>Hide All <em>&lt;label&gt;</em></strong><br> <em>Hides
+        all annotation rows whose label matches the one clicked. (This
+        option is only shown for annotations that relate to individual
+        sequences, not for whole alignment annotations. Since Jalview
+        2.8.2.)</em></li>
+    <li><strong>Delete This Row</strong><br> <em>Deletes
+        the annotation row whose label was clicked in order to bring up
+        the menu.</em></li>
+    <li><strong>Show All Hidden Rows</strong><br> <em>Shows
+        all hidden annotation rows.</em></li>
+    <li><strong>Export Annotation</strong> <em>(Application
+        only)</em><br> <em>Annotations can be saved to file or
+        output to a text window in either the Jalview annotations format
+        or as a spreadsheet style set of comma separated values (CSV). </em>
+    </li>
+    <li><strong>Show Values in Text Box</strong> <em>(applet
+        only)</em><br> <em>Opens a text box with a list of
+        comma-separated values corresponding to the annotation
+        (numerical or otherwise) at each position in the row. This is
+        useful to export alignment quality measurements for further
+        analysis.</em></li>
+    <li><strong>Scale Label To Column</strong><em>(introduced
+        in 2.5)</em><br> <em>Selecting this toggles whether column
+        labels will be shrunk to fit within each column, or displayed
+        using the view's standard font size.</em></li>
+  </ul>
+  <p>
+    <strong>Editing labels and secondary structure annotation
+      rows</strong>
+  </p>
+  <p>
+    Use the <strong>left mouse button</strong> to select a position
+    along the row that are to be annotated - these regions will be
+    coloured red. Press <strong>Control</strong> or <strong>shift</strong>
+    in combination with the left-click to either select an additional
+    position, or a range of positions on the alignment.
+  </p>
+  <p>
+    Once positions have been selected, use the <strong>right
+      mouse button</strong> and select one of the following from the <strong>annotation
+      menu</strong>:
+  </p>
+  <ul>
+    <li>Helix<br> <em>Marks selected positions with a
+        helix glyph (a red oval), and optional text label (see below). A
+        dialog box will open for you to enter the text. Consecutive
+        ovals will be rendered as an unbroken red line.</em>
+    </li>
+    <li>Sheet<br> <em>Marks selected positions with a
+        sheet glyph (a green arrow oriented from left to right), and
+        optional text label (see below). A dialog box will open for you
+        to enter the text. Consecutive arrows will be joined together to
+        form a single green arrow.</em>
+    </li>
+    <li><a name="rna">RNA Helix</a> (only shown when working with
+      nucleotide sequences)<br> <em>Marks selected positions
+        as participating in a base pair either upstream or downstream.
+        When the dialog box opens, enter a '(' to indicate these bases
+        pair with columns upstream (to right), and ')' to indicate this
+        region pairs with bases to the left of the highlighted columns.
+        Other kinds of base-pair annotation are also supported (e.g. 'A'
+        and 'a', or '&lt;' and '&gt;'), and Jalview will suggest an
+        appropriate symbol based on the closest unmatched parenthesis to
+        the left.<br />If any brackets do not match up, then an orange
+        square will highlight the first position where a bracket was
+        found not to match.
+    </em></li>
+    <li>Label<br> <em>Set the text label at the selected
+        positions. A dialog box will open for you to enter the text. If
+        more than one consecutive position is marked with the same
+        label, only the first position's label will be rendered.</em>
+    </li>
+    <li>Colour<br> <em>Changes the colour of the
+        annotation text label.</em>
+    </li>
+    <li>Remove Annotation<br> <em>Blanks any annotation
+        at the selected positions on the row. Note: <strong>This
+          cannot be undone</strong>
+    </em>
+    </li>
+  </ul>
+  <p>
+    User defined annotation is stored and retrieved using <a
+      href="../features/jalarchive.html">Jalview Archives</a>.
+  </p>
+  <p>
+    <em>Current Limitations</em>
+  </p>
+  <p>
+    The Jalview user interface does not support interactive creation and
+    editing of quantitative annotation (histograms and line graphs), or
+    to create annotation associated with a specific sequence or group.
+    It is also incapable of annotation grouping or changing the style of
+    existing annotation (e.g. to change between line or bar charts, or
+    to make multiple line graphs). These annotation capabilities are
+    only possible by the import of an <a href="annotationsFormat.html">Annotation
+      file</a>.<br>
+  </p>
 </body>
 </html>
index 744370b..fcdb908 100755 (executable)
@@ -31,9 +31,8 @@
     Alignment annotations can be imported onto an alignment since
     version 2.08 of Jalview, via an annotations file. It is a simple
     ASCII text file consisting of tab delimited records similar to the <a
-      href="featuresFormat.html"
-    >Sequence Features File</a>, and introduced primarily for use with the
-    Jalview applet.
+      href="featuresFormat.html">Sequence Features File</a>, and
+    introduced primarily for use with the Jalview applet.
   </p>
 
   <p>
@@ -55,8 +54,8 @@
     alignment window.
   </p>
   <p>
-    <strong>THE ANNOTATION FILE FORMAT</strong> <br />An annotation file
-    consists of lines containing an instruction followed by tab
+    <strong>THE ANNOTATION FILE FORMAT</strong> <br />An annotation
+    file consists of lines containing an instruction followed by tab
     delimited fields. Any lines starting with &quot;#&quot; are
     considered comments, and ignored. The sections below describe the
     structure of an annotation file.
   </ul>
   <p>
     At the end of this document, you can also find notes on <a
-      href="#compatibility"
-    >compatibility</a> of annotation files across different versions of
-    Jalview. An <a href="#exampleann">example annotation file</a> is
-    also provided along with instructions on how to import it to
-    Jalview.
+      href="#compatibility">compatibility</a> of annotation files
+    across different versions of Jalview. An <a href="#exampleann">example
+      annotation file</a> is also provided along with instructions on how to
+    import it to Jalview.
   </p>
   <hr />
   <p>
     followed by a <em>description</em> for the row, which is shown in a
     tooltip when the user mouses over the annotation row's label. Since
     Jalview 2.7, the description field may also contain HTML tags (in
-    the same way as a <a href="featuresFormat.html">sequence feature's</a>
-    label), providing the text is enclosed in an &lt;html/&gt; tag.
+    the same way as a <a href="featuresFormat.html">sequence
+      feature's</a> label), providing the text is enclosed in an
+    &lt;html/&gt; tag.
   <ul>
     <em>Please note: URL links embedded in HTML descriptions are
       not yet supported.</em>
     <em>GRAPH_TYPE</em>. The allowed values of <em>GRAPH_TYPE</em> and
     corresponding interpretation of each <em>Value</em> are shown below:
 
+
   
   <ul>
     <li><strong>BAR_GRAPH</strong><br> Plots a histogram with
@@ -190,9 +190,9 @@ GRAPHLINE&#9;<em>graph_name</em>&#9;<em>value</em>&#9;<em>label</em>&#9;<em>colo
   </ul>
   </p>
   <p>
-    <strong><a name="groupdefs">SEQUENCE_GROUP</a></strong><br /> Groups
-    of sequences and column ranges can be defined using a tab delimited
-    statement like:
+    <strong><a name="groupdefs">SEQUENCE_GROUP</a></strong><br />
+    Groups of sequences and column ranges can be defined using a tab
+    delimited statement like:
   </p>
   <pre>SEQUENCE_GROUP&#9;Group_Name&#9;Group_Start&#9;Group_End&#9;<em>Sequences</em>
   </pre>
@@ -296,8 +296,8 @@ GRAPHLINE&#9;<em>graph_name</em>&#9;<em>value</em>&#9;<em>label</em>&#9;<em>colo
       <tr>
         <td width="50%">hide</td>
         <td>Boolean (default false) indicating whether the rows in
-          this group should be marked as hidden.<br />
-        <em>Note:</em> if the group is sequence associated (specified by
+          this group should be marked as hidden.<br /> <em>Note:</em>
+          if the group is sequence associated (specified by
           SEQUENCE_REF), then all members will be hidden and marked as
           represented by the reference sequence.
         </td>
index cb7ccc0..59b4936 100644 (file)
@@ -40,8 +40,7 @@
   </p>
   <p>
     The BioJSON specification is published at <a
-      href="http://jalview.github.io/biojson/"
-    >http://jalview.github.io/biojson/</a>.
+      href="http://jalview.github.io/biojson/">http://jalview.github.io/biojson/</a>.
   </p>
   <p>
     <em>Import of BioJSON data from HTML pages</em>
index 39dff75..5ae00af 100644 (file)
   </p>
   <p>
     Since Jalview 2.8.2, <a href="http://www.cgl.ucsf.edu/chimera/">Chimera</a>
-    (http://www.cgl.ucsf.edu/chimera/) has been integrated into Jalview
-    for interactively viewing structures opened by entries in the <strong>&quot;Structure&quot;</strong>
-    submenu in the <a href="../menus/popupMenu.html">sequence id
-      pop-up menu</a> (if you can't see this, then you need to <a
-      href="viewingpdbs.html"
-    >associate a PDB structure</a> with the sequence). Chimera is
-    available from the Jalview desktop, provided Chimera has been
-    separately installed.
+    (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>.
   </p>
   <p>
     You can set a default choice of Jmol or Chimera structure viewer in
     <a href="preferences.html#structure"> Preferences</a>. You can also
     optionally specify the path to the Chimera program here (if it
-    differs from the standard paths searched by Jalview).
+    differs from the standard paths searched by Jalview).<br /> <strong>Please
+      make sure your version of Chimera is up to date. Jalview requires
+      at least Chimera version 1.11.1</strong>
+  </p>
   <p>
     If you save your Jalview session as a project file, the state of any
     open Chimera windows will also be saved, and can be reopened by
     loading the project file on any machine with Chimera installed. <em>Since
       Jalview 2.9.</em>
-    <!-- <p>The following menu entries are provided for viewing structure data<br>
-  <ul>
-    <li>The <strong>&quot;Structure&#8594;View
-        Structure&#8594;</strong> submenu allows a single PDB structure to be chosen
-      for display from the available structures for a sequence.
-    </li>
-    <li>The <strong>&quot;Structure&#8594;View all <em>N</em>
-        structures
-    </strong> option will open a new window containing all structures associated
-      with the current selection.
-    </li>
-    <li>The <strong>&quot;Structure&#8594;View all <em>N</em>
-        representative structures
-    </strong> option will open a new window containing exactly one structure per
-      currently selected sequence.<br /></li>
-  </ul>
-  <br> 
-</p> -->
   <p>
     <a name="align"><strong>Superposing structures based on
         their aligned sequences</strong></a><br> If several structures are
     number and chain code ([RES]Num:Chain). Moving the mouse over an
     associated residue in an alignment window highlights the associated
     atoms in the displayed structures. When residues are selected in the
-    Chimera window, they are highlighted on the alignment. For
-    comprehensive details of Chimera's commands, refer to the tool's
-    Help menu.
+    Chimera window, they are highlighted on the alignment.
+  <p>For comprehensive details of Chimera's commands, refer to the
+    tool's Help menu.</p>
+  <p>
+    <strong>Selecting residues in Jalview from Chimera</strong><br />
+    When a selection is highlighted in a Jalview window, use the
+    <em>Select&#8594;Select Highlighted Region</em> or press <em>B</em>
+    to add the mapped positions to the alignment window's column
+    selection.<br /> <em>Hint: Use your machine's 'switch
+      application' key combination (Alt-Tab on Windows and Linux,
+      Cmd-Tab on OSX) to quickly switch between UCSF Chimera and Jalview
+      before pressing 'B' to select highlighted regions.</em>
+  </p>
   <p>
     Basic screen operations (see <a
-      href="http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/mouse.html"
-    >Chimera help</a> at
+      href="http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/mouse.html">Chimera
+      help</a> at
     http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/mouse.html
     for full details).
   <table border="1">
         </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
+            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.
             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>.
+            href="../colourSchemes/index.html">amino acid
+              colours</a>.
         </em></li>
       </ul></li>
     <li><strong>Chimera<br>
   </p>
   Jalview and Chimera communicate using Chimera's
   <a
-    href="http://www.cgl.ucsf.edu/chimera/current/docs/ContributedSoftware/restserver/restserver.html"
-  >REST service</a>
+    href="http://www.cgl.ucsf.edu/chimera/current/docs/ContributedSoftware/restserver/restserver.html">REST
+    service</a>
   (http://www.cgl.ucsf.edu/chimera/current/docs/ContributedSoftware/restserver/restserver.html).
   <br> Technically this requires both Chimera and Jalview to open
   ports on the local network, and this may be blocked by Windows
index 1d6f62d..e065494 100644 (file)
@@ -67,8 +67,8 @@
         <div align="center">-annotations FILE/URL</div>
       </td>
       <td>Add precalculated annotations to the alignment. See <a
-        href="annotationsFormat.html" target="NEW"
-      >Annotation File</a> description.
+        href="annotationsFormat.html" target="NEW">Annotation
+          File</a> description.
       </td>
     </tr>
     <tr>
       <td>
         <div align="center">-nonews</div>
       <td>
-        <div align="left">Disable check for <a href="../webServices/newsreader.html">Jalview news</a> on startup (not recommended other than for classroom / demo usage)</div>
+        <div align="left">
+          Disable check for <a href="../webServices/newsreader.html">Jalview
+            news</a> on startup (not recommended other than for classroom /
+          demo usage)
+        </div>
       </td>
     </tr>
     <tr>
       <td><div align="left">Create Scalable Vector Graphics
           file FILE from alignment.</div></td>
     </tr>
+    <tr>
+      <td><div align="center">-biojsMSA FILE</div></td>
+      <td><div align="left">Write an HTML page to display
+          the alignment with the <a href="biojsmsa.html">
+          BioJS MSAviewer MSA</a>
+          </div>
+      </td>
+    </tr>
   </table>
 </body>
 </html>
index 2b7d0ec..b260cee 100644 (file)
@@ -31,8 +31,8 @@
     The 'Select/Hide by Annotation' window allows columns to be selected
     or hidden according to annotation rows on the alignment. The dialog
     box is opened <em>via</em> &quot;<strong>Select&#8594;Select/Hide
-      Columns by Annotation...</strong>&quot;, and different filters are
-    presented dependent upon the data shown in the selected annotation
+      Columns by Annotation...</strong>&quot;, and different filters are then
+    presented for filtering data according to the selected annotation
     row.
   </p>
   <table>
       <td><img src="AnnotationColumnSelectionWithoutSM.gif"></td>
     </tr>
   </table>
-
-  <p>If an annotation with numeric values is selected, the threshold
+  <p>The drop down menu lists the annotation available on the
+    alignment. Sequence associated annotation rows will be shown with
+    the sequence ID appended to the annotation label. It is only
+    possible to select one row at a time.</p>
+  <p>
+    If an annotation with numeric values is selected, the threshold
     filter option is activated. For other types of annotation, use the
     text box and secondary structure check boxes (right). The radio
     buttons at the bottom of the dialog specify the action applied to
-    columns matching the query.</p>
+    columns matching the query.<br /> <em>Note: annotation
+      containing only numeric labels (e.g. T-COFFEE column confidence
+      scores) will not be treated as quantitative data. You will need to
+      enter search expressions to select columns in this case.</em>
+  </p>
   <ul>
     <li><strong>Search Filter</strong>
       <ul>
index 0e1f109..9cffc51 100644 (file)
@@ -56,8 +56,8 @@
   <pre>java -Djava.ext.dirs=$INSTALL_DIR$/lib -cp $INSTALL_DIR$/jalview.jar jalview.bin.Jalview -open [FILE] </pre>
   <p>
     Use '-help' to get more information on the <a
-      href="clarguments.html"
-    >command line arguments</a> that Jalview accepts.
+      href="clarguments.html">command line arguments</a> that
+    Jalview accepts.
   </p>
   <p>&nbsp;</p>
   <p>&nbsp;</p>
index a6a17a5..68a594a 100644 (file)
   <strong>Creating Sequence Features</strong>
   <p>
     Jalview can create sequence features from the matches of a <a
-      href="search.html"
-    >regular expression search</a>, or from the currently selected area
-    via the <strong>&quot;selection&#8594;Create sequence
-      feature&quot;</strong> entry in the <a href="../menus/popupMenu.html">selection
-      area popup menu</a>. In both cases, the <strong>Create
-      Features</strong> dialog box will then be opened:
+      href="search.html">regular expression search</a>, or from the
+    currently selected area via the <strong>&quot;selection&#8594;Create
+      sequence feature&quot;</strong> entry in the <a
+      href="../menus/popupMenu.html">selection area popup menu</a>. In
+    both cases, the <strong>Create Features</strong> dialog box will
+    then be opened:
   </p>
   <p>
     <img src="crnewfeature.gif">
index 90958ae..1965e70 100644 (file)
   <p>
     <strong>DAS Sequence Feature Retrieval</strong>
   </p>
-  <p>
-    Jalview includes a client for retrieving sequences and their
-    features via the Distributed Annotation System.
-  </p>
+  <p>Jalview includes a client for retrieving sequences and their
+    features via the Distributed Annotation System.</p>
   <ol>
     <li>Open the Feature Settings panel by selecting &quot;View
       -&gt; Feature Settings...&quot;</li>
     </li>
   </ol>
   <p>
-    If your DAS source selection contains sources which use Uniprot
-    accession ids, you will be asked whether Jalview should find Uniprot
+    If your DAS source selection contains sources which use UniProt
+    accession ids, you will be asked whether Jalview should find UniProt
     Accession ids for the given sequence names. It is important to
-    realise that many DAS sources only use Uniprot accession ids, rather
-    than Swissprot/Uniprot sequence names.<br> The <a
-      href="../webServices/dbreffetcher.html"
-    >database reference fetcher</a> documentation describes how Jalview
-    discovers what database references are appropriate for the sequences
-    in the alignment.
+    realise that many DAS sources only use UniProt accession ids, rather
+    than Swissprot/UniProt sequence names.<br> The <a
+      href="../webServices/dbreffetcher.html">database
+      reference fetcher</a> documentation describes how Jalview discovers
+    what database references are appropriate for the sequences in the
+    alignment.
   <ul>
     <li><em>Note</em><br> Please remember to save your
       alignment if either the start/end numbering, or the sequence IDs
   <p>
     <em>DAS support was introduced in Jalview Version 2.1.</em>
   </p>
-  <br/>
+  <br />
   <p>
-    <em>The DAS registry at http://www.dasregistry.org was decommissioned early in 2015. An unmaintained mirror is currently hosted at http://www.ebi.ac.uk/das-srv/registry/.</em>
+    <em>The DAS registry at http://www.dasregistry.org was
+      decommissioned early in 2015. An unmaintained mirror is currently
+      hosted at http://www.ebi.ac.uk/das-srv/registry/.</em>
   </p>
   <p>&nbsp;
 </body>
index a86d37f..9600070 100644 (file)
   </p>
   <p>
     Jalview can retrieve sequences and features from many <a
-      href="http://biodas.org/"
-    >DAS</a> sources. The DAS sources that it uses are discovered and
-    selected <em>via</em> the DAS settings panel, opened either from the
-    <a href="featuresettings.html">View&#8594;Feature Settings</a>
-    dialog box from the alignment window's menu bar, or the <a
-      href="featuresettings.html"
-    >Tools&#8594;Preferences</a> dialog box opened from the Desktop menu
-    bar.
+      href="http://biodas.org/">DAS</a> sources. The DAS sources
+    that it uses are discovered and selected <em>via</em> the DAS
+    settings panel, opened either from the <a
+      href="featuresettings.html">View&#8594;Feature Settings</a> dialog
+    box from the alignment window's menu bar, or the <a
+      href="featuresettings.html">Tools&#8594;Preferences</a>
+    dialog box opened from the Desktop menu bar.
   </p>
   <p>
     <img src="das.gif">
index 748eeba..14e98e5 100644 (file)
     <!-- and <strong>Feature Group</strong>  -->
     pull down menu. In addition to the Name, group, colour and
     description attributes described for the <a
-      href="creatinFeatures.html"
-    >new feature dialog box</a>, a feature's start and end position can be
-    changed either by entering a new position directly or by using the
-    adjacent up and down buttons.
+      href="creatinFeatures.html">new feature dialog box</a>, a
+    feature's start and end position can be changed either by entering a
+    new position directly or by using the adjacent up and down buttons.
   </p>
   <p>
     Select <strong>Amend</strong> to update the feature, <strong>Delete</strong>
diff --git a/help/html/features/ensemblsequencefetcher.html b/help/html/features/ensemblsequencefetcher.html
new file mode 100644 (file)
index 0000000..e547c58
--- /dev/null
@@ -0,0 +1,96 @@
+<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>Fetching ENSEMBL Data in Jalview</title>
+</head>
+<body>
+
+  <strong>Fetching ENSEMBL Data in Jalview</strong>
+  <br /> Jalview Version 2.10 (October 2016) introduced support to
+  retrieve annotated transcripts, peptides and genomic contigs from
+  <a href="http://www.ensembl.org">ENSEMBL</a>.
+  <br />
+  <img src="selectfetchdb.gif" align="right" width="480" height="204"
+    alt="Database selection dialog with Ensembl sequence source tooltip">
+
+  <p>Two types of ENSEMBL source are provided. ENSEMBL queries the
+    main ENSEMBL warehouse containing data for higher eukaryotes, and
+    EnsemblGenomes, which queries Ensembl Pathogens, and other
+    warehouses.</p>
+  <p>
+    <strong>General Use</strong><br /> If you have a set of Ensembl
+    gene or transcript IDs, then you can retrieve them <em>via</em> the
+    sequence fetcher dialog opened after selecting the most appropriate
+    source (either 'ENSEMBL', or Ensembl Genomes). However, Jalview's
+    Ensembl client has a couple of additional capabilities:
+  </p>
+  <p>
+    <strong>Retrieving aligned transcripts for a genomic ID</strong>
+  </p>
+  <p>If a single genomic identifier is entered in the Ensembl
+    fetcher, Jalview will return all transcripts and products for the
+    locus, and display them in a split view - complete with sequence
+    variant annotation.</p>
+  <p>
+    <strong>Retrieving orthologs for a gene ID</strong>
+  </p>
+  <p>
+    If a gene ID is entered (e.g. fox1), Jalview will resolve Ensembl
+    genomic identifiers for a predefined set of taxa (Mouse, Rat, Human,
+    Yeast in Jalview 2.10).<br />
+  </p>
+  <p>
+    <strong><a name="ensemblannotation">Ensembl Sequence
+        Features</a></strong><br /> Jalview 2.10 includes support for the
+    visualisation and transfer genomic and transcriptomic sequence
+    features onto protein product sequences. Retrieval of a genomic
+    locus results in a set of transcripts that are annotated with
+    nucleotide variant information and exonic regions. By default,
+    intronic regions will be hidden.
+  </p>
+  <p>
+    <strong><a name="variantvis">Variant information on
+        Protein Products</a></strong><br />Jalview can translate genomic variant
+    annotation into protein sequence variant codes for variants
+    intersecting coding regions of a gene. To see this in action, use
+    the <strong>Calculate&#8594;Show cross-references</strong> menu to
+    view protein product sequences for the currently displayed (or
+    selected) sequences. The same menu allows you to recover Ensembl
+    exon, transcript and variant information when viewing UniProt
+    sequences.
+  </p>
+  <p>
+    <strong>Viewing more information about variant annotation</strong><br />
+    Variants are highlighted as red sequence features on the protein
+    sequence, with each one reporting all protein sequence variants
+    observed at that position as a result of the genomic variants.
+    Right-clicking a variant allows you to open the Ensembl Variants web
+    page for each variant, via the <strong>Link</strong> submenu.
+  </p>
+  <p>
+    <strong>Work in Progress !</strong><br />In the next few releases,
+    we hope to improve and extend Jalview's support for working with
+    Ensembl. If you have any problems, questions or suggestions then
+    please get in contact with us via the Jalview discussion list.
+  </p>
+</body>
+</html>
\ No newline at end of file
index 9f33b7b..fd6b99f 100755 (executable)
     a colour the feature).</p>
 
   <p>
-    If your sequence annotation is already available in GFF Format (see
-    <a href="http://gmod.org/wiki/GFF2">gmod.org/wiki/GFF2</a>),
-    then you can leave it as is, after first adding a line containing
-    only 'GFF' after any Jalview feature colour definitions (<em>this
-      mixed format capability was added in Jalview 2.6</em>). Alternately,
+    If your sequence annotation is already available in <a href="http://gmod.org/wiki/GFF2">GFF2</a> (http://gmod.org/wiki/GFF2) or
+    <a href="https://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md">GFF3</a> 
+    (http://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md) format, 
+    then you can leave it as is, after first adding a line containing only
+    'GFF' after any Jalview feature colour definitions (<em>this
+    mixed format capability was added in Jalview 2.6</em>). Alternately,
     you can use Jalview's own sequence feature annotation format, which
     additionally allows HTML and URLs to be directly attached to each
     piece of annotation.
 </pre>
 
   This format allows two alternate ways of referring to a sequence,
-  either by its text ID, or its index (base 0) in an associated alignment.
-  Normally, sequence features are associated with sequences rather than
-  alignments, and the sequenceIndex field is given as &quot;-1&quot;. In
-  order to specify a sequence by its index in a particular alignment,
-  the sequenceId should be given as &quot;ID_NOT_SPECIFIED&quot;,
-  otherwise the sequenceId field will be used in preference to the
-  sequenceIndex field.
+  either by its text ID, or its index (base 0) in an associated
+  alignment. Normally, sequence features are associated with sequences
+  rather than alignments, and the sequenceIndex field is given as
+  &quot;-1&quot;. In order to specify a sequence by its index in a
+  particular alignment, the sequenceId should be given as
+  &quot;ID_NOT_SPECIFIED&quot;, otherwise the sequenceId field will be
+  used in preference to the sequenceIndex field.
   </p>
 
 
     description line will be translated into URL links. A link symbol
     will be displayed adjacent to any feature which includes links, and
     these are made available from the <a
-      href="../menus/popupMenu.html#sqid.popup"
-    >links submenu</a> of the popup menu which is obtained by
-    right-clicking when a link symbol is displayed in the tooltip.<br>
-    <em>Non-positional features</em><br> Specify the <em>start</em>
-    and <em>end</em> for a feature to be <strong>0</strong> in order to
-    attach it to the whole sequence. Non-positional features are shown
-    in a tooltip when the mouse hovers over the sequence ID panel, and
-    any embedded links can be accessed from the popup menu.<br /> <em>Scores</em><br>
+      href="../menus/popupMenu.html#sqid.popup">links submenu</a>
+    of the popup menu which is obtained by right-clicking when a link
+    symbol is displayed in the tooltip.<br> <em>Non-positional
+      features</em><br> Specify the <em>start</em> and <em>end</em> for
+    a feature to be <strong>0</strong> in order to attach it to the
+    whole sequence. Non-positional features are shown in a tooltip when
+    the mouse hovers over the sequence ID panel, and any embedded links
+    can be accessed from the popup menu.<br /> <em>Scores</em><br>
     Scores can be associated with sequence features, and used to sort
     sequences or shade the alignment (this was added in Jalview 2.5).
     The score field is optional, and malformed scores will be ignored.
index 200fc8f..3d7c944 100755 (executable)
   </p>
   <p>
     <strong><em>Feature settings pop-up menu</em></strong><br> <strong>Right-click</strong>
-    on a feature to open a pop-up menu that allows you to sort the
-    alignment or current selection using that feature type (see below),
-    or toggle the type of colouring used for the feature. Features may
-    be highlighted with either a single colour or a <a
-      href="featureschemes.html"
-    >feature colourscheme</a> based on either the scores associated with
-    that feature or from the feature's description (e.g. to distinguish
-    different names associated with a DOMAIN feature).
+    on a feature to open a pop-up menu that allows you to
+  <ul>
+    <li>Hide, show and select columns containing that feature</li>
+    <li>Sort the alignment or current selection using that feature
+      type (see below)</li>
+    <li>Toggle the type of colouring used for the feature</li>
+  </ul>
+  <p>
+    Features may be highlighted with either a single colour or a <a
+      href="featureschemes.html">feature colourscheme</a> based on
+    either the scores associated with that feature or from the feature's
+    description (e.g. to distinguish different names associated with a
+    DOMAIN feature).
   </p>
   <p>
-    <strong>Ordering alignment by features</strong><br> The 'Seq
-    Sort by Score' and 'Seq Sort by Density' buttons will sort the
-    alignment based on the average score or total number of currently
-    active features and groups on each sequence. To order the alignment
-    using a specific feature type, use the <em>sort by ..</em> entries
-    in the pop-up menu for that type.<br> <em>Feature sorting
-      and graduated feature colouring were introduced in Jalview 2.5</em>
+    <strong><a name="sortbyfeature">Ordering alignment by
+        features</a></strong><br> The 'Seq Sort by Score' and 'Seq Sort by
+    Density' buttons will sort the alignment based on the average score
+    or total number of currently active features and groups on each
+    sequence. To order the alignment using a specific feature type, use
+    the <em>sort by ..</em> entries in the pop-up menu for that type.<br>
+    <em>Feature sorting and graduated feature colouring were
+      introduced in Jalview 2.5</em>
   </p>
 
   <p>
     ordering based on the average length of each feature type.
   </p>
   <p>
-    The <strong><em>transparency slider setting</em></strong> controls the visibility
-    of features rendered below other features. Reducing the transparency
-    will mean that features at the top of the list can obscure features
-    lower down, and increasing it allows the user to 'see through' the
-    upper layers of a set of features.
+    The <strong><em>transparency slider setting</em></strong> controls
+    the visibility of features rendered below other features. Reducing
+    the transparency will mean that features at the top of the list can
+    obscure features lower down, and increasing it allows the user to
+    'see through' the upper layers of a set of features.
   </p>
   <p>
     <strong><em>You can save all features, with their
index a2bc627..254f92e 100644 (file)
     <strong>The Groovy Shell</strong>
   </p>
   <p>
-    <a href="http://www.groovy-lang.org/">Groovy</a> is an &quot;<em>agile
-      and dynamic language for the Java platform</em>&quot;. The groovy
-    scripting language makes it extremely easy to programmatically
-    interact with Java programs, in much the same way that Javascript is
-    used to generate and interact with applets and other objects on the
-    page.
+    Groovy (<a href="http://www.groovy-lang.org/">www.groovy-lang.org</a>)
+    is an &quot;<em>agile and dynamic language for the Java
+      platform</em>&quot;. The groovy scripting language makes it extremely
+    easy to programmatically interact with Java programs, in much the
+    same way that Javascript is used to generate and interact with
+    applets and other objects on the page.
   </p>
   <p>
-    <strong><em>Getting Groovy...</em> </strong><br> Jalview comes with
-    an embedded installation of Groovy. All you need is to select <strong>Tools&#8594;Groovy
-      Console...</strong> menu option 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 Console</a> appear. This allows you to interactively execute Groovy
-    scripts within the Jalview run-time environment.
+    <em>Getting Groovy...</em><br> Jalview comes with an embedded
+    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
+      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
+    groovy script whilst viewing an alignment.
   </p>
   <p>
     <strong>Executing groovy scripts on Jalview startup</strong><br>
     </em>
   </p>
   <p>
-    <strong>Executing a groovy script on a particular alignment</strong><br/>
-    
-  <p>
     <strong>Access to Jalview's functions from Groovy Scripts</strong><br>
-    There is as yet no properly defined scripting interface to Jalview,
-    but all the public methods of the jalview class hierarchy can be
-    called from Groovy scripts. The access point for this is the <strong>Jalview</strong>
-    object defined in the groovy environment which corresponds to the
-  <pre>jalview.gui.Desktop</pre>
-  object which manages all the Jalview windows. Here's an example to get
-  you started:
-  <br>
+    The scripting interface to Jalview is still a work in progress, so
+    we recommend you also take a look at Jalview's source, since all the
+    public methods of the jalview class hierarchy can be called from
+    Groovy scripts. In addition, the following objects are also defined:
+
+
+  
+  <ul>
+    <li><strong>Jalview</strong> - this is bound to <code>jalview.bin.Jalview</code>.<br />Useful
+      methods include:
+      <ul>
+        <li>Jalview.getAlignFrames() - returns a list of
+          jalview.gui.AlignFrame objects</li>
+        <li>Jalview.getCurrentAlignFrame() - returns the alignment
+          window which is currently being looked at by the user</li>
+      </ul></li>
+    <li><strong>currentAlFrame</strong> - this is only defined when
+      running a Groovy script via the -groovy command line argument. It
+      returns the first alignment window created after acting on the
+      other arguments passed on the command line.</li>
+  </ul>
+  <p>
+    <em>A simple script</em><br />
   <ul>
     <li>Getting the title, alignment and first sequence from the
       current alignFrame<br> <pre>
@@ -77,13 +91,26 @@ def alignment = alf[0].viewport.alignment;
 def seq = alignment.getSequenceAt(0);
 </pre>
     </li>
-    <li>When running a groovy script from the command line, the
-      alignment that was just loaded can be referred to like so:<br>
-    <pre>
+    <li>If you wanted to do the same thing from the command line,
+      you can refer to alignment that was just loaded with
+      currentAlFrame:<br> <pre>
 print currentAlFrame.getTitle();</pre>
   </ul>
-  If you have downloaded the InstallAnywhere version of Jalview, you can
-  find additional groovy scripts in the examples/groovy subfolder of the
-  installation directory.
+  <p>
+    <em>Example scripts</em><br />If you have downloaded the
+    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>.
+  </p>
+  <p>
+    <em>Using Groovy to add new Alignment Calculations</em><br />We've
+    simplified the alignment analysis programming interface in Jalview
+    2.10 to make it easy for you to add your own dynamic annotation
+    tracks with Groovy. Have a look at the <a
+      href="../groovy/featureCounter.html">featureCounter.groovy</a>
+    example for more information.
+  </p>
+
 </body>
 </html>
index ac9b8b1..d69f877 100644 (file)
@@ -86,9 +86,9 @@
     <li><strong><a href="../calculations/tree.html">Tree</a></strong>,
       <strong><a href="../calculations/pairwise.html">pairwise
           alignment</a></strong> and <strong><a
-        href="../calculations/pca.html"
-      >PCA</a></strong> calculations will only be performed using the <em>visible</em>
-      parts of the alignment.</li>
+        href="../calculations/pca.html">PCA</a></strong> calculations will
+      only be performed using the <em>visible</em> parts of the
+      alignment.</li>
     <li><a href="../webServices/msaclient.html">Multiple
         Sequence Alignments</a> are performed locally on on each visible
       chunk of the input, and concatenated with the hidden regions to
index 3fa1563..0cd6168 100644 (file)
     structures opened by entries in the <strong>&quot;Structure&quot;</strong>
     submenu in the <a href="../menus/popupMenu.html">sequence id
       pop-up menu</a> (if you can't see this, then you need to <a
-      href="viewingpdbs.html"
-    >associate a PDB structure</a> with the sequence). Jmol is available
-    from the Jalview desktop and should also run in the JalviewLite
-    applet, providing the browser supports Java 1.5. If Jmol is not
-    available, then the original <a href="pdbviewer.html">internal
-      pdb viewer</a> will be used as a fallback.
+      href="viewingpdbs.html">associate a PDB structure</a> with
+    the sequence). Jmol is available from the Jalview desktop and should
+    also run in the JalviewLite applet, providing the browser supports
+    Java 1.5. If Jmol is not available, then the original <a
+      href="pdbviewer.html">internal pdb viewer</a> will be used as a
+    fallback.
   </p>
   <!-- <p>The following menu entries are provided for viewing structure data<br>
   <ul>
       based structure superposition was added in Jalview 2.6</em>
   </p>
   <p>
-    <strong>Controls</strong><br> The structure is by default
-    rendered as a ribbon diagram. Moving the mouse over the structure
-    brings up tooltips giving the residue name, PDB residue number and
-    chain code, atom name and number
-    ([RES]Num:Chain.AtomName#AtomNumber). If a mapping exists to a
-    residue in any associated sequences, then this will be highlighted
-    in each one's alignment window. The converse also occurs - moving
-    the mouse over an associated residue in an alignment window
-    highlights the associated atoms in the displayed structures.
+    <strong>Controls</strong><br> The structure is by default rendered
+    as a ribbon diagram. Moving the mouse over the structure brings up
+    tooltips giving the residue name, PDB residue number and chain code,
+    atom name and number ([RES]Num:Chain.AtomName#AtomNumber). If a
+    mapping exists to a residue in any associated sequences, then this
+    will be highlighted in each one's alignment window. The converse
+    also occurs - moving the mouse over an associated residue in an
+    alignment window highlights the associated atoms in the displayed
+    structures. Press B or use
+    <em>Select&#8594;Select Highlighted columns</em> from any linked
+    alignment window to mark the columns highlighted after mousing over
+    the structure.
   </p>
   <p>Selecting a residue highlights its associated sequence residue
     and alpha carbon location. Double clicking an atom allows distances
         </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
+            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.
             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>.
+            href="../colourSchemes/index.html">amino acid
+              colours</a>.
         </em></li>
       </ul></li>
     <li><strong>Jmol<br>
     Jmol scripting console.</p>
   <p>
     The state of each Jmol display is stored within <a
-      href="jalarchive.html"
-    >Jalview archives</a> as a Jmol state recovery script file. This means
-    that any Jmol visualization effects that you add beyond those
-    provided by Jalview will be able to be stored and recovered along
-    with the displayed alignments in Jalview.
+      href="jalarchive.html">Jalview archives</a> as a Jmol state
+    recovery script file. This means that any Jmol visualization effects
+    that you add beyond those provided by Jalview will be able to be
+    stored and recovered along with the displayed alignments in Jalview.
   </p>
   <p>
     <strong>More Information</strong>
     Jmol is a sophisticated program in its own right, with its own
     command console and scripting language. Only the essentials have
     been described here - the interested reader is referred to <a
-      href="http://jmol.sourceforge.net/docs/"
-    >Jmol's own comprehensive online documentation</a>.
+      href="http://jmol.sourceforge.net/docs/">Jmol's own
+      comprehensive online documentation</a>.
   </p>
   </p>
 </body>
index 6df0fd4..b507fe1 100644 (file)
@@ -1,28 +1,55 @@
 <!DOCTYPE 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.
+ -->
 <html>
 <head>
 <meta charset="UTF-8">
 <title>mmCIF File Format</title>
 </head>
 <body>
-       <strong>mmCIF File Format</strong>
-       <p>The mmCIF file format (macromolecular Crystallographic
-               Information) was developed under the auspices of the International Union of Crystallography (IUCr) to extend the Crystallographic Information
-               File (CIF) data representation used for describing small molecule
-               structures and associated diffraction experiments.</p>
-       <strong>Merits of mmCIF file format</strong>
-       <ul>
-               <li>Large structures (containing >62 chains and/or 99999 ATOM
-                       records) that cannot be fully represented in the PDB file format are
-                       available in the PDB archive as single PDBx/mmCIF files.</li>
-               <li>PDBx/mmCIF file format provides richer data annotation</li>         
-               <li>PDBx/mmCIF became the standard PDB archive format in 2014.
-                       Since 2016 the PDB File Format is no longer being modified or
-                       extended to support new content.
-               </li>
-       </ul>
+  <strong>What is mmCIF ?</strong>
+  <br />mmCIF stands for 'macro-molecular Crystallographic Information
+  File'. This format was developed by the PDB consortium and the
+  International Union of Crystallography (IUCr), based on
+  Crystallographic Information File (CIF), a format used for describing
+  the structures of small molecules.
+  <br />mmCIF became the recommended format for the exchange of
+  biomacromolecular structures in 2014.
+  <p>
+    <strong>mmCIF and Jalview</strong> <br />Since Jalview 2.10, mmCIF
+    is used for structures downloaded from the PDB. This means:
+  </p>
+  <ol>
+    <li>Jalview can use the mmCIF to read structures that are too
+      large to be represented by a single PDB file. (ie, with more than
+      >62 chains and/or 99999 ATOM records).</li>
+    <li>Jalview users will have access to the richer annotation
+      provided by PDBx/mmCIF files.</li>
+    <li>There may be slight differences between sequences
+      containing modified residues for structures downloaded in mmCIF
+      format. This is because mmCIF differs from the PDB format in the
+      way it describes non-standard sequence data.</li>
+  </ol>
 
-       <em>mmCIF file format support for importing 3D structure data from
-               flat file and EMBL-PDBe via mmCIF was added in Jalview 2.9.1</em>
+  <em>Support for importing 3D structure data from flat file and
+    EMBL-PDBe as mmCIF was added in Jalview 2.10</em>
 </body>
-</html>
\ No newline at end of file
+</html>
index 1700de5..cc7183c 100644 (file)
@@ -74,8 +74,7 @@
   <p>
     A tree calculated on a particular view, or loaded onto it, is by
     default associated with just that view. However, the <a
-      href="../calculations/treeviewer.html"
-    >Tree Viewer's</a> <strong>&quot;View&#8594;Associate
+      href="../calculations/treeviewer.html">Tree Viewer's</a> <strong>&quot;View&#8594;Associate
       leaves&quot;</strong> submenu allows a tree's view association to be
     changed to to any or all other views.
   </p>
index b243168..97a779a 100644 (file)
Binary files a/help/html/features/pdbseqfetcher.png and b/help/html/features/pdbseqfetcher.png differ
index 0465762..2962ba6 100644 (file)
@@ -40,8 +40,7 @@
     <strong>&quot;File &#8594;Fetch Sequences&quot;</strong>).
   </p>
   <img src="pdbseqfetcher.png" align="left"
-    alt="PDB sequence fetcher (introduced in Jalview 2.9)"
-  />
+    alt="PDB sequence fetcher (introduced in Jalview 2.9)" />
 
   <p>
     <strong>Searching the PDB Database</strong>
@@ -56,9 +55,9 @@
   </p>
   <p>
   <ul>
-    <li><strong>Searching a specific PDB field</strong><br />If you
-      want to find structures based on a specific PDB metadata field,
-      you can select it from the drop-down menu.</li>
+    <li><strong>Searching a specific PDB field</strong><br />If
+      you want to find structures based on a specific PDB metadata
+      field, you can select it from the drop-down menu.</li>
     <li><strong>Retrieving a unique chain for a PDB entry</strong><br>To
       retrieve a specific chain for a PDB entry, append the PDB ID with
       a colon followed by the chain code in the search box.<br /> e.g
index fd13f57..05bf2f1 100755 (executable)
       pop-up menu</a>. The internal PDB viewer is not able to show
     superpositions, so no other options are provided. Structures can
     only be viewed for sequences which have an <a
-      href="viewingpdbs.html"
-    >associated PDB structure</a>, and the PDB Viewer will only be
-    associated with the particular alignment view from which it was
-    opened.
+      href="viewingpdbs.html">associated PDB structure</a>, and the
+    PDB Viewer will only be associated with the particular alignment
+    view from which it was opened.
   </p>
   <p>
     <strong>Controls</strong>
         </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 view, including any
-            Uniprot sequence features or region colourings.<br>
+            UniProt sequence features or region colourings.<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
               Jalview colourschemes.<br>
           </em></strong> The remaining entries apply the colourschemes available from
           the standard and user defined <a
-          href="../colourSchemes/index.html"
-        >amino acid colours</a>.</em></li>
+          href="../colourSchemes/index.html">amino acid
+            colours</a>.</em></li>
       </ul></li>
     <li><strong>View<br>
     </strong><em> These options can be turned off to improve performance
index 4af43de..6a8c86c 100755 (executable)
@@ -63,8 +63,8 @@
     </li>
     <li>The <a href="../webServices/webServicesPrefs.html"><strong>&quot;Web
           Service&quot;</strong> Preferences</a> tab allows you to configure the <a
-      href="http://www.compbio.dundee.ac.uk/jabaws"
-    >JABAWS</a> servers that Jalview uses, and change the layout of the
+      href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>
+      servers that Jalview uses, and change the layout of the
       alignment's Web Services menu.
     </li>
   </ul>
@@ -78,9 +78,8 @@
   </p>
   <p>
     <em>Open Overview Window</em> - When this is selected, the <a
-      href="overview.html"
-    >alignment overview</a> panel is opened by default for a new alignment
-    window.
+      href="overview.html">alignment overview</a> panel is opened
+    by default for a new alignment window.
   </p>
   <p>
     <em>Show Annotations</em> - If this is selected the new window will
     <em>Open file</em> - If this is selected then the default alignment
     file will be opened when Jalview is started. You can change the
     default file by clicking on file name and either typing in the file
-    path or selecting it from the file chooser window.<br />
-    <em>Note: The default example alignment is updated periodically
-      to demonstrate new features in Jalview.</em>
+    path or selecting it from the file chooser window.<br /> <em>Note:
+      The default example alignment is updated periodically to
+      demonstrate new features in Jalview.</em>
   </p>
   <p>
     <a name="colours"><strong>&quot;Colours&quot;
   <p>
     <em>Annotation Shading Default</em> - set the default minimum and
     maximum colours used when <a
-      href="../colourSchemes/annotationColouring.html"
-    >Colour by Annotation...</a> is selected from the alignment window's
-    colours menu.
+      href="../colourSchemes/annotationColouring.html">Colour
+      by Annotation...</a> is selected from the alignment window's colours
+    menu.
   </p>
   <p>
     <a name="structure"><strong>&quot;Structure&quot;
     <em>URL Link From Sequence ID</em><br> These definitions are
     used to generate URLs from a sequence's ID or database cross
     references. Read more about <a
-      href="../webServices/urllinks.html#urllinks"
-    >configuring URL links here</a>.
+      href="../webServices/urllinks.html#urllinks">configuring
+      URL links here</a>.
   </p>
   <p>
     <em>Default Browser (Unix)</em><br> Its difficult in Java to
   </p>
   <p>
     When this option is enabled, Jalview embeds <a
-      href="bioJsonFormat.html"
-    >BioJSON</a> data within HTML files exported from Jalview at
-    generation time. This enables the exported HTML files to be
-    extracted and imported back into the Jalview desktop application at
-    a later time.
+      href="bioJsonFormat.html">BioJSON</a> data within HTML files
+    exported from Jalview at generation time. This enables the exported
+    HTML files to be extracted and imported back into the Jalview
+    desktop application at a later time.
   <p>
     <em>Use Modeller Output</em>
   </p>
index 9766782..69f3315 100755 (executable)
@@ -65,6 +65,19 @@ td {
     Settings&quot; under the &quot;View&quot; menu to change the
     visibility and colour of the new sequence feature.</p>
   <p>
+  <p>
+    <strong>Selecting regions from Search Results</strong>
+  </p>
+  <p>
+    Press 'B' or use the <em>Select Highlighted Columns</em> option from
+    the alignment window's select menu to add columns containing
+    highlighted search results to the alignment window's column
+    selection. Alt-'B' will add all but the highlighted columns, and
+    Ctrl (or Cmd) -B will toggle the column selection for the
+    highlighted region.
+  </p>
+  <p>
+  
     <strong>A quick Regular Expression Guide</strong>
   </p>
   <p>A regular expression is not just a simple text query - although
@@ -73,7 +86,7 @@ td {
     the match. For example, a simple query like &quot;ACDED&quot; would
     match all occurences of that string, but &quot;ACD+ED&quot; matches
     both 'ACDDED' and 'ACDDDDDDDDED'. More usefully, the query
-    &quot;[ILGVMA]{;5,}&quot; would find stretches of small, hydrophobic
+    &quot;[GVATC]{;5,}&quot; would find stretches of small, hydrophobic
     amino acids of at least five residues in length.</p>
   <p>
     The table below describes some of the regular expression syntax:<br>
index 6e1ce10..de0a7e6 100644 (file)
Binary files a/help/html/features/selectfetchdb.gif and b/help/html/features/selectfetchdb.gif differ
index 0ec5f3b..3c9d2b8 100755 (executable)
@@ -29,7 +29,7 @@
   <p>
     Jalview can colour parts of a sequence based on the presence of
     sequence features - which may be retrieved from database records
-    (such as Uniprot), the result of <a href="search.html">sequence
+    (such as UniProt), the result of <a href="search.html">sequence
       motif searches</a> or simply read from a <a href="featuresFormat.html">sequence
       features file</a>. You can also <a href="creatinFeatures.html">create
       features</a> from the results of searches or the current selection,
   <p>
     By default, Jalview will assign a color to each feature based on its
     type. These colours can be changed from the <a
-      href="featuresettings.html"
-    >feature settings</a> and <a href="editingFeatures.html">amend
-      features</a> dialog boxes. Since Jalview 2.5, it is also possible to
-    define <a href="featureschemes.html">feature colourschemes</a> to
-    shade features based on their associated scores or text labels.
+      href="featuresettings.html">feature settings</a> and <a
+      href="editingFeatures.html">amend features</a> dialog boxes. Since
+    Jalview 2.5, it is also possible to define <a
+      href="featureschemes.html">feature colourschemes</a> to shade
+    features based on their associated scores or text labels.
   </p>
   <p>
     <strong>Sequence Feature Groups</strong>
   <p>
     Since Jalview 2.08, sequence features assigned to a sequence can be
     organised into groups, which may indicate that the features were all
-    retrieved from the same database (such as Uniprot features), or
+    retrieved from the same database (such as UniProt features), or
     generated by the same analysis process (as might be specified in a <a
-      href="featuresFormat.html"
-    >sequence features file</a>).
+      href="featuresFormat.html">sequence features file</a>).
   </p>
   <p>
     <strong>Sequence Feature Inheritance</strong>
   <p>
     Once sequence features have been loaded, their display can be fully
     controlled using the alignment window's <a
-      href="featuresettings.html"
-    >Sequence Feature Settings</a> dialog box. Feature colour schemes and
-    display parameters are unique to a particular alignment, so it is
-    possible to colour the same sequence features differently in
-    different alignment views.<br> Since Jalview 2.1, it is
-    possible to add <a href="dassettings.html">DAS features</a> to an
-    alignment via the DAS tabbed pane of the feature settings window.
+      href="featuresettings.html">Sequence Feature Settings</a>
+    dialog box. Feature colour schemes and display parameters are unique
+    to a particular alignment, so it is possible to colour the same
+    sequence features differently in different alignment views.<br>
+    Since Jalview 2.1, it is possible to add <a href="dassettings.html">DAS
+      features</a> to an alignment via the DAS tabbed pane of the feature
+    settings window.
   </p>
   <p>
     <strong>View&#8594;Sequence ID Tooltip&#8594;Show
     Precalculated Sequence Features may be added to an alignment from
     the command line, drag and drop, or from the &quot;File&#8594;Load
     Features / Annotations&quot; menu item. See the <a
-      href="featuresFormat.html"
-    >Features File Format</a> for more details.
+      href="featuresFormat.html">Features File Format</a> for more
+    details.
   </p>
 </body>
 </html>
index 4aa7234..44aa1c2 100755 (executable)
     Institute, or, since Jalview 2.4, DAS servers capable of the <em>sequence</em>
     command (configured in <a href="dassettings.html">DAS settings</a>).
   </p>
-  <img src="seqfetcher.gif" align="center"
-    alt="The Jalview Sequence Fetcher Dialog Box"
-  >
-  <p>The Sequence Fetcher dialog box can be opened via the
-    &quot;File&quot; menu on the main desktop in order to retrieve
-    sequences as a new alignment, or opened via the &quot;File&quot;
-    menu of an existing alignment to import additional sequences. There
-    may be a short delay when the sequence fetcher is first opened,
-    whilst Jalview compiles the list of available sequence datasources
-    from the currently defined DAS server registry.</p>
+  <p>The Sequence Fetcher can be opened via the &quot;File&quot;
+    menu on the main desktop in order to retrieve sequences as a new
+    alignment, or opened via the &quot;File&quot; menu of an existing
+    alignment to import additional sequences. There may be a short delay
+    when the sequence fetcher is first opened, whilst Jalview compiles
+    the list of available sequence datasources from the currently
+    defined DAS server registry.</p>
   <p>
-    First, <strong>select the database you want to retrieve
-      sequences from</strong> by clicking the button labeled 'Select database
-    retrieval source'. If a database source is already selected, then
-    the button's label will change to show the currently selected
-    database.
+    Every time a new fetcher is opened, you will need to <strong>select
+      the database you want to retrieve sequences</strong> from the database
+    chooser.
   </p>
-  <img src="selectfetchdb.gif" align="left"
-    alt="Database selection dialog for fetching sequences (introduced in Jalview 2.8)"
-  >
-  <p>Since Jalview 2.8, the available databases are shown as a tree
-    in a popup dialog box. The databases are ordered alphabetically, and
-    if there are many sources for the same type of sequence identifier,
-    they will be grouped together in a sub-branch branch labeled with
-    the identifier.</p>
+  <img src="selectfetchdb.gif" align="left" width="480" height="204"
+    alt="Database selection dialog for fetching sequences (introduced in Jalview 2.8)">
   <p>
-    Once you have selected the sequence database using the popup dialog
-    box, <strong>enter one or more 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.
-  </p>
-  <p>
-    <strong>Fetching from The PDB with the EMBL-EBI PDBe Search
-      Interface</strong>
-  </p>
-  <p>
-    Since Jalview 2.9, selecting PDB as the sequence database will open
-    the <a href="pdbsequencefetcher.html">PDB Sequence Fetcher</a> for
-    discovering and retrieving structures.
+    The databases are shown as a tree, and ordered alphabetically;
+    tooltips are shown if you mouse over some sources, explaining what
+    the database will retrieve. You can select one by using the up/down
+    arrow keys and hitting return, or by double clicking with the mouse.
+    <br />
+    <em>If you have DAS sources enabled, then you may have several
+      sources for the same type of sequence identifier, and these will
+      be grouped together in a sub-branch branch labeled with the
+      identifier.</em>
   </p>
+  <p>Once you have selected a sequence database, its fetcher dialog
+    will open. Jalview provides two types of dialog:</p>
+  <ol>
+    <li><strong>The Free-text Search Interface</strong> <br />Free-text
+      search clients are provided for PDB (Since 2.9), and UniProt
+      (Since 2.10). They provide access to each database's own query
+      system, enabling you to retrieve data by accession, free text
+      description, or any other type of supported field. For full
+      details, see each client's help page:
+      <ul>
+        <li><a href="pdbsequencefetcher.html">PDB Sequence
+            Fetcher</a></li>
+        <li><a href="uniprotsequencefetcher.html">UniProt
+            Sequence Fetcher</a></li>
+      </ul></li>
+    <li><strong>Accession based sequence retrieval</strong> <br />
+
+      <img src="seqfetcher.gif" align="center"
+      alt="The Jalview Sequence Fetcher Dialog Box"><br /> To
+      retrieve sequences, simply <strong>enter one or more
+        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>
+  </ol>
   <p>
     <strong>Only retrieving part of a sequence</strong>
   </p>
   <p>
-    DAS sources (indicated by a &quot;<em>(DAS)</em>&quot;) allow a
-    range to be specified in addition to a sequence ID. To retrieve 50
-    residues starting at position 35 in UNIPROT sequence P73137 using
-    the UNIPROT DAS server, you would enter &quot;'P73137:35,84'.<br />
-    <em>Full support for DAS range queries was introduced in
-      Jalview 2.8</em>
+    When using DAS sources (indicated by a &quot;<em>(DAS)</em>&quot;),
+    you can append a range in addition to a sequence ID. For example, to
+    retrieve 50 residues starting at position 35 in UNIPROT sequence
+    P73137 using the UNIPROT DAS server, you would enter
+    &quot;'P73137:35,84'.<br /> <em>Full support for DAS range
+      queries was introduced in Jalview 2.8</em>
   </p>
 
   <p>If you use the WSDBFetch sequence fetcher services (EMBL,
-    Uniprot, PFAM, and RFAM) in work for publication, please cite:</p>
+    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
index 60ac6ab..ce41702 100644 (file)
@@ -26,6 +26,7 @@
   <p>
     <strong>Mapping Between Different Sequences</strong>
   </p>
+  <!--  TODO: review and check if this page is really needed -->
   <p>A new feature in Jalview 2.3 is the ability to map between
     sequences in different domains, based on alignment, or by the use of
     explicit mappings provided by databases.</p>
     correspondence between DNA and protein sequences. This mapping can
     be imported directly from EMBL and EMBLCDS database records
     retrieved by the <a href="seqfetch.html">Sequence Fetcher</a>, and
-    allows sequence features to be mapped directly from Uniprot das
+    allows sequence features to be mapped directly from UniProt das
     sources to their coding region on EMBL sequence records.
   </p>
-   <p>In Jalview 2.9.1 <a href="siftsmapping.html">SIFTS Mapping</a> was added as a better means for explicitly identifying the coordinates corresponding to a displayed sequence when viewing a PDB structure associated with a sequence </p>
+  <em><a href="siftsmapping.html">SIFTS Mapping</a> between PDB and
+    UniProt data was introduced in Jalview 2.10</em>
 </body>
 </html>
index 08089ad..c12d45b 100644 (file)
@@ -1,66 +1,90 @@
 <!DOCTYPE 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.
+ -->
 <html>
 <head>
 <meta charset="UTF-8">
-<title>SIFTS Mapping</title>
+<title>SIFTS Mapping from UniProt for PDB Structures</title>
 </head>
 <body>
-  <p><strong>SIFTS Mapping</strong></p>
-  
+
   <p>
-       SIFTS (Structure Integration with Function, Taxonomy
-       and Sequences) provides an up-to-date resource for residue-level
-       mapping between Uniprot and PDB entries. The information is updated and
-       released weekly simultaneously with the release of new PDB entries.
-       SIFTS Entries are published as XML files and made publicly available via an FTP
-       site hosted at the European Bioinformatics Institute. 
+    <strong>SIFTS Mapping for UniProt sequences and PDB
+      Structures</strong><br /> SIFTS (Structure Integration with Function,
+    Taxonomy and Sequences) is a database of residue-level mappings
+    between UniProt protein sequences, and protein structures found in
+    the PDB. The database is updated for each PDB release, and is
+    provided by the <a href="https://www.ebi.ac.uk/pdbe/docs/sifts/">PDBe
+      at EMBL-EBI</a>.
   </p>
-       
+  <p>When Jalview imports PDB data for a protein sequence found in
+    UniProt, either via the 'View 3D Structure...' option, or the 'Fetch
+    DB Refs' web services menu, Jalview will also download its SIFTS
+    record and use that information to construct a mapping between the
+    sequence and downloaded structure.</p>
+  <p>If, for some reason, no SIFTS mapping data exists, then Jalview
+    will generate a mapping using the built-in Needleman and Wunsch
+    global alignment algorithm. This is how sequence-structure mappings
+    were created before version 2.10.</p>
   <p>
-    At the point of viewing a PDB structure, if the default mapping method is set as 'SIFTS', 
-    Jalview will download a SIFTS file 
-       for the target entry and uses it to accurately map the sequence residues with the 
-       structure residue. Prior to SIFTS integration, Jalview uses Needleman and Wunsch 
-       Alignment algorithm to  map sequence residues to structure residues, and that may not 
-       always result to a correct mapping since it is computational determined.        
+    <strong>Controlling and troubleshooting SIFTS mappings</strong> <br />
+    Configuration options controlling whether SIFTS mappings are used
+    can be found in the <strong>Tools &rarr; Preferences &rarr;
+      Structure tab</strong>, under 'Sequence &harr; Structure method'.<br /> <em>Note:</em>
+    Changing the configuration will only affect how new mappings are
+    created. In order to recompute mappings for structures already
+    loaded, please reload the sequence & structural data.
   </p>
-  
+
   <p>
-  <strong>Configuration</strong><br/>
-       The default mapping method can be configured via <strong>Tools &rarr; Preferences &rarr; 
-       Structure tab</strong> Then scroll to the 'Sequence &harr; Structure method' section of 
-       the dialog box and change the default method. When 'SIFTS' is enabled as the default, all 
-       mappings between 'Sequence &harr; Structure' is performed via SIFTS provided that there 
-       is a valid SIFTS resource for the PDB entry. If no valid SIFTS resource is available, then 
-       the 'Sequence &harr; Structure' mapping falls back to Needleman and Wunsch Alignment algorithm.
-  </p>
-       
-  <p><strong>Multi-Chain Mappings</strong>
-  <br/>One of the main merits of SIFTS is the ability to accurately achieve multi-chain mapping 
-  (one-to-many) between a single Uniprot sequence and its corresponding multiple chains in 
-  PDB. Consequently, mousing over the uniprot sequence in the alignment window results 
-  to highlighting multiple corresponding positions in the structure viewer for the mapped chains. 
+    <strong>Multi-Chain Mappings</strong> <br />SIFTS gives Jalview the
+    ability to display multi-chain mappings between UniProt sequences
+    and PDB structure data. This is important when working with
+    multimeric proteins, when the biological assembly can contain
+    several structures for the same protein sequence. Multi-chain
+    mapping allows all residues in a structure to be located in the
+    alignment, and also, when shading the structure by sequence colours,
+    enables conservation patterns between oligomer interfaces to be
+    explored.
   </p>
+  <p>To see this in action, Retrieve the UniProt sequence
+    FER1_MAIZE, and then view one of its structures: 3B2F. Mousing over
+    the sequence results to two positions being highlighted in the
+    structure, and colouring the alignment transfers the color to all
+    the mapped chains in the structure.</p>
+
   <p>
-  To see this in action, load uniprot sequence for FER1_MAIZE then veiw PDB structure for 3B2F, you
-  will notice that mousing over the sequence results to two positions being highlighted in the 
-  structure, also colouring the sequence transfers the color to all the mapped chains in the structure.
-  </p>
-  
+    <Strong>Viewing Mapping Output</Strong> <br /> The mapping provided
+    by the SIFTS record is accessible via <strong>File &rarr;
+      View mapping</strong> menu of the structure viewers. The screenshot below
+    shows the mapping created between UniProt sequence FER1_MAIZE and
+    proteins in PDB 3B2F, which reports mappings for two chains. The
+    mapping method is also reported (highlighted with red border).
   <p>
-  <Strong>Viewing Mapping Output</Strong> <br/>
-  The mapping output is accessible via <strong>File &rarr; View mapping</strong> menu of the structure 
-  viewers. The screenshot below is the mapping output for the <Strong>{FER1_MAIZE &harr; 3B2F}</Strong> 
-  example described above. Observe that all the two chains were mapped. The mapping method used can be 
-  seen within the area highlighted with red boarder. This is useful for visually ascertaining the 
-  mapping method when in doubt.    
+
+    &emsp;<img src="sifts_mapping_output.png" align="left"
+      alt="SIFTS mapping output" /> <br />
   <p>
-       
-       &emsp;<img src="sifts_mapping_output.png" align="left" alt="SIFTS mapping output" />
-       
-  <p><em>SIFTS Mapping integration was added in Jalview 2.9.1</em></p>
-       
+    <em>SIFTS Mapping integration was added in Jalview 2.10</em>
+  </p>
+
 </body>
-</html>
\ No newline at end of file
+</html>
index 1c36abd..03b993c 100644 (file)
   <ul>
     <li>Mouseover or scrolling of either alignment is followed by
       the other (unless you turn off <strong><a
-        href="../menus/alwview.html"
-      >"View&#8594;Automatic Scrolling"</a></strong>)
+        href="../menus/alwview.html">"View&#8594;Automatic
+          Scrolling"</a></strong>)
     </li>
     <li>On selecting rows, columns or regions in one alignment, the
       corresponding selection is made in the other</li>
     <li>Sequence ordering in one alignment (using the cursor, or <strong><a
-        href="../calculations/sorting.html"
-      >"Calculate&#8594;Sort")</a></strong> is also applied to the other
+        href="../calculations/sorting.html">"Calculate&#8594;Sort")</a></strong>
+      is also applied to the other
     </li>
     <li>Editing (gap insertion / deletion) in the protein alignment
       is reflected in the cDNA (but not vice versa)</li>
     <li>Any trees imported or created with <strong><a
-        href="../calculations/tree.html"
-      >"Calculate Tree"</a></strong> on one of the views allow both cDNA and
-      Protein views to be grouped, coloured or sorted.
+        href="../calculations/tree.html">"Calculate Tree"</a></strong> on
+      one of the views allow both cDNA and Protein views to be grouped,
+      coloured or sorted.
     </li>
     <li>To allow for the different widths in cDNA and Protein
       alignments, the <strong><a href="../menus/alwformat.html">"Format&#8594;Font"</a></strong>
   </ul>
   <p>
     An alignment annotation row on the protein alignment shows the <strong><a
-      href="../calculations/consensus.html"
-    >cDNA consensus</a></strong> for each peptide column.<br /> This consensus may
-    reveal variation in nucleotides coding for conserved protein
-    residues.
+      href="../calculations/consensus.html">cDNA consensus</a></strong> for
+    each peptide column.<br /> This consensus may reveal variation in
+    nucleotides coding for conserved protein residues.
   </p>
 
   <a name="opensplit" />
index 296a751..fc71826 100644 (file)
     <strong>Structure Chooser</strong>
   </p>
 
-  The Structure Chooser interface provides a smart technique for
-  selecting PDB structures to view in Jalview by querying readily
-  available meta-data of structures. The Interface can be invoked by
-  selecting the
-  <strong>"3D Structure Data.."</strong> option from a sequence's
-  <a href="../menus/popupMenu.html">pop-up menu</a>. Some of the main
-  features it provides are listed below:
+  <p>
+    The Structure Chooser interface allows you to interactively select
+    which PDB 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
+    provides:
+  </p>
   <ul>
     <li>Automatic discovery, retrieval and association of PDB
-      entries for an alignment's sequences</li>
-    <li>Visualisation of discovered structures' meta-data</li>
-    <li>Ability to configure the meta-data entries to visualise</li>
-    <li>Auto-selection of the best structure via filtering by the
-      available metric parameters in the meta-data (i.e. resolution,
-      quality etc).</li>
-    <li>Selection of multiple structures in a single operation</li>
-  </ul>
-  Additionally, the Structure Chooser retains the following contemporary
-  features of Jalview:
-  <ul>
-    <li>Manual association of PDB entries via entering the PDB Id
-      or From File</li>
-    <li>Ability to view cached PDB entries</li>
+      entries for sequences</li>
+    <li>Exploration of meta-data for available 3D structures</li>
+    <li>Automatic selection of the 'best structure' to display for
+      each sequence</li>
+    <li>Manual association of PDB entries by entering a PDB Id</li>
+    <li>Association of structure data from a local file (in mmCIF
+      or PDB format)</li>
   </ul>
-
-
-  <strong>Associating PDB files with Sequences</strong>
-  <br> Discovery/Association of PDB entries to a sequence now
-  happens automatically during the initialisation of the Structure
-  Chooser Interface. Jalview uses the sequence's ID to query the PDB
-  Rest API provided by the EBI to discover PDB Ids associated with the
-  sequence.
-
-  <br>
-  <br>
-  <strong>Configuring displayed meta-data for Structures</strong>
-  <br> To configure the visible meta-data displayed for the
-  discovered structures, click the 'Configure Displayed Columns' tab,
-  then tick the options which you intend to make visible.
-
-  <br>
-  <br>
-  <strong>Auto-selection of best Structures</strong>
-  <br> Jalview can automatically filter and select the best
-  structures using various metric categories avaialble from the
-  meta-data of the structures. To perform this simply select any of the
-  following options from the drop-down menu in the Structure Chooser
-  interface: Best Uniprot coverage, Higest Resolution, Best Quality,
-  Highest Protein Chain etc. When the 'Invert' option is selected,
-  Jalview returns an inverse result for the current selected option in
-  the drop-down menu.
+  <p>
+    <strong>Selecting and Viewing Structures</strong>
+  </p>
+  <p>
+    Once one or more structures have been selected, pressing the <strong>View</strong>
+    button will import them into <a
+      href="viewingpdbs.html#afterviewbutton">a new or existing
+      structure view</a>.
+  </p>
+  <p>
+    <strong>Automated discovery of structure data</strong>
+  </p>
+  <p>
+    After selecting "3D Structure Data ..", Jalview queries the PDB via
+    the PDBe SOLR Rest API provided by EMBL-EBI to discover PDB IDs
+    associated with the sequence. It does this based on the sequence's
+    ID string, and any other associated database IDs. <br />
+    <br />
+  <p>
+    <strong><a name="cachedstructview">Viewing existing
+        structures for your sequences</a></strong>
+  </p>
+  <p>
+    If you have already loaded 3D structure data for the selected
+    sequences, the structure chooser will first open with the <strong>Cached
+      Structures View</strong>. This view shows associations between each
+    sequence, and chains for 3D structure files already in memory. If
+    you want to download additional structures, select one of the other
+    options from the drop down menu.
+  </p>
+  <p>
+    <strong>Selection of the best structure for each sequence</strong>
+  </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
+    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
+    selected, structures are selected in reverse order for the current
+    criteria (e.g. worst quality rather than best).</p>
   <p>
 
     <img src="schooser_main.png" style="width: 464px; height: 369px;">
        <p><img src="schooser_cached.png"> -->
     <br>The screenshot above shows the Structure Chooser interface
     along with the meta-data of auto-discovered structures for the
-    sample alignment. Note however that if no structures were
-    auto-discovered, a different interface for manual association will
-    be invoked as seen in the screenshot below.
+    sample alignment. If no structures were
+    auto-discovered, options for manually associating PDB records will be shown (see below).
   <p>
-    <img src="schooser_enter-id.png"
-      style="width: 464px; height: 369px;"
-    >
+    <strong>Exploration of meta-data for available structures</strong>
+  </p>
+  <p>Information on each structure available is displayed in columns
+    in the dialog box. By default, only the title, resolution and PDB
+    identifier are shown, but many more are provided by the PDBe. To
+    configure which ones are displayed, select the 'Configure Displayed
+    Columns' tab and tick the columns which you want to see.</p>
   <p>
+    <img src="schooser_enter-id.png"
+      style="width: 464px; height: 369px;">
+      <br/>
     <strong>Manual selection/association of PDB files with
       Sequences</strong>
   </p>
-  <p>To manually associate PDB files with a sequence, select any of
-    the follwing options listed below from the drop-down menu in the
-    interface:
+  <p>To manually associate PDB files with a sequence, select 'From
+    File', or 'Enter PDB Id' from the drop-down menu:
   <ul>
-    <li><strong>From File</strong> - You can load a PDB file from
-      the local machine or network and associate it with the selected
-      sequence. PDB files associated in this way will also be saved in
-      the <a href="jalarchive.html">Jalview Archive file</a>.<br></li>
-    <li><strong>Enter PDB Id</strong> - Jalview will use the PDB
-      Rest API, provided by the EBI, to fetch the PDB file with the
-      entered Id.<br></li>
-    <li><strong>Cached PDB Entries</strong> - You can view PDB
-      structures which have previously been downloaded/viewed using this
-      option. Jalview caches previously downloaded PDB entries in the
-      computer memory. However, if the project is saved before exiting
-      Jalview, Jalview will serialize the cached entries to the file
-      system.</li>
+    <li><strong>From File</strong> - allows you to load a PDB file
+      from the local machine or network and associate it with the
+      selected sequence. PDB files associated in this way will also be
+      saved in the <a href="jalarchive.html">Jalview Archive file</a>.<br></li>
+    <li><strong>Enter PDB Id</strong> - allows you specify a PDB ID
+      for your sequence. The PDB Rest API, provided by EMBL-EBI, is used
+      to validate and fetch structure data.<br></li>
   </ul>
 
   <p>
index 376180a..182b206 100644 (file)
   <p>
     <strong>UniProtKB query fields</strong>
   </p>
-<p>Supported query fields for searching specific data in UniProtKB (see also <a href="text-search">query syntax</a>).</p>
+  <p>
+    Supported query fields for searching specific data in UniProtKB (see
+    also <a href="uniprotsequencefetcher.html#text-search">query
+      syntax</a>).
+  </p>
 
-<table  border="1" width="95%">
-  <tr>
-    <th>Field</th>
-    <th>Example</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td>accession</td>
-    <td>
-      <code>accession:P62988</code>
-    </td>
-    <td>
-        Lists all entries with the primary or secondary
-        accession number P62988.
-    </td>
-  </tr>
-  <tr>
-    <td>active</td>
-    <td>
-      <code>active:no </code>
-    </td>
-    <td>
-        Lists all obsolete entries.
-    </td>
-  </tr>
-  <tr>
-    <td>annotation</td>
-    <td>
-      <code>
-        annotation:(type:non-positional)
-        <br />
-        annotation:(type:positional)
-        <br />
-        annotation:(type:mod_res "Pyrrolidone carboxylic acid" evidence:experimental)
-      </code>
-    </td>
-    <td>
-      Lists all entries with:
-      <ul>
-        <li>any general annotation (comments [CC])</li>
-        <li>any sequence annotation (features [FT])</li>
-        <li>at least one amino acid modified with a Pyrrolidone carboxylic acid group</li>
-      </ul>
-    </td>
-  </tr>
-  <tr>
-    <td>author</td>
-    <td>
-      <code>
-        author:ashburner
-      </code>
-    </td>
-    <td>
-        Lists all entries with at least one reference co-authored by Michael Ashburner.
-    </td>
-  </tr>
-  <tr>
-    <td>cdantigen</td>
-    <td>
-      <code>
-        cdantigen:CD233
-      </code>
-    </td>
-    <td>
-        Lists all entries whose cluster of differentiation number is CD233.
-    </td>
-  </tr>
-  <tr>
-    <td>citation</td>
-    <td>
-      <code>
-        citation:("intracellular structural proteins")
-        <br />
-        citation:(author:ashburner journal:nature)
-        citation:9169874
-      </code>
-    </td>
-    <td>
-      Lists all entries with a literature citation:
-      <ul>
-        <li>containing the phrase "intracellular structural proteins" in either title or abstract</li>
-        <li>co-authored by Michael Ashburner and published in Nature</li>
-        <li>with the PubMed identifier 9169874</li>
-      </ul>
-    </td>
-  </tr>
-  <tr>
-    <td>cluster</td>
-    <td>
-      <code>
-        cluster:UniRef90_A5YMT3
-      </code>
-    </td>
-    <td>
-        Lists all entries in the UniRef 90% identity cluster whose
-        representative sequence is UniProtKB entry A5YMT3.
-    </td>
-  </tr>
-  <tr>
-       <td>count</td>
-       <td>
-               <code>
-                       annotation:(type:transmem count:5)<br />
-                       annotation:(type:transmem count:[5 TO *])<br />
-                       annotation:(type:cofactor count:[3 TO *])
-               </code>
-       </td>
-       <td>Lists all entries with:
-               <ul>
-                       <li>exactly 5 transmembrane regions</li>
-                       <li>5 or more transmembrane regions</li>
-                       <li>3 or more Cofactor comments</li>
-               </ul>
-       </td>
-  </tr>
-  <tr>
-    <td>created</td>
-    <td>
-      <code>
-        created:[20121001 TO *]<br />
-        reviewed:yes AND created:[current TO *]
-      </code>
-    </td>
-    <td>
-        Lists all entries created since October 1st 2012.<br />
+  <table border="1" width="95%">
+    <tr>
+      <th>Field</th>
+      <th>Example</th>
+      <th>Description</th>
+    </tr>
+    <tr>
+      <td>accession</td>
+      <td><code>accession:P62988</code></td>
+      <td>Lists all entries with the primary or secondary accession
+        number P62988.</td>
+    </tr>
+    <tr>
+      <td>active</td>
+      <td><code>active:no </code></td>
+      <td>Lists all obsolete entries.</td>
+    </tr>
+    <tr>
+      <td>annotation</td>
+      <td><code>
+          annotation:(type:non-positional) <br />
+          annotation:(type:positional) <br /> annotation:(type:mod_res
+          "Pyrrolidone carboxylic acid" evidence:experimental)
+        </code></td>
+      <td>Lists all entries with:
+        <ul>
+          <li>any general annotation (comments [CC])</li>
+          <li>any sequence annotation (features [FT])</li>
+          <li>at least one amino acid modified with a Pyrrolidone
+            carboxylic acid group</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td>author</td>
+      <td><code> author:ashburner </code></td>
+      <td>Lists all entries with at least one reference co-authored
+        by Michael Ashburner.</td>
+    </tr>
+    <tr>
+      <td>cdantigen</td>
+      <td><code> cdantigen:CD233 </code></td>
+      <td>Lists all entries whose cluster of differentiation number
+        is CD233.</td>
+    </tr>
+    <tr>
+      <td>citation</td>
+      <td><code>
+          citation:("intracellular structural proteins") <br />
+          citation:(author:ashburner journal:nature) citation:9169874
+        </code></td>
+      <td>Lists all entries with a literature citation:
+        <ul>
+          <li>containing the phrase "intracellular structural
+            proteins" in either title or abstract</li>
+          <li>co-authored by Michael Ashburner and published in
+            Nature</li>
+          <li>with the PubMed identifier 9169874</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td>cluster</td>
+      <td><code> cluster:UniRef90_A5YMT3 </code></td>
+      <td>Lists all entries in the UniRef 90% identity cluster
+        whose representative sequence is UniProtKB entry A5YMT3.</td>
+    </tr>
+    <tr>
+      <td>count</td>
+      <td><code>
+          annotation:(type:transmem count:5)<br />
+          annotation:(type:transmem count:[5 TO *])<br />
+          annotation:(type:cofactor count:[3 TO *])
+        </code></td>
+      <td>Lists all entries with:
+        <ul>
+          <li>exactly 5 transmembrane regions</li>
+          <li>5 or more transmembrane regions</li>
+          <li>3 or more Cofactor comments</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td>created</td>
+      <td><code>
+          created:[20121001 TO *]<br /> reviewed:yes AND
+          created:[current TO *]
+        </code></td>
+      <td>Lists all entries created since October 1st 2012.<br />
         Lists all new UniProtKB/Swiss-Prot entries in the last release.
-    </td>
-  </tr>
-  <tr>
-    <td>database</td>
-    <td>
-      <code>
-        database:(type:pfam)
-        <br />
-        database:(type:pdb 1aut)
-      </code>
-    </td>
-    <td>
-      Lists all entries with:
-      <ul>
-        <li>a cross-reference to the Pfam database</li>
-        <li>a cross-reference to the PDB database entry 1aut</li>
-      </ul>
-     
-    </td>
-  </tr>
-  <tr>
-    <td>domain</td>
-    <td>
-      <code>
-        domain:VWFA
-      </code>
-    </td>
-    <td>
-        Lists all entries with a Von Willebrand factor type A domain described
-        in the 'Family and Domains' section.
-    </td>
-  </tr>
-  <tr>
-    <td>ec</td>
-    <td>
-      <code>
-        ec:3.2.1.23
-      </code>
-    </td>
-    <td>
-        Lists all beta-galactosidases.
-    </td>
-  </tr>
-  <tr>
-       <td>evidence</td>
-       <td>
-               <code>
-                       annotation:(type:signal evidence:ECO_0000269)<br />
-                       (type:mod_res phosphoserine evidence:ECO_0000269)<br />
-                       annotation:(type:function AND evidence:ECO_0000255)
-               </code>
-       </td>
-       <td>Lists all entries with:
-               <ul>
-                       <li>a signal sequence whose positions have been experimentally proven</li>
-                       <li>experimentally proven phosphoserine sites</li>
-                       <li>a function manually asserted according to rules</li>
-               </ul>
-       </td>
-  </tr>
-  <tr>
-    <td>family</td>
-    <td>
-      <code>
-        family:serpin
-      </code>
-    </td>
-    <td>
-        Lists all entries belonging to the Serpin family of proteins.
-    </td>
-  </tr>
-  <tr>
-    <td>fragment</td>
-    <td>
-      <code>
-        fragment:yes
-      </code>
-    </td>
-    <td>
-        Lists all entries with an incomplete sequence.
-    </td>
-  </tr>
+      </td>
+    </tr>
+    <tr>
+      <td>database</td>
+      <td><code>
+          database:(type:pfam) <br /> database:(type:pdb 1aut)
+        </code></td>
+      <td>Lists all entries with:
+        <ul>
+          <li>a cross-reference to the Pfam database</li>
+          <li>a cross-reference to the PDB database entry 1aut</li>
+        </ul>
+
+      </td>
+    </tr>
+    <tr>
+      <td>domain</td>
+      <td><code> domain:VWFA </code></td>
+      <td>Lists all entries with a Von Willebrand factor type A
+        domain described in the 'Family and Domains' section.</td>
+    </tr>
+    <tr>
+      <td>ec</td>
+      <td><code> ec:3.2.1.23 </code></td>
+      <td>Lists all beta-galactosidases.</td>
+    </tr>
+    <tr>
+      <td>evidence</td>
+      <td><code>
+          annotation:(type:signal evidence:ECO_0000269)<br />
+          (type:mod_res phosphoserine evidence:ECO_0000269)<br />
+          annotation:(type:function AND evidence:ECO_0000255)
+        </code></td>
+      <td>Lists all entries with:
+        <ul>
+          <li>a signal sequence whose positions have been
+            experimentally proven</li>
+          <li>experimentally proven phosphoserine sites</li>
+          <li>a function manually asserted according to rules</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td>family</td>
+      <td><code> family:serpin </code></td>
+      <td>Lists all entries belonging to the Serpin family of
+        proteins.</td>
+    </tr>
+    <tr>
+      <td>fragment</td>
+      <td><code> fragment:yes </code></td>
+      <td>Lists all entries with an incomplete sequence.</td>
+    </tr>
+
+    <tr>
+      <td>gene</td>
+      <td><code> gene:HSPC233 </code></td>
+      <td>Lists all entries for proteins encoded by gene HSPC233.</td>
+    </tr>
+    <tr>
+      <td>go</td>
+      <td><code>
+          go:cytoskeleton <br /> go:0015629
+        </code></td>
+      <td>Lists all entries associated with:
+        <ul>
+          <li>a GO term containing the word "cytoskeleton"</li>
+          <li>the GO term Actin cytoskeleton and any subclasses</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td>host</td>
+      <td><code>
+          host:mouse <br /> host:10090 <br /> host:40674
+        </code></td>
+      <td>Lists all entries for viruses infecting:
+        <ul>
+          <li>organisms with a name containing the word "mouse"</li>
+          <li>Mus musculus (Mouse)</li>
+          <li>all mammals (all taxa classified under the taxonomy
+            node for Mammalia)</li>
+        </ul>
+      </td>
+    </tr>
+    <tr>
+      <td>id</td>
+      <td><code>id:P00750</code></td>
+      <td>Returns the entry with the primary accession number
+        P00750.</td>
+    </tr>
+    <tr>
+      <td>inn</td>
+      <td><code> inn:Anakinra </code></td>
+      <td>Lists all entries whose "International Nonproprietary
+        Name" is Anakinra.</td>
+    </tr>
+    <tr>
+      <td>interactor</td>
+      <td><code> interactor:P00520 </code></td>
+      <td>Lists all entries describing interactions with the
+        protein described by entry P00520.</td>
+    </tr>
+    <tr>
+      <td>keyword</td>
+      <td><code> keyword:toxin </code></td>
+      <td>Lists all entries associated with the keyword Toxin.</td>
+    </tr>
+    <tr>
+      <td>length</td>
+      <td><code> length:[500 TO 700] </code></td>
+      <td>Lists all entries describing sequences of length between
+        500 and 700 residues.</td>
+    </tr>
+    <tr>
+      <td>lineage</td>
+      <td />
+      <td>This field is a synonym for the field <code>taxonomy</code>.
+      </td>
+    </tr>
+    <tr>
+      <td>mass</td>
+      <td><code> mass:[500000 TO *] </code></td>
+      <td>Lists all entries describing sequences with a mass of at
+        least 500,000 Da.</td>
+    </tr>
+    <tr>
+      <td>method</td>
+      <td><code>
+          method:maldi <br /> method:xray
+        </code></td>
+      <td>Lists all entries for proteins identified by:
+        matrix-assisted laser desorption/ionization (MALDI),
+        crystallography (X-Ray). The <code>method</code> field searches
+        names of physico-chemical identification methods in the
+        'Biophysicochemical properties' subsection of the 'Function'
+        section, the 'Publications' and 'Cross-references' sections.
+      </td>
+    </tr>
+    <tr>
+      <td>mnemonic</td>
+      <td><code> mnemonic:ATP6_HUMAN </code></td>
+      <td>Lists all entries with entry name (ID) ATP6_HUMAN.
+        Searches also obsolete entry names.</td>
+    </tr>
+    <tr>
+      <td>modified</td>
+      <td><code>
+          modified:[20120101 TO 20120301]<br /> reviewed:yes AND
+          modified:[current TO *]
+        </code></td>
+      <td>Lists all entries that were last modified between January
+        and March 2012.<br /> Lists all UniProtKB/Swiss-Prot entries
+        modified in the last release.
+      </td>
+    </tr>
+    <tr>
+      <td>name</td>
+      <td><code> name:"prion protein" </code></td>
+      <td>Lists all entries for prion proteins.</td>
+    </tr>
+    <tr>
+      <td>organelle</td>
+      <td><code> organelle:Mitochondrion </code></td>
+      <td>Lists all entries for proteins encoded by a gene of the
+        mitochondrial chromosome.</td>
+    </tr>
+    <tr>
+      <td>organism</td>
+      <td><code>
+          organism:"Ovis aries" <br /> organism:9940 <br />
+          organism:sheep <br />
+        </code></td>
+      <td>Lists all entries for proteins expressed in sheep (first
+        2 examples) and organisms whose name contains the term "sheep".
+      </td>
+    </tr>
 
-  <tr>
-    <td>gene</td>
-    <td>
-      <code>
-        gene:HSPC233
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins encoded by gene HSPC233.
-    </td>
-  </tr>
-  <tr>
-    <td>go</td>
-    <td>
-      <code>
-        go:cytoskeleton
-        <br />
-        go:0015629
-      </code>
-    </td>
-    <td>
-      Lists all entries associated with:
-      <ul>
-        <li>a GO term containing the word "cytoskeleton"</li>
-        <li>the GO term Actin cytoskeleton and any subclasses</li>
-      </ul>
-    </td>
-  </tr>
-  <tr>
-    <td>host</td>
-    <td>
-      <code>
-        host:mouse
-        <br />
-        host:10090
-        <br />
-        host:40674
-      </code>
-    </td>
-    <td>
-      Lists all entries for viruses infecting:
-      <ul>
-        <li>organisms with a name containing the word "mouse"</li>
-        <li>Mus musculus (Mouse)</li>
-        <li>all mammals (all taxa classified under the taxonomy node for Mammalia)</li>
-      </ul>
-    </td>
-  </tr>
-  <tr>
-    <td>id</td>
-    <td>
-      <code>id:P00750</code>
-    </td>
-    <td>
-        Returns the entry with the primary
-        accession number P00750.
-    </td>
-  </tr>
-  <tr>
-    <td>inn</td>
-    <td>
-      <code>
-        inn:Anakinra
-      </code>
-    </td>
-    <td>
-        Lists all entries whose "International Nonproprietary Name" is Anakinra.
-    </td>
-  </tr>
-  <tr>
-    <td>interactor</td>
-    <td>
-      <code>
-        interactor:P00520
-      </code>
-    </td>
-    <td>
-        Lists all entries describing interactions with the protein described by
-        entry P00520.
-    </td>
-  </tr>
-  <tr>
-    <td>keyword</td>
-    <td>
-      <code>
-        keyword:toxin
-      </code>
-    </td>
-    <td>
-        Lists all entries associated with the keyword Toxin.
-    </td>
-  </tr>
-  <tr>
-    <td>length</td>
-    <td>
-      <code>
-        length:[500 TO 700]
-      </code>
-    </td>
-    <td>
-        Lists all entries describing sequences of length between 500 and 700 residues.
-    </td>
-  </tr>
-  <tr>
-    <td>lineage</td>
-    <td />
-    <td>
-      This field is a synonym for the field <code>taxonomy</code>.
-    </td>
-  </tr>
-  <tr>
-    <td>mass</td>
-    <td>
-      <code>
-        mass:[500000 TO *]
-      </code>
-    </td>
-    <td>
-        Lists all entries describing sequences with a mass of at least 500,000 Da.
-    </td>
-  </tr>
-  <tr>
-    <td>method</td>
-    <td>
-      <code>
-        method:maldi
-        <br />
-        method:xray
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins identified by: matrix-assisted laser
-        desorption/ionization (MALDI), crystallography (X-Ray). The
-        <code>method</code> field searches names of physico-chemical
-        identification methods in the 'Biophysicochemical properties' subsection of the 'Function' section, the 'Publications' and
-        'Cross-references' sections.
-    </td>
-  </tr>
-  <tr>
-    <td>mnemonic</td>
-    <td>
-      <code>
-        mnemonic:ATP6_HUMAN
-      </code>
-    </td>
-    <td>
-        Lists all entries with entry name (ID) ATP6_HUMAN. Searches also
-        obsolete entry names.
-    </td>
-  </tr>
-  <tr>
-    <td>modified</td>
-    <td>
-      <code>
-        modified:[20120101 TO 20120301]<br />
-        reviewed:yes AND modified:[current TO *]
-      </code>
-    </td>
-    <td>
-        Lists all entries that were last modified between January and March 2012.<br />
-        Lists all UniProtKB/Swiss-Prot entries modified in the last release.
-    </td>
-  </tr>
-  <tr>
-    <td>name</td>
-    <td>
-      <code>
-        name:"prion protein"
-      </code>
-    </td>
-    <td>
-        Lists all entries for prion proteins.
-    </td>
-  </tr>
-  <tr>
-    <td>organelle</td>
-    <td>
-      <code>
-        organelle:Mitochondrion
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins encoded by a gene of the mitochondrial
-        chromosome.
-    </td>
-  </tr>
-  <tr>
-    <td>organism</td>
-    <td>
-      <code>
-        organism:"Ovis aries"
-        <br />
-        organism:9940
-        <br />
-        organism:sheep
-        <br />
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins expressed in sheep (first 2 examples) and
-        organisms whose name contains the term "sheep".
-    </td>
-  </tr>
-  <tr>
-    <td>plasmid</td>
-    <td>
-      <code>
-        plasmid:ColE1
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins encoded by a gene of plasmid ColE1.
-    </td>
-  </tr>
-  <tr>
-    <td>proteome</td>
-    <td>
-      <code>
-        proteome:UP000005640
-      </code>
-    </td>
-    <td>
-        Lists all entries from the human proteome.
-    </td>
-  </tr>
-  <tr>
-    <td>proteomecomponent</td>
-    <td>
-      <code>
-        proteomecomponent:"chromosome 1" and organism:9606
-      </code>
-    </td>
-    <td>
-        Lists all entries from the human chromosome 1.
-    </td>
-  </tr>
-  <tr>
-    <td>replaces</td>
-    <td>
-      <code>
-        replaces:P02023
-      </code>
-    </td>
-    <td>
-        Lists all entries that were created from a merge with entry P02023.
-    </td>
-  </tr>
-  <tr>
-    <td>reviewed</td>
-    <td>
-      <code>
-        reviewed:yes
-      </code>
-    </td>
-    <td>
-        Lists all UniProtKB/Swiss-Prot entries.
-    </td>
-  </tr>
-  <tr>
-    <td>scope</td>
-    <td>
-      <code>
-        scope:mutagenesis
-      </code>
-    </td>
-    <td>
-        Lists all entries containing a reference that was used to gather
-        information about mutagenesis.
-    </td>
-  </tr>
-  <tr>
-    <td>sequence</td>
-    <td>
-      <code>
-        sequence:P05067-9
-      </code>
-    </td>
-    <td>
-        Lists all entries containing a link to isoform 9 of the sequence
-        described in entry P05067. Allows searching by specific sequence
-        identifier.
-    </td>
-  </tr>
-  <tr>
-    <td>sequence_modified</td>
-    <td>
-      <code>
-        sequence_modified:[20120101 TO 20120301]<br />
-        reviewed:yes AND sequence_modified:[current TO *]
-      </code>
-    </td>
-    <td>
-        Lists all entries whose sequences were last modified between January and March 2012.<br />
-        Lists all UniProtKB/Swiss-Prot entries whose sequences were modified in the last release.
-    </td>
-  </tr>
-  <tr>
-    <td>source</td>
-    <td>
-      <code>
-        source:intact
-      </code>
-    </td>
-    <td>
-        Lists all entries containing a GO term whose annotation source is the
-        IntAct database.
-    </td>
-  </tr>
-  <tr>
-    <td>strain</td>
-    <td>
-      <code>
-        strain:wistar
-      </code>
-    </td>
-    <td>
-        Lists all entries containing a reference relevant to strain wistar.
-    </td>
-  </tr>
-  <tr>
-    <td>taxonomy</td>
-    <td>
-      <code>
-        taxonomy:40674
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins expressed in Mammals. This field is used to retrieve
-        entries for all organisms classified below a given taxonomic node taxonomy classification).
-    </td>
-  </tr>
-  <tr>
-    <td>tissue</td>
-    <td>
-      <code>
-        tissue:liver
-      </code>
-    </td>
-    <td>
-        Lists all entries containing a reference describing the protein sequence
-        obtained from a clone isolated from liver.
-    </td>
-  </tr>
-  <tr>
-    <td>web</td>
-    <td>
-      <code>
-        web:wikipedia
-      </code>
-    </td>
-    <td>
-        Lists all entries for proteins that are described in Wikipedia.
-    </td>
-  </tr>
-</table>
+    <tr>
+      <td>plasmid</td>
+      <td><code> plasmid:ColE1 </code></td>
+      <td>Lists all entries for proteins encoded by a gene of
+        plasmid ColE1.</td>
+    </tr>
+    <tr>
+      <td>proteome</td>
+      <td><code> proteome:UP000005640 </code></td>
+      <td>Lists all entries from the human proteome.</td>
+    </tr>
+    <tr>
+      <td>proteomecomponent</td>
+      <td><code> proteomecomponent:"chromosome 1" and
+          organism:9606 </code></td>
+      <td>Lists all entries from the human chromosome 1.</td>
+    </tr>
+    <tr>
+      <td>replaces</td>
+      <td><code> replaces:P02023 </code></td>
+      <td>Lists all entries that were created from a merge with
+        entry P02023.</td>
+    </tr>
+    <tr>
+      <td>reviewed</td>
+      <td><code> reviewed:yes </code></td>
+      <td>Lists all UniProtKB/Swiss-Prot entries.</td>
+    </tr>
+    <tr>
+      <td>scope</td>
+      <td><code> scope:mutagenesis </code></td>
+      <td>Lists all entries containing a reference that was used to
+        gather information about mutagenesis.</td>
+    </tr>
+    <tr>
+      <td>sequence</td>
+      <td><code> sequence:P05067-9 </code></td>
+      <td>Lists all entries containing a link to isoform 9 of the
+        sequence described in entry P05067. Allows searching by specific
+        sequence identifier.</td>
+    </tr>
+    <tr>
+      <td>sequence_modified</td>
+      <td><code>
+          sequence_modified:[20120101 TO 20120301]<br /> reviewed:yes
+          AND sequence_modified:[current TO *]
+        </code></td>
+      <td>Lists all entries whose sequences were last modified
+        between January and March 2012.<br /> Lists all
+        UniProtKB/Swiss-Prot entries whose sequences were modified in
+        the last release.
+      </td>
+    </tr>
+    <tr>
+      <td>source</td>
+      <td><code> source:intact </code></td>
+      <td>Lists all entries containing a GO term whose annotation
+        source is the IntAct database.</td>
+    </tr>
+    <tr>
+      <td>strain</td>
+      <td><code> strain:wistar </code></td>
+      <td>Lists all entries containing a reference relevant to
+        strain wistar.</td>
+    </tr>
+    <tr>
+      <td>taxonomy</td>
+      <td><code> taxonomy:40674 </code></td>
+      <td>Lists all entries for proteins expressed in Mammals. This
+        field is used to retrieve entries for all organisms classified
+        below a given taxonomic node taxonomy classification).</td>
+    </tr>
+    <tr>
+      <td>tissue</td>
+      <td><code> tissue:liver </code></td>
+      <td>Lists all entries containing a reference describing the
+        protein sequence obtained from a clone isolated from liver.</td>
+    </tr>
+    <tr>
+      <td>web</td>
+      <td><code> web:wikipedia </code></td>
+      <td>Lists all entries for proteins that are described in
+        Wikipedia.</td>
+    </tr>
+  </table>
 
 </body>
 </html>
\ No newline at end of file
index 9b2e3fa..edd8995 100644 (file)
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
 <head>
-<title>The Uniprot Free Text Search Interface</title>
+<title>The UniProt Free Text Search Interface</title>
 </head>
 <body>
 
-  <strong>The Uniprot Free Text Search Interface</strong>
+  <strong>The UniProt Free Text Search Interface</strong>
+  <br /> Since version 2.10 (October 2016), the Jalview Desktop
+  provides a search interface for interactive discovery and retrieval of
+  sequence data from UniProt. This dialog enables UniProt sequence
+  metadata to be searched with free text and structured queries, which
+  allows sequences to be located via gene name, keywords, or even
+  <em>via</em> manual cross-referencing from UniProt or other
+  bioinformatics websites.
   <p>
-    Jalview provides a specialised interface that allows fast and
-    efficient discovery and retrieval of data from the Uniprot database.
-    It allows
-    interactive querying of Uniprot metadata with free text and structured
-    queries, so sequences can be located without prior knowledge of
-    their database accessions, or <em>via</em> manual cross-referencing
-    from Uniprot or other bioinformatics websites.
+    To open the UniProt Sequence Fetcher, select UniProt as the database
+    from any <a href="seqfetch.html">Sequence Fetcher</a> dialog (opened
+    <em>via</em> <strong>&quot;File &#8594;Fetch
+      Sequences&quot;</strong>).
   </p>
   <p>
-    To open the UniProt Sequence Fetcher, select UniProt as the database from
-    any <a href="seqfetch.html">Sequence Fetcher</a> dialog (opened <em>via</em>
-    <strong>&quot;File &#8594;Fetch Sequences&quot;</strong>).
-  </p>
-  <p>
-  <img src="uniprotseqfetcher.png" align="left"
-    alt="Uniprot sequence fetcher (introduced in Jalview 2.9.1)"
-  />
+    <img src="uniprotseqfetcher.png" align="left"
+      alt="UniProt sequence fetcher (introduced in Jalview 2.10)" />
   </p>
 
   <p>
-    <strong>Searching the Uniprot Database</strong>
+    <strong>Searching the UniProt Database</strong>
   </p>
   <p>
-    To search the Uniprot, begin typing in the text box. The results of your
-    query are shown in the search results tab, which queries Uniprot after 1.5secs every time
-    you type in the search text box. You can sort results according to
-    the displayed columns, and select entries with the mouse or
-    keyboard. Once you have selected one or more entries, hit the <strong>OK</strong>
-    button to retrieve and visualise the sequences in Jalview Alignment interface.
+    To search UniProt, simply begin typing in the text box. After a
+    short delay (about 1.5 seconds), results will be shown in the table
+    below. You can sort results by clicking on the displayed columns,
+    and select entries with the mouse or keyboard. Once you have
+    selected one or more entries, hit the <strong>OK</strong> button to
+    retrieve the sequences.
   </p>
   <ul>
-    <li><strong>Searching a specific Uniprot field </strong> If you
-      want to find sequences based on a specific Uniprot metadata field,
-      you can select it from the drop-down menu.</li>
-      
+    <li><strong>Searching a specific UniProt field </strong> To
+      find sequences with particular UniProt metadata, you can select a
+      field to search from the drop-down menu.</li>
+
+
+    <li><strong>Bulk UniProt record retrieval</strong><br> To
+      retrieve several uniprot accessions at once, first select <strong>UniProt
+        ID</strong> from the dropdown menu, then paste in the accession IDs as a
+      semi-colon separated list. (e.g. fila_human; mnt_human;
+      mnt_mouse).<br />Hitting Return or OK will automatically fetch
+      those IDs, like the default Sequence Fetcher interface.</li>
 
-               <li><strong>Bulk Uniprot retrieval</strong><br>
-      Firstly, switch the search target to Uniprot Id, then enter multiple IDs by separating them with a semi-colon.
-      e.g. fila_human; mnt_human; mnt_mouse.<br />Hitting Return or OK will automatically
-      fetch those IDs, like the default Sequence Fetcher interface.</li>
-      
-            <li><strong>Advanced / Custom querying</strong>  
-      The table below provides a brief overview of the supported Uniprot query syntax (see <a href="uniprotqueryfields.html">query fields for UniProtKB</a>):
-               <table border="1" width="95%">
-                               <tr>
-                                       <td><code>human antigen</code></td>
-                                       <td rowspan="3">All entries containing both terms.</td>
-                               </tr>
-                               <tr>
-                                       <td><code>human AND antigen</code></td>
-                               </tr>
-                               <tr>
-                                       <td><code>human &amp;&amp; antigen</code></td>
-                               </tr>
-                               <tr>
-                                       <td><code>"human antigen"</code></td>
-                                       <td>All entries containing both terms in the exact order.</td>
-                               </tr>
-                               <tr>
-                                       <td><code>human -antigen</code></td>
-                                       <td rowspan="3">All entries containing the term <code>human</code>
-                                               but not <code>antigen</code>.
-                                       </td>
-                               </tr>
-                               <tr>
-                                       <td><code>human NOT antigen</code></td>
-                               </tr>
-                               <tr>
-                                       <td><code>human ! antigen</code></td>
-                               </tr>
-                               <tr>
-                                       <td><code>human OR mouse</code></td>
-                                       <td rowspan="2">All entries containing either term.</td>
-                               </tr>
-                               <tr>
-                                       <td><code>human || mouse</code></td>
-                               </tr>
-                               <tr>
-                                       <td><code>antigen AND (human OR mouse)</code></td>
-                                       <td>Using parentheses to override boolean precedence rules.</td>
-                               </tr>
-                               <tr>
-                                       <td><code>anti*</code></td>
-                                       <td>All entries containing terms starting with <code>anti</code>.
-                                               Asterisks can also be used at the beginning and within terms. <strong>Note:</strong>
-                                               Terms starting with an asterisk or a single letter followed by an
-                                               asterisk can slow down queries considerably.
-                                       </td>
-                               </tr>
-                               <tr>
-                                       <td><code> author:Tiger*</code></td>
-                                       <td>Citations that have an author whose name starts with <code>Tiger</code>.
-                                               To search in a specific field of a dataset, you must prefix your
-                                               search term with the field name and a colon. To discover what
-                                               fields can be queried explicitly, observe the query hints that are
-                                               shown after submitting a query or use the query builder (see
-                                               below).
-                                       </td>
-                               </tr>
-                               <tr>
-                                       <td><code>length:[100 TO *]</code></td>
-                                       <td>All entries with a sequence of at least 100 amino acids.</td>
-                               </tr>
-                               <tr>
-                                       <td><code>citation:(author:Arai author:Chung)</code></td>
-                                       <td>All entries with a publication that was coauthored by two
-                                               specific authors.</td>
-                               </tr>
-                       </table>
-               </li>
-</ul>
+    <li><strong><a name="text-search">Complex queries
+          with the UniProt query Syntax</a></strong> The text box also allows complex
+      queries to be entered. The table below provides a brief overview
+      of the supported syntax (see <a href="uniprotqueryfields.html">query
+        fields for UniProtKB</a>):
+      <table border="1" width="95%">
+        <tr>
+          <td><code>human antigen</code></td>
+          <td rowspan="3">All entries containing both terms.</td>
+        </tr>
+        <tr>
+          <td><code>human AND antigen</code></td>
+        </tr>
+        <tr>
+          <td><code>human &amp;&amp; antigen</code></td>
+        </tr>
+        <tr>
+          <td><code>"human antigen"</code></td>
+          <td>All entries containing both terms in the exact order.</td>
+        </tr>
+        <tr>
+          <td><code>human -antigen</code></td>
+          <td rowspan="3">All entries containing the term <code>human</code>
+            but not <code>antigen</code>.
+          </td>
+        </tr>
+        <tr>
+          <td><code>human NOT antigen</code></td>
+        </tr>
+        <tr>
+          <td><code>human ! antigen</code></td>
+        </tr>
+        <tr>
+          <td><code>human OR mouse</code></td>
+          <td rowspan="2">All entries containing either term.</td>
+        </tr>
+        <tr>
+          <td><code>human || mouse</code></td>
+        </tr>
+        <tr>
+          <td><code>antigen AND (human OR mouse)</code></td>
+          <td>Using parentheses to override boolean precedence
+            rules.</td>
+        </tr>
+        <tr>
+          <td><code>anti*</code></td>
+          <td>All entries containing terms starting with <code>anti</code>.
+            Asterisks can also be used at the beginning and within
+            terms. <strong>Note:</strong> Terms starting with an
+            asterisk or a single letter followed by an asterisk can slow
+            down queries considerably.
+          </td>
+        </tr>
+        <tr>
+          <td><code> author:Tiger*</code></td>
+          <td>Citations that have an author whose name starts with
+            <code>Tiger</code>. To search in a specific field of a
+            dataset, you must prefix your search term with the field
+            name and a colon. To discover what fields can be queried
+            explicitly, observe the query hints that are shown after
+            submitting a query or use the query builder (see below).
+          </td>
+        </tr>
+        <tr>
+          <td><code>length:[100 TO *]</code></td>
+          <td>All entries with a sequence of at least 100 amino
+            acids.</td>
+        </tr>
+        <tr>
+          <td><code>citation:(author:Arai author:Chung)</code></td>
+          <td>All entries with a publication that was coauthored by
+            two specific authors.</td>
+        </tr>
+      </table></li>
+  </ul>
   <p>
     <strong>Result pagination</strong>
   </p>
-  The query results returned from the Uniprot server are paginated for performance optimisation. 
-  The button labelled <strong>'&nbsp;&lt;&lt;&nbsp;'</strong> and <strong>'&nbsp;&gt;&gt;&nbsp;'</strong> can be used to navigate to the next or previous result page respectively. 
-  The page range is shown on the title bar of the Free Text Search interface. Jalview's pagination implementation supports multiple selection of entries across multiple pages. 
-  
-  
- <p>
-    <strong>Customising The Uniprot Sequence Fetcher</strong>
-  </p>
+  The query results returned from the UniProt server are paginated for
+  performance optimisation. The button labelled
+  <strong>'&nbsp;&lt;&lt;&nbsp;'</strong> and
+  <strong>'&nbsp;&gt;&gt;&nbsp;'</strong> can be used to navigate to the
+  next or previous result page respectively. The page range is shown on
+  the title bar of the Free Text Search interface. Jalview's pagination
+  implementation supports multiple selection of entries across multiple
+  pages.
+
+
   <p>
-    To change the displayed meta-data in the search result, click the
-    'Customise Displayed Options' tab, and select the fields you'd like
-    to displayed or remove. 
+    <strong>Customising The UniProt Sequence Fetcher</strong>
   </p>
+  <p>To change the displayed meta-data in the search result, click
+    the 'Customise Displayed Options' tab, and select the fields you'd
+    like to be displayed or removed.</p>
   <p>
-    <em>The Uniprot Free Test Search Interface was introduced in
-      Jalview 2.9.1</em>
+    <em>The UniProt Free Test Search Interface was introduced in
+      Jalview 2.10.0</em>
   </p>
 </body>
 </html>
\ No newline at end of file
index ce446f3..77f56dc 100644 (file)
@@ -27,9 +27,9 @@
     <strong>The VARNA RNA Viewer</strong>
   </p>
   <p>
-    <a href="http://varna.lri.fr">VARNA</a> was integrated
-    into Jalview 2.8 to allow interactive viewing of RNA secondary
-    structure annotation. It is opened by selecting the <strong>&quot;Structure&#8594;View
+    <a href="http://varna.lri.fr">VARNA</a> was integrated into Jalview
+    2.8 to allow interactive viewing of RNA secondary structure
+    annotation. It is opened by selecting the <strong>&quot;Structure&#8594;View
       Structure:&quot;</strong> option in the <a href="../menus/popupMenu.html">sequence
       id pop-up menu</a> (if you can't see this, then no RNA structure is
     associated with your sequence or alignment). In the pop-up menu all
@@ -86,8 +86,8 @@
   <p>
     VARNA is a very powerful RNA viewer on its own. Only the essentials
     have been described here - the interested reader is referred to <a
-      href="http://varna.lri.fr/index.php?page=manual&css=varna"
-    >VARNA's own comprehensive online documentation</a>.
+      href="http://varna.lri.fr/index.php?page=manual&css=varna">VARNA's
+      own comprehensive online documentation</a>.
   </p>
 </body>
 </html>
index d4819f1..f60da1a 100755 (executable)
 </head>
 <body>
   <p>
-    <strong>Viewing PDB Structures</strong>
+    <strong>Discovering and Viewing PDB Structures</strong>
   </p>
-  Jalview can be used to view protein structures by following the steps
-  below:
+  Jalview can be used to explore the 3D structures of sequences in an
+  alignment by following the steps below:
   <ol>
     <li>Select the <strong>"3D Structure Data..."</strong> option
       from a sequence's <a href="../menus/popupMenu.html">pop-up
           pane.
         </li>
         <li>However, if no structure was found, the <a
-          href="structurechooser.html"
-        >Structure Chooser</a> interface will present options for manual
-          association of PDB structures.
+          href="structurechooser.html">Structure Chooser</a> interface
+          will present options for manual association of PDB structures.
         </li>
       </ul>
     </li>
-    <li><strong>Selecting Structures</strong><br /> If structures
-      have been discovered, then some will already be selected according
-      to predefined selection criteria, such as structures with the
-      highest resolution. Use the drop down menu to select structures
-      according to different criteria, or, alternatively, choose
-      structures manually by selecting with the keyboard and mouse.
+    <li><strong>Selecting Structures</strong><br />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
+      criteria shown in the drop-down menu. The default criteria is
+      'highest resolution', simply choose another to pick structures in
+      a different way.<br />
       <ul>
-        <li><strong>Viewing Cached Structures</strong><br />If you
-          have previously downloaded structures for your sequences, they
-          can be viewed by selecting the <strong>Cached PDB
-            Entries</strong> option from the drop down menu at the top of the
-          dialog box.</li>
+        <li><strong>Viewing Cached Structures</strong><br />If
+          previously downloaded structures are available for your
+          sequences, the structure chooser will automatically offer them
+          via the <strong>Cached PDB Entries</strong> view. If you wish
+          to download new structures, select one of the PDBe selection
+          criteria from the drop-down menu.</li>
+      </ul></li>
+    <li><strong>To view selected structures, click the <strong>"View"</strong>
+        button.
+    </strong><br />
+      <ul>
+        <li>Additional structure data will be downloaded with the
+          EMBL-EBI's dbfetch service</li>
+        <li><a href="siftsmapping.html">SIFTS</a> records will also
+          be downloaded for mapping UniProt protein sequence data to PDB
+          coordinates.</li>
+        <li>A new structure viewer will open, or you will be
+          prompted to add structures to existing viewers (see <a
+          href="#afterviewbutton">below</a> for details).
+        </li>
       </ul></li>
-    <li>To view selected structures, click the <strong>"View"</strong>
-      button.
-    </li>
   </ol>
-
+  <p>
+  <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
     the <a href="xsspannotation.html">Annotation from Structure</a> page
     for more information.
   </p>
-
   <p>
-    If a <strong>single</strong> PDB structure is selected, one of the
-    following will happen:
+    <strong><a name="afterviewbutton">After pressing the
+        'View' button in the Structure Chooser</a></strong><br /> The behaviour of
+    the 'View' button depends on the number of structures selected, and
+    whether structure views already exist for the selected structures or
+    aligned sequences.
+  </p>
+  <p>
+    If multiple structures are selected, then Jalview will always create
+    a new structure view. The selected structures will be imported into
+    this view, and superposed with the matched positions from the
+    aligned sequences.<br /> If a <strong>single</strong> PDB structure
+    is selected, one of the following will happen:
   </p>
 
   <ul>
 
     <li>If another structure is already shown for the current
       alignment, then you will be asked if you want to add and <a
-      href="jmol.html#align"
-    >align this structure</a> to the structure in the existing view. (<em>new
-        feature in Jalview 2.6</em>).
-    </li>
+      href="jmol.html#align"></a> to
+    the structure in the existing view. (<em>new feature in Jalview
+      2.6</em>).
+  </li>
 
     <li>If the structure is already shown, then you will be
       prompted to associate the sequence with an existing view of the
 
 
   <p>
-    <strong>Importing PDB Entries or files in PDB format</strong><br>
-    You can retrieve sequences from the PDB using the <a
-      href="pdbsequencefetcher.html"
-    >Sequence Fetcher</a>. Any sequences retrieved with this service are
-    automatically associated with their source database entry. For PDB
-    sequences, simply select PDB as the database and enter your known
-    PDB id (appended with ':' and a chain code, if desired).<br>
-    Jalview will also read PDB files directly. Simply load in the file
+    <strong>Retrieving sequences from the PDB</strong><br>You can
+    retrieve sequences from the PDB using the <a
+      href="pdbsequencefetcher.html">Sequence Fetcher</a>. The sequences
+    retrieved with this service are derived directly from the PDB 3D
+    structure data, which can be viewed in the same way above. Secondary
+    structure and temperature factor annotation can also be added. <br />
+
+    <br>Jalview will also read PDB files directly - either in PDB
+    format, or <a href="mmcif.html">mmCIF</a>. Simply load in the file
     as you would an alignment file. The sequences of any protein or
     nucleotide chains will be extracted from the file and viewed in the
     alignment window.
   </p>
 
   <p>
-    <strong>Importing PDB Entries or files in mmCIF format</strong><br>
-    <a href="mmcif.html">mmCIF file format</a> provides an alternative means for 
-    importing 3D structure data from flat file and EMBL-PDBe 
-    web-service. To enable mmCIF as the default format for 
-    importing PBD sequences from the PDB sequence fetcher, add or modify the 
-    property  
-    <code>DEFAULT_STRUCTURE_FORMAT=mmCIF</code> in Jalview properties file. 
-    Once this is done, the steps followed in retrieving PDB format files above can 
-    be followed to obtain the same data with mmCIF. <em>mmCIF format file support was added in Jalview 2.9.1.</em></p>
-    
-   
-
-  <p>
     <strong>Associating a large number of PDB files to
       sequences in an alignment</strong><br /> It is often the case when working
     with structure alignments that you will have a directory of PDB
     desktop, Jalview will give you the option of associating PDB files
     with sequences that have the same filename. This means, for example,
     you can automatically associate PDB files with names like '1gaq.pdb'
-    with sequences that have an ID like '1gaq'. <br />
-    <em>Note: This feature was added in Jalview 2.7</em>
+    with sequences that have an ID like '1gaq'. <br /> <em>Note:
+      This feature was added in Jalview 2.7</em>
   </p>
   <p>
     <em>Note for Jalview applet users:<br> Due to the applet
       Features"</strong> menu item and the <a href="featuresettings.html">Feature
       Settings dialog box</a>.
   </p>
+  <br />
+  <hr>
+  <p>
+    <strong>Switching between mmCIF and PDB format for
+      downloading files from the PDB</strong><br /> Jalview now employs the <a
+      href="mmcif.html">mmCIF format</a> for importing 3D structure data
+    from flat file and EMBL-PDBe web-service, as recommended by the
+    wwwPDB. If you prefer (for any reason) to download data as PDB files
+    instead, then first close Jalview, and add the following line to
+    your .jalview_properties file:<br />
+    <code> PDB_DOWNLOAD_FORMAT=PDB </code>
+    <br /> When this setting is configured, Jalview will only request
+    PDB format files from EMBL-EBI's PDBe.<br /> <em>mmCIF format
+      file support was added in Jalview 2.10.</em>
+  </p>
 
   <p>
     <em><strong>Outstanding problem with cut'n'pasted
-        files in Jalview 2.6 and Jalview 2.7</strong><br> Structures
-      imported via the cut'n'paste dialog box will not be correctly
-      highlighted or coloured when they are displayed in structure
-      views, especially if they contain more than one PDB structure. See
-      the bug report at http://issues.jalview.org/browse/JAL-623 for
-      news on this problem.</em>
+        files in Jalview 2.6 and Jalview 2.7</strong><br>Structures imported
+      via the cut'n'paste dialog box will not be correctly highlighted
+      or coloured when they are displayed in structure views, especially
+      if they contain more than one PDB structure. See the bug report at
+      http://issues.jalview.org/browse/JAL-623 for news on this problem.</em>
   </p>
+
 </body>
 </html>
 
index 1c6ab7b..870b005 100644 (file)
     tab in the <strong>Tools&rarr;Preferences</strong> dialog allow the
     processing of structure data to be disabled, or selectively enabled.
     For more information, take a look at the <a
-      href="preferences.html#structure"
-    >documentation for the structure panel</a>.
+      href="preferences.html#structure">documentation for the
+      structure panel</a>.
   </p>
   <p>
     <em>The display of secondary structure data was introduced in
       Jalview 2.8.2, and is made possible by Jalview's use of <a
-      href="jmol.html"
-    >Jmol's DSSP implementation</a>, based on the original <a
-      href="http://www.ncbi.nlm.nih.gov/pubmed/6667333"
-    >Kabsch and Sander algorithm</a> ported by <a
-      href="http://swift.cmbi.ru.nl/gv/dssp/"
-    >Robbie P. Joosten and colleagues</a>, and a client for <a
-      href="https://github.com/fjossinet/PyRNA"
-    >Fabrice Jossinet's pyRNA services</a> that was developed by Anne
-      Menard, Jim Procter and Yann Ponty as part of the Jalview Summer
-      of Code 2012.
+      href="jmol.html">Jmol's DSSP implementation</a>, based on the
+      original <a href="http://www.ncbi.nlm.nih.gov/pubmed/6667333">Kabsch
+        and Sander algorithm</a> ported by <a
+      href="http://swift.cmbi.ru.nl/gv/dssp/">Robbie P. Joosten
+        and colleagues</a>, and a client for <a
+      href="https://github.com/fjossinet/PyRNA">Fabrice
+        Jossinet's pyRNA services</a> that was developed by Anne Menard, Jim
+      Procter and Yann Ponty as part of the Jalview Summer of Code 2012.
     </em>
   </p>
 </body>
diff --git a/help/html/groovy/featureCounter.html b/help/html/groovy/featureCounter.html
new file mode 100644 (file)
index 0000000..2ebaf45
--- /dev/null
@@ -0,0 +1,269 @@
+<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>Extending Jalview with Groovy - Feature Counter Example</title>
+</head>
+<body>
+  <p>
+    <strong>Extending Jalview with Groovy - A customisable
+      feature counter</strong><br /> <br />The groovy script below shows how to
+    add a new calculation track to a Jalview alignment window.
+  </p>
+  <p>As currently written, it will add two tracks to a protein
+    alignment view which count Pfam features in each column, and ones
+    where a charge residue also occur.</p>
+  <p>To try it for yourself:</p>
+  <ol>
+    <li>Copy and paste it into the groovy script console</li>
+    <li>Load the example Feredoxin project (the one that opens by
+      default when you first launched Jalview)</li>
+    <li>Select <strong>Calculations&#8594;Execute Groovy
+        Script</strong> from the alignment window's menu bar to run the script on
+      the current view.
+    </li>
+  </ol>
+  <em><a
+    href="http://www.jalview.org/examples/groovy/featureCounter.groovy">http://www.jalview.org/examples/groovy/featureCounter.groovy</a>
+    - rendered with <a href="http://hilite.me">hilite.me</a></em>
+  <!-- HTML generated using hilite.me -->
+  <div
+    style="background: #ffffff; 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: #888888">/*</span>
+<span style="color: #888888"> * Jalview - A Sequence Alignment Editor and Viewer (Version 2.10)</span>
+<span style="color: #888888"> * Copyright (C) 2016 The Jalview Authors</span>
+<span style="color: #888888"> * </span>
+<span style="color: #888888"> * This file is part of Jalview.</span>
+<span style="color: #888888"> * </span>
+<span style="color: #888888"> * Jalview is free software: you can redistribute it and/or</span>
+<span style="color: #888888"> * modify it under the terms of the GNU General Public License </span>
+<span style="color: #888888"> * as published by the Free Software Foundation, either version 3</span>
+<span style="color: #888888"> * of the License, or (at your option) any later version.</span>
+<span style="color: #888888"> *  </span>
+<span style="color: #888888"> * Jalview is distributed in the hope that it will be useful, but </span>
+<span style="color: #888888"> * WITHOUT ANY WARRANTY; without even the implied warranty </span>
+<span style="color: #888888"> * of MERCHANTABILITY or FITNESS FOR A PARTICULAR </span>
+<span style="color: #888888"> * PURPOSE.  See the GNU General Public License for more details.</span>
+<span style="color: #888888"> * </span>
+<span style="color: #888888"> * You should have received a copy of the GNU General Public License</span>
+<span style="color: #888888"> * along with Jalview.  If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>
+<span style="color: #888888"> * The Jalview Authors are detailed in the &#39;AUTHORS&#39; file.</span>
+<span style="color: #888888"> */</span>
+<span style="color: #008800; font-weight: bold">import</span> <span
+        style="color: #0e84b5; font-weight: bold">jalview.workers.FeatureCounterI</span><span
+        style="color: #333333">;</span>
+<span style="color: #008800; font-weight: bold">import</span> <span
+        style="color: #0e84b5; font-weight: bold">jalview.workers.AlignmentAnnotationFactory</span><span
+        style="color: #333333">;</span>
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * Example script that registers two alignment annotation calculators</span>
+<span style="color: #888888"> * - one that counts residues in a column with Pfam annotation</span>
+<span style="color: #888888"> * - one that counts only charged residues with Pfam annotation</span>
+<span style="color: #888888"> *</span>
+<span style="color: #888888"> * To try:</span>
+<span style="color: #888888"> * 1. load uniref50.fa from the examples folder</span>
+<span style="color: #888888"> * 2. load features onto it from from examples/exampleFeatures.txt</span>
+<span style="color: #888888"> * 3. Open this script in the Groovy console.</span>
+<span style="color: #888888"> * 4. Either execute this script from the console, or via Calculate-&gt;Run Groovy Script</span>
+<span style="color: #888888"> </span>
+<span style="color: #888888"> * To explore further, try changing this script to count other kinds of occurrences of </span>
+<span style="color: #888888"> * residue and sequence features at columns in an alignment.</span>
+<span style="color: #888888"> */</span>
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * A closure that returns true for any Charged residue</span>
+<span style="color: #888888"> */</span>
+<span style="color: #333399; font-weight: bold">def</span> isCharged <span
+        style="color: #333333">=</span> <span style="color: #333333">{</span> residue <span
+        style="color: #333333">-&gt;</span>
+    <span style="color: #008800; font-weight: bold">switch</span><span
+        style="color: #333333">(</span>residue<span
+        style="color: #333333">)</span> <span style="color: #333333">{</span>
+        <span style="color: #008800; font-weight: bold">case</span> <span
+        style="color: #333333">[</span><span
+        style="background-color: #fff0f0">&#39;D&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;d&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;E&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;e&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;H&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;h&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;K&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;k&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;R&#39;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&#39;r&#39;</span><span
+        style="color: #333333">]:</span>
+            <span style="color: #008800; font-weight: bold">return</span> <span
+        style="color: #008800; font-weight: bold">true</span>
+    <span style="color: #333333">}</span>
+    <span style="color: #008800; font-weight: bold">false</span>
+<span style="color: #333333">}</span> 
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * A closure that returns 1 if sequence features include type &#39;Pfam&#39;, else 0</span>
+<span style="color: #888888"> * Argument should be a list of SequenceFeature </span>
+<span style="color: #888888"> */</span>
+<span style="color: #333399; font-weight: bold">def</span> hasPfam <span
+        style="color: #333333">=</span> <span style="color: #333333">{</span> features <span
+        style="color: #333333">-&gt;</span> 
+    <span style="color: #008800; font-weight: bold">for</span> <span
+        style="color: #333333">(</span>sf <span
+        style="color: #008800; font-weight: bold">in</span> features<span
+        style="color: #333333">)</span>
+    <span style="color: #333333">{</span>
+        <span style="color: #888888">/*</span>
+<span style="color: #888888">         * Here we inspect the type of the sequence feature.</span>
+<span style="color: #888888">         * You can also test sf.description, sf.score, sf.featureGroup,</span>
+<span style="color: #888888">         * sf.strand, sf.phase, sf.begin, sf.end</span>
+<span style="color: #888888">         * or sf.getValue(attributeName) for GFF &#39;column 9&#39; properties</span>
+<span style="color: #888888">         */</span>
+        <span style="color: #008800; font-weight: bold">if</span> <span
+        style="color: #333333">(</span><span
+        style="background-color: #fff0f0">&quot;Pfam&quot;</span><span
+        style="color: #333333">.</span><span style="color: #0000CC">equals</span><span
+        style="color: #333333">(</span>sf<span style="color: #333333">.</span><span
+        style="color: #0000CC">type</span><span style="color: #333333">))</span>
+        <span style="color: #333333">{</span>
+            <span style="color: #008800; font-weight: bold">return</span> <span
+        style="color: #008800; font-weight: bold">true</span>
+        <span style="color: #333333">}</span>
+    <span style="color: #333333">}</span>
+    <span style="color: #008800; font-weight: bold">false</span>
+<span style="color: #333333">}</span>
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * Closure that computes an annotation based on </span>
+<span style="color: #888888"> * presence of particular residues and features</span>
+<span style="color: #888888"> * Parameters are</span>
+<span style="color: #888888"> * - the name (label) for the alignment annotation</span>
+<span style="color: #888888"> * - the description (tooltip) for the annotation</span>
+<span style="color: #888888"> * - a closure (groovy function) that tests whether to include a residue</span>
+<span style="color: #888888"> * - a closure that tests whether to increment count based on sequence features  </span>
+<span style="color: #888888"> */</span>
+<span style="color: #333399; font-weight: bold">def</span> getColumnCounter <span
+        style="color: #333333">=</span> <span style="color: #333333">{</span> name<span
+        style="color: #333333">,</span> desc<span style="color: #333333">,</span> acceptResidue<span
+        style="color: #333333">,</span> acceptFeatures <span
+        style="color: #333333">-&gt;</span>
+    <span style="color: #333333">[</span>
+     <span style="color: #997700; font-weight: bold">getName:</span> <span
+        style="color: #333333">{</span> name <span
+        style="color: #333333">},</span> 
+     <span style="color: #997700; font-weight: bold">getDescription:</span> <span
+        style="color: #333333">{</span> desc <span
+        style="color: #333333">},</span>
+     <span style="color: #997700; font-weight: bold">getMinColour:</span> <span
+        style="color: #333333">{</span> <span style="color: #333333">[</span><span
+        style="color: #0000DD; font-weight: bold">0</span><span
+        style="color: #333333">,</span> <span
+        style="color: #0000DD; font-weight: bold">255</span><span
+        style="color: #333333">,</span> <span
+        style="color: #0000DD; font-weight: bold">255</span><span
+        style="color: #333333">]</span> <span style="color: #333333">},</span> <span
+        style="color: #888888">// cyan</span>
+     <span style="color: #997700; font-weight: bold">getMaxColour:</span> <span
+        style="color: #333333">{</span> <span style="color: #333333">[</span><span
+        style="color: #0000DD; font-weight: bold">0</span><span
+        style="color: #333333">,</span> <span
+        style="color: #0000DD; font-weight: bold">0</span><span
+        style="color: #333333">,</span> <span
+        style="color: #0000DD; font-weight: bold">255</span><span
+        style="color: #333333">]</span> <span style="color: #333333">},</span> <span
+        style="color: #888888">// blue</span>
+     <span style="color: #997700; font-weight: bold">count:</span> 
+         <span style="color: #333333">{</span> res<span
+        style="color: #333333">,</span> feats <span
+        style="color: #333333">-&gt;</span> 
+            <span style="color: #333399; font-weight: bold">def</span> c <span
+        style="color: #333333">=</span> <span
+        style="color: #0000DD; font-weight: bold">0</span>
+            <span style="color: #008800; font-weight: bold">if</span> <span
+        style="color: #333333">(</span>acceptResidue<span
+        style="color: #333333">.</span><span style="color: #0000CC">call</span><span
+        style="color: #333333">(</span>res<span style="color: #333333">))</span>
+            <span style="color: #333333">{</span>
+                <span style="color: #008800; font-weight: bold">if</span> <span
+        style="color: #333333">(</span>acceptFeatures<span
+        style="color: #333333">.</span><span style="color: #0000CC">call</span><span
+        style="color: #333333">(</span>feats<span style="color: #333333">))</span>
+                <span style="color: #333333">{</span>
+                    c<span style="color: #333333">++</span>
+                <span style="color: #333333">}</span>
+            <span style="color: #333333">}</span>
+            c
+         <span style="color: #333333">}</span>
+     <span style="color: #333333">]</span> <span
+        style="color: #008800; font-weight: bold">as</span> FeatureCounterI
+<span style="color: #333333">}</span>
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * Define an annotation row that counts any residue with Pfam domain annotation</span>
+<span style="color: #888888"> */</span>
+<span style="color: #333399; font-weight: bold">def</span> pfamAnnotation <span
+        style="color: #333333">=</span> getColumnCounter<span
+        style="color: #333333">(</span><span
+        style="background-color: #fff0f0">&quot;Pfam&quot;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&quot;Count of residues with Pfam domain annotation&quot;</span><span
+        style="color: #333333">,</span> <span style="color: #333333">{</span><span
+        style="color: #008800; font-weight: bold">true</span><span
+        style="color: #333333">},</span> hasPfam<span
+        style="color: #333333">)</span>
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * Define an annotation row that counts charged residues with Pfam domain annotation</span>
+<span style="color: #888888"> */</span>
+<span style="color: #333399; font-weight: bold">def</span> chargedPfamAnnotation <span
+        style="color: #333333">=</span> getColumnCounter<span
+        style="color: #333333">(</span><span
+        style="background-color: #fff0f0">&quot;Pfam charged&quot;</span><span
+        style="color: #333333">,</span> <span
+        style="background-color: #fff0f0">&quot;Count of charged residues with Pfam domain annotation&quot;</span><span
+        style="color: #333333">,</span> isCharged<span
+        style="color: #333333">,</span> hasPfam<span
+        style="color: #333333">)</span>
+
+<span style="color: #888888">/*</span>
+<span style="color: #888888"> * Register the annotations</span>
+<span style="color: #888888"> */</span>
+AlignmentAnnotationFactory<span style="color: #333333">.</span><span
+        style="color: #0000CC">newCalculator</span><span
+        style="color: #333333">(</span>pfamAnnotation<span
+        style="color: #333333">)</span> 
+AlignmentAnnotationFactory<span style="color: #333333">.</span><span
+        style="color: #0000CC">newCalculator</span><span
+        style="color: #333333">(</span>chargedPfamAnnotation<span
+        style="color: #333333">)</span>
+</pre>
+  </div>
+</body>
+</html>
index 5bb9020..62b46a9 100755 (executable)
@@ -45,8 +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-test.jalview.org/about/documentation"
-    >http://www.jalview.org/about/documentation</a>).
+      href="http://www-test.jalview.org/about/documentation">http://www.jalview.org/about/documentation</a>).
   </p>
   <p>
     If you are using the Jalview Desktop application and are looking for
@@ -55,8 +54,7 @@
     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="http://www.jalview.org/community">http://www.jalview.org/community</a>
   </p>
 
   <p>
@@ -70,8 +68,8 @@
     <strong>25</strong> (9) 1189-1191 doi: 10.1093/bioinformatics/btp033
   </p>
   <p>
-    <strong>The Jalview Authors</strong><br /> The following people have
-    contributed to Jalview's development:
+    <strong>The Jalview Authors</strong><br /> The following people
+    have contributed to Jalview's development:
   <ul>
     <li>Jalview 1
       <ul>
index 46e7fe4..8a554aa 100755 (executable)
@@ -25,8 +25,7 @@
 <body>
   <p>
     <strong>Exporting alignments as graphics and lineart<a
-      name="export"
-    ></a></strong>
+      name="export"></a></strong>
   </p>
   <p>
     The alignment view can be printed using <strong>File&#8594;Print</strong>,
index 46e2189..3f6a058 100644 (file)
     Much of the information retrieved by Jalview about a sequence is
     visualized on the alignment. Often, however, there are a huge number
     of ontology terms, cross-references, links to publications and other
-    kinds of data shown in the sequence ID tooltip that cannot be
-    examined. In this case, you can view and export the information
-    shown in a sequence's ID tooltip by right-clicking and selecting the
+    kinds of data associated with a sequence, and only some of these are shown in 
+    sequence ID tooltip. To show the full set of annotation and database links for
+    a sequence, right-click and select the
     <strong>&quot;<em>(sequence's name)</em></em>&rarr;Sequence
       Details ...&quot;
     </strong> entry from the <a href="../menus/popupMenu.html">pop-up menu</a>.
   </p>
   <p>
     <strong>Annotation Reports for a range of sequences</strong><br />
-    If you would like to view the tooltips for a number of sequences,
+    If you would like to view database and metadata for a number of sequences,
     simply select them all and then use the <strong>Selection&rarr;Sequence
       Details ...</strong> entry in the <a href="../menus/popupMenu.html">pop-up
       menu</a>.
   </p>
   <img src="seqreport.gif"
-    alt="Sequence Annotation is displayed as HTML in a report window"
-  />
+    alt="Sequence Annotation is displayed as HTML in a report window" />
   <p>
     <strong>Copying and pasting annotation to other programs</strong><br>
     The <strong>File&rarr;Save</strong> option in the sequence
index d887f18..af4e2c4 100755 (executable)
@@ -95,9 +95,9 @@ td {
     <tr>
       <td width="17%">JSON</td>
       <td width="60%">Data starts with '{' <br>Data ends with
-        '}' <br>
-      <br>See <a href="../features/bioJsonFormat.html">BioJSON</a>
-        for more infomation about the Jalview JSON format <br></td>
+        '}' <br> <br>See <a
+        href="../features/bioJsonFormat.html">BioJSON</a> for more
+        infomation about the Jalview JSON format <br></td>
       <td width="23%">.json</td>
     </tr>
 
index d2196c1..b0d6b04 100755 (executable)
   </p>
   <p>
     Jalview can also read Jalview specific files for <a
-      href="../features/featuresFormat.html"
-    >sequence features</a> and <a
-      href="../features/annotationsFormat.html"
-    >alignment annotation</a>.
+      href="../features/featuresFormat.html">sequence features</a>
+    and <a href="../features/annotationsFormat.html">alignment
+      annotation</a>.
   </p>
   <p>
     <strong>Output</strong>
index 1fc5f39..d6157fb 100755 (executable)
   </p>
   <p>
     The homology modelling program, <a
-      href="http://salilab.org/modeller/"
-    >Modeller</a> uses a special form of the PIR format where information
-    about sequence numbering and chain codes are written into the
-    'description' line between the PIR protein tag and the protein
-    alignment entry:
+      href="http://salilab.org/modeller/">Modeller</a> uses a
+    special form of the PIR format where information about sequence
+    numbering and chain codes are written into the 'description' line
+    between the PIR protein tag and the protein alignment entry:
   </p>
   <pre>&gt;P1;Q93Z60_ARATH
 sequence:Q93Z60_ARATH:1:.:118:.:.
@@ -52,12 +51,12 @@ KDPLPDAEDWDGVKGKLQHLE*
     no information is lost if this parsing process fails.</p>
   <p>
     The 'Modeller Output' flag in the 'Output' tab of the Jalview <a
-      href="../features/preferences.html"
-    >Preferences dialog box</a> controls whether Jalview will also output
-    MODELLER style PIR files. In this case, any existing 'non-modeller
-    PIR' header information in the description string of an alignment is
-    appended to an automatically generated modeller description line for
-    that sequence.
+      href="../features/preferences.html">Preferences dialog
+      box</a> controls whether Jalview will also output MODELLER style PIR
+    files. In this case, any existing 'non-modeller PIR' header
+    information in the description string of an alignment is appended to
+    an automatically generated modeller description line for that
+    sequence.
   </p>
   <p>The general format used for generating the Modeller/PIR
     sequence description line is shown below :
index c8e5aec..08d1889 100644 (file)
@@ -30,8 +30,8 @@
     T-COFFEE score files like the <a href="#tcoffeeeg">one below</a> can
     be displayed on the alignment using the <strong><em>Colours&rarr;T-COFFEE
         Scores</em></strong> or <strong><em>Colour &rarr; <a
-        href="../colourSchemes/annotationColouring.html"
-      >Colour by Annotation</a></em></strong> options.
+        href="../colourSchemes/annotationColouring.html">Colour
+          by Annotation</a></em></strong> options.
   </p>
   <img src="../colourSchemes/colbytcoffee.png" />
   <p>
index f129551..1a5fc18 100755 (executable)
     Jalview has two distinct modes of keyboard operation - in 'Normal'
     mode, single keystrokes (including those shown next to menu items)
     provide short cuts to common commands. In <a
-      href="features/cursorMode.html"
-    >'Cursor'</a> mode (enabled by <em>F2</em>), some of these are
-    disabled and more complex 'Compound Keystrokes' can be entered to
-    perform precise navigation, selection and editing operations.
+      href="features/cursorMode.html">'Cursor'</a> mode (enabled by
+    <em>F2</em>), some of these are disabled and more complex 'Compound
+    Keystrokes' can be entered to perform precise navigation, selection
+    and editing operations.
   </p>
   <table border="1">
     <tr>
@@ -167,6 +167,19 @@ columns are selected, you should use the <a href="features/hiddenRegions.html">H
       <td>Both</td>
       <td>Launches the search window</td>
     </tr>
+    <tr><td><strong>B</strong></td>
+      <td>Both</td>
+      <td>Add highlighted columns to current column selection</td>
+    </tr>
+    <tr><td><strong>Alt 'B'</strong></td>
+      <td>Both</td>
+      <td>Add all but the currently highlighted columns to current selection</td>
+    </tr>
+    <tr><td><strong>Control 'B'</strong></td>
+      <td>Both</td>
+      <td>Toggle the column selection marks for the currently highlighted 
+          columns (or all others if Alt is also pressed)</td>
+    </tr>
     <tr>
       <td><strong>H</strong></td>
       <td>Both</td>
@@ -279,7 +292,7 @@ columns are selected, you should use the <a href="features/hiddenRegions.html">H
       <td>Cursor</td>
       <td>Move cursor to a particular column (<strong><em>p1</em></strong>)
         and row (<strong><em>p2</em></strong>) in the alignment.<br>
-      <em>e.g. '5,6&lt;Return&gt;' moves the cursor to the 5th
+        <em>e.g. '5,6&lt;Return&gt;' moves the cursor to the 5th
           column in the 6th sequence.</em></td>
     </tr>
     <tr>
@@ -317,25 +330,22 @@ columns are selected, you should use the <a href="features/hiddenRegions.html">H
       <td><strong><em>[p]</em><br>Space</strong></td>
       <td>Cursor</td>
       <td>Inserts one (or optionally <strong><em>p</em></strong>)
-        gaps at the current position.<br>
-      <em>Hold down Control or Shift to insert gaps over a sequence
-          group</em></td>
+        gaps at the current position.<br> <em>Hold down
+          Control or Shift to insert gaps over a sequence group</em></td>
     </tr>
     <tr>
       <td><strong><em>[p]</em><br>Delete<br></strong></td>
       <td>Cursor</td>
       <td>Removes one (or optionally <strong><em>p</em></strong>)
-        gaps at the cursor position.<br>
-      <em>Hold down Control or Shift to insert gaps over a sequence
-          group</em></td>
+        gaps at the cursor position.<br> <em>Hold down Control
+          or Shift to insert gaps over a sequence group</em></td>
     </tr>
     <tr>
       <td><strong><em>[p]</em><br>Backspace<br></strong></td>
       <td>Cursor</td>
       <td>Removes one (or optionally <strong><em>p</em></strong>)
-        gaps at the cursor position.<br>
-      <em>Hold down Control or Shift to insert gaps over a sequence
-          group</em></td>
+        gaps at the cursor position.<br> <em>Hold down Control
+          or Shift to insert gaps over a sequence group</em></td>
     </tr>
   </table>
   <p>&nbsp;</p>
index 9c856a9..2142f98 100755 (executable)
         file. You can obtain a JNLP file with modified memory settings
         from our service with the following link (replace 2G with
         desired memory in G or M):<br /> <a
-          href="http://www.jalview.org/services/launchApp?jvm-max-heap=2G"
-        >http://www.jalview.org/services/launchApp?jvm-max-heap=2G</a>
+          href="http://www.jalview.org/services/launchApp?jvm-max-heap=2G">http://www.jalview.org/services/launchApp?jvm-max-heap=2G</a>
       </p>
       <p>
         Alternatively, if you want to create your own JNLP file then
         please download the latest JNLP file from <a
-          href="http://www.jalview.org/webstart/jalview.jnlp"
-        >http://www.jalview.org/webstart/jalview.jnlp</a> and modify the
-        max-heap-size parameter for the j2se tag in the
+          href="http://www.jalview.org/webstart/jalview.jnlp">http://www.jalview.org/webstart/jalview.jnlp</a>
+        and modify the max-heap-size parameter for the j2se tag in the
         &lt;resources&gt; element. e.g.
       <pre>
 &lt;j2se version="1.7+" initial-heap-size="500M" max-heap-size="1000M"/&gt;
@@ -109,6 +107,7 @@ lax.nl.java.option.java.heap.size.initial=500m
             The lines you need to change are in the <em>Info.plist</em>
             file inside the <em>Jalview.app/Contents</em> directory
             (which is where the installAnywhere installation was made) :
+
           
           <pre>
 &lt;key&ht;VMOptions&lt;/key&ht;
index ce339cc..167cb25 100755 (executable)
@@ -33,7 +33,7 @@
       <ul>
         <li><strong>Fetch Sequence</strong><br> <em>Shows
             a dialog window in which you can retrieve known ids from
-            Uniprot, EMBL, EMBLCDS, PFAM, Rfam, or PDB database using
+            UniProt, EMBL, EMBLCDS, PFAM, Rfam, or PDB database using
             Web Services provided by the European Bioinformatics
             Institute. See <a href="../features/seqfetch.html">Sequence
               Fetcher</a>
         </em></li>
         <li><strong>Load Features / Annotations<br>
         </strong><em>Load files describing precalculated <a
-            href="../features/featuresFormat.html"
-          >sequence features</a> or <a
-            href="../features/annotationsFormat.html"
-          >alignment annotations</a>.
+            href="../features/featuresFormat.html">sequence
+              features</a> or <a href="../features/annotationsFormat.html">alignment
+              annotations</a>.
         </em></li>
         <li><strong>Close (Control W)</strong><br> <em>Close
             the alignment window. Make sure you have saved your
         </strong><em>All columns which only contain gap characters
             (&quot;-&quot;, &quot;.&quot;) will be deleted.<br> You
             may set the default gap character in <a
-            href="../features/preferences.html"
-          >preferences</a>.
+            href="../features/preferences.html">preferences</a>.
         </em></li>
         <li><strong>Remove All Gaps (Control Shift E)</strong><br>
           <em>Gap characters (&quot;-&quot;, &quot;.&quot;) will be
             deleted from the selected area of the alignment. If no
             selection is made, ALL the gaps in the alignment will be
             removed.<br> You may set the default gap character in <a
-            href="../features/preferences.html"
-          >preferences</a>.
+            href="../features/preferences.html">preferences</a>.
         </em></li>
         <li><strong>Remove Redundancy (Control D)<br>
         </strong><em>Selecting this option brings up a window asking you to
             with alignment analysis programs which require 'properly
             aligned sequences' to be all the same length.<br> You
             may set the default for <strong>Pad Gaps</strong> in the <a
-            href="../features/preferences.html"
-          >preferences</a>.
+            href="../features/preferences.html">preferences</a>.
         </em></li>
       </ul></li>
     <li><strong>Select</strong>
             <strong>WARNING</strong>: This cannot be undone.
         </em></li>
         <li><strong><a
-            href="../features/columnFilterByAnnotation.html"
-          >Select/Hide Columns by Annotation</a></strong> <br /> <em>Select
-            or Hide columns in the alignment according to secondary
-            structure, labels and values shown in alignment annotation
-            rows. </em></li>
+            href="../features/columnFilterByAnnotation.html">Select/Hide
+              Columns by Annotation</a></strong> <br /> <em>Select or Hide
+            columns in the alignment according to secondary structure,
+            labels and values shown in alignment annotation rows. </em></li>
+        <li><strong>Select Highlighted Columns</strong> <br /> <em>Selects
+        the columns currently highlighted as a result of a find, mouse
+        over, or selection event from a linked structure viewer or other
+        application. Modifiers will work on some platforms: ALT will add
+        all but the highlighted set to the column selection, and CTRL
+        (or META) will toggle the selection. </em></li>
       </ul></li>
     <li><strong>View</strong>
       <ul>
         <li><strong>Show Sequence Features</strong><br> <em>Show
             or hide sequence features on this alignment.</em></li>
         <li><strong><a
-            href="../features/featuresettings.html"
-          >Sequence Feature Settings...</a> </strong><em><br> <em>Opens
-              the Sequence Feature Settings dialog box to control the
-              colour and display of sequence features on the alignment,
-              and configure and retrieve features from DAS annotation
+            href="../features/featuresettings.html">Sequence
+              Feature Settings...</a> </strong><em><br> <em>Opens the
+              Sequence Feature Settings dialog box to control the colour
+              and display of sequence features on the alignment, and
+              configure and retrieve features from DAS annotation
               servers.</em></li>
         <li><strong>Sequence ID Tooltip</strong><em>
             (application only) <br>This submenu's options allow the
             rendering. </em></li>
         <li><strong>Wrap<br>
         </strong><em>When ticked, the alignment display is &quot;<a
-            href="../features/wrap.html"
-          >wrapped</a>&quot; to the width of the alignment window. This is
-            useful if your alignment has only a few sequences to view
-            its full width at once.
+            href="../features/wrap.html">wrapped</a>&quot; to
+            the width of the alignment window. This is useful if your
+            alignment has only a few sequences to view its full width at
+            once.
         </em><br> Additional options for display of sequence numbering
           and scales are also visible in wrapped layout mode:<br>
           <ul>
-            <li><strong>Scale Above</strong><br>
-            <em> Show the alignment column position scale.</em></li>
-            <li><strong>Scale Left</strong><br>
-            <em> Show the sequence position for the first aligned
-                residue in each row in the left column of the alignment.</em></li>
-            <li><strong>Scale Right</strong><br>
-            <em> Show the sequence position for the last aligned
-                residue in each row in the right-most column of the
-                alignment.</em></li>
+            <li><strong>Scale Above</strong><br> <em>
+                Show the alignment column position scale.</em></li>
+            <li><strong>Scale Left</strong><br> <em> Show
+                the sequence position for the first aligned residue in
+                each row in the left column of the alignment.</em></li>
+            <li><strong>Scale Right</strong><br> <em>
+                Show the sequence position for the last aligned residue
+                in each row in the right-most column of the alignment.</em></li>
             <li><strong>Show Sequence Limits<br>
             </strong><em>If this box is selected the sequence name will have
                 the start and end position of the sequence appended to
           colour will be applied to all currently defined groups.<br>
       </em></li>
       <li><strong><a
-          href="../colourSchemes/textcolour.html"
-        >Colour Text...</a> </strong><em><br> Opens the Colour Text
-          dialog box to set a different text colour for light and dark
-          background, and the intensity threshold for transition between
-          them. </em></li>
+          href="../colourSchemes/textcolour.html">Colour
+            Text...</a> </strong><em><br> Opens the Colour Text dialog box
+          to set a different text colour for light and dark background,
+          and the intensity threshold for transition between them. </em></li>
       <li>Colour Scheme options: <strong>None, ClustalX,
           Blosum62 Score, Percentage Identity, Zappo, Taylor,
           Hydrophobicity, Helix Propensity, Strand Propensity, Turn
       <li><strong>By Annotation</strong><br> <em>Colours
           the alignment on a per-column value from a specified
           annotation. See <a
-          href="../colourSchemes/annotationColouring.html"
-        >Annotation Colouring</a>.
+          href="../colourSchemes/annotationColouring.html">Annotation
+            Colouring</a>.
       </em><br></li>
       <li><strong>By RNA Helices</strong><br> <em>Colours
           the helices of an RNA alignment loaded from a Stockholm file.
           provided in this menu.</strong></li>
       <li><strong>Pairwise Alignments</strong><br> <em>Applies
           Smith and Waterman algorithm to selected sequences. See <a
-          href="../calculations/pairwise.html"
-        >pairwise alignments</a>.
+          href="../calculations/pairwise.html">pairwise
+            alignments</a>.
       </em><br></li>
       <li><strong>Principal Component Analysis</strong><br> <em>Shows
           a spatial clustering of the sequences based on similarity
           scores calculated with the alignment. See <a
-          href="../calculations/pca.html"
-        >Principal Component Analysis</a>.
+          href="../calculations/pca.html">Principal
+            Component Analysis</a>.
       </em> <br></li>
       <li><strong>Extract Scores ... (optional)</strong><br> <em>This
           option is only visible if Jalview detects one or more
       or elsewhere. You need a continuous network connection in order to
       use these services through Jalview.</p>
     <ul>
-      <li><strong>Alignment</strong><br />
-      <em> Align the currently selected sequences or all sequences
-          in the alignment, or re-align unaligned sequences to the
-          aligned sequences. Entries in this menu provide access to the
-          various alignment programs supported by <a
-          href="../webServices/JABAWS.html"
-        >JABAWS</a>. See the <a href="../webServices/msaclient.html">Multiple
-            Sequence Alignment webservice client</a> entry for more
-          information.
+      <li><strong>Alignment</strong><br /> <em> Align the
+          currently selected sequences or all sequences in the
+          alignment, or re-align unaligned sequences to the aligned
+          sequences. Entries in this menu provide access to the various
+          alignment programs supported by <a
+          href="../webServices/JABAWS.html">JABAWS</a>. See the
+          <a href="../webServices/msaclient.html">Multiple Sequence
+            Alignment webservice client</a> entry for more information.
       </em></li>
       <li><strong>Secondary Structure Prediction</strong>
         <ul>
           <li><strong>Multi-Harmony</strong><br> <em>Performs
               functional residue analysis on a protein family alignment
               with sub-families defined on it. See the <a
-              href="../webServices/shmr.html"
-            >Multi-Harmony service</a> entry for more information.
+              href="../webServices/shmr.html">Multi-Harmony
+                service</a> entry for more information.
           </em></li>
         </ul></li>
     </ul></li>
index f8f4889..8ac116b 100755 (executable)
@@ -25,8 +25,8 @@
 
 <body>
   <p>
-    <strong>Alignment Window Annotations Menu</strong> (Since Jalview
-    2.8.2)
+    <strong>Alignment Window Annotations Menu</strong> <em>Since
+      Jalview 2.8.2</em>
   </p>
   <ul>
     <li><strong>Show Alignment Related</strong><em><br>
@@ -44,8 +44,7 @@
         example, Consensus).</em></li>
     <li><em>You can also selectively show or hide annotations
         from the <a href="./popupMenu.html">Popup</a> or <a
-        href="../features/annotation.html"
-      >Annotation</a> menus.
+        href="../features/annotation.html">Annotation</a> menus.
     </em></li>
     <li><strong>Sort by Sequence</strong><em><br>Sort
         sequence-specific annotations by sequence order in the alignment
index ad9596a..cd09693 100755 (executable)
   <ul>
     <li><strong>Annotation Label Popup Menu</strong><br> <em>This
         menu is opened by clicking anywhere on the annotation row labels
-        area (below the sequence ID area).</em>
+        area (below the sequence ID area).</em> <br />
+    <em><strong>Mac Users:</strong> pressing CTRL whilst clicking
+        the mouse/track pad is the same as a right-click. See your
+        system's settings to configure your track-pad's corners to
+        generate right-clicks.</em>
       <ul>
         <li><strong>Add New Row</strong><br> <em>Adds a
             new, named annotation row (a dialog box will pop up for you
index 34e8d75..8032348 100755 (executable)
       </ul></li>
     <li><strong>Pairwise Alignments</strong><br> <em>Applies
         Smith and Waterman algorithm to selected sequences. See <a
-        href="../calculations/pairwise.html"
-      >pairwise alignments</a>.
+        href="../calculations/pairwise.html">pairwise
+          alignments</a>.
     </em><br></li>
     <li><strong>Principal Component Analysis</strong><br> <em>Shows
         a spatial clustering of the sequences based on similarity scores
         calculated over the alignment.. See <a
-        href="../calculations/pca.html"
-      >Principal Component Analysis</a>.
+        href="../calculations/pca.html">Principal Component
+          Analysis</a>.
     </em> <br></li>
     <li><strong>Extract Scores ... (optional)</strong><br> <em>This
         option is only visible if Jalview detects one or more
         parsed into sequence associated annotation which can then be
         used to sort the alignment via the Sort by&#8594;Score menu.
     </em> <br></li>
-    <li><strong>Translate as cDNA</strong> (not applet)<br>
-    <em>This option is visible for nucleotide alignments. Selecting
-        this option shows the DNA's calculated protein product in a new
-        <a href="../features/splitView.html">split frame</a> window.
-        Note that the translation is not frame- or intron-aware; it
-        simply translates all codons in each sequence, using the
-        standard <a href="../misc/geneticCode.html">genetic code</a>
-        (any incomplete final codon is discarded). You can perform this
-        action on the whole alignment, or selected rows, columns, or
-        regions.
+    <li><strong>Translate as cDNA</strong> (not applet)<br> <em>This
+        option is visible for nucleotide alignments. Selecting this
+        option shows the DNA's calculated protein product in a new <a
+        href="../features/splitView.html">split frame</a> window. Note
+        that the translation is not frame- or intron-aware; it simply
+        translates all codons in each sequence, using the standard <a
+        href="../misc/geneticCode.html">genetic code</a> (any incomplete
+        final codon is discarded). You can perform this action on the
+        whole alignment, or selected rows, columns, or regions.
     </em> <br></li>
     <li><strong>Reverse, Reverse Complement</strong> (not applet)<br>
-    <em>These options are visible for nucleotide alignments. Selecting them adds the reverse (or reverse complement)
-    of the sequences (or selected region) as new sequences in the alignment. To try this out, add this sequence and
-    perform 'Reverse Complement' followed by 'Translate as cDNA':
-    <br><small>
-    Seq GTCATTTGCGCGTGTTGATTATTCGGACCGCTCCACTTCCCTTTACTCGTGCGTTCAATTGATTTAATCCTC
-    TGGGGGGGCTCTGGTTTACATAGCTTAAATCTATTCCATTCAAGGAAGCTCATG</small>
+      <em>These options are visible for nucleotide alignments.
+        Selecting them adds the reverse (or reverse complement) of the
+        sequences (or selected region) as new sequences in the
+        alignment. To try this out, add this sequence and perform
+        'Reverse Complement' followed by 'Translate as cDNA': <br>
+      <small> Seq
+          GTCATTTGCGCGTGTTGATTATTCGGACCGCTCCACTTCCCTTTACTCGTGCGTTCAATTGATTTAATCCTC
+          TGGGGGGGCTCTGGTTTACATAGCTTAAATCTATTCCATTCAAGGAAGCTCATG</small>
     </em> <br></li>
     <li><strong>Get Cross-References</strong> (not applet)<br>
-    <em>This option is visible where sequences have
+      <em>This option is visible where sequences have
         cross-references to other standard databases; for example, an
         EMBL entry may have cross-references to one or more UNIPROT
         entries. Select the database to view all cross-referenced
index 846a1bd..eb8e839 100755 (executable)
     </strong><em>All columns which only contain gap characters
         (&quot;-&quot;, &quot;.&quot;) will be deleted.<br> You may
         set the default gap character in <a
-        href="../features/preferences.html"
-      >preferences</a>.
+        href="../features/preferences.html">preferences</a>.
     </em></li>
     <li><strong>Remove All Gaps (Control Shift E)</strong><br>
       <em>Gap characters (&quot;-&quot;, &quot;.&quot;) will be
         deleted from the selected area of the alignment. If no selection
         is made, ALL the gaps in the alignment will be removed.<br>
         You may set the default gap character in <a
-        href="../features/preferences.html"
-      >preferences</a>.
+        href="../features/preferences.html">preferences</a>.
     </em></li>
     <li><strong>Remove Redundancy (Control D)<br>
     </strong><em>Selecting this option brings up a window asking you to
index 10d510d..b8445af 100755 (executable)
   </p>
   <ul>
     <li><strong>Fetch Sequence</strong><br> <em>Shows a
-        dialog window in which you can select known ids from Uniprot,
+        dialog window in which you can select known ids from UniProt,
         EMBL, EMBLCDS, PDB, PFAM, or RFAM databases using Web Services
         provided by the European Bioinformatics Institute. See <a
-        href="../features/seqfetch.html"
-      >Sequence Fetcher</a>
+        href="../features/seqfetch.html">Sequence Fetcher</a>
     </em>.</li>
     <li><strong>Add Sequences</strong><em><br> Add
         sequences to the visible alignment from file, URL, or cut &amp;
@@ -86,9 +85,9 @@
     <li><strong>Export Image</strong> <em><br> Creates an
         alignment graphic with the current view's annotation, alignment
         background colours and group colours. If the alignment is <a
-        href="../features/wrap.html"
-      >wrapped</a>, the output will also be wrapped and will have the same
-        visible residue width as the open alignment. </em>
+        href="../features/wrap.html">wrapped</a>, the output will
+        also be wrapped and will have the same visible residue width as
+        the open alignment. </em>
       <ul>
         <li><strong>HTML<br>
         </strong><em>Create a <a href="../io/export.html">web page</a> from
     </em></li>
     <li><strong>Load Features / Annotations<br>
     </strong><em>Load files describing precalculated <a
-        href="../features/featuresFormat.html"
-      >sequence features</a> or <a
-        href="../features/annotationsFormat.html"
-      >alignment annotations</a>.
+        href="../features/featuresFormat.html">sequence
+          features</a> or <a href="../features/annotationsFormat.html">alignment
+          annotations</a>.
     </em></li>
     <li><strong>Close (Control W)</strong><br> <em>Close
         the alignment window. Make sure you have saved your alignment
index a7cee0b..092e623 100644 (file)
       for faster alignment rendering. </em></em></li>
   <li><strong>Wrap<br>
   </strong><em>When ticked, the alignment display is &quot;<a
-      href="../features/wrap.html"
-    >wrapped</a>&quot; to the width of the alignment window. This is
-      useful if your alignment has only a few sequences to view its full
-      width at once.<br> Additional options for display of sequence
-      numbering and scales are also visible in wrapped layout mode:
+      href="../features/wrap.html">wrapped</a>&quot; to the width
+      of the alignment window. This is useful if your alignment has only
+      a few sequences to view its full width at once.<br>
+      Additional options for display of sequence numbering and scales
+      are also visible in wrapped layout mode:
   </em>
     <ul>
       <li><strong>Scale Left</strong><br> <em>Show the
index a80f239..07828a3 100644 (file)
         <strong>WARNING</strong>: This cannot be undone.
     </em></li>
     <li><strong><a
-        href="../features/columnFilterByAnnotation.html"
-      >Select/Hide Columns by Annotation</a></strong> <br /> <em>Select or
-        Hide columns in the alignment according to secondary structure,
-        labels and values shown in alignment annotation rows. </em></li>
+        href="../features/columnFilterByAnnotation.html">Select/Hide
+          Columns by Annotation</a></strong> <br /> <em>Select or Hide columns
+        in the alignment according to secondary structure, labels and
+        values shown in alignment annotation rows. </em></li>
+    <li><strong>Select Highlighted Columns</strong> <br /> <em>Selects
+        the columns currently highlighted as a result of a find, mouse
+        over, or selection event from a linked structure viewer or other
+        application. Modifiers will work on some platforms: ALT will add
+        all but the highlighted set to the column selection, and CTRL
+        (or META) will toggle the selection. </em></li>
   </ul>
 </body>
 </html>
index edbd1e9..20e784b 100755 (executable)
           </ul></li>
         <li><strong>Fetch Sequence<br>
         </strong><em>Shows a dialog window in which you can select known ids
-            from Uniprot, EMBL, EMBLCDS or PDB database using Web
+            from UniProt, EMBL, EMBLCDS or PDB database using Web
             Services provided by the European Bioinformatics Institute.</em></li>
         <li><strong>Save Project</strong><br> <em>Saves
             all currently open alignment windows with their current view
             settings and any associated trees, as a <a
-            href="../features/jalarchive.html"
-          >Jalview Archive</a> (which has a .jar extension).
+            href="../features/jalarchive.html">Jalview
+              Archive</a> (which has a .jar extension).
         </em></li>
         <li><strong>Load Project</strong><br> <em>Loads
             Jalview archives <strong>only</strong>.
         window to the top of the pile when it is selected.
         <ul>
           <li><strong>Close All</strong><br> Close all
-            alignment and analysis windows.<br>
-          <strong>Note: This will erase all alignments from
-              memory, and cannot be undone!</strong></li>
+            alignment and analysis windows.<br> <strong>Note:
+              This will erase all alignments from memory, and cannot be
+              undone!</strong></li>
           <li><strong>Raise Associated Windows</strong><br>
             Bring all windows associated with the current alignment to
             the top of the pile.</li>
index cbc4217..d799378 100755 (executable)
   <p>
     The <a href="popupMenu.html">Popup Menus</a> are opened by clicking
     with the right mouse button in the alignment display area or on a
-    sequence label in the alignment window.
+    sequence label in the alignment window.<br /> <em><strong>Mac
+        Users:</strong> pressing CTRL whilst clicking the mouse/track pad is the
+      same as a right-click. See your system's settings to configure
+      your track-pad's corners to generate right-clicks.</em>
   </p>
   <p>
     The <a href="alwannotationpanel.html">Annotations Menu</a> is opened
index 353fb41..d42f854 100755 (executable)
     <strong>Popup Menu</strong><br> <em>This menu is visible
       when right clicking either within a selected region on the
       alignment or on a selected sequence name. It may not be accessible
-      when in 'Cursor Mode' (toggled with the F2 key).</em>
+      when in 'Cursor Mode' (toggled with the F2 key).</em><br /> <em><strong>Mac
+        Users:</strong> pressing CTRL whilst clicking the mouse/track pad is the
+      same as a right-click. See your system's settings to configure
+      your track-pad's corners to generate right-clicks.</em>
   </p>
   <ul>
     <li><strong>Selection</strong>
@@ -36,9 +39,9 @@
         <li><a name="sqreport"><strong>Sequence
               Details...<br>
           </strong></a><em>(Since Jalview 2.8)<br>Open an <a
-            href="../io/exportseqreport.html"
-          >HTML report containing the annotation and database cross
-              references</a>&nbsp;normally shown in the sequence's tooltip.
+            href="../io/exportseqreport.html">HTML report
+              containing the annotation and database cross references</a>&nbsp;normally
+            shown in the sequence's tooltip.
         </em></li>
         <li><strong>Show Annotations...<br>
         </strong><em>Choose to show (unhide) either All or a selected type
         </strong><em>The selection area will be output to a a text window in
             the selected alignment format. </em></li>
         <li><strong><a
-            href="../features/creatinFeatures.html"
-          >Create Sequence Feature...</a></strong><br> <em>Opens the
-            dialog box for creating sequence features over the currently
-            selected region on each selected sequence.</em></li>
+            href="../features/creatinFeatures.html">Create
+              Sequence Feature...</a></strong><br> <em>Opens the dialog box
+            for creating sequence features over the currently selected
+            region on each selected sequence.</em></li>
         <li><strong>Create Group<br>
         </strong><em>This will define a new group from the current
             selection.</em><strong> </strong></li>
         <li><a name="sqreport"><strong>Sequence
               Details ...<br>
           </strong></a><em>(Since Jalview 2.8)<br>Open an <a
-            href="../io/exportseqreport.html"
-          >HTML report containing the annotation and database cross
-              references</a> normally shown in the sequence's tooltip.
+            href="../io/exportseqreport.html">HTML report
+              containing the annotation and database cross references</a>
+            normally shown in the sequence's tooltip.
         </em></li>
         <li><strong>Edit Name/Description<br>
         </strong><em>You may edit the name and description of each sequence.
             and sequence description to be entered. Press OK to accept
             your edit. To save sequence descriptions, you must save in
             Fasta, PIR or Jalview File format.</em></li>
-        <li><strong>Add <a href="../features/annotation.html#seqannots">Reference Annotations</a></strong><br>
-              <em>When enabled, copies any available alignment
-              annotation for this sequence to the current view.</em></li>
+        <li><strong>Add <a
+            href="../features/annotation.html#seqannots">Reference
+              Annotations</a></strong><br> <em>When enabled, copies any
+            available alignment annotation for this sequence to the
+            current view.</em></li>
         <li><strong>Set as Reference</strong> or <strong>Unmark
-            as Reference</strong><br /> Sets or unsets the reference sequence for
-          the the alignment.</li>
+            as Reference</strong><br /> Sets or unsets the reference sequence
+          for the the alignment.</li>
 
         <li><strong>Represent Group With (Sequence Id)</strong><br>
           <em>All sequences in the current selection group will be
               Connections tab.<br> Since Jalview 2.4, links will
               also be made for database cross references (where the
               database name exactly matches the link name set up in <a
-              href="../features/preferences.html"
-            >Preferences</a>). <br>Since Jalview 2.5, links are also
-              shown for non-positional sequence features attached to the
-              sequence, and any regular-expression based URL links that
-              matched the description line.
+              href="../features/preferences.html">Preferences</a>).
+              <br>Since Jalview 2.5, links are also shown for
+              non-positional sequence features attached to the sequence,
+              and any regular-expression based URL links that matched
+              the description line.
           </em><strong><br> </strong></li>
       </ul></li>
     <li><strong>3D Structure Data...</strong> </strong><em>This menu is
         visible when you right-click on a sequence name. When this
-        option is clicked, Jalview will open a <a
-        href="../features/structurechooser.html"
-      >'Structure Chooser' </a> dialogue with options to select the
-        structure which will eventually be opened in a 3D interactive
-        view.<br> These entries will only be present if the
-        sequence has <a href="../features/viewingpdbs.html">associated
-          PDB structures</a>.
+        option is clicked, Jalview will open the <a
+        href="../features/structurechooser.html">'Structure Chooser'
+      </a>, which allows you to discover and view 3D structures for the
+        current selection. For more info, see <a
+        href="../features/viewingpdbs.html">viewing PDB structures</a>.
     </em></li>
-    <li><strong>VARNA 2D Structure</strong><br />
-    <em> If the sequence or alignment has RNA structure, then <strong>VARNA
+    <li><strong>VARNA 2D Structure</strong><br /> <em> If the
+        sequence or alignment has RNA structure, then <strong>VARNA
           2D Structure</strong> entries will also be present enabling you to open
         a linked view of the RNA structure in <a
-        href="../features/varna.html"
-      >VARNA</a>.
+        href="../features/varna.html">VARNA</a>.
     </em></li>
     <li><a name="hideinserts"><strong>Hide Insertions</strong></a><br />
       <em>Hides columns containing gaps in the current sequence or
index ee44c91..33282e9 100755 (executable)
     elsewhere. You need a continuous network connection in order to use
     these services through Jalview.</p>
   <ul>
-    <li><strong>Alignment</strong><br />
-    <em> Align the currently selected sequences or all sequences in
-        the alignment, or re-align unaligned sequences to the aligned
-        sequences. Entries in this menu provide access to the various
-        alignment programs supported by <a
-        href="../webServices/JABAWS.html"
-      >JABAWS</a>. See the <a href="../webServices/msaclient.html">Multiple
+    <li><strong>Alignment</strong><br /> <em> Align the
+        currently selected sequences or all sequences in the alignment,
+        or re-align unaligned sequences to the aligned sequences.
+        Entries in this menu provide access to the various alignment
+        programs supported by <a href="../webServices/JABAWS.html">JABAWS</a>.
+        See the <a href="../webServices/msaclient.html">Multiple
           Sequence Alignment webservice client</a> entry for more
         information.
     </em></li>
@@ -96,8 +95,8 @@
         <li><strong>Multi-Harmony</strong><br> <em>Performs
             functional residue analysis on a protein family alignment
             with sub-families defined on it. See the <a
-            href="../webServices/shmr.html"
-          >Multi-Harmony service</a> entry for more information.
+            href="../webServices/shmr.html">Multi-Harmony
+              service</a> entry for more information.
         </em></li>
       </ul></li>
   </ul>
index 51274d7..b53f6ef 100755 (executable)
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
 <head>
-<title>Amino Acid Properties</title>
+<style>
+body {
+    font-size: 100%;
+}
+table {
+    border: solid;
+    border-collapse: separate;
+}
+th, td {
+    border-style:none;
+    font-family: "Courier New", Courier, mono;
+    font-size: large;
+}
+</style><title>Amino Acid Properties</title>
 </head>
 <body>
   <div align="center">
     <h1>Amino Acid Properties</h1>
     <img src="properties.gif"> <br>
-    <table width="295" border="1" cellspacing="0" cellpadding="0">
-      <tr>
-        <td width="291"><pre>
-            <font size="4" face="Courier New, Courier, mono"><strong>ILVCAGMFYWHKREQDNSTPBZX-</strong>
-XXXXXXXXXXX&middot;&middot;&middot;&middot;&middot;&middot;&middot;X&middot;&middot;&middot;XX Hydrophobic
-&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XXXXXXXXXX&middot;XXXXX Polar
-&middot;&middot;XXXX&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XXXXX&middot;&middot;XX Small
-&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;X&middot;&middot;XX Proline
-&middot;&middot;&middot;&middot;XX&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;X&middot;&middot;&middot;&middot;XX Tiny
-XXX&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XX Aliphatic
-&middot;&middot;&middot;&middot;&middot;&middot;&middot;XXXX&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XX Aromatic
-&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XXX&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XX Positive
-&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;X&middot;X&middot;&middot;&middot;&middot;&middot;&middot;XX Negative
-&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;&middot;XXXX&middot;X&middot;&middot;&middot;&middot;&middot;&middot;XX Charged</font>
-          </pre></td>
-      </tr>
+    <table>
+    <tr><th>ILVCA</th><th>GMFYW</th><th>HKREQ</th><th>DNSTP</th><th>BZX-</th><th></th></tr>
+      <tr><td>XXXXX</td><td>XXXXX</td><td>XX&middot;&middot;&middot;</td><td>&middot;&middot;&middot;X&middot;</td><td>&middot;&middot;XX</td><td>Hydrophobic</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;XX</td><td>XXXXX</td><td>XXXX&middot;</td><td>XXXX</td><td>Polar</td></tr>
+<tr><td>&middot;&middot;XXX</td><td>X&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>XXXXX</td><td>&middot;&middot;XX</td><td>Small</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;X</td><td>&middot;&middot;XX</td><td>Proline</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;X</td><td>X&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;X&middot;&middot;</td><td>&middot;&middot;XX</td><td>Tiny</td></tr>
+<tr><td>XXX&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;XX</td><td>Aliphatic</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;XXX</td><td>X&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;XX</td><td>Aromatic</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>XXX&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;XX</td><td>Positive</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;X&middot;</td><td>X&middot;&middot;&middot;&middot;</td><td>&middot;&middot;XX</td><td>Negative</td></tr>
+<tr><td>&middot;&middot;&middot;&middot;&middot;</td><td>&middot;&middot;&middot;&middot;&middot;</td><td>XXXX&middot;</td><td>X&middot;&middot;&middot;&middot;</td><td>&middot;&middot;XX</td><td>Charged</td></tr>
     </table>
+    </font>
   </div>
   <p>
     <br> From Livingstone, C. D. and Barton, G. J. (1993), <br>
index de2741b..2d5aa08 100644 (file)
@@ -57,17 +57,16 @@ td {
   way:
   <ul>
     <li><em>RFAM</em> - Sequences can be <a
-      href="../features/seqfetch.html"
-    >fetched</a> from the RFAM database by accession number or ID.</li>
+      href="../features/seqfetch.html">fetched</a> from the RFAM
+      database by accession number or ID.</li>
     <li><em>Stockholm files</em> - WUSS (or VIENNA) dot-bracket
       notation found in the secondary structure annotation line will be
       imported as sequence or alignment associated secondary structure
       annotation.</li>
     <li><em>Clustal files</em> - certain RNA alignment programs,
-      such as <a
-      href="http://rna.informatik.uni-freiburg.de/LocARNA"
-    >LocaRNA</a> output consensus RNA secondary structure lines in the
-      line normally reserved for the Clustal consensus line in a clustal
+      such as <a href="http://rna.informatik.uni-freiburg.de/LocARNA">LocaRNA</a>
+      output consensus RNA secondary structure lines in the line
+      normally reserved for the Clustal consensus line in a clustal
       file.</li>
     <li><em>RNAML</em> Jalview can import RNAML files containing
       sequences and extended secondary structure annotation derived from
@@ -79,7 +78,7 @@ td {
     the alignment will have a secondary structure line shown below it,
     and a number of additional options become available:
   <ul>
-    <li><a href="../colourschemes/rnaHelicesColouring.html">RNA
+    <li><a href="../colourSchemes/rnahelicesColouring.html">RNA
         Helix colouring</a> - highlights columns of alignment involved in
       particular RNA helices, Uses the first displayed secondary
       structure annotation.</li>
@@ -103,9 +102,9 @@ td {
       per-sequence secondary structure is available).</li>
   </ul>
   <p>
-    <strong>Pseudo-knots</strong><br /> Jalview 2.8.2 introduced limited
-    support for working with structures including pseudoknots. Where
-    possible, extended WUSS symbols (e.g. different types of
+    <strong>Pseudo-knots</strong><br /> Jalview 2.8.2 introduced
+    limited support for working with structures including pseudoknots.
+    Where possible, extended WUSS symbols (e.g. different types of
     parentheses, or upper and lower case letters) are preserved when
     parsing RNA structure annotation and will be shaded differently when
     displayed in the structure.<br /> Extended WUSS annotation is also
index 5c6939a..37ae169 100644 (file)
@@ -38,8 +38,7 @@
     <li><em>HTTP logs on the Jalview website</em><br> We
       record IP addresses of machines which access the web site, either
       via the browser when downloading the application, or when the
-      Jalview Desktop user interface is launched.<br>
-    <br>
+      Jalview Desktop user interface is launched.<br> <br>
       <ul>
         <li><i>The JNLP file at
             www.jalview.org/webstart/jalview.jnlp is retrieved to
@@ -53,8 +52,7 @@
             interactions with the public Jalview web services are
             logged, but we delete all job data (input data and results)
             after about two weeks.</i></li>
-      </ul>
-      <br></li>
+      </ul> <br></li>
     <li><em>Google Analytics</em><br> Since Jalview 2.4.0b2,
       the Jalview Desktop records usage data with Google Analytics via
       the <a href="http://code.google.com/p/jgoogleanalytics/">JGoogleAnalytics</a>
     run Jalview in 'headless mode' via the command line, then the
     program shouldn't try to contact any of the web servers mentioned
     above (if it does, then it's a bug!). You can also specify some <a
-      href="features/commandline.html"
-    >command line options</a> to disable the questionnaire and usage
-    statistics check. Finally, the <a
-      href="features/preferences.html#connections"
-    >Connections Tab</a> of the Jalview preferences contains options for
-    controlling the submission of usage statistics.
+      href="features/commandline.html">command line options</a> to
+    disable the questionnaire and usage statistics check. Finally, the <a
+      href="features/preferences.html#connections">Connections
+      Tab</a> of the Jalview preferences contains options for controlling
+    the submission of usage statistics.
   <p>
     <strong>Other Web Clients in Jalview</strong><br> The Jalview
     desktop is intended to make it easier to interact with web-based
index 5a5020a..6f44b3d 100755 (executable)
     <tr>
       <td width="60" nowrap>
         <div align="center">
-          <strong><a name="Jalview.2.9.1">2.9.1</a><br /> <em>21/6/2016</em></strong>
+          <strong><a name="Jalview.2.10.1">2.10.1</a><br />
+            <em>29/11/2016</em></strong>
+        </div>
+      </td>
+      <td><div align="left">
+          <em>General</em>
+          <ul>
+            <li>
+              <!-- JAL-98 -->Improved memory usage: sparse arrays used
+              for all consensus calculations
+            </li>
+            <li>
+              <!-- JAL-2177 -->Jmol updated to version 14.6.4 (released 3rd Oct 2016)
+            </li>
+            <li>Updated Jalview's Certum code signing certificate
+              for 2016-2017</li>
+          </ul>
+          <em>Application</em>
+          <ul>
+            <li>
+              <!-- JAL-1723 -->Sequence ID tool tip presents abridged
+              set of database cross-references, sorted alphabetically
+            </li>
+            <li>
+              <!-- JAL-2282-->New replacement token for creating URLs <em>just</em>
+              from database cross references. Users with custom links
+              will receive a <a href="webServices/urllinks.html#warning">warning
+                dialog</a> asking them to update their preferences.
+            </li>
+            <li>
+              <!-- JAL-2287-->Cancel button and escape listener on
+              dialog warning user about disconnecting Jalview from a
+              Chimera session
+            </li>
+            <li>
+              <!-- JAL-2320-->Jalview's Chimera control window closes if
+              the Chimera it is connected to is shut down
+            </li>
+            <li>
+              <!-- JAL-1738-->New keystroke (B) and Select highlighted
+              columns menu item to mark columns containing
+              highlighted regions (e.g. from structure selections or results
+              of a Find operation)
+            </li>
+            <li>
+              <!-- JAL-2284-->Command line option for batch-generation
+              of HTML pages rendering alignment data with the BioJS
+              MSAviewer
+            </li>
+          </ul>
+        </div></td>
+      <td>
+        <div align="left">
+          <em>General</em>
+          <ul>
+            <li>
+              <!-- JAL-2286 -->Columns with more than one modal residue
+              are not coloured or thresholded according to percent
+              identity (first observed in Jalview 2.8.2)
+            </li>
+            <li>
+              <!-- JAL-2301 -->Threonine incorrectly reported as not
+              hydrophobic
+            </li>
+            <li>
+              <!-- JAL-2318 -->Updates to documentation pages (above PID
+              threshold, amino acid properties)
+            </li>
+            <li>
+              <!-- JAL-2292 -->Lower case residues in sequences are not
+              reported as mapped to residues in a structure file in the
+              View Mapping report
+            </li>
+            <li>
+              <!--JAL-2324 -->Identical features with non-numeric scores
+              could be added multiple times to a sequence
+            </li>
+            <li>
+              <!--JAL-2323, JAL-2333,JAL-2335,JAL-2327 -->Disulphide
+              bond features shown as two highlighted residues rather
+              than a range in linked structure views, and treated
+              correctly when selecting and computing trees from features
+            </li>
+            <li>
+              <!-- JAL-2281-->Custom URL links for database
+              cross-references are matched to database name regardless
+              of case
+            </li>
+
+          </ul>
+          <em>Application</em>
+          <ul>
+            <li>
+              <!-- JAL-2282-->Custom URL links for specific database
+              names without regular expressions also offer links from
+              Sequence ID
+            </li>
+            <li>
+              <!-- JAL-2315-->Removing a single configured link in the
+              URL links pane in Connections preferences doesn't actually
+              update Jalview configuration
+            </li>
+            <li>
+              <!-- JAL-2272-->CTRL-Click on a selected region to open
+              the alignment area popup menu doesn't work on El-Capitan
+            </li>
+            <li>
+              <!-- JAL-2280 -->Jalview doesn't offer to associate mmCIF
+              files with similarly named sequences if dropped onto the
+              alignment
+            </li>
+            <li>
+              <!-- JAL-2312 -->Additional mappings are shown for PDB
+              entries where more chains exist in the PDB accession than
+              are reported in the SIFTS file
+            </li>
+            <li>
+              <!-- JAL-2317-->Certain structures do not get mapped to
+              the structure view when displayed with Chimera
+            </li>
+            <li>
+              <!-- JAL-2317-->No chains shown in the Chimera view
+              panel's View->Show Chains submenu
+            </li>
+            <li>
+              <!--JAL-2277 -->Export as HTML with embedded SVG doesn't
+              work for wrapped alignment views
+            </li>
+            <li>
+              <!--JAL-2197 -->Rename UI components for running JPred
+              predictions from 'JNet' to 'JPred'
+            </li>
+            <li>
+              <!-- JAL-2337,JAL-2277 -->Export as PNG or SVG is
+              corrupted when annotation panel vertical scroll is not at
+              first annotation row
+            </li>
+            <li>
+              <!--JAL-2332 -->Attempting to view structure for Hen
+              lysozyme results in a PDB Client error dialog box
+            </li>
+          </ul>
+<!--           <em>New Known Issues</em>
+          <ul>
+            <li></li>
+          </ul> -->
+        </div>
+      </td>
+    </tr>
+      <td width="60" nowrap>
+        <div align="center">
+          <strong><a name="Jalview.2.10.0b1">2.10.0b1</a><br />
+            <em>25/10/2016</em></strong>
+        </div>
+      </td>
+      <td><em>Application</em>
+        <ul>
+          <li>3D Structure chooser opens with 'Cached structures'
+            view if structures already loaded</li>
+          <li>Progress bar reports models as they are loaded to
+            structure views</li>
+        </ul></td>
+      <td>
+        <div align="left">
+          <em>General</em>
+          <ul>
+            <li>Colour by conservation always enabled and no tick
+              shown in menu when BLOSUM or PID shading applied</li>
+            <li>FER1_ARATH and FER2_ARATH labels were switched in
+              example sequences/projects/trees</li>
+          </ul>
+          <em>Application</em>
+          <ul>
+            <li>Jalview projects with views of local PDB structure
+              files saved on Windows cannot be opened on OSX</li>
+            <li>Multiple structure views can be opened and
+              superposed without timeout for structures with multiple
+              models or multiple sequences in alignment</li>
+            <li>Cannot import or associated local PDB files without
+              a PDB ID HEADER line</li>
+            <li>RMSD is not output in Jmol console when
+              superposition is performed</li>
+            <li>Drag and drop of URL from Browser fails for Linux
+              and OSX versions earlier than El Capitan</li>
+            <li>ENA client ignores invalid content from ENA server</li>
+            <li>Exceptions are not raised in console when ENA
+              client attempts to fetch non-existent IDs via Fetch DB
+              Refs UI option</li>
+            <li>Exceptions are not raised in console when a new
+              view is created on the alignment</li>
+            <li>OSX right-click fixed for group selections:
+              CMD-click to insert/remove gaps in groups and CTRL-click
+              to open group pop-up menu</li>
+          </ul>
+          <em>Build and deployment</em>
+          <ul>
+            <li>URL link checker now copes with multi-line anchor
+              tags</li>
+          </ul>
+          <em>New Known Issues</em>
+          <ul>
+            <li>Drag and drop from URL links in browsers do not
+              work on Windows</li>
+          </ul>
+        </div>
+      </td>
+    </tr>
+    <tr>
+      <td width="60" nowrap>
+        <div align="center">
+          <strong><a name="Jalview.2.10.0">2.10.0</a><br /> <em>06/10/2016</em></strong>
         </div>
       </td>
       <td><em>General</em>
         <ul>
-            <li><!-- JAL---></li>
-            <li><!-- JAL-192 --->Alignment ruler shows positions relative to reference sequence</li>
+          <li>
+          <!-- JAL-2124 -->Updated Spanish translations.
+          </li> 
+          <li>
+            <!-- JAL-2164,JAL-1919,JAL-2148 -->Jmol now primary parser
+            for importing structure data to Jalview. Enables mmCIF and
+            better PDB parsing.
+          </li>
+          <li>
+            <!-- JAL-192 --->Alignment ruler shows positions relative to
+            reference sequence
+          </li>
+          <li>
+            <!-- JAL-2202 -->Position/residue shown in status bar when
+            mousing over sequence associated annotation
+          </li>
+          <li>
+            <!-- JAL-2171 -->Default RNA SS symbol to 'matching bracket'
+            for manual entry
+          </li>
+          <li>
+            <!-- JAL-2214 -->RNA Structure consensus indicates wc-only
+            '()', canonical '[]' and invalid '{}' base pair populations
+            for each column
+          </li>
+          <li>
+            <!-- JAL-2092 -->Feature settings popup menu options for
+            showing or hiding columns containing a feature
+          </li>
+          <li>
+            <!-- JAL-1557 -->Edit selected group by double clicking on
+            group and sequence associated annotation labels
+          </li>
+          <li>
+            <!-- JAL-2236 -->Sequence name added to annotation label in
+            select/hide columns by annotation and colour by annotation
+            dialogs
+          </li>
+
         </ul> <em>Application</em>
         <ul>
-            <li><!-- JAL---></li>
-            <li><!-- JAL-2027-->Support for reverse-complement coding regions in ENA and EMBL</li>
-            <li><!-- JAL-1855, JAL-2113, JAL-2114-->Upgrade to EMBL XML 1.2 for ENA record retrieval</li>
-            <li><!--  JAL 1812 -->New 'execute Groovy script' option in an alignment window's Calculate menu</li>
-            <li><!--  JAL 1812 -->Allow groovy scripts that call Jalview.getAlignFrames() to run in headless mode</li>
-            <li><!-- JAL-1369 --->Store/restore reference sequence in Jalview projects</li>
-             
-        </ul> <em>Applet</em>
+          <li>
+            <!-- JAL-2050-->Automatically hide introns when opening a
+            gene/transcript view
+          </li>
+          <li>
+            <!-- JAL-1563 -->Uniprot Sequence fetcher Free Text Search
+            dialog
+          </li>
+          <li>
+            <!--  JAL-1957, JAL-1479 JAL-1491 -->UniProt - PDB protein
+            structure mappings with the EMBL-EBI PDBe SIFTS database
+          </li>
+          <li>
+            <!-- JAL-2079 -->Updated download sites used for Rfam and
+            Pfam sources to xfam.org
+          </li>
+          <li>
+            <!-- JAL-2084 -->Disabled Rfam(Full) in the sequence fetcher
+          </li>
+          <li>
+            <!-- JAL-2123 -->Show residue labels in Chimera when mousing
+            over sequences in Jalview
+          </li>
+          <li>
+            <!-- JAL-2027-->Support for reverse-complement coding
+            regions in ENA and EMBL
+          </li>
+          <li>
+            <!-- JAL-1855, JAL-2113, JAL-2114-->Upgrade to EMBL XML 1.2
+            for record retrieval via ENA rest API
+          </li>
+          <li>
+            <!-- JAL-2027 -->Support for ENA CDS records with reverse
+            complement operator
+          </li>
+          <li>
+            <!--  JAL-1812 -->Update to groovy-2.4.6-indy - for faster
+            groovy script execution
+          </li>
+          <li>
+            <!--  JAL-1812 -->New 'execute Groovy script' option in an
+            alignment window's Calculate menu
+          </li>
+          <li>
+            <!--  JAL-1812 -->Allow groovy scripts that call
+            Jalview.getAlignFrames() to run in headless mode
+          </li>
+          <li>
+            <!--  JAL-2068 -->Support for creating new alignment
+            calculation workers from groovy scripts
+          </li>
+          <li>
+            <!-- JAL-1369 --->Store/restore reference sequence in
+            Jalview projects
+          </li>
+          <li>
+            <!-- JAL-1803 -->Chain codes for a sequence's PDB
+            associations are now saved/restored from project
+          </li>
+          <li>
+            <!-- JAL-1993 -->Database selection dialog always shown
+            before sequence fetcher is opened
+          </li>
+          <li>
+            <!-- JAL-2183 -->Double click on an entry in Jalview's
+            database chooser opens a sequence fetcher
+          </li>
+          <li>
+            <!-- JAL-1563 -->Free-text search client for UniProt using
+            the UniProt REST API
+          </li>
+          <li>
+            <!-- JAL-2168 -->-nonews command line parameter to prevent
+            the news reader opening
+          </li>
+          <li>
+            <!-- JAL-2028 -->Displayed columns for PDBe and Uniprot
+            querying stored in preferences
+          </li>
+          <li>
+            <!-- JAL-2091 -->Pagination for displaying PDBe and Uniprot
+            search results
+          </li>
+          <li>
+            <!-- JAL-1977-->Tooltips shown on database chooser
+          </li>
+          <li>
+            <!--  JAL-391 -->Reverse complement function in calculate
+            menu for nucleotide sequences
+          </li>
+          <li>
+            <!-- JAL-2005, JAL-599 -->Alignment sort by feature scores
+            and feature counts preserves alignment ordering (and
+            debugged for complex feature sets).
+          </li>
+          <li>
+            <!-- JAL-2152-->Chimera 1.11.1 minimum requirement for
+            viewing structures with Jalview 2.10
+          </li>
+          <li>
+            <!-- JAL-1705, JAL-1975, JAL-2050,JAL-2041,JAL-2105 -->Retrieve
+            genome, transcript CCDS and gene ids via the Ensembl and
+            Ensembl Genomes REST API
+          </li>
+          <li>
+            <!-- JAL-2049 -->Protein sequence variant annotation
+            computed for 'sequence_variant' annotation on CDS regions
+            (Ensembl)
+          </li>
+          <li>
+            <!-- JAL-2232 -->ENA CDS 'show cross references' for Uniprot
+            sequences
+          </li>
+          <li>
+            <!-- JAL-2213,JAL-1856 -->Improved warning messages when DB
+            Ref Fetcher fails to match, or otherwise updates sequence
+            data from external database records.
+          </li>
+          <li>
+            <!-- JAL-2154 -->Revised Jalview Project format for
+            efficient recovery of sequence coding and alignment
+            annotation relationships.
+          </li>
+        </ul> <!-- <em>Applet</em>
         <ul>
-            <li><!-- JAL---></li>
-        </ul></td>
+          <li>
+            -- JAL---
+          </li>
+        </ul> --></td>
       <td>
         <div align="left">
           <em>General</em>
           <ul>
-            <li><!-- JAL-2077 -->reinstate CTRL-click for opening pop-up menu on OSX</li>
-            <li><!-- JAL-2018-->Export features in Jalview format (again) includes graduated colourschemes</li>
-            <li><!-- JAL-1722, JAL-2001-->More responsive when working with big alignments and lots of hidden columns</li>
-            <li><!-- JAL-2053-->hidden column markers not always rendered at right of alignment window</li>
-            <li><!-- JAL-2067, JAL-  -->Tidied up links in help file table of contents</li>
-            <li><!-- JAL-2072  -->Feature based tree calculation not shown for DNA alignments</li>
-            <li><!-- JAL-2075  -->Hidden columns ignored during feature based tree calculation</li>
-            <li><!-- JAL-2065  -->Alignment view stops updating when show unconserved enabled for group on alignment</li>
-            <li><!--  JAL-2086  -->Cannot insert gaps into sequence when set as reference</li>
-            
+            <li>
+              <!-- JAL-2077 -->reinstate CTRL-click for opening pop-up
+              menu on OSX
+            </li>
+            <li>
+              <!-- JAL-2018-->Export features in Jalview format (again)
+              includes graduated colourschemes
+            </li>
+            <li>
+              <!-- JAL-2172,JAL-1722, JAL-2001-->More responsive when
+              working with big alignments and lots of hidden columns
+            </li>
+            <li>
+              <!-- JAL-2053-->Hidden column markers not always rendered
+              at right of alignment window
+            </li>
+            <li>
+              <!-- JAL-2067 -->Tidied up links in help file table of
+              contents
+            </li>
+            <li>
+              <!-- JAL-2072  -->Feature based tree calculation not shown
+              for DNA alignments
+            </li>
+            <li>
+              <!-- JAL-2075  -->Hidden columns ignored during feature
+              based tree calculation
+            </li>
+            <li>
+              <!-- JAL-2065  -->Alignment view stops updating when show
+              unconserved enabled for group on alignment
+            </li>
+            <li>
+              <!--  JAL-2086  -->Cannot insert gaps into sequence when
+              set as reference
+            </li>
+            <li>
+              <!-- JAL-2146 -->Alignment column in status incorrectly
+              shown as &quot;Sequence position&quot; when mousing over
+              annotation
+            </li>
+            <li>
+              <!--  JAL-2099 -->Incorrect column numbers in ruler when
+              hidden columns present
+            </li>
+            <li>
+              <!--  JAL-1577 -->Colour by RNA Helices not enabled when
+              user created annotation added to alignment
+            </li>
+            <li>
+              <!-- JAL-1841 -->RNA Structure consensus only computed for
+              '()' base pair annotation
+            </li>
+            <li>
+              <!-- JAL-2215, JAL-1841 -->Enabling 'Ignore Gaps' results
+              in zero scores for all base pairs in RNA Structure
+              Consensus
+            </li>
+            <li>
+              <!-- JAL-2174-->Extend selection with columns containing
+              feature not working
+            </li>
+            <li>
+              <!-- JAL-2275 -->Pfam format writer puts extra space at
+              beginning of sequence
+            </li>
+            <li>
+              <!-- JAL-1827 -->Incomplete sequence extracted from pdb
+              entry 3a6s
+            </li>
+            <li>
+              <!-- JAL-2238 -->Cannot create groups on an alignment from
+              from a tree when t-coffee scores are shown
+            </li>
+            <li>
+              <!-- JAL-1836,1967 -->Cannot import and view PDB
+              structures with chains containing negative resnums (4q4h)
+            </li>
+            <li>
+              <!--  JAL-1998 -->ArithmeticExceptions raised when parsing
+              some structures
+            </li>
+            <li>
+              <!--  JAL-1991, JAl-1952 -->'Empty' alignment blocks added
+              to Clustal, PIR and PileUp output
+            </li>
+            <li>
+              <!--  JAL-2008 -->Reordering sequence features that are
+              not visible causes alignment window to repaint
+            </li>
+            <li>
+              <!--  JAL-2006 -->Threshold sliders don't work in
+              graduated colour and colour by annotation row for e-value
+              scores associated with features and annotation rows
+            </li>
+            <li>
+              <!-- JAL-1797 -->amino acid physicochemical conservation
+              calculation should be case independent
+            </li>
+            <li>
+              <!-- JAL-2173 -->Remove annotation also updates hidden
+              columns
+            </li>
+            <li>
+              <!-- JAL-2234 -->FER1_ARATH and FER2_ARATH mislabelled in
+              example file (uniref50.fa, feredoxin.fa, unaligned.fa,
+              exampleFile_2_7.jar, exampleFile.jar, exampleFile_2_3.jar)
+            </li>
+            <li>
+              <!-- JAL-2065 -->Null pointer exceptions and redraw
+              problems when reference sequence defined and 'show
+              non-conserved' enabled
+            </li>
+            <li>
+              <!-- JAL-1306 -->Quality and Conservation are now shown on
+              load even when Consensus calculation is disabled
+            </li>
+            <li>
+              <!-- JAL-1932 -->Remove right on penultimate column of 
+              alignment does nothing
+            </li>
           </ul>
           <em>Application</em>
           <ul>
-            <li><!-- JAL-1944 not yet fixed Error thrown when exporting a view with hidden sequences as flat-file alignment--></li>
-            <li><!-- JAL-1911-->Corrupt preferences for SVG, EPS & HTML output when running on non-gb/us i18n platforms</li>
-            <li><!-- JAL-1552-->URLs and links can imported by drag'n'drop on OSX webstart</li>
-            <li><!-- JAL-2030-->InstallAnywhere distribution fails when launching Chimera</li>
-            <li><!-- JAL-2080-->Jalview very slow to launch via webstart (also hotfix for 2.9.0b2)</li>
-            <li><!--  JAL-2085  -->Cannot save project when view has a reference sequence defined</li>
-            <li><!--  JAL-1011  -->Columns are suddenly selected in other alignments and views when revealing hidden columns</li>
-            <li><!--  JAL-1989  -->Hide columns not mirrored in complement view in a cDNA/Protein splitframe</li>
-            <li><!--  JAL-1369 -->Cannot save/restore representative sequence from project when only one sequence is represented</li>
-            <!--  may exclude, this is an external service stability issue  JAL-1941 /> RNA 3D structure not added via DSSR service</li> -->
+            <li>
+              <!-- JAL-1552-->URLs and links can't be imported by
+              drag'n'drop on OSX when launched via webstart (note - not
+              yet fixed for El Capitan)
+            </li>
+            <li>
+              <!-- JAL-1911-->Corrupt preferences for SVG, EPS & HTML
+              output when running on non-gb/us i18n platforms
+            </li>
+            <li>
+              <!-- JAL-1944 -->Error thrown when exporting a view with
+              hidden sequences as flat-file alignment
+            </li>
+            <li>
+              <!-- JAL-2030-->InstallAnywhere distribution fails when
+              launching Chimera
+            </li>
+            <li>
+              <!-- JAL-2080-->Jalview very slow to launch via webstart
+              (also hotfix for 2.9.0b2)
+            </li>
+            <li>
+              <!--  JAL-2085  -->Cannot save project when view has a
+              reference sequence defined
+            </li>
+            <li>
+              <!--  JAL-1011  -->Columns are suddenly selected in other
+              alignments and views when revealing hidden columns
+            </li>
+            <li>
+              <!--  JAL-1989  -->Hide columns not mirrored in complement
+              view in a cDNA/Protein splitframe
+            </li>
+            <li>
+              <!--  JAL-1369 -->Cannot save/restore representative
+              sequence from project when only one sequence is
+              represented
+            </li>
+            <li>
+              <!-- JAL-2002 -->Disabled 'Best Uniprot Coverage' option
+              in Structure Chooser
+            </li>
+            <li>
+              <!-- JAL-2215 -->Modifying 'Ignore Gaps' on consensus or
+              structure consensus didn't refresh annotation panel
+            </li>
+            <li>
+              <!-- JAL-1962 -->View mapping in structure view shows
+              mappings between sequence and all chains in a PDB file
+            </li>
+            <li>
+              <!-- JAL-2102, JAL-2101, JAL-2102, -->PDB and Uniprot FTS
+              dialogs format columns correctly, don't display array
+              data, sort columns according to type
+            </li>
+            <li>
+              <!-- JAL-1975 -->Export complete shown after destination
+              file chooser is cancelled during an image export
+            </li>
+            <li>
+              <!-- JAL-2025 -->Error when querying PDB Service with
+              sequence name containing special characters
+            </li>
+            <li>
+              <!-- JAL-2024 -->Manual PDB structure querying should be
+              case insensitive
+            </li>
+            <li>
+              <!-- JAL-2104 -->Large tooltips with broken HTML
+              formatting don't wrap
+            </li>
+            <li>
+              <!-- JAL-1128 -->Figures exported from wrapped view are
+              truncated so L looks like I in consensus annotation
+            </li>
+            <li>
+              <!-- JAL-2003 -->Export features should only export the
+              currently displayed features for the current selection or
+              view
+            </li>
+            <li>
+              <!-- JAL-2036 -->Enable 'Get Cross-References' in menu
+              after fetching cross-references, and restoring from project
+            </li>
+            <li>
+              <!-- JAL-2032 -->Mouseover of a copy of a sequence is not
+              followed in the structure viewer
+            </li>
+            <li>
+              <!-- JAL-2163 -->Titles for individual alignments in
+              splitframe not restored from project
+            </li>
+            <li>
+              <!-- JAL-2145 -->missing autocalculated annotation at
+              trailing end of protein alignment in transcript/product
+              splitview when pad-gaps not enabled by default
+            </li>
+            <li>
+              <!-- JAL-1797 -->amino acid physicochemical conservation
+              is case dependent
+            </li>
+            <li>
+              <!-- JAL-1448 -->RSS reader doesn't stay hidden after last
+              article has been read (reopened issue due to
+              internationalisation problems)
+            </li>
+            <li>
+              <!-- JAL-1960 -->Only offer PDB structures in structure
+              viewer based on sequence name, PDB and UniProt
+              cross-references
+            </li>
+
+            <li>
+              <!-- JAL-1976 -->No progress bar shown during export of
+              alignment as HTML
+            </li>
+            <li>
+              <!-- JAL-2213 -->Structures not always superimposed after
+              multiple structures are shown for one or more sequences.
+            </li>
+            <li>
+              <!-- JAL-1370 -->Reference sequence characters should not
+              be replaced with '.' when 'Show unconserved' format option
+              is enabled.
+            </li>
+            <li>
+              <!-- JAL-1823 -->Cannot specify chain code when entering
+              specific PDB id for sequence
+            </li>
+            <li>
+              <!-- JAL-1944 -->File->Export->.. as doesn't work when
+              'Export hidden sequences' is enabled, but 'export hidden
+              columns' is disabled.
+            </li>
+            <li>
+              <!--JAL-2026-->Best Quality option in structure chooser
+              selects lowest rather than highest resolution structures
+              for each sequence
+            </li>
+            <li>
+              <!-- JAL-1887 -->Incorrect start and end reported for PDB
+              to sequence mapping in 'View Mappings' report
+            </li>
+            <li>
+              <!-- JAL-2284 -->Unable to read old Jalview projects that
+              contain non-XML data added after Jalvew wrote project.
+            </li>
+            <li><!-- JAL-2118 -->Newly created annotation row reorders
+              after clicking on it to create new annotation for a
+              column.
+            </li>
+            <!--  may exclude, this is an external service stability issue  JAL-1941 
+            -- > RNA 3D structure not added via DSSR service</li> -->
           </ul>
           <em>Applet</em>
           <ul>
-            <li><!--  --></li>
+            <li>
+              <!-- JAL-2151 -->Incorrect columns are selected when
+              hidden columns present before start of sequence
+            </li>
+            <li>
+              <!-- JAL-1986 -->Missing dependencies on applet pages
+              (JSON jars)
+            </li>
+            <li>
+              <!-- JAL-1947 -->Overview pixel size changes when
+              sequences are hidden in applet
+            </li>
+            <li>
+              <!-- JAL-1996 -->Updated instructions for applet
+              deployment on examples pages.
+            </li>
           </ul>
         </div>
       </td>
           <li>Updated Spanish translations of localized text for
             2.9</li>
         </ul> <em>Application</em>
-      <ul>
+        <ul>
           <!-- <li>cDNA/Protein splitframe window geometry preserved in Jalview projects</li>-->
           <li>Signed OSX InstallAnywhere installer<br></li>
           <li>Support for per-sequence based annotations in BioJSON</li>
         </ul> <em>Applet</em>
         <ul>
           <li>Split frame example added to applet examples page</li>
+        </ul><em>Build and Deployment</em>
+        <ul>
+          <li><!--  JAL-1888 -->New ant target for running Jalview's test suite</li>
         </ul></td>
       <td>
         <div align="left">
             <a href="https://www.certum.eu">Certum</a> to the Jalview
             open source project).
           </li>
-          <li>Jalview SRS links replaced by Uniprot and EBI-search
+          <li>Jalview SRS links replaced by UniProt and EBI-search
           </li>
           <li>Output in Stockholm format</li>
           <li>Allow import of data from gzipped files</li>
             current built in colourscheme is saved as new scheme</li>
           <li>AlignFrame-&gt;Save in application pops up save
             dialog for valid filename/format</li>
-          <li>Cannot view associated structure for Uniprot sequence</li>
-          <li>PDB file association breaks for Uniprot sequence
+          <li>Cannot view associated structure for UniProt sequence</li>
+          <li>PDB file association breaks for UniProt sequence
             P37173</li>
           <li>Associate PDB from file dialog does not tell you
             which sequence is to be associated with the file</li>
           <li>URL links generated from description line for
             regular-expression based URL links (applet and application)
 
+
+
+
+
           
           <li>Non-positional feature URL links are shown in link
             menu</li>
             between different screens.</li>
           <li>New preference items for sequence ID tooltip and
             consensus annotation</li>
-          <li>Client to submit sequences and IDs to Envision2 Workflows</li>
+          <li>Client to submit sequences and IDs to Envision2
+            Workflows</li>
           <li><em>Vamsas Capabilities</em>
             <ul>
               <li>Improved VAMSAS synchronization (Jalview archive
           <li>Save works when Jalview project is default format</li>
           <li>Save as dialog opened if current alignment format is
             not a valid output format</li>
-          <li>Uniprot canonical names introduced for both das and
+          <li>UniProt canonical names introduced for both das and
             vamsas</li>
           <li>Histidine should be midblue (not pink!) in Zappo</li>
           <li>error messages passed up and output when data read
             due to null pointer exceptions</li>
           <li>Secondary structure lines are drawn starting from
             first column of alignment</li>
-          <li>Uniprot XML import updated for new schema release in
+          <li>UniProt XML import updated for new schema release in
             July 2008</li>
           <li>Sequence feature to sequence ID match for Features
             file is case-insensitive</li>
           <li>PCA and PDB Viewers zoom via mouse roller
           <li>User-defined sub-tree colours and sub-tree selection
 
+
+
+
+
           
           <li>'New Window' button on the 'Output to Text box'
         </ul>
             of alignment)
           <li>Slowed DAS Feature Fetching for increased robustness.
 
+
+
+
+
           
           <li>Made angle brackets in ASCII feature descriptions
             display correctly
           <li>Re-instated Zoom function for PCA
           <li>Sequence descriptions conserved in web service
             analysis results
-          <li>Uniprot ID discoverer uses any word separated by
+          <li>UniProt ID discoverer uses any word separated by
             &#8739;
           <li>WsDbFetch query/result association resolved
           <li>Tree leaf to sequence mapping improved
           <li>Smooth fonts switch moved to FontChooser dialog box.
 
+
+
+
+
           
         </ul>
       </td>
index 73090d0..72a336a 100644 (file)
     and <strong>A</strong>nalysis of <strong>Molecular</strong> <strong>S</strong>equences,
     <strong>Alignements</strong> and <strong>S</strong>tructures).
     Currently, the only other VAMSAS enabled application is <a
-      href="http://www.topali.org"
-    >TOPALi</a> - a user friendly program for phylogenetics and
-    evolutionary analysis.
+      href="http://www.topali.org">TOPALi</a> - a user friendly
+    program for phylogenetics and evolutionary analysis.
   <p>
     VAMSAS enabled applications access a shared bioinformatics dataset
     containing sequences, alignments, annotation and trees, which can be
     represented by an XML document analogous to a <a
-      href="../features/jalarchive.html"
-    >Jalview Project Archive</a>.
+      href="../features/jalarchive.html">Jalview Project
+      Archive</a>.
   </p>
   <br>
   <strong>Connecting to a VAMSAS session</strong>
index 6d4a461..5cec67d 100644 (file)
     The majority of these scores were described by Valdar in 2002
     (Scoring residue conservation. <em>Proteins: Structure,
       Function, and Genetics</em> 43(2): 227-241. <a
-      href="http://www.ncbi.nlm.nih.gov/pubmed/12112692"
-    >PubMed</a> or available on the <a
-      href="http://valdarlab.unc.edu/publications.html"
-    >Valdar Group publications page</a>), but the SMERFs score was
-    developed later and described by Manning et al. in 2008 (<a
-      href="http://www.biomedcentral.com/1471-2105/9/51"
-    >BMC Bioinformatics 2008, 9:51 doi:10.1186/1471-2105-9-51</a>).
+      href="http://www.ncbi.nlm.nih.gov/pubmed/12112692">PubMed</a>
+    or available on the <a
+      href="http://valdarlab.unc.edu/publications.html">Valdar
+      Group publications page</a>), but the SMERFs score was developed later
+    and described by Manning et al. in 2008 (<a
+      href="http://www.biomedcentral.com/1471-2105/9/51">BMC
+      Bioinformatics 2008, 9:51 doi:10.1186/1471-2105-9-51</a>).
   </p>
   <p>
     <strong>Enabling and disabling AACon calculations</strong><br />
     <strong>Configuring which AACon calculations are performed</strong><br />
     The <strong>Web Services&rarr;Conservation&rarr;Change
       AACon Settings ...</strong> menu entry will open a <a
-      href="webServicesParams.html"
-    >web services parameter dialog</a> for the currently configured AACon
-    server. Standard presets are provided for quick and more expensive
-    conservation calculations, and parameters are also provided to
-    change the way that SMERFS calculations are performed.<br /> <em>AACon
-      settings for an alignment are saved in <a
-      href="../features/jalarchive.html"
-    >Jalview projects</a> along with the latest calculation results.
+      href="webServicesParams.html">web services parameter
+      dialog</a> for the currently configured AACon server. Standard presets
+    are provided for quick and more expensive conservation calculations,
+    and parameters are also provided to change the way that SMERFS
+    calculations are performed.<br /> <em>AACon settings for an
+      alignment are saved in <a href="../features/jalarchive.html">Jalview
+        projects</a> along with the latest calculation results.
     </em>
   </p>
   <p>
index 6750b55..f74e4c4 100644 (file)
@@ -42,8 +42,7 @@
     the <a href="webServicesPrefs.html">Web Services Preferences
       Panel</a>, and detailed information about a particular service is
     available from the help text and web pages accessible from its <a
-      href="webServicesParams.html"
-    >job parameters dialog box</a>.
+      href="webServicesParams.html">job parameters dialog box</a>.
   </p>
   <p>
     <strong>Obtaining JABAWS</strong><br> One of the aims of JABAWS
     stand-alone execution of analysis programs, or as a job submission
     engine - enabling larger numbers of jobs to be handled. If you would
     like to download and install JABAWS for your own use, please go to <a
-      href="http://www.compbio.dundee.ac.uk/jabaws"
-    >http://www.compbio.dundee.ac.uk/jabaws</a> for more information.
+      href="http://www.compbio.dundee.ac.uk/jabaws">http://www.compbio.dundee.ac.uk/jabaws</a>
+    for more information.
   </p>
   <p>
     <strong>Configuring your own JABAWS services for use by
       Jalview</strong><br> Once you have downloaded and installed JABAWS,
     and verified it is working, all that is needed is to add the URL for
     your JABAWS server(s) to the list in the <a
-      href="webServicesPrefs.html"
-    >Web Services Preferences Panel</a>. After adding your service and
-    saving your preferences or hitting the 'refresh web services'
-    button, you should be able to submit jobs to the server via the
-    alignment window's web services menu. Your JABAWS servers list is
-    stored in your Jalview preferences, so you will only have to
-    configure Jalview once for each new server.
+      href="webServicesPrefs.html">Web Services Preferences
+      Panel</a>. After adding your service and saving your preferences or
+    hitting the 'refresh web services' button, you should be able to
+    submit jobs to the server via the alignment window's web services
+    menu. Your JABAWS servers list is stored in your Jalview
+    preferences, so you will only have to configure Jalview once for
+    each new server.
   </p>
   <p>
     <em>Support for accessing JABAWS servers was introduced in
index 432e0a6..36e43aa 100644 (file)
@@ -36,8 +36,7 @@
     Gruber, and Peter F. Stadler, <em>RNAalifold: Improved
       consensus structure prediction for RNA alignments</em> (BMC
     Bioinformatics, 9:474, 2008). Download the paper at <a
-      href="http://www.biomedcentral.com/1471-2105/9/474"
-    >http://www.biomedcentral.com/1471-2105/9/474</a>.
+      href="http://www.biomedcentral.com/1471-2105/9/474">http://www.biomedcentral.com/1471-2105/9/474</a>.
   </p>
   <p>
     <strong>Running RNAalifold from Jalview</strong><br />
@@ -54,8 +53,7 @@
     <Strong>RNAalifold prediction parameters</Strong> <br /> JABAWS and
     Jalview only provide access to a selection of the RNAalifold
     arguments. For a full description, see the documentation at <a
-      href="http://www.tbi.univie.ac.at/RNA/RNAalifold.html"
-    >http://www.tbi.univie.ac.at/RNA/RNAalifold.html</a>.
+      href="http://www.tbi.univie.ac.at/RNA/RNAalifold.html">http://www.tbi.univie.ac.at/RNA/RNAalifold.html</a>.
   </p>
   <p>
     <strong>Supported Arguments which give alternate structures</strong>
@@ -75,8 +73,7 @@
     Calculate an MEA structure where the expected Accuracy is computed
     from the base pair probabilities. A more detailed description can be
     found in the <strong>RNAfold</strong> program documentation at <a
-      href="http://www.tbi.univie.ac.at/RNA/RNAfold.html"
-    >http://www.tbi.univie.ac.at/RNA/RNAfold.html</a>.
+      href="http://www.tbi.univie.ac.at/RNA/RNAfold.html">http://www.tbi.univie.ac.at/RNA/RNAfold.html</a>.
   </p>
   <p>
     <strong>Example RNAalifold Structure Annotation rows</strong>
index e919f3f..83c80ba 100644 (file)
 <p>
 <p>
   <strong>Discovering Database References for Sequences</strong><br>
-  Database references are associated with a sequence are displayed as a
-  list in the tooltip shown when mousing over its sequence ID. Jalview
-  uses references for the retrieval of <a
-    href="../features/viewingpdbs.html"
-  >PDB structures</a> and <a href="../features/dasfeatures.html">DAS
-    features</a>, and for retrieving sequence cross-references such as the
-  protein products of a DNA sequence.
+  Database references associated with a sequence are displayed as an
+  abbreviated list in the tooltip shown when mousing over its sequence
+  ID, and can be viewed in full via the
+  <a href="../io/exportseqreport.html">Sequence Details</a> window. .
+  Jalview also uses references for the retrieval of
+  <a href="../features/viewingpdbs.html">PDB structures</a> and <a
+    href="../features/dasfeatures.html">DAS features</a>, and for
+  retrieving sequence cross-references such as the protein products of a
+  DNA sequence.
 </p>
 <p>
   <strong>Initiating reference retrieval</strong><br> The
 <p>
   <strong>The Sequence Identification Process</strong><br> The
   method of accession id discovery is derived from the method which
-  earlier Jalview versions used for Uniprot sequence feature retrieval,
-  and was originally restricted to the identification of valid Uniprot
+  earlier Jalview versions used for UniProt sequence feature retrieval,
+  and was originally restricted to the identification of valid UniProt
   accessions.<br> Essentially, Jalview will try to retrieve records
   from a subset of the databases accessible by the <a
-    href="../features/seqfetch.html"
-  >sequence fetcher</a> using each sequence's ID string (or each string in
-  the ID separated by the '&#8739;' symbol).
+    href="../features/seqfetch.html">sequence fetcher</a> using each
+  sequence's ID string (or each string in the ID separated by the
+  '&#8739;' symbol).
 </p>
 <p>If a record (or set of records) is retrieved by any query derived
   from the ID string of a sequence, then the sequence is aligned to the
index 1463554..d0b497c 100755 (executable)
       <ul>
         <li>Programs for <a href="msaclient.html">multiple
             sequence alignment</a>, made available <em>via</em> <a
-          href="JABAWS.html"
-        >Java Bioinformatic Analysis Web Service (JABAWS)</a> servers.
+          href="JABAWS.html">Java Bioinformatic Analysis
+            Web Service (JABAWS)</a> servers.
         </li>
         <li>Jalview SOAP Web Services for <a href="jnet.html">secondary
             structure prediction</a> based at the University of Dundee.
         </li>
         <li>Services for alignment analysis, such as <a
-          href="shmr.html"
-        >Multi-Harmony</a>.
+          href="shmr.html">Multi-Harmony</a>.
       </ul>
       <p>
         <strong>Web Service Dialog Box</strong>
         citation information, and monitors the progress of the
         calculation. The cancel button will permanently cancel the job,
         but this is only possible for some services.</p> The <a
-      href="webServicesPrefs.html"
-    >Web Services Preference panel</a> controls the display and appearance
-      of the submission and analysis services in the <strong>Web
-        Services</strong> menu.
+      href="webServicesPrefs.html">Web Services Preference
+        panel</a> controls the display and appearance of the submission and
+      analysis services in the <strong>Web Services</strong> menu.
     </li>
     <li>If Jalview encounters problems accessing any services, it
       may display a <a href="webServicesPrefs.html#wswarnings">warning
   <p>
     <strong>More about Jalview's Web Services</strong> <br>
     Jalview's distributed computations utilise <a
-      href="http://en.wikipedia.org/wiki/SOAP"
-    >SOAP</a> and <a
-      href="http://en.wikipedia.org/wiki/Representational_State_Transfer"
-    >REST</a> web services exposing sequence alignment, analysis, and
-    secondary structure prediction programs. Originally, Jalview 2's
-    services were maintained by the Barton group at the University of
-    Dundee, and ran programs on the Life Sciences High-performance
-    Computing Cluster. With the advent of <a
-      href="http://www.compbio.dundee.ac.uk/jabaws"
-    >JABAWS</a>, however, it is possible for anyone to host Jalview web
-    services.
+      href="http://en.wikipedia.org/wiki/SOAP">SOAP</a> and <a
+      href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a>
+    web services exposing sequence alignment, analysis, and secondary
+    structure prediction programs. Originally, Jalview 2's services were
+    maintained by the Barton group at the University of Dundee, and ran
+    programs on the Life Sciences High-performance Computing Cluster.
+    With the advent of <a href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS</a>,
+    however, it is possible for anyone to host Jalview web services.
   </p>
 </body>
 </html>
index 0dfbd10..396a3a7 100755 (executable)
@@ -38,8 +38,7 @@
       JPred4: a protein secondary structure prediction server<br /> <em>Nucleic
         Acids Research</em>, <strong>Web Server issue</strong> (first
       published 15th April 2015)<br /> <a
-      href="http://dx.doi.org/10.1093/nar/gkv332"
-    >http://dx.doi.org/10.1093/nar/gkv332</a>
+      href="http://dx.doi.org/10.1093/nar/gkv332">http://dx.doi.org/10.1093/nar/gkv332</a>
     </li>
     <li>Cole C., Barber J.D. and Barton G.J. (2008) The Jpred 3
       secondary structure prediction server <em>Nucleic Acids
   </p>
   <em>JNet annotation created in Jalview 2.8.2 and later versions
     can be displayed on other alignments via the <a
-    href="../features/annotation.html#seqannots"
-  >Add reference annotation</a> Sequence ID popup menu option.
+    href="../features/annotation.html#seqannots">Add reference
+      annotation</a> Sequence ID popup menu option.
   </em>
   <em>As of Jalview 2.6, the Jnet service accessed accessed via the
     'Secondary structure prediction' submenu should be considered a
index 6266036..2fbbdbc 100644 (file)
@@ -63,8 +63,8 @@
     <li><a href="http://www.drive5.com/muscle">Muscle</a> (version
       3.8.31)</li>
     <li><a
-      href="http://www.tcoffee.org/Projects_home_page/t_coffee_home_page.html"
-    >Tcoffee</a> (version 8.99)</li>
+      href="http://www.tcoffee.org/Projects_home_page/t_coffee_home_page.html">Tcoffee</a>
+      (version 8.99)</li>
     <li><a href="http://probcons.stanford.edu/">Probcons</a>
       (version 1.12)</li>
   </ul>
     <strong>Multiple Alignments of Sequences with hidden
       columns</strong><br> Multiple alignment services are 'column
     separable' analysis operations. If the input contains <a
-      href="../features/hiddenRegions.html"
-    >hidden columns</a> then each visible segment of the input sequence
-    set will be submitted for alignment separately, and the results
-    concatenated (with the hidden regions preserved) once all alignment
-    functions have completed. Each sub-job's state is reported in its
-    own tab:
+      href="../features/hiddenRegions.html">hidden columns</a> then
+    each visible segment of the input sequence set will be submitted for
+    alignment separately, and the results concatenated (with the hidden
+    regions preserved) once all alignment functions have completed. Each
+    sub-job's state is reported in its own tab:
   <p>
   <center>
     <strong>Multiple Multiple Sequence Alignment sub jobs
index 5ec088a..c3c1d3f 100644 (file)
   <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 Desktop News Channel</a>.
+      href="http://www.jalview.org/feeds/desktop/rss">Jalview
+      Desktop News Channel</a>.
   </p>
 
   <p>We will use the desktop news channel to keep you informed of
     important updates relevant to users of the Jalview desktop, such as
     web service outages and user community events.</p>
-  <p>The news reader will be launched automatically when you start
-    the Desktop if new items are available. Should you want to browse
-    older items, however, you can open it manually from the 'Jalview
-    news reader' option in the Desktop's <a href="../menus/desktopMenu.html">'Tools' menu</a>.</p><br/>
-  <div style="text-align: center;"><img src="jalviewrssreader.gif" width="513"
-    height="337" alt="Snapshot of the Jalview Desktop's RSS reader"/></div>
+  <p>
+    The news reader will be launched automatically when you start the
+    Desktop if new items are available. Should you want to browse older
+    items, however, you can open it manually from the 'Jalview news
+    reader' option in the Desktop's <a href="../menus/desktopMenu.html">'Tools'
+      menu</a>.
+  </p>
+  <br />
+  <div style="text-align: center;">
+    <img src="jalviewrssreader.gif" width="513" height="337"
+      alt="Snapshot of the Jalview Desktop's RSS reader" />
+  </div>
 
-  <br/><p>
+  <br />
+  <p>
     The <em>Jalview news reader</em> was introduced in <a
-      href="http://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="http://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>.
   </p>
-  <br/><em>From Jalview 2.10.0, check for news on startup can be disabled with <a href="../features/clarguments.html">command-line parameter</a> &#39;-nonews&#39;. 
-  This is not recommended for normal use, but may be useful to avoid interruptions when teaching, demonstrating, recording etc.</em>
+  <br />
+  <em>If you need to prevent the news-reader opening, then add the
+    <a href="../features/clarguments.html">command-line parameter</a>
+    &#39;-nonews&#39; to Jalview's command-line launch.
+  </em>
 </body>
 </html>
index 57e6698..1c35bf3 100644 (file)
     The <strong>Web Services&rarr;Disorder</strong> menu in the
     alignment window allows access to protein disorder prediction
     services provided by the configured <a
-      href="http://www.compbio.dundee.ac.uk/jabaws"
-    >JABAWS servers</a>. Each service operates on sequences in the
-    alignment or currently selected region (<em>since Jalview
-      2.8.0b1</em>) to identify regions likely to be unstructured or
-    flexible, or alternately, fold to form globular domains.
+      href="http://www.compbio.dundee.ac.uk/jabaws">JABAWS
+      servers</a>. Each service operates on sequences in the alignment or
+    currently selected region (<em>since Jalview 2.8.0b1</em>) to
+    identify regions likely to be unstructured or flexible, or
+    alternately, fold to form globular domains.
   </p>
   <p>
     Predictor results include both <a
-      href="../features/seqfeatures.html"
-    >sequence features</a> and sequence associated <a
-      href="../features/annotation.html"
-    >alignment annotation</a> rows. Features display is controlled from
-    the <a href="../features/featureSettings.html">Feature Settings</a>
+      href="../features/seqfeatures.html">sequence features</a> and
+    sequence associated <a href="../features/annotation.html">alignment
+      annotation</a> rows. Features display is controlled from the <a
+      href="../features/featuresettings.html">Feature Settings</a>
     dialog box. Clicking on the ID for a disorder prediction annotation
     row will highlight or select (if double clicked) the associated
     sequence for that row. You can also use the <em>Sequence
       Associated</em> option in the <a
-      href="../colourSchemes/annotationColouring.html"
-    >Colour By Annotation</a> dialog box to colour sequences according to
-    the results of predictors shown as annotation rows.
+      href="../colourSchemes/annotationColouring.html">Colour
+      By Annotation</a> dialog box to colour sequences according to the
+    results of predictors shown as annotation rows.
   </p>
   <p>JABAWS 2.0 provides four disorder predictors which are
     described below:</p>
       <td>Sequence Feature &amp;<br />Annotation Row
       </td>
       <td>Predicts loops/coils according to DSSP definition<a
-        href="#dsspstates"
-      >[1]</a>.<br />Features mark range(s) of residues predicted as
-        loops/coils, and annotation row gives raw value for each
-        residue. Value over 0.516 indicates loop/coil.
+        href="#dsspstates">[1]</a>.<br />Features mark range(s)
+        of residues predicted as loops/coils, and annotation row gives
+        raw value for each residue. Value over 0.516 indicates
+        loop/coil.
       </td>
     </tr>
     <tr>
 
   <p>
     <strong><a name="ronn"></a><a
-      href="http://www.strubi.ox.ac.uk/RONN"
-    >RONN</a></strong> <em>a.k.a.</em> Regional Order Neural Network<br />This
-    predictor employs an approach known as the 'bio-basis' method to
-    predict regions of disorder in sequences based on their local
-    similarity with a gold-standard set of disordered protein sequences.
-    It yields a set of disorder prediction scores, which are shown as
-    sequence annotation below the alignment.
+      href="http://www.strubi.ox.ac.uk/RONN">RONN</a></strong> <em>a.k.a.</em>
+    Regional Order Neural Network<br />This predictor employs an
+    approach known as the 'bio-basis' method to predict regions of
+    disorder in sequences based on their local similarity with a
+    gold-standard set of disordered protein sequences. It yields a set
+    of disorder prediction scores, which are shown as sequence
+    annotation below the alignment.
   </p>
   <table border="1">
     <tr>
   </p>
   <p>
     <strong><a name="iupred"></a><a
-      href="http://iupred.enzim.hu/Help.php"
-    >IUPred</a></strong><br /> IUPred employs an empirical model to estimate
-    likely regions of disorder. There are three different prediction
-    types offered, each using different parameters optimized for
-    slightly different applications. It provides raw scores based on two
-    models for predicting regions of 'long disorder' and 'short
-    disorder'. A third predictor identifies regions likely to form
-    structured domains.
+      href="http://iupred.enzim.hu/Help.php">IUPred</a></strong><br />
+    IUPred employs an empirical model to estimate likely regions of
+    disorder. There are three different prediction types offered, each
+    using different parameters optimized for slightly different
+    applications. It provides raw scores based on two models for
+    predicting regions of 'long disorder' and 'short disorder'. A third
+    predictor identifies regions likely to form structured domains.
   </p>
   <table border="1">
     <tr>
   </table>
   <p>
     <strong><a name="globplot"></a><a
-      href="http://globplot.embl.de/"
-    >GLOBPLOT</a></strong><br /> Defines regions of globularity or natively
-    unstructured regions based on a running sum of the propensity of
-    residues to be structured or unstructured. The propensity is
-    calculated based on the probability of each amino acid being
-    observed within well defined regions of secondary structure or
-    within regions of random coil. The initial signal is smoothed with a
-    Savitzky-Golay filter, and its first order derivative computed.
-    Residues for which the first order derivative is positive are
-    designated as natively unstructured, whereas those with negative
-    values are structured.<br />
+      href="http://globplot.embl.de/">GLOBPLOT</a></strong><br /> Defines
+    regions of globularity or natively unstructured regions based on a
+    running sum of the propensity of residues to be structured or
+    unstructured. The propensity is calculated based on the probability
+    of each amino acid being observed within well defined regions of
+    secondary structure or within regions of random coil. The initial
+    signal is smoothed with a Savitzky-Golay filter, and its first order
+    derivative computed. Residues for which the first order derivative
+    is positive are designated as natively unstructured, whereas those
+    with negative values are structured.<br />
   <table border="1">
     <tr>
       <td><strong>Name</strong></td>
index 29e2c1e..803def7 100755 (executable)
     a protein sequence multiple alignment that has been sub-divided into
     groups containing at least two non-identical protein sequences. An
     easy way to create groups is to use the built-in <a
-      href="../calculations/tree.html"
-    >neighbour-joining or UPGMA tree</a> routines to calculate a tree for
-    the alignment, and then click on the tree to subdivide the
-    alignment.
+      href="../calculations/tree.html">neighbour-joining or
+      UPGMA tree</a> routines to calculate a tree for the alignment, and
+    then click on the tree to subdivide the alignment.
   </p>
   <p>
     The SHMR service operates on the currently selected visible
     region(s) of the alignment. Once submitted, a job progress window
     will display status information about your job, including a URL
     which allows you to visit the status page on the <a
-      href="http://zeus.few.vu.nl/programs/shmrwww/"
-    >IBIVU SHMR server</a>.
+      href="http://zeus.few.vu.nl/programs/shmrwww/">IBIVU SHMR
+      server</a>.
   </p>
   <p>When the job is complete, Jalview will automatically open a new
     window containing the alignment and groups that were submitted for
     analysis, with additional histograms added portraying the SHMR
     scores for each column of the sub-grouped alignment.</p>
   <p>
-    If you use this service in your work, please cite :<br />
+    If you use this service in your work, please cite :<br /> 
     <a name="shmrref" /> Brandt, B.W.*, Feenstra, K.A*. and Heringa, J.
     (2010) Multi-Harmony: detecting functional specificity from sequence
     alignment. <a
-      href="http://nar.oxfordjournals.org/cgi/content/abstract/gkq415"
-    >Nucleic Acids Res. 38: W35-W40.</a> (<em>* joint first authors</em>)
-  
+      href="http://nar.oxfordjournals.org/cgi/content/abstract/gkq415">Nucleic
+      Acids Res. 38: W35-W40.</a> (<em>* joint first authors</em>)
   <p>
     <strong><em>Note:</em></strong> The Multi-Harmony service is
     implemented with a prototype of Jalview's RESTful web service client
index 7a23d58..088a539 100644 (file)
@@ -28,9 +28,8 @@
     and the desktop application are able to open URLs as 'popups' in
     your web browser. <br> Double-clicking on the ID of a sequence
     will open the first URL that can be generated from its sequence ID.
-    This is often the SRS site, but you can easily configure your own <a
-      href="#urllinks"
-    >sequence URL links</a>.
+    This is by default the EMBL-EBI site, but you can easily configure your own <a
+      href="#urllinks">sequence URL links</a>.
   </p>
   <p>
     Other links for a sequence either derived from any other configured
   <p>
     <strong><a name="urllinks">Configuring URL Links</a></strong> <br>URL
     links are defined in the &quot;Connections&quot; tab of the <a
-      href="../features/preferences.html"
-    >Jalview desktop preferences</a>, or specified as <a
-      href="http://www.jalview.org/examples/appletParameters.html#parameters"
-    >applet parameters</a>. <br> By default the item &quot;SRS&quot;
-    is added to this link menu. This link will show a web page in your
-    default browser with the selected sequence id as part of the URL.<br>
+    href="../features/preferences.html">Jalview desktop
+    preferences</a>, or specified as <a
+    href="http://www.jalview.org/examples/appletParameters.html#parameters">applet
+    parameters</a>. <br> By default the item &quot;EMBL-EBI Search&quot; is added
+    to this link menu. This link will show a web page in your default
+    browser with the selected sequence id as part of the URL.<br>
     In the preferences dialog box, click <strong>new</strong> to add a
     new link, and <strong>edit</strong> to modify an existing link, or <strong>delete</strong>
     to remove it.<br> You can name the link, this will be displayed
     on a new menu item under the &quot;Link&quot; menu when you right
     click on a sequence id. <br> The URL string must contain a
-    token that can be replaced with a sequence ID. The simplest token is
+    token that can be replaced with a sequence ID or DB accession ID. The simplest token is
     &quot;$SEQUENCE_ID$&quot;, which will be replaced by the chosen
-    sequence id when you click on it.
+    sequence id when you click on it. 
   </p>
   <p>
     eg.<br> UniRef100 =
     Swissprot = http://www.expasy.org/uniprot/$SEQUENCE_ID$ <br> <br>
     Links will also be made for any database cross references associated
     with the sequence where the database name exactly matches a URL link
-    name. In this case, the $SEQUENCE_ID$ string will be replaced with
+    name. In this case, the $DB_ACCESSION$ string will be replaced with
     the accession string for the database cross-reference, rather than
-    the sequence ID for the sequence (<em>since Jalview 2.4</em>).
+    the sequence ID for the sequence (<em>since Jalview 2.10.1</em>).
+  </p>
+  <p>
+    <strong><a name="warning">Warning dialog about updating
+        your configured URL links</a></strong><br /> In the desktop
+    prior to Jalview 2.10.1, the only way to configure custom links for
+    a particular database cross-reference for a sequence was to give it
+    a name that
+    <em>exactly</em> matched the database source, and a regular
+    expression for filtering out any spurious matches generated when the
+    custom linked was tested against the Sequence's ID string. Since the
+    introduction of the $DB_ACCESSION$ token, however, $SEQUENCE_ID$
+    will not be used for database cross-reference accession strings, and
+    if you have custom links configured, Jalview will raise a warning
+    message so let you know that you may need to update your links to
+    use $DB_ACCESSION$.
   </p>
   <p>
     <strong>Regular Expression Substitution</strong><br> A url may
     contain a string of the form $SEQUENCE_ID=/<em>regular
-      expression</em>/=$. In this case, the regular expression will be
-    applied to the full sequence ID string and the resulting match will
+    expression</em>/=$ or $DB_ACCESSION=/<em>regular expression</em>/=$. 
+    In this case, the regular expression will be
+    applied to the full sequence ID or DB accession ID string and the resulting match will
     be inserted into the URL. Groups of parentheses can be used to
     specify which regions of the regular expression will be used to
     generate the URL:
index 585cdfb..84eccc3 100644 (file)
 
   <p>
     Some Jalview services, including those provided by <a
-      href="JABAWS.html"
-    >JABAWS</a>, support a range of parameters and options, enabling you
-    to employ the most appropriate settings for the input data. In
-    addition to any preset combinations provided by services themselves,
-    the Web services parameters dialog box also allows you to create and
-    store your own parameter sets, so they can be accessed quickly from
-    the presets menu.
+      href="JABAWS.html">JABAWS</a>, support a range of parameters
+    and options, enabling you to employ the most appropriate settings
+    for the input data. In addition to any preset combinations provided
+    by services themselves, the Web services parameters dialog box also
+    allows you to create and store your own parameter sets, so they can
+    be accessed quickly from the presets menu.
   </p>
   <p>
     <Strong>Accessing the parameter dialog box</Strong><br> The
@@ -61,8 +60,8 @@
   <p>
   <center>
     <img src="wsparams.gif" align="center" width="480" height="499"
-      alt="Analysis Parameters Dialog Box for JABAWS Services"
-    > <br> Parameter settings dialog box for JABAWS MAFFT Service
+      alt="Analysis Parameters Dialog Box for JABAWS Services">
+    <br> Parameter settings dialog box for JABAWS MAFFT Service
   </center>
   </p>
   <p>The menu and text box at the top of the dialog box displays the
@@ -73,6 +72,7 @@
     this), allowing you to provide notes to accompany the parameter set.
     The modification of these or any of the option or parameter settings
     will enable one or more of the following buttons, that allow you to:
+
   
   <ul>
     <li><em>Revert</em> the changes you have made. This will undo
index 1950058..0ebeea5 100644 (file)
@@ -38,8 +38,8 @@
   <p>
   <center>
     <img src="wsprefs.gif" align="center"
-      alt="Web Services Preferences Panel" width="571" height="461"
-    ><br> Web Services Preference Panel
+      alt="Web Services Preferences Panel" width="571" height="461"><br>
+    Web Services Preference Panel
   </center>
   </p>
   <p>
@@ -85,8 +85,8 @@
   <center>
     <img src="invalidurldialog.gif" align="center"
       alt="Web Services Invalid URL Warning dialog box" width="389"
-      height="258"
-    ><br> Web Services Invalid URL Warning dialog box
+      height="258"><br> Web Services Invalid URL Warning
+    dialog box
   </center>
   <br>
   <strong><em>Note:</em></strong> this warning will be shown if you are
index d7a93c6..e8b9c96 100755 (executable)
 </head>
 <body>
   <p>
-    <strong>What's new ?</strong>
+    <strong>What's new in Jalview 2.10.1 ?</strong>
   </p>
   <p>
-    Jalview 2.9.1 is the next major release in the Jalview 2.9 series. Full details are in the
-    <a href="releases.html#Jalview.2.9.1">Jalview 2.9.1 Release Notes</a>.
+    Jalview 2.10.1 was released on 24th November 2016. Full details are
+    in the <a href="releases.html#Jalview.2.10.1">Jalview 2.10.1
+      Release Notes</a>, but the highlights are below. This is also the
+    first release to include contributions from Kira Mour&atilde;o, who
+    joined Jalview's core development team in October 2016.
   </p>
-  <p>
-    <strong>Highlights in Jalview 2.9.1</strong>
   <ul>
+    <li><strong>More memory efficient</strong><br />We've slimmed
+      down the consensus analysis data structures used by Jalview so
+      even wider alignments can be worked with.</li>
+    <li><strong>Select highlighted region</strong><br />Press 'B'
+      or use the new menu option in the alignment window's Select menu
+      to mark columns containing highlighted regions generated from
+      structure selections, mouse-overs, or resulting from a
+      Find operation.</li>
+    <li><strong>New custom link mechanism for opening URLs
+        for database cross references.</strong><br /> If you have customised URL
+      links in your Jalview preferences, then you may already have seen
+      the <a href="webServices/urllinks.html">Update your links
+        warning dialog.</a></li>
+    <li><strong>New command line export option for BioJS
+        MSAviewer</strong><br />A number of small bugs with the HTML export
+      functions from the Jalview desktop were also fixed.</li>
+    <li><strong>Small but significant changes to the
+        physicochemical properties and consensus calculations</strong><br />Threonine
+      is no longer considered a non-hydrophobic residue in the protein
+      conservation calculation, and minor bugs addressed in PID and
+      consensus colouring.</li>
   </ul>
 
 </body>
diff --git a/lib/Jmol-14.2.14_2015.06.11.jar b/lib/Jmol-14.2.14_2015.06.11.jar
deleted file mode 100644 (file)
index 1470745..0000000
Binary files a/lib/Jmol-14.2.14_2015.06.11.jar and /dev/null differ
diff --git a/lib/Jmol-14.6.4_2016.10.26.jar b/lib/Jmol-14.6.4_2016.10.26.jar
new file mode 100644 (file)
index 0000000..1016c3f
Binary files /dev/null and b/lib/Jmol-14.6.4_2016.10.26.jar differ
index ac1a2e3..b569f55 100644 (file)
@@ -59,8 +59,8 @@ file.reference.jalview-src=src
 file.reference.jaxrpc.jar=lib/jaxrpc.jar
 file.reference.JGoogleAnalytics_0.3.jar=lib/JGoogleAnalytics_0.3.jar
 file.reference.jhall.jar=lib/jhall.jar
-file.reference.Jmol-14.2.14_2015.06.11.jar=lib/Jmol-14.2.14_2015.06.11.jar
-file.reference.JmolApplet-14.2.14_2015.06.11.jar=appletlib/JmolApplet-14.2.14_2015.06.11.jar
+file.reference.Jmol-14.6.4_2016.10.26.jar=lib/Jmol-14.6.4_2016.10.26.jar
+file.reference.JmolApplet-14.6.4_2016.10.26.jar=appletlib/JmolApplet-14.6.4_2016.10.26.jar
 file.reference.log4j-1.2.8.jar=lib/log4j-1.2.8.jar
 file.reference.mail.jar=lib/mail.jar
 file.reference.min-jaba-client.jar=lib/min-jaba-client-2.0.jar
@@ -92,7 +92,7 @@ javac.classpath=\
     ${file.reference.jaxrpc.jar}:\
     ${file.reference.JGoogleAnalytics_0.3.jar}:\
     ${file.reference.jhall.jar}:\
-    ${file.reference.Jmol-14.2.14_2015.06.11.jar}:\
+    ${file.reference.Jmol-14.6.4_2016.10.26.jar}:\
     ${file.reference.miglayout-4.0-swing.jar}:\
     ${file.reference.log4j-1.2.8.jar}:\
     ${file.reference.mail.jar}:\
@@ -101,7 +101,7 @@ javac.classpath=\
     ${file.reference.xml-apis.jar}:\
     ${file.reference.xercesImpl.jar}:\
     ${file.reference.wsdl4j.jar}:\
-    ${file.reference.JmolApplet-14.2.14_2015.06.11.jar} \
+    ${file.reference.JmolApplet-14.6.4_2016.10.26.jar} \
     ${file.reference.varna-3.9-dev.jar}
 # Space-separated list of extra javac options
 javac.compilerargs=
index d41c2ca..3488ac6 100644 (file)
@@ -1,4 +1,4 @@
-YEAR=2014
-AUTHORS=J Procter, AM Waterhouse, M Carstairs, TC Ofoegbu, J Engelhardt, LM Lui, A Menard, D Barton, N Sherstnev, D Roldan-Martinez, M Clamp, S Searle, G Barton
-AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Mungo Carstairs, Tochukwu 'Charles' Ofoegbu, Jan Engelhardt, Lauren Lui, Anne Menard, Daniel Barton, Natasha Sherstnev, David Roldan-Martinez, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
+YEAR=2016
+AUTHORS=J Procter, M Carstairs, TC Ofoegbu, K Mourao, AM Waterhouse, J Engelhardt, LM Lui, A Menard, D Barton, N Sherstnev, D Roldan-Martinez, M Clamp, S Searle, G Barton
+AUTHORFNAMES=Jim Procter, Mungo Carstairs, Tochukwu 'Charles' Ofoegbu, Kira Mourao, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Anne Menard, Daniel Barton, Natasha Sherstnev, David Roldan-Martinez, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
  
\ No newline at end of file
index 01b921a..3b80821 100644 (file)
@@ -28,6 +28,9 @@
        -->
        <class name="jalview.datamodel.xdb.embl.EmblFile">
                <map-to xml="ROOT"/>
+               <field name="text" type="string">
+                       <bind-xml node="text"/>
+               </field>
                <field name="entries" type="jalview.datamodel.xdb.embl.EmblEntry" collection="vector">
                        <bind-xml name="entry"/>
                </field>
index 5ac50bb..278b86e 100644 (file)
@@ -44,7 +44,7 @@ _data_column.preferred_col_width
 _data_column.is_shown_by_default
 _data_column.is_searchable
 PDB Id;pdb_id;String;g2;40;60;45;true;true
-Title;title;String;g6;300;1500;400;true;false
+Title;title;String;g6;50;1500;400;true;false
 Molecule;molecule_name;String;g3;50;400;95;false;true
 Molecule Type;molecule_type;String;g3;50;400;95;false;true
 Sequence;molecule_sequence;String;g6;50;400;95;false;false
@@ -111,7 +111,7 @@ R Free;r_free;Double|T|3;g1;50;150;85;false;false
 Number of Polymer Entities;number_of_polymer_entities;int;g6;50;400;95;false;false
 Number of Bound Entities;number_of_bound_entities;int;g6;50;400;95;false;false
 Crystallisation Reservoir;crystallisation_reservoir;String;g6;50;400;95;false;false
-Data Scalling Software;data_scaling_software;String;g4;50;400;95;false;false
+Data Scaling Software;data_scaling_software;String;g4;50;400;95;false;false
 Detector;detector;String;g6;50;400;95;false;false
 Detector Type;detector_type;String;g6;50;400;95;false;false
 Modified Residue Flag;modified_residue_flag;String;g6;50;400;95;false;false
index b01464a..6360dc7 100644 (file)
@@ -125,6 +125,8 @@ action.change_font_tree_panel = Change Font (Tree Panel)
 action.colour = Colour
 action.calculate = Calculate
 action.select_all = Select all
+action.select_highlighted_columns = Select Highlighted Columns
+tooltip.select_highlighted_columns = Press B to mark highlighted columns, Ctrl-(or Cmd)-B to toggle, and Alt-B to mark all but highlighted columns 
 action.deselect_all = Deselect all
 action.invert_selection = Invert selection
 action.using_jmol = Using Jmol
@@ -382,8 +384,8 @@ label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation =
 label.translation_failed = Translation Failed
 label.error_when_translating_sequences_submit_bug_report = Unfortunately, something went wrong when translating your sequences.\nPlease take a look in the Jalview java console\nand submit a bug report including the stacktrace.
 label.implementation_error  = Implementation error:
-label.automatically_associate_pdb_files_with_sequences_same_name = Do you want to automatically associate the {0} PDB files with sequences in the alignment that have the same name?
-label.automatically_associate_pdb_files_by_name = Automatically Associate PDB files by name
+label.automatically_associate_structure_files_with_sequences_same_name = Do you want to automatically associate the {0} structure file(s) with sequences in the alignment that have the same name?
+label.automatically_associate_structure_files_by_name = Automatically Associate Structure files by name
 label.ignore_unmatched_dropped_files_info = <html>Do you want to <em>ignore</em> the {0} files whose names did not match any sequence IDs ?</html>
 label.ignore_unmatched_dropped_files = Ignore unmatched dropped files?
 label.view_name_original = Original
@@ -729,8 +731,8 @@ label.move_url_down = Move URL Down
 label.add_sbrs_definition = Add a SBRS Definition
 label.edit_sbrs_definition = Edit SBRS Definition
 label.delete_sbrs_definition = Delete SBRS Definition
-label.your_sequences_have_been_verified = Your sequences have been verified against known sequence databases. Some of the ids have been\n altered, most likely the start/end residue will have been updated.\n Save your alignment to maintain the updated id.\n\n
-label.sequence_names_updated = Sequence names updated
+label.your_sequences_have_been_verified = Your sequences have been verified against known sequence databases.\n(Use Calculate | Show flanking regions to show enclosing sequence.)\nTo preserve data changes, save your alignment.\n\n
+label.sequences_updated = Sequences updated
 label.dbref_search_completed = DBRef search completed
 label.show_all_chains = Show all chains
 label.fetch_all_param = Fetch all {0}
@@ -772,7 +774,7 @@ label.select_backgroud_colour = Select Background Colour
 label.invalid_font = Invalid Font
 label.separate_multiple_accession_ids = Enter one or more accession IDs separated by a semi-colon ";"
 label.separate_multiple_query_values = Enter one or more {0}s separated by a semi-colon ";"
-label.search_all = Enter one or more search values separated by a semi-colon ";" (Note: This Searches the entire database)
+label.search_all = Enter one or more search values separated by a semi-colon ";" (Note: This searches the entire database)
 label.replace_commas_semicolons = Replace commas with semi-colons
 label.parsing_failed_syntax_errors_shown_below_param = Parsing failed. Syntax errors shown below {0}
 label.parsing_failed_unrecoverable_exception_thrown_param = \nParsing failed. An unrecoverable exception was thrown\:\n {0}
@@ -787,8 +789,10 @@ label.hide_columns_containing = Hide columns containing
 label.hide_columns_not_containing = Hide columns that do not contain
 option.trim_retrieved_seqs = Trim retrieved sequences
 label.trim_retrieved_sequences = When the reference sequence is longer than the sequence that you are working with, only keep the relevant subsequences.
-label.use_sequence_id_1 = Use $SEQUENCE_ID$ or $SEQUENCE_ID=/<regex>/=$
-label.use_sequence_id_2 = \nto embed sequence id in URL
+label.use_sequence_id_1 = Use $DB_ACCESSION$ or $DB_ACCESSION=/<regex>/=$
+label.use_sequence_id_2 = to embed accession id in URL
+label.use_sequence_id_3 = Use $SEQUENCE_ID$ similarly to embed sequence id
+label.use_sequence_id_4 = 
 label.ws_parameters_for = Parameters for {0}
 label.switch_server = Switch server
 label.choose_jabaws_server = Choose a server for running this service
@@ -1128,7 +1132,7 @@ status.das_feature_fetching_complete = DAS Feature Fetching Complete
 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.opening_file = opening file
+status.opening_file_for = opening file for
 status.colouring_chimera = Colouring Chimera
 label.font_doesnt_have_letters_defined = Font doesn't have letters defined\nso cannot be used\nwith alignment data
 label.font_too_small = Font size is too small
@@ -1142,7 +1146,7 @@ warn.user_defined_width_requirements = The user defined width for the\nannotatio
 label.couldnt_create_sequence_fetcher = Couldn't create SequenceFetcher
 warn.couldnt_create_sequence_fetcher_client = Could not create the sequence fetcher client. Check error logs for details.
 warn.server_didnt_pass_validation = Service did not pass validation.\nCheck the Jalview Console for more details.
-warn.url_must_contain = Sequence URL must contain $SEQUENCE_ID$ or a regex $SEQUENCE_ID=/<regex>/=$
+warn.url_must_contain = Sequence URL must contain $SEQUENCE_ID$, $DB_ACCESSION$, or a regex
 warn.urls_not_contacted = URLs that could not be contacted
 warn.urls_no_jaba = URLs without any JABA Services
 info.validate_jabaws_server = Validate JabaWS Server ?\n(Look in console output for results)
@@ -1266,3 +1270,8 @@ status.exporting_alignment_as_x_file = Exporting alignment as {0} file
 label.column = Column
 label.cant_map_cds = Unable to map CDS to protein\nCDS missing or incomplete
 label.operation_failed = Operation failed
+label.SEQUENCE_ID_no_longer_used = $SEQUENCE_ID$ is no longer used for DB accessions
+label.SEQUENCE_ID_for_DB_ACCESSION1 = Please review your URL links in the 'Connections' tab of the Preferences window:
+label.SEQUENCE_ID_for_DB_ACCESSION2 = URL links using '$SEQUENCE_ID$' for DB accessions now use '$DB_ACCESSION$'.
+label.do_not_display_again = Do not display this message again
+label.output_seq_details = Output Sequence Details to list all database references
index 87538be..e5b5e27 100644 (file)
@@ -122,6 +122,8 @@ action.change_font_tree_panel = Cambiar fuente (panel del 
 action.colour = Color
 action.calculate = Calcular
 action.select_all = Seleccionar Todo
+action.select_highlighted_columns = Seleccionar columnas resaltadas
+tooltip.select_highlighted_columns = Presione B para marcar las columnas resaltadas, Ctrl (o Cmd)-B para cambiarlas, y Alt-B para marcar todas menos las columnas resaltadas
 action.deselect_all = Deseleccionar Todo
 action.invert_selection = Invertir selección
 action.using_jmol = Usar Jmol
@@ -351,8 +353,8 @@ label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation =
 label.translation_failed = Translation Failed
 label.error_when_translating_sequences_submit_bug_report = Desafortunadamente, algo fue mal a la hora de traducir tus secuencias.\nPor favor, revisa la consola Jalview java \ny presenta un informe de error que incluya el seguimiento.
 label.implementation_error  = Error de implementación:
-label.automatically_associate_pdb_files_with_sequences_same_name = Quieres asociar automáticamente los {0} ficheros PDB con las secuencias del alineamiento que tengan el mismo nombre?
-label.automatically_associate_pdb_files_by_name = Asociar los ficheros PDB por nombre automáticamente
+label.automatically_associate_structure_files_with_sequences_same_name = Quieres asociar automáticamente los {0} ficheros estructura con las secuencias del alineamiento que tengan el mismo nombre?
+label.automatically_associate_structure_files_by_name = Asociar los ficheros estructura por nombre automáticamente
 label.ignore_unmatched_dropped_files_info = Quieres <em>ignorar</em> los {0} ficheros cuyos nombres no coincidan con ningún IDs de las secuencias ?
 label.ignore_unmatched_dropped_files = Ignorar los ficheros sin coincidencias?
 label.enter_view_name = Introduzca un nombre para la vista
@@ -674,8 +676,8 @@ label.move_url_down = Mover la URL hacia abajo
 label.add_sbrs_definition = Añadir una definición SBRS 
 label.edit_sbrs_definition = Editar una definición SBRS 
 label.delete_sbrs_definition = Borrar una definición SBRS 
-label.your_sequences_have_been_verified = Sus secuencias has sido verificadas en una base de datos de secuencias conocidas. Algunos de sus ID se han alterado y\n, probablemente, el residuo de inicio/fin se haya actualizado.\nGuarde su alineamiento para mantener el ID actualizado.\n\n 
-label.sequence_names_updated = Nombres de secuencia actualizados
+label.your_sequences_have_been_verified = Sus secuencias has sido verificadas en una base de datos de secuencias conocidas.\n(Usar Calcular | Mostrar flancos para ver ampliación.)\nPara mantener los datos actualizados, guarde su alineamiento.\n\n 
+label.sequences_updated = Secuencias actualizadas
 label.dbref_search_completed = Búsqueda de DBRef terminada
 label.show_all_chains = Mostrar todas las cadenas
 label.fetch_all_param = Recuperar todas {0}
@@ -720,8 +722,10 @@ label.select_columns_containing = Seleccione las columnas que contengan
 label.select_columns_not_containing = Seleccione las columnas que no contengan
 option.trim_retrieved_seqs = Ajustar las secuencias recuperadas
 label.trim_retrieved_sequences = Cuando la secuencia de referencia es más larga que la secuencia con la que está trabajando, sólo se mantienen las subsecuencias relevantes.
-label.use_sequence_id_1 = Utilice $SEQUENCE_ID$ o $SEQUENCE_ID=/<regex>/=$
-label.use_sequence_id_2 = \nto para embeber el id de la secuencia en una URL
+label.use_sequence_id_1 = Utilice $DB_ACCESSION$ o $DB_ACCESSION=/<regex>/=$
+label.use_sequence_id_2 = para embeber el ID de accesión en una URL
+label.use_sequence_id_3 = Utilice $SEQUENCE_ID$ de manera similar para embeber
+label.use_sequence_id_4 = el ID de la secuencia
 label.ws_parameters_for = Parámetros para {0}
 label.switch_server = Cambiar servidor
 label.open_jabaws_web_page = Abra el página principal del servidor JABAWS en un navegador web
@@ -1068,7 +1072,7 @@ warn.user_defined_width_requirements = La anchura definida por el usuario para l
 label.couldnt_create_sequence_fetcher = No es posible crear SequenceFetcher
 warn.couldnt_create_sequence_fetcher_client = No es posible crear el cliente de recuperador de secuencias. Comprueba el fichero de log para más detalles.
 warn.server_didnt_pass_validation = El servicio no ha pasado la validaci\u00F3n.\nCompruebe la consola de Jalview para m\u00E1s detalles.
-warn.url_must_contain = La URL de la secuencia debe contener $SEQUENCE_ID$ o un regex $SEQUENCE_ID=/<regex>/=$
+warn.url_must_contain = La URL de la secuencia debe contener $SEQUENCE_ID$, $DB_ACCESSION$ o un regex
 info.validate_jabaws_server = \u00BFValidar el servidor JabaWS?\n(Consulte la consola de salida para obtener los resultados)
 label.test_server = Â¿Probar servidor?
 info.you_want_jalview_to_find_uniprot_accessions = \u00BFDesea que Jalview encuentre\nUniprot Accession ids para los nombres de secuencias dados?
@@ -1127,7 +1131,7 @@ action.yes=S
 label.export_settings=Exportar Ajustes
 label.linked_view_title=Vista vinculada de cDNA y proteína
 label.couldnt_read_data=No se pudo leer los datos
-status.opening_file=abriendo fichero
+status.opening_file_for=abriendo fichero para
 label.except_selected_sequences=Todo excepto secuencias seleccionadas
 label.structure_chooser_no_of_structures=Selector de Estructuras - {0} Encontró ({1})
 label.search_filter=filtro de búsqueda
@@ -1267,3 +1271,8 @@ status.exporting_alignment_as_x_file = Exportando alineamiento como fichero tipo
 label.column = Columna
 label.cant_map_cds = No se pudo mapear CDS a proteína\nDatos CDS faltantes o incompletos
 label.operation_failed = Operación fallada
+label.SEQUENCE_ID_no_longer_used = $SEQUENCE_ID$ no se utiliza más para accesiones DB
+label.SEQUENCE_ID_for_DB_ACCESSION1 = Por favor, revise sus URLs en la pestaña 'Conexiones' de la ventana de Preferencias:
+label.SEQUENCE_ID_for_DB_ACCESSION2 = URL enlaza usando '$SEQUENCE_ID$' para accesiones DB ahora usar '$DB_ACCESSION$'.
+label.do_not_display_again = No mostrar este mensaje de nuevo
+label.output_seq_details = Seleccionar Detalles de la secuencia para ver todas
index a8634af..4a981ad 100755 (executable)
@@ -80,7 +80,7 @@
         <class name="jalview.datamodel.PDBEntry">
                <field name="type"><bind-xml node="attribute"/></field>
                <field name="id"><bind-xml node="attribute"/></field>
-               <field name="property" collection="hashtable">
+               <field name="props" collection="hashtable">
                        <bind-xml name="property">
                           <class name="org.exolab.castor.mapping.MapItem">
                              <field name="key">
index 1a7e7f5..aac796c 100644 (file)
@@ -190,8 +190,10 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     for (int i = 0; i < pdb.getChains().size(); i++)
     {
 
-      mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
-              + pdb.getChains().elementAt(i).sequence.getSequenceAsString());
+      mappingDetails
+              .append("\n\nPDB Sequence is :\nSequence = "
+                      + pdb.getChains().elementAt(i).sequence
+                              .getSequenceAsString());
       mappingDetails.append("\nNo of residues = "
               + pdb.getChains().elementAt(i).residues.size() + "\n\n");
 
@@ -200,8 +202,8 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
       // Align the sequence to the pdb
       // TODO: DNa/Pep switch
       AlignSeq as = new AlignSeq(sequence,
-              pdb.getChains().elementAt(i).sequence,
-              pdb.getChains().elementAt(i).isNa ? AlignSeq.DNA : AlignSeq.PEP);
+              pdb.getChains().elementAt(i).sequence, pdb.getChains()
+                      .elementAt(i).isNa ? AlignSeq.DNA : AlignSeq.PEP);
       as.calcScoreMatrix();
       as.traceAlignment();
       PrintStream ps = new PrintStream(System.out)
index fe6a0ac..904e307 100755 (executable)
@@ -126,6 +126,7 @@ public class Atom
     }
     return false;
   }
+
   public Atom(float x, float y, float z)
   {
     this.x = x;
index 7b4e0f0..292de91 100644 (file)
@@ -189,8 +189,10 @@ public class PDBCanvas extends JPanel implements MouseListener,
     for (int i = 0; i < pdb.getChains().size(); i++)
     {
 
-      mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
-              + pdb.getChains().elementAt(i).sequence.getSequenceAsString());
+      mappingDetails
+              .append("\n\nPDB Sequence is :\nSequence = "
+                      + pdb.getChains().elementAt(i).sequence
+                              .getSequenceAsString());
       mappingDetails.append("\nNo of residues = "
               + pdb.getChains().elementAt(i).residues.size() + "\n\n");
 
index cf794b6..783a4e2 100755 (executable)
@@ -31,6 +31,7 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureImportSettings;
 import jalview.structure.StructureMapping;
+import jalview.util.Comparison;
 
 import java.awt.Color;
 import java.util.List;
@@ -146,7 +147,9 @@ public class PDBChain
         pdbpos++;
       }
 
-      if (as.astr1.charAt(i) == as.astr2.charAt(i))
+      boolean sameResidue = Comparison.isSameResidue(as.astr1.charAt(i),
+              as.astr2.charAt(i), false);
+      if (sameResidue)
       {
         if (pdbpos >= residues.size())
         {
@@ -199,7 +202,8 @@ public class PDBChain
     }
     for (int i = 0; i < features.length; i++)
     {
-      if (features[i].getFeatureGroup().equals(pdbid))
+      if (features[i].getFeatureGroup() != null
+              && features[i].getFeatureGroup().equals(pdbid))
       {
         SequenceFeature tx = new SequenceFeature(features[i]);
         tx.setBegin(1 + residues.elementAt(tx.getBegin() - offset).atoms
@@ -357,53 +361,53 @@ public class PDBChain
       else
       {
 
-      // Make a new Residue object with the new atoms vector
-      residues.addElement(new Residue(resAtoms, resNumber - 1, count));
+        // Make a new Residue object with the new atoms vector
+        residues.addElement(new Residue(resAtoms, resNumber - 1, count));
 
-      Residue tmpres = residues.lastElement();
-      Atom tmpat = tmpres.atoms.get(0);
-      // Make A new SequenceFeature for the current residue numbering
+        Residue tmpres = residues.lastElement();
+        Atom tmpat = tmpres.atoms.get(0);
+        // Make A new SequenceFeature for the current residue numbering
         SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
-              + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
-              + count, offset + count, pdbid);
-      resFeatures.addElement(sf);
-      resAnnotation.addElement(new Annotation(tmpat.tfactor));
-      // Keep totting up the sequence
+                + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
+                + count, offset + count, pdbid);
+        resFeatures.addElement(sf);
+        resAnnotation.addElement(new Annotation(tmpat.tfactor));
+        // Keep totting up the sequence
 
-      if ((symbol = ResidueProperties.getAA3Hash().get(tmpat.resName)) == null)
-      {
-        String nucname = tmpat.resName.trim();
-        // use the aaIndex rather than call 'toLower' - which would take a bit
-        // more time.
-        deoxyn = nucname.length() == 2
-                && ResidueProperties.aaIndex[nucname.charAt(0)] == ResidueProperties.aaIndex['D'];
-        if (tmpat.name.equalsIgnoreCase("CA")
-                || ResidueProperties.nucleotideIndex[nucname
-                        .charAt((deoxyn ? 1 : 0))] == -1)
+        if ((symbol = ResidueProperties.getAA3Hash().get(tmpat.resName)) == null)
         {
+          String nucname = tmpat.resName.trim();
+          // use the aaIndex rather than call 'toLower' - which would take a bit
+          // more time.
+          deoxyn = nucname.length() == 2
+                  && ResidueProperties.aaIndex[nucname.charAt(0)] == ResidueProperties.aaIndex['D'];
+          if (tmpat.name.equalsIgnoreCase("CA")
+                  || ResidueProperties.nucleotideIndex[nucname
+                          .charAt((deoxyn ? 1 : 0))] == -1)
+          {
             char r = ResidueProperties
                     .getSingleCharacterCode(ResidueProperties
                             .getCanonicalAminoAcid(tmpat.resName));
             seq.append(r == '0' ? 'X' : r);
             // System.err.println("PDBReader:Null aa3Hash for " +
             // tmpat.resName);
+          }
+          else
+          {
+            // nucleotide flag
+            nucleotide = true;
+            seq.append(nucname.charAt((deoxyn ? 1 : 0)));
+          }
         }
         else
         {
-          // nucleotide flag
-          nucleotide = true;
-          seq.append(nucname.charAt((deoxyn ? 1 : 0)));
-        }
-      }
-      else
-      {
-        if (nucleotide)
-        {
-          System.err
-                  .println("Warning: mixed nucleotide and amino acid chain.. its gonna do bad things to you!");
+          if (nucleotide)
+          {
+            System.err
+                    .println("Warning: mixed nucleotide and amino acid chain.. its gonna do bad things to you!");
+          }
+          seq.append(ResidueProperties.aa[((Integer) symbol).intValue()]);
         }
-        seq.append(ResidueProperties.aa[((Integer) symbol).intValue()]);
-      }
         count++;
       }
     }
@@ -425,11 +429,11 @@ public class PDBChain
 
     if (StructureImportSettings.isShowSeqFeatures())
     {
-    for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
-    {
-      sequence.addSequenceFeature(resFeatures.elementAt(i));
-      resFeatures.setElementAt(null, i);
-    }
+      for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
+      {
+        sequence.addSequenceFeature(resFeatures.elementAt(i));
+        resFeatures.setElementAt(null, i);
+      }
     }
     if (visibleChainAnnotation)
     {
index 39bc4ef..8db6fa8 100755 (executable)
@@ -129,18 +129,17 @@ public class PDBViewer extends JInternalFrame implements Runnable
       worker.start();
     }
 
-    if (pdbentry.getProperty() != null)
+    String method = (String) pdbentry.getProperty("method");
+    if (method != null)
     {
-      if (pdbentry.getProperty().get("method") != null)
-      {
-        title.append(" Method: ");
-        title.append(pdbentry.getProperty().get("method"));
-      }
-      if (pdbentry.getProperty().get("chains") != null)
-      {
-        title.append(" Chain:");
-        title.append(pdbentry.getProperty().get("chains"));
-      }
+      title.append(" Method: ");
+      title.append(method);
+    }
+    String ch = (String) pdbentry.getProperty("chains");
+    if (ch != null)
+    {
+      title.append(" Chain:");
+      title.append(ch);
     }
     Desktop.addInternalFrame(this, title.toString(), 400, 400);
   }
@@ -416,34 +415,50 @@ public class PDBViewer extends JInternalFrame implements Runnable
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isPopupTrigger())
+            if (evt.isPopupTrigger()) // Mac
             {
-              radioItem.removeActionListener(radioItem.getActionListeners()[0]);
-
-              int option = JOptionPane.showInternalConfirmDialog(
-                      jalview.gui.Desktop.desktop,
-                      MessageManager
-                              .getString("label.remove_from_default_list"),
-                      MessageManager
-                              .getString("label.remove_user_defined_colour"),
-                      JOptionPane.YES_NO_OPTION);
-              if (option == JOptionPane.YES_OPTION)
-              {
-                jalview.gui.UserDefinedColours
-                        .removeColourFromDefaults(radioItem.getText());
-                coloursMenu.remove(radioItem);
-              }
-              else
+              offerRemoval(radioItem);
+            }
+          }
+
+          @Override
+          public void mouseReleased(MouseEvent evt)
+          {
+            if (evt.isPopupTrigger()) // Windows
+            {
+              offerRemoval(radioItem);
+            }
+          }
+
+          /**
+           * @param radioItem
+           */
+          void offerRemoval(final JRadioButtonMenuItem radioItem)
+          {
+            radioItem.removeActionListener(radioItem.getActionListeners()[0]);
+
+            int option = JOptionPane.showInternalConfirmDialog(
+                    jalview.gui.Desktop.desktop, MessageManager
+                            .getString("label.remove_from_default_list"),
+                    MessageManager
+                            .getString("label.remove_user_defined_colour"),
+                    JOptionPane.YES_NO_OPTION);
+            if (option == JOptionPane.YES_OPTION)
+            {
+              jalview.gui.UserDefinedColours
+                      .removeColourFromDefaults(radioItem.getText());
+              coloursMenu.remove(radioItem);
+            }
+            else
+            {
+              radioItem.addActionListener(new ActionListener()
               {
-                radioItem.addActionListener(new ActionListener()
+                @Override
+                public void actionPerformed(ActionEvent evt)
                 {
-                  @Override
-                  public void actionPerformed(ActionEvent evt)
-                  {
-                    user_actionPerformed(evt);
-                  }
-                });
-              }
+                  user_actionPerformed(evt);
+                }
+              });
             }
           }
         });
index 060de45..6d3d342 100755 (executable)
@@ -57,8 +57,7 @@ public class PDBfile extends StructureFile
   }
 
   public PDBfile(boolean addAlignmentAnnotations, boolean predictSecStr,
-          boolean externalSecStr,
-          FileParse source) throws IOException
+          boolean externalSecStr, FileParse source) throws IOException
   {
     super(false, source);
     addSettings(addAlignmentAnnotations, predictSecStr, externalSecStr);
@@ -147,7 +146,7 @@ public class PDBfile extends StructureFile
           Atom tmpatom = new Atom(line);
           try
           {
-          tmpchain = findChain(tmpatom.chain);
+            tmpchain = findChain(tmpatom.chain);
             if (tmpatom.resNumIns.trim().equals(lastID))
             {
               // phosphorylated protein - seen both CA and P..
@@ -205,8 +204,6 @@ public class PDBfile extends StructureFile
     markCalcIds();
   }
 
-
-
   /**
    * Process a parsed chain to construct and return a Sequence, and add it to
    * the list of sequences parsed.
index 95221d2..1d57a31 100644 (file)
@@ -1,3 +1,35 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2006 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 package ext.edu.ucsf.rbvi.strucviz2;
 
 import java.awt.Color;
index c0c7c46..736e459 100644 (file)
@@ -1,3 +1,35 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2006 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 package ext.edu.ucsf.rbvi.strucviz2;
 
 import jalview.ws.HttpClientUtils;
@@ -27,6 +59,10 @@ import ext.edu.ucsf.rbvi.strucviz2.port.ListenerThreads;
  */
 public class ChimeraManager
 {
+  private static final int REST_REPLY_TIMEOUT_MS = 15000;
+
+  private static final int CONNECTION_TIMEOUT_MS = 100;
+
   private static final boolean debug = false;
 
   private int chimeraRestPort;
@@ -782,8 +818,8 @@ public class ChimeraManager
     BufferedReader response = null;
     try
     {
-      response = HttpClientUtils
-              .doHttpUrlPost(restUrl, commands, 100, 5000);
+      response = HttpClientUtils.doHttpUrlPost(restUrl, commands, CONNECTION_TIMEOUT_MS,
+              REST_REPLY_TIMEOUT_MS);
       String line = "";
       while ((line = response.readLine()) != null)
       {
index 7da7a48..d2f4b11 100644 (file)
@@ -1,3 +1,35 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2006 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 package ext.edu.ucsf.rbvi.strucviz2;
 
 import java.awt.Color;
index 6fd6340..effe556 100644 (file)
@@ -1,3 +1,35 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2006 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 package ext.edu.ucsf.rbvi.strucviz2;
 
 import jalview.bin.Cache;
index 08a6cb7..77c1883 100644 (file)
@@ -1,3 +1,35 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2006 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 package ext.edu.ucsf.rbvi.strucviz2;
 
 /**
index 2b2ce48..379097c 100644 (file)
@@ -1,3 +1,35 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2006 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 package ext.edu.ucsf.rbvi.strucviz2.port;
 
 import java.io.BufferedReader;
index fb49541..17874e6 100755 (executable)
@@ -24,7 +24,15 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.Profile;
+import jalview.datamodel.ProfileI;
+import jalview.datamodel.Profiles;
+import jalview.datamodel.ProfilesI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.ResidueCount.SymbolCounts;
 import jalview.datamodel.SequenceI;
+import jalview.ext.android.SparseIntArray;
+import jalview.util.Comparison;
 import jalview.util.Format;
 import jalview.util.MappingUtils;
 import jalview.util.QuickSort;
@@ -44,20 +52,8 @@ import java.util.List;
  */
 public class AAFrequency
 {
-  private static final int TO_UPPER_CASE = 'A' - 'a'; // -32
-
-  public static final String MAXCOUNT = "C";
-
-  public static final String MAXRESIDUE = "R";
-
-  public static final String PID_GAPS = "G";
-
-  public static final String PID_NOGAPS = "N";
-
   public static final String PROFILE = "P";
 
-  public static final String ENCODED_CHARS = "E";
-
   /*
    * Quick look-up of String value of char 'A' to 'Z'
    */
@@ -71,13 +67,13 @@ public class AAFrequency
     }
   }
 
-  public static final Hashtable[] calculate(List<SequenceI> list,
+  public static final ProfilesI calculate(List<SequenceI> list,
           int start, int end)
   {
     return calculate(list, start, end, false);
   }
 
-  public static final Hashtable[] calculate(List<SequenceI> sequences,
+  public static final ProfilesI calculate(List<SequenceI> sequences,
           int start, int end, boolean profile)
   {
     SequenceI[] seqs = new SequenceI[sequences.size()];
@@ -87,307 +83,262 @@ public class AAFrequency
       for (int i = 0; i < sequences.size(); i++)
       {
         seqs[i] = sequences.get(i);
-        if (seqs[i].getLength() > width)
+        int length = seqs[i].getLength();
+        if (length > width)
         {
-          width = seqs[i].getLength();
+          width = length;
         }
       }
 
-      Hashtable[] reply = new Hashtable[width];
-
       if (end >= width)
       {
         end = width;
       }
 
-      calculate(seqs, start, end, reply, profile);
+      ProfilesI reply = calculate(seqs, width, start, end, profile);
       return reply;
     }
   }
 
-  public static final void calculate(SequenceI[] sequences, int start,
-          int end, Hashtable[] result, boolean profile)
+  /**
+   * Calculate the consensus symbol(s) for each column in the given range.
+   * 
+   * @param sequences
+   * @param width
+   *          the full width of the alignment
+   * @param start
+   *          start column (inclusive, base zero)
+   * @param end
+   *          end column (exclusive)
+   * @param saveFullProfile
+   *          if true, store all symbol counts
+   */
+  public static final ProfilesI calculate(final SequenceI[] sequences,
+          int width, int start, int end, boolean saveFullProfile)
   {
-    Hashtable residueHash;
-    int maxCount, nongap, i, j, v;
-    int jSize = sequences.length;
-    String maxResidue;
-    char c = '-';
-    float percentage;
+    // long now = System.currentTimeMillis();
+    int seqCount = sequences.length;
+    boolean nucleotide = false;
+    int nucleotideCount = 0;
+    int peptideCount = 0;
 
-    int[] values = new int[255];
+    ProfileI[] result = new ProfileI[width];
 
-    char[] seq;
-
-    for (i = start; i < end; i++)
+    for (int column = start; column < end; column++)
     {
-      residueHash = new Hashtable();
-      maxCount = 0;
-      maxResidue = "";
-      nongap = 0;
-      values = new int[255];
+      /*
+       * Apply a heuristic to detect nucleotide data (which can
+       * be counted in more compact arrays); here we test for
+       * more than 90% nucleotide; recheck every 10 columns in case
+       * of misleading data e.g. highly conserved Alanine in peptide!
+       * Mistakenly guessing nucleotide has a small performance cost,
+       * as it will result in counting in sparse arrays.
+       * Mistakenly guessing peptide has a small space cost, 
+       * as it will use a larger than necessary array to hold counts. 
+       */
+      if (nucleotideCount > 100 && column % 10 == 0)
+      {
+        nucleotide = (9 * peptideCount < nucleotideCount);
+      }
+      ResidueCount residueCounts = new ResidueCount(nucleotide);
 
-      for (j = 0; j < jSize; j++)
+      for (int row = 0; row < seqCount; row++)
       {
-        if (sequences[j] == null)
+        if (sequences[row] == null)
         {
           System.err
                   .println("WARNING: Consensus skipping null sequence - possible race condition.");
           continue;
         }
-        seq = sequences[j].getSequence();
-        if (seq.length > i)
+        char[] seq = sequences[row].getSequence();
+        if (seq.length > column)
         {
-          c = seq[i];
-
-          if (c == '.' || c == ' ')
+          char c = seq[column];
+          residueCounts.add(c);
+          if (Comparison.isNucleotide(c))
           {
-            c = '-';
+            nucleotideCount++;
           }
-
-          if (c == '-')
-          {
-            values['-']++;
-            continue;
-          }
-          else if ('a' <= c && c <= 'z')
+          else if (!Comparison.isGap(c))
           {
-            c += TO_UPPER_CASE;
+            peptideCount++;
           }
-
-          nongap++;
-          values[c]++;
-
         }
         else
         {
-          values['-']++;
-        }
-      }
-      if (jSize == 1)
-      {
-        maxResidue = String.valueOf(c);
-        maxCount = 1;
-      }
-      else
-      {
-        for (v = 'A'; v <= 'Z'; v++)
-        {
-          // TODO why ignore values[v] == 1?
-          if (values[v] < 1 /* 2 */|| values[v] < maxCount)
-          {
-            continue;
-          }
-
-          if (values[v] > maxCount)
-          {
-            maxResidue = CHARS[v - 'A'];
-          }
-          else if (values[v] == maxCount)
-          {
-            maxResidue += CHARS[v - 'A'];
-          }
-          maxCount = values[v];
+          /*
+           * count a gap if the sequence doesn't reach this column
+           */
+          residueCounts.addGap();
         }
       }
-      if (maxResidue.length() == 0)
-      {
-        maxResidue = "-";
-      }
-      if (profile)
-      {
-        // TODO use a 1-dimensional array with jSize, nongap in [0] and [1]
-        residueHash.put(PROFILE, new int[][] { values,
-            new int[] { jSize, nongap } });
-      }
-      residueHash.put(MAXCOUNT, new Integer(maxCount));
-      residueHash.put(MAXRESIDUE, maxResidue);
 
-      percentage = ((float) maxCount * 100) / jSize;
-      residueHash.put(PID_GAPS, new Float(percentage));
+      int maxCount = residueCounts.getModalCount();
+      String maxResidue = residueCounts.getResiduesForCount(maxCount);
+      int gapCount = residueCounts.getGapCount();
+      ProfileI profile = new Profile(seqCount, gapCount, maxCount,
+              maxResidue);
 
-      if (nongap > 0)
+      if (saveFullProfile)
       {
-        // calculate for non-gapped too
-        percentage = ((float) maxCount * 100) / nongap;
+        profile.setCounts(residueCounts);
       }
-      residueHash.put(PID_NOGAPS, new Float(percentage));
 
-      result[i] = residueHash;
+      result[column] = profile;
     }
+    return new Profiles(result);
+    // long elapsed = System.currentTimeMillis() - now;
+    // System.out.println(elapsed);
   }
 
   /**
-   * Compute all or part of the annotation row from the given consensus
-   * hashtable
+   * Make an estimate of the profile size we are going to compute i.e. how many
+   * different characters may be present in it. Overestimating has a cost of
+   * using more memory than necessary. Underestimating has a cost of needing to
+   * extend the SparseIntArray holding the profile counts.
    * 
-   * @param consensus
-   *          - pre-allocated annotation row
-   * @param hconsensus
-   * @param iStart
-   * @param width
-   * @param ignoreGapsInConsensusCalculation
-   * @param includeAllConsSymbols
-   * @param nseq
+   * @param profileSizes
+   *          counts of sizes of profiles so far encountered
+   * @return
    */
-  public static void completeConsensus(AlignmentAnnotation consensus,
-          Hashtable[] hconsensus, int iStart, int width,
-          boolean ignoreGapsInConsensusCalculation,
-          boolean includeAllConsSymbols, long nseq)
+  static int estimateProfileSize(SparseIntArray profileSizes)
   {
-    completeConsensus(consensus, hconsensus, iStart, width,
-            ignoreGapsInConsensusCalculation, includeAllConsSymbols, null,
-            nseq);
+    if (profileSizes.size() == 0)
+    {
+      return 4;
+    }
+
+    /*
+     * could do a statistical heuristic here e.g. 75%ile
+     * for now just return the largest value
+     */
+    return profileSizes.keyAt(profileSizes.size() - 1);
   }
 
   /**
    * Derive the consensus annotations to be added to the alignment for display.
    * This does not recompute the raw data, but may be called on a change in
-   * display options, such as 'show logo', which may in turn result in a change
-   * in the derived values.
+   * display options, such as 'ignore gaps', which may in turn result in a
+   * change in the derived values.
    * 
    * @param consensus
    *          the annotation row to add annotations to
-   * @param hconsensus
+   * @param profiles
    *          the source consensus data
-   * @param iStart
-   *          start column
-   * @param width
-   *          end column
-   * @param ignoreGapsInConsensusCalculation
-   *          if true, use the consensus calculated ignoring gaps
-   * @param includeAllConsSymbols
+   * @param startCol
+   *          start column (inclusive)
+   * @param endCol
+   *          end column (exclusive)
+   * @param ignoreGaps
+   *          if true, normalise residue percentages ignoring gaps
+   * @param showSequenceLogo
    *          if true include all consensus symbols, else just show modal
    *          residue
-   * @param alphabet
    * @param nseq
    *          number of sequences
    */
   public static void completeConsensus(AlignmentAnnotation consensus,
-          Hashtable[] hconsensus, int iStart, int width,
-          boolean ignoreGapsInConsensusCalculation,
-          boolean includeAllConsSymbols, char[] alphabet, long nseq)
+          ProfilesI profiles, int startCol, int endCol, boolean ignoreGaps,
+          boolean showSequenceLogo, long nseq)
   {
+    // long now = System.currentTimeMillis();
     if (consensus == null || consensus.annotations == null
-            || consensus.annotations.length < width)
+            || consensus.annotations.length < endCol)
     {
-      // called with a bad alignment annotation row - wait for it to be
-      // initialised properly
+      /*
+       * called with a bad alignment annotation row 
+       * wait for it to be initialised properly
+       */
       return;
     }
 
-    final Format fmt = getPercentageFormat(nseq);
-
-    for (int i = iStart; i < width; i++)
+    for (int i = startCol; i < endCol; i++)
     {
-      Hashtable hci;
-      if (i >= hconsensus.length || ((hci = hconsensus[i]) == null))
+      ProfileI profile = profiles.get(i);
+      if (profile == null)
       {
-        // happens if sequences calculated over were shorter than alignment
-        // width
+        /*
+         * happens if sequences calculated over were 
+         * shorter than alignment width
+         */
         consensus.annotations[i] = null;
-        continue;
+        return;
       }
-      Float fv = (Float) hci
-              .get(ignoreGapsInConsensusCalculation ? PID_NOGAPS : PID_GAPS);
-      if (fv == null)
-      {
-        consensus.annotations[i] = null;
-        // data has changed below us .. give up and
-        continue;
-      }
-      float value = fv.floatValue();
-      String maxRes = hci.get(AAFrequency.MAXRESIDUE).toString();
-      StringBuilder mouseOver = new StringBuilder(64);
-      if (maxRes.length() > 1)
+
+      final int dp = getPercentageDp(nseq);
+
+      float value = profile.getPercentageIdentity(ignoreGaps);
+
+      String description = getTooltip(profile, value, showSequenceLogo,
+              ignoreGaps, dp);
+
+      String modalResidue = profile.getModalResidue();
+      if ("".equals(modalResidue))
       {
-        mouseOver.append("[").append(maxRes).append("] ");
-        maxRes = "+";
+        modalResidue = "-";
       }
-      else
+      else if (modalResidue.length() > 1)
       {
-        mouseOver.append(hci.get(AAFrequency.MAXRESIDUE) + " ");
+        modalResidue = "+";
       }
-      int[][] profile = (int[][]) hci.get(AAFrequency.PROFILE);
-      if (profile != null && includeAllConsSymbols)
-      {
-        int sequenceCount = profile[1][0];
-        int nonGappedCount = profile[1][1];
-        int normalisedBy = ignoreGapsInConsensusCalculation ? nonGappedCount
-                : sequenceCount;
-        mouseOver.setLength(0);
-        if (alphabet != null)
-        {
-          for (int c = 0; c < alphabet.length; c++)
-          {
-            float tval = profile[0][alphabet[c]] * 100f / normalisedBy;
-            mouseOver
-                    .append(((c == 0) ? "" : "; "))
-                    .append(alphabet[c])
-                    .append(" ")
-                    .append(((fmt != null) ? fmt.form(tval) : ((int) tval)))
-                    .append("%");
-          }
-        }
-        else
-        {
-          // TODO do this sort once only in calculate()?
-          // char[][] ca = new char[profile[0].length][];
-          char[] ca = new char[profile[0].length];
-          float[] vl = new float[profile[0].length];
-          for (int c = 0; c < ca.length; c++)
-          {
-            ca[c] = (char) c;
-            // ca[c] = new char[]
-            // { (char) c };
-            vl[c] = profile[0][c];
-          }
-          QuickSort.sort(vl, ca);
-          for (int p = 0, c = ca.length - 1; profile[0][ca[c]] > 0; c--)
-          {
-            final char residue = ca[c];
-            if (residue != '-')
-            {
-              float tval = profile[0][residue] * 100f / normalisedBy;
-              mouseOver
-                      .append((((p == 0) ? "" : "; ")))
-                      .append(residue)
-                      .append(" ")
-                      .append(((fmt != null) ? fmt.form(tval)
-                              : ((int) tval))).append("%");
-              p++;
-            }
-          }
-        }
-      }
-      else
-      {
-        mouseOver.append(
-                (((fmt != null) ? fmt.form(value) : ((int) value))))
-                .append("%");
-      }
-      consensus.annotations[i] = new Annotation(maxRes,
-              mouseOver.toString(), ' ', value);
+      consensus.annotations[i] = new Annotation(modalResidue, description,
+              ' ', value);
     }
+    // long elapsed = System.currentTimeMillis() - now;
+    // System.out.println(-elapsed);
   }
 
   /**
-   * Returns a Format designed to show all significant figures for profile
-   * percentages. For less than 100 sequences, returns null (the integer
-   * percentage value will be displayed). For 100-999 sequences, returns "%3.1f"
+   * Returns a tooltip showing either
+   * <ul>
+   * <li>the full profile (percentages of all residues present), if
+   * showSequenceLogo is true, or</li>
+   * <li>just the modal (most common) residue(s), if showSequenceLogo is false</li>
+   * </ul>
+   * Percentages are as a fraction of all sequence, or only ungapped sequences
+   * if ignoreGaps is true.
    * 
-   * @param nseq
+   * @param profile
+   * @param pid
+   * @param showSequenceLogo
+   * @param ignoreGaps
+   * @param dp
+   *          the number of decimal places to format percentages to
    * @return
    */
-  protected static Format getPercentageFormat(long nseq)
+  static String getTooltip(ProfileI profile, float pid,
+          boolean showSequenceLogo, boolean ignoreGaps, int dp)
   {
-    int scale = 0;
-    while (nseq >= 10)
+    ResidueCount counts = profile.getCounts();
+
+    String description = null;
+    if (counts != null && showSequenceLogo)
     {
-      scale++;
-      nseq /= 10;
+      int normaliseBy = ignoreGaps ? profile.getNonGapped() : profile
+              .getHeight();
+      description = counts.getTooltip(normaliseBy, dp);
+    }
+    else
+    {
+      StringBuilder sb = new StringBuilder(64);
+      String maxRes = profile.getModalResidue();
+      if (maxRes.length() > 1)
+      {
+        sb.append("[").append(maxRes).append("]");
+      }
+      else
+      {
+        sb.append(maxRes);
+      }
+      if (maxRes.length() > 0)
+      {
+        sb.append(" ");
+        Format.appendPercentage(sb, pid, dp);
+        sb.append("%");
+      }
+      description = sb.toString();
     }
-    return scale <= 1 ? null : new Format("%3." + (scale - 1) + "f");
+    return description;
   }
 
   /**
@@ -399,46 +350,46 @@ public class AAFrequency
    * in descending order of percentage value
    * </pre>
    * 
-   * @param hconsensus
-   *          the data table from which to extract and sort values
+   * @param profile
+   *          the data object from which to extract and sort values
    * @param ignoreGaps
    *          if true, only non-gapped values are included in percentage
    *          calculations
    * @return
    */
-  public static int[] extractProfile(Hashtable hconsensus,
+  public static int[] extractProfile(ProfileI profile,
           boolean ignoreGaps)
   {
     int[] rtnval = new int[64];
-    int[][] profile = (int[][]) hconsensus.get(AAFrequency.PROFILE);
-    if (profile == null)
+    ResidueCount counts = profile.getCounts();
+    if (counts == null)
     {
       return null;
     }
-    char[] ca = new char[profile[0].length];
-    float[] vl = new float[profile[0].length];
-    for (int c = 0; c < ca.length; c++)
-    {
-      ca[c] = (char) c;
-      vl[c] = profile[0][c];
-    }
-    QuickSort.sort(vl, ca);
+
+    SymbolCounts symbolCounts = counts.getSymbolCounts();
+    char[] symbols = symbolCounts.symbols;
+    int[] values = symbolCounts.values;
+    QuickSort.sort(values, symbols);
     int nextArrayPos = 2;
     int totalPercentage = 0;
-    int distinctValuesCount = 0;
-    final int divisor = profile[1][ignoreGaps ? 1 : 0];
-    for (int c = ca.length - 1; profile[0][ca[c]] > 0; c--)
+    final int divisor = ignoreGaps ? profile.getNonGapped() : profile
+            .getHeight();
+
+    /*
+     * traverse the arrays in reverse order (highest counts first)
+     */
+    for (int i = symbols.length - 1; i >= 0; i--)
     {
-      if (ca[c] != '-')
-      {
-        rtnval[nextArrayPos++] = ca[c];
-        final int percentage = (int) (profile[0][ca[c]] * 100f / divisor);
-        rtnval[nextArrayPos++] = percentage;
-        totalPercentage += percentage;
-        distinctValuesCount++;
-      }
+      int theChar = symbols[i];
+      int charCount = values[i];
+
+      rtnval[nextArrayPos++] = theChar;
+      final int percentage = (charCount * 100) / divisor;
+      rtnval[nextArrayPos++] = percentage;
+      totalPercentage += percentage;
     }
-    rtnval[0] = distinctValuesCount;
+    rtnval[0] = symbols.length;
     rtnval[1] = totalPercentage;
     int[] result = new int[rtnval.length + 1];
     result[0] = AlignmentAnnotation.SEQUENCE_PROFILE;
@@ -647,7 +598,7 @@ public class AAFrequency
       StringBuilder samePercent = new StringBuilder();
       String percent = null;
       String lastPercent = null;
-      Format fmt = getPercentageFormat(nseqs);
+      int percentDecPl = getPercentageDp(nseqs);
 
       for (int j = codons.length - 1; j >= 0; j--)
       {
@@ -669,7 +620,9 @@ public class AAFrequency
         final int pct = codonCount * 100 / totalCount;
         String codon = String
                 .valueOf(CodingUtils.decodeCodon(codonEncoded));
-        percent = fmt == null ? Integer.toString(pct) : fmt.form(pct);
+        StringBuilder sb = new StringBuilder();
+        Format.appendPercentage(sb, pct, percentDecPl);
+        percent = sb.toString();
         if (showProfileLogo || codonCount == modalCodonCount)
         {
           if (percent.equals(lastPercent) && j > 0)
@@ -695,4 +648,23 @@ public class AAFrequency
               mouseOver.toString(), ' ', pid);
     }
   }
+
+  /**
+   * Returns the number of decimal places to show for profile percentages. For
+   * less than 100 sequences, returns zero (the integer percentage value will be
+   * displayed). For 100-999 sequences, returns 1, for 1000-9999 returns 2, etc.
+   * 
+   * @param nseq
+   * @return
+   */
+  protected static int getPercentageDp(long nseq)
+  {
+    int scale = 0;
+    while (nseq >= 100)
+    {
+      scale++;
+      nseq /= 10;
+    }
+    return scale;
+  }
 }
index 369721d..86bf721 100755 (executable)
@@ -620,7 +620,10 @@ public class AlignSeq
       {
         if ((i + (j * len)) < astr1.length())
         {
-          if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len))
+          boolean sameChar = Comparison.isSameResidue(
+                  astr1.charAt(i + (j * len)), astr2.charAt(i + (j * len)),
+                  false);
+          if (sameChar
                   && !jalview.util.Comparison.isGap(astr1.charAt(i
                           + (j * len))))
           {
@@ -663,8 +666,7 @@ public class AlignSeq
     }
 
     pid = pid / (aseq1.length - count) * 100;
-    output = output.append(new Format("Percentage ID = %2.2f\n")
-            .form(pid));
+    output = output.append(new Format("Percentage ID = %2.2f\n").form(pid));
     try
     {
       os.print(output.toString());
index 5ee4bcb..59cdccf 100755 (executable)
@@ -719,10 +719,12 @@ public class AlignmentSorter
   public static void sortByFeature(String featureLabel, String groupLabel,
           int start, int stop, AlignmentI alignment, String method)
   {
-    sortByFeature(featureLabel == null ? null
+    sortByFeature(
+            featureLabel == null ? null
                     : Arrays.asList(new String[] { featureLabel }),
-            groupLabel == null ? null
-            : Arrays.asList(new String[]{ groupLabel }), start, stop, alignment, method);
+            groupLabel == null ? null : Arrays
+                    .asList(new String[] { groupLabel }), start, stop,
+            alignment, method);
   }
 
   private static boolean containsIgnoreCase(final String lab,
@@ -747,8 +749,8 @@ public class AlignmentSorter
   }
 
   public static void sortByFeature(List<String> featureLabels,
-          List<String> groupLabels, int start, int stop, AlignmentI alignment,
-          String method)
+          List<String> groupLabels, int start, int stop,
+          AlignmentI alignment, String method)
   {
     if (method != FEATURE_SCORE && method != FEATURE_LABEL
             && method != FEATURE_DENSITY)
index d1cd5a3..34fe221 100644 (file)
@@ -22,7 +22,6 @@ package jalview.analysis;
 
 import static jalview.io.gff.GffConstants.CLINICAL_SIGNIFICANCE;
 
-import jalview.api.DBRefEntryI;
 import jalview.datamodel.AlignedCodon;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
@@ -74,7 +73,9 @@ public class AlignmentUtils
 {
 
   private static final int CODON_LENGTH = 3;
+
   private static final String SEQUENCE_VARIANT = "sequence_variant:";
+
   private static final String ID = "ID";
 
   /**
@@ -447,8 +448,8 @@ public class AlignmentUtils
      */
     if (cdnaLength != mappedLength && cdnaLength > 2)
     {
-      String lastCodon = String.valueOf(cdnaSeqChars, cdnaLength - CODON_LENGTH, CODON_LENGTH)
-              .toUpperCase();
+      String lastCodon = String.valueOf(cdnaSeqChars,
+              cdnaLength - CODON_LENGTH, CODON_LENGTH).toUpperCase();
       for (String stop : ResidueProperties.STOP)
       {
         if (lastCodon.equals(stop))
@@ -510,8 +511,7 @@ public class AlignmentUtils
 
     int aaPos = 0;
     int dnaPos = cdnaStart;
-    for (; dnaPos < cdnaSeqChars.length - 2
-            && aaPos < aaSeqChars.length; dnaPos += CODON_LENGTH, aaPos++)
+    for (; dnaPos < cdnaSeqChars.length - 2 && aaPos < aaSeqChars.length; dnaPos += CODON_LENGTH, aaPos++)
     {
       String codon = String.valueOf(cdnaSeqChars, dnaPos, CODON_LENGTH);
       final String translated = ResidueProperties.codonTranslate(codon);
@@ -937,7 +937,7 @@ public class AlignmentUtils
               .println("alignCdsSequenceAsProtein needs aligned sequence!");
       return false;
     }
-    
+
     List<AlignedCodonFrame> dnaMappings = MappingUtils
             .findMappingsForSequence(cdsSeq, mappings);
     for (AlignedCodonFrame mapping : dnaMappings)
@@ -959,7 +959,8 @@ public class AlignmentUtils
                   .getFromRanges());
           int mappedToLength = MappingUtils
                   .getLength(mapList.getToRanges());
-          boolean addStopCodon = (cdsLength == mappedFromLength * CODON_LENGTH + CODON_LENGTH)
+          boolean addStopCodon = (cdsLength == mappedFromLength
+                  * CODON_LENGTH + CODON_LENGTH)
                   || (peptide.getDatasetSequence().getLength() == mappedFromLength - 1);
           if (cdsLength != mappedToLength && !addStopCodon)
           {
@@ -1098,7 +1099,7 @@ public class AlignmentUtils
     // TODO resolve JAL-2022 so this fudge can be removed
     int mappedSequenceCount = protein.getHeight() - unmappedProtein.size();
     addUnmappedPeptideStarts(alignedCodons, mappedSequenceCount);
-    
+
     return alignedCodons;
   }
 
@@ -1689,11 +1690,20 @@ public class AlignmentUtils
            * didn't find mapped CDS sequence - construct it and add
            * its dataset sequence to the dataset
            */
-          cdsSeq = makeCdsSequence(dnaSeq.getDatasetSequence(), aMapping);
-          SequenceI cdsSeqDss = cdsSeq.createDatasetSequence();
+          cdsSeq = makeCdsSequence(dnaSeq.getDatasetSequence(), aMapping,
+                  dataset).deriveSequence();
+          // cdsSeq has a name constructed as CDS|<dbref>
+          // <dbref> will be either the accession for the coding sequence,
+          // marked in the /via/ dbref to the protein product accession
+          // or it will be the original nucleotide accession.
+          SequenceI cdsSeqDss = cdsSeq.getDatasetSequence();
+
           cdsSeqs.add(cdsSeq);
+
           if (!dataset.getSequences().contains(cdsSeqDss))
           {
+            // check if this sequence is a newly created one
+            // so needs adding to the dataset
             dataset.addSequence(cdsSeqDss);
           }
 
@@ -1702,10 +1712,12 @@ public class AlignmentUtils
            */
           List<int[]> cdsRange = Collections.singletonList(new int[] { 1,
               cdsSeq.getLength() });
-          MapList cdsToProteinMap = new MapList(cdsRange, mapList.getToRanges(),
-                  mapList.getFromRatio(), mapList.getToRatio());
+          MapList cdsToProteinMap = new MapList(cdsRange,
+                  mapList.getToRanges(), mapList.getFromRatio(),
+                  mapList.getToRatio());
           AlignedCodonFrame cdsToProteinMapping = new AlignedCodonFrame();
-          cdsToProteinMapping.addMap(cdsSeq, proteinProduct, cdsToProteinMap);
+          cdsToProteinMapping.addMap(cdsSeqDss, proteinProduct,
+                  cdsToProteinMap);
 
           /*
            * guard against duplicating the mapping if repeating this action
@@ -1715,31 +1727,15 @@ public class AlignmentUtils
             mappings.add(cdsToProteinMapping);
           }
 
-          /*
-           * copy protein's dbrefs to CDS sequence
-           * this enables Get Cross-References from CDS alignment
-           */
-          DBRefEntry[] proteinRefs = DBRefUtils.selectDbRefs(false,
-                  proteinProduct.getDBRefs());
-          if (proteinRefs != null)
-          {
-            for (DBRefEntry ref : proteinRefs)
-            {
-              DBRefEntry cdsToProteinRef = new DBRefEntry(ref);
-              cdsToProteinRef.setMap(new Mapping(proteinProduct,
-                      cdsToProteinMap));
-              cdsSeqDss.addDBRef(cdsToProteinRef);
-            }
-          }
-
+          propagateDBRefsToCDS(cdsSeqDss, dnaSeq.getDatasetSequence(),
+                  proteinProduct, aMapping);
           /*
            * add another mapping from original 'from' range to CDS
            */
           AlignedCodonFrame dnaToCdsMapping = new AlignedCodonFrame();
           MapList dnaToCdsMap = new MapList(mapList.getFromRanges(),
-                  cdsRange, 1,
-                  1);
-          dnaToCdsMapping.addMap(dnaSeq.getDatasetSequence(), cdsSeq,
+                  cdsRange, 1, 1);
+          dnaToCdsMapping.addMap(dnaSeq.getDatasetSequence(), cdsSeqDss,
                   dnaToCdsMap);
           if (!mappings.contains(dnaToCdsMapping))
           {
@@ -1753,12 +1749,37 @@ public class AlignmentUtils
            * same source and accession, so need a different accession for
            * the CDS from the dna sequence
            */
-          DBRefEntryI dnaRef = dnaDss.getSourceDBRef();
-          if (dnaRef != null)
+
+          // specific use case:
+          // Genomic contig ENSCHR:1, contains coding regions for ENSG01,
+          // ENSG02, ENSG03, with transcripts and products similarly named.
+          // cannot add distinct dbrefs mapping location on ENSCHR:1 to ENSG01
+
+          // JBPNote: ?? can't actually create an example that demonstrates we
+          // need to
+          // synthesize an xref.
+
+          for (DBRefEntry primRef : dnaDss.getPrimaryDBRefs())
           {
+            // creates a complementary cross-reference to the source sequence's
+            // primary reference.
+
+            DBRefEntry cdsCrossRef = new DBRefEntry(primRef.getSource(),
+                    primRef.getSource() + ":" + primRef.getVersion(),
+                    primRef.getAccessionId());
+            cdsCrossRef
+                    .setMap(new Mapping(dnaDss, new MapList(dnaToCdsMap)));
+            cdsSeqDss.addDBRef(cdsCrossRef);
+
+            // problem here is that the cross-reference is synthesized -
+            // cdsSeq.getName() may be like 'CDS|dnaaccession' or
+            // 'CDS|emblcdsacc'
             // assuming cds version same as dna ?!?
-            DBRefEntry proteinToCdsRef = new DBRefEntry(dnaRef.getSource(),
-                    dnaRef.getVersion(), cdsSeq.getName());
+
+            DBRefEntry proteinToCdsRef = new DBRefEntry(
+                    primRef.getSource(), primRef.getVersion(),
+                    cdsSeq.getName());
+            //
             proteinToCdsRef.setMap(new Mapping(cdsSeqDss, cdsToProteinMap
                     .getInverse()));
             proteinProduct.addDBRef(proteinToCdsRef);
@@ -1767,7 +1788,7 @@ public class AlignmentUtils
           /*
            * transfer any features on dna that overlap the CDS
            */
-          transferFeatures(dnaSeq, cdsSeq, cdsToProteinMap, null,
+          transferFeatures(dnaSeq, cdsSeq, dnaToCdsMap, null,
                   SequenceOntologyI.CDS);
         }
       }
@@ -1814,7 +1835,8 @@ public class AlignmentUtils
     int mappedFromLength = MappingUtils.getLength(aMapping.getMap()
             .getFromRanges());
     int dnaLength = seqDss.getLength();
-    if (mappedFromLength == dnaLength || mappedFromLength == dnaLength - CODON_LENGTH)
+    if (mappedFromLength == dnaLength
+            || mappedFromLength == dnaLength - CODON_LENGTH)
     {
       return seqDss;
     }
@@ -1830,7 +1852,8 @@ public class AlignmentUtils
       for (SequenceToSequenceMapping map : acf.getMappings())
       {
         Mapping mapping = map.getMapping();
-        if (mapping != aMapping && mapping.getMap().getFromRatio() == CODON_LENGTH
+        if (mapping != aMapping
+                && mapping.getMap().getFromRatio() == CODON_LENGTH
                 && proteinProduct == mapping.getTo()
                 && seqDss != map.getFromSeq())
         {
@@ -1864,9 +1887,14 @@ public class AlignmentUtils
    * 
    * @param seq
    * @param mapping
+   * @param dataset
+   *          - existing dataset. We check for sequences that look like the CDS
+   *          we are about to construct, if one exists already, then we will
+   *          just return that one.
    * @return CDS sequence (as a dataset sequence)
    */
-  static SequenceI makeCdsSequence(SequenceI seq, Mapping mapping)
+  static SequenceI makeCdsSequence(SequenceI seq, Mapping mapping,
+          AlignmentI dataset)
   {
     char[] seqChars = seq.getSequence();
     List<int[]> fromRanges = mapping.getMap().getFromRanges();
@@ -1901,12 +1929,124 @@ public class AlignmentUtils
     String mapFromId = mapping.getMappedFromId();
     String seqId = "CDS|" + (mapFromId != null ? mapFromId : seq.getName());
     SequenceI newSeq = new Sequence(seqId, newSeqChars, 1, newPos);
+    if (dataset != null)
+    {
+      SequenceI[] matches = dataset.findSequenceMatch(newSeq.getName());
+      if (matches != null)
+      {
+        boolean matched = false;
+        for (SequenceI mtch : matches)
+        {
+          if (mtch.getStart() != newSeq.getStart())
+          {
+            continue;
+          }
+          if (mtch.getEnd() != newSeq.getEnd())
+          {
+            continue;
+          }
+          if (!Arrays.equals(mtch.getSequence(), newSeq.getSequence()))
+          {
+            continue;
+          }
+          if (!matched)
+          {
+            matched = true;
+            newSeq = mtch;
+          }
+          else
+          {
+            System.err
+                    .println("JAL-2154 regression: warning - found (and ignnored a duplicate CDS sequence):"
+                            + mtch.toString());
+          }
+        }
+      }
+    }
     // newSeq.setDescription(mapFromId);
 
     return newSeq;
   }
 
   /**
+   * add any DBRefEntrys to cdsSeq from contig that have a Mapping congruent to
+   * the given mapping.
+   * 
+   * @param cdsSeq
+   * @param contig
+   * @param mapping
+   * @return list of DBRefEntrys added.
+   */
+  public static List<DBRefEntry> propagateDBRefsToCDS(SequenceI cdsSeq,
+          SequenceI contig, SequenceI proteinProduct, Mapping mapping)
+  {
+
+    // gather direct refs from contig congrent with mapping
+    List<DBRefEntry> direct = new ArrayList<DBRefEntry>();
+    HashSet<String> directSources = new HashSet<String>();
+    if (contig.getDBRefs() != null)
+    {
+      for (DBRefEntry dbr : contig.getDBRefs())
+      {
+        if (dbr.hasMap() && dbr.getMap().getMap().isTripletMap())
+        {
+          MapList map = dbr.getMap().getMap();
+          // check if map is the CDS mapping
+          if (mapping.getMap().equals(map))
+          {
+            direct.add(dbr);
+            directSources.add(dbr.getSource());
+          }
+        }
+      }
+    }
+    DBRefEntry[] onSource = DBRefUtils.selectRefs(
+            proteinProduct.getDBRefs(),
+            directSources.toArray(new String[0]));
+    List<DBRefEntry> propagated = new ArrayList<DBRefEntry>();
+
+    // and generate appropriate mappings
+    for (DBRefEntry cdsref : direct)
+    {
+      // clone maplist and mapping
+      MapList cdsposmap = new MapList(Arrays.asList(new int[][] { new int[]
+      { cdsSeq.getStart(), cdsSeq.getEnd() } }), cdsref.getMap().getMap()
+              .getToRanges(), 3, 1);
+      Mapping cdsmap = new Mapping(cdsref.getMap().getTo(), cdsref.getMap()
+              .getMap());
+
+      // create dbref
+      DBRefEntry newref = new DBRefEntry(cdsref.getSource(),
+              cdsref.getVersion(), cdsref.getAccessionId(), new Mapping(
+                      cdsmap.getTo(), cdsposmap));
+
+      // and see if we can map to the protein product for this mapping.
+      // onSource is the filtered set of accessions on protein that we are
+      // tranferring, so we assume accession is the same.
+      if (cdsmap.getTo() == null && onSource != null)
+      {
+        List<DBRefEntry> sourceRefs = DBRefUtils.searchRefs(onSource,
+                cdsref.getAccessionId());
+        if (sourceRefs != null)
+        {
+          for (DBRefEntry srcref : sourceRefs)
+          {
+            if (srcref.getSource().equalsIgnoreCase(cdsref.getSource()))
+            {
+              // we have found a complementary dbref on the protein product, so
+              // update mapping's getTo
+              newref.getMap().setTo(proteinProduct);
+            }
+          }
+        }
+      }
+      cdsSeq.addDBRef(newref);
+      propagated.add(newref);
+    }
+    return propagated;
+  }
+
+  /**
    * Transfers co-located features on 'fromSeq' to 'toSeq', adjusting the
    * feature start/end ranges, optionally omitting specified feature types.
    * Returns the number of features copied.
@@ -2347,7 +2487,9 @@ public class AlignmentUtils
         StringBuilder link = new StringBuilder(32);
         try
         {
-          link.append(desc).append(" ").append(id)
+          link.append(desc)
+                  .append(" ")
+                  .append(id)
                   .append("|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=")
                   .append(URLEncoder.encode(id, "UTF-8"));
           sf.addLink(link.toString());
@@ -2356,8 +2498,7 @@ public class AlignmentUtils
           // as if
         }
       }
-      String clinSig = (String) var.variant
-              .getValue(CLINICAL_SIGNIFICANCE);
+      String clinSig = (String) var.variant.getValue(CLINICAL_SIGNIFICANCE);
       if (clinSig != null)
       {
         sf.setValue(CLINICAL_SIGNIFICANCE, clinSig);
@@ -2513,7 +2654,7 @@ public class AlignmentUtils
   {
     AlignmentI copy = new Alignment(new Alignment(seqs));
     copy.setDataset(dataset);
-
+    boolean isProtein = !copy.isNucleotide();
     SequenceIdMatcher matcher = new SequenceIdMatcher(seqs);
     if (xrefs != null)
     {
@@ -2524,7 +2665,8 @@ public class AlignmentUtils
         {
           for (DBRefEntry dbref : dbrefs)
           {
-            if (dbref.getMap() == null || dbref.getMap().getTo() == null)
+            if (dbref.getMap() == null || dbref.getMap().getTo() == null
+                    || dbref.getMap().getTo().isProtein() != isProtein)
             {
               continue;
             }
@@ -2605,7 +2747,7 @@ public class AlignmentUtils
           }
           newCol++;
         }
-        
+
         /*
          * trim trailing gaps
          */
index 21d990c..7b9da46 100755 (executable)
@@ -22,36 +22,52 @@ package jalview.analysis;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.ResidueCount.SymbolCounts;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
 
 import java.awt.Color;
-import java.util.Enumeration;
-import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
 import java.util.Vector;
 
 /**
  * Calculates conservation values for a given set of sequences
- * 
- * @author $author$
- * @version $Revision$
  */
 public class Conservation
 {
+  /*
+   * need to have a minimum of 3% of sequences with a residue
+   * for it to be included in the conservation calculation
+   */
+  private static final int THRESHOLD_PERCENT = 3;
+
+  private static final int TOUPPERCASE = 'a' - 'A';
+
   SequenceI[] sequences;
 
   int start;
 
   int end;
 
-  Vector seqNums; // vector of int vectors where first is sequence checksum
+  Vector<int[]> seqNums; // vector of int vectors where first is sequence
+                         // checksum
 
   int maxLength = 0; // used by quality calcs
 
   boolean seqNumsChanged = false; // updated after any change via calcSeqNum;
 
-  Hashtable[] total;
+  /*
+   * a map per column with {property, conservation} where conservation value is
+   * 1 (property is conserved), 0 (absence of property is conserved) or -1
+   * (property is not conserved i.e. column has residues with and without it)
+   */
+  Map<String, Integer>[] total;
 
   boolean canonicaliseAa = true; // if true then conservation calculation will
 
@@ -60,34 +76,29 @@ public class Conservation
   // symbol
 
   /** Stores calculated quality values */
-  public Vector quality;
+  private Vector<Double> quality;
 
   /** Stores maximum and minimum values of quality values */
-  public Double[] qualityRange = new Double[2];
-
-  String consString = "";
+  private double[] qualityRange = new double[2];
 
-  Sequence consSequence;
+  private Sequence consSequence;
 
-  Hashtable propHash;
-
-  int threshold;
+  /*
+   * percentage of residues in a column to qualify for counting conservation
+   */
+  private int threshold;
 
-  String name = "";
+  private String name = "";
 
-  int[][] cons2;
+  private int[][] cons2;
 
   private String[] consSymbs;
 
   /**
-   * Creates a new Conservation object.
+   * Constructor using default threshold of 3%
    * 
    * @param name
    *          Name of conservation
-   * @param propHash
-   *          hash of properties for each symbol
-   * @param threshold
-   *          to count the residues in residueHash(). commonly used value is 3
    * @param sequences
    *          sequences to be used in calculation
    * @param start
@@ -95,11 +106,31 @@ public class Conservation
    * @param end
    *          end residue position
    */
-  public Conservation(String name, Hashtable propHash, int threshold,
+  public Conservation(String name, List<SequenceI> sequences, int start,
+          int end)
+  {
+    this(name, THRESHOLD_PERCENT, sequences, start, end);
+  }
+
+  /**
+   * Constructor
+   * 
+   * @param name
+   *          Name of conservation
+   * @param threshold
+   *          percentage of sequences at or below which property conservation is
+   *          ignored
+   * @param sequences
+   *          sequences to be used in calculation
+   * @param start
+   *          start column position
+   * @param end
+   *          end column position
+   */
+  public Conservation(String name, int threshold,
           List<SequenceI> sequences, int start, int end)
   {
     this.name = name;
-    this.propHash = propHash;
     this.threshold = threshold;
     this.start = start;
     this.end = end;
@@ -151,7 +182,7 @@ public class Conservation
         seqNums.addElement(new int[sq.length() + 1]);
       }
 
-      if (sq.hashCode() != ((int[]) seqNums.elementAt(i))[0])
+      if (sq.hashCode() != seqNums.elementAt(i)[0])
       {
         int j;
         int len;
@@ -193,154 +224,187 @@ public class Conservation
    */
   public void calculate()
   {
-    Hashtable resultHash, ht;
-    int thresh, j, jSize = sequences.length;
-    int[] values; // Replaces residueHash
-    String type, res = null;
-    char c;
-    Enumeration enumeration2;
+    int height = sequences.length;
 
-    total = new Hashtable[maxLength];
+    total = new Map[maxLength];
 
-    for (int i = start; i <= end; i++)
+    for (int column = start; column <= end; column++)
     {
-      values = new int[255];
+      ResidueCount values = countResidues(column);
+
+      /*
+       * percentage count at or below which we ignore residues
+       */
+      int thresh = (threshold * height) / 100;
 
-      for (j = 0; j < jSize; j++)
+      /*
+       * check observed residues in column and record whether each 
+       * physico-chemical property is conserved (+1), absence conserved (0),
+       * or not conserved (-1)
+       * Using TreeMap means properties are displayed in alphabetical order
+       */
+      Map<String, Integer> resultHash = new TreeMap<String, Integer>();
+      SymbolCounts symbolCounts = values.getSymbolCounts();
+      char[] symbols = symbolCounts.symbols;
+      int[] counts = symbolCounts.values;
+      for (int j = 0; j < symbols.length; j++)
       {
-        if (sequences[j].getLength() > i)
+        char c = symbols[j];
+        if (counts[j] > thresh)
         {
-          c = sequences[j].getCharAt(i);
-
-          if (canonicaliseAa)
-          { // lookup the base aa code symbol
-            c = (char) jalview.schemes.ResidueProperties.aaIndex[sequences[j]
-                    .getCharAt(i)];
-            if (c > 20)
-            {
-              c = '-';
-            }
-            else
-            {
-              // recover canonical aa symbol
-              c = jalview.schemes.ResidueProperties.aa[c].charAt(0);
-            }
-          }
-          else
-          {
-            // original behaviour - operate on ascii symbols directly
-            // No need to check if its a '-'
-            if (c == '.' || c == ' ')
-            {
-              c = '-';
-            }
-
-            c = toUpperCase(c);
-          }
-          values[c]++;
+          recordConservation(resultHash, String.valueOf(c));
+        }
+      }
+      if (values.getGapCount() > thresh)
+      {
+        recordConservation(resultHash, "-");
+      }
+
+      if (total.length > 0)
+      {
+        total[column - start] = resultHash;
+      }
+    }
+  }
+
+  /**
+   * Updates the conservation results for an observed residue
+   * 
+   * @param resultMap
+   *          a map of {property, conservation} where conservation value is +1
+   *          (all residues have the property), 0 (no residue has the property)
+   *          or -1 (some do, some don't)
+   * @param res
+   */
+  protected static void recordConservation(Map<String, Integer> resultMap,
+          String res)
+  {
+    res = res.toUpperCase();
+    for (Entry<String, Map<String, Integer>> property : ResidueProperties.propHash
+            .entrySet())
+    {
+      String propertyName = property.getKey();
+      Integer residuePropertyValue = property.getValue().get(res);
+
+      if (!resultMap.containsKey(propertyName))
+      {
+        /*
+         * first time we've seen this residue - note whether it has this property
+         */
+        if (residuePropertyValue != null)
+        {
+          resultMap.put(propertyName, residuePropertyValue);
         }
         else
         {
-          values['-']++;
+          /*
+           * unrecognised residue - use default value for property
+           */
+          resultMap.put(propertyName, property.getValue().get("-"));
         }
       }
-
-      // What is the count threshold to count the residues in residueHash()
-      thresh = (threshold * (jSize)) / 100;
-
-      // loop over all the found residues
-      resultHash = new Hashtable();
-      for (char v = '-'; v < 'Z'; v++)
+      else
       {
-
-        if (values[v] > thresh)
+        Integer currentResult = resultMap.get(propertyName);
+        if (currentResult.intValue() != -1
+                && !currentResult.equals(residuePropertyValue))
         {
-          res = String.valueOf(v);
+          /*
+           * property is unconserved - residues seen both with and without it
+           */
+          resultMap.put(propertyName, Integer.valueOf(-1));
+        }
+      }
+    }
+  }
 
-          // Now loop over the properties
-          enumeration2 = propHash.keys();
+  /**
+   * Counts residues (upper-cased) and gaps in the given column
+   * 
+   * @param column
+   * @return
+   */
+  protected ResidueCount countResidues(int column)
+  {
+    ResidueCount values = new ResidueCount(false);
 
-          while (enumeration2.hasMoreElements())
-          {
-            type = (String) enumeration2.nextElement();
-            ht = (Hashtable) propHash.get(type);
-
-            // Have we ticked this before?
-            if (!resultHash.containsKey(type))
-            {
-              if (ht.containsKey(res))
-              {
-                resultHash.put(type, ht.get(res));
-              }
-              else
-              {
-                resultHash.put(type, ht.get("-"));
-              }
-            }
-            else if (((Integer) resultHash.get(type)).equals(ht.get(res)) == false)
-            {
-              resultHash.put(type, new Integer(-1));
-            }
-          }
+    for (int row = 0; row < sequences.length; row++)
+    {
+      if (sequences[row].getLength() > column)
+      {
+        char c = sequences[row].getCharAt(column);
+        if (canonicaliseAa)
+        {
+          int index = ResidueProperties.aaIndex[c];
+          c = index > 20 ? '-' : ResidueProperties.aa[index].charAt(0);
+        }
+        else
+        {
+          c = toUpperCase(c);
+        }
+        if (Comparison.isGap(c))
+        {
+          values.addGap();
+        }
+        else
+        {
+          values.add(c);
         }
       }
-
-      if (total.length > 0)
+      else
       {
-        total[i - start] = resultHash;
+        values.addGap();
       }
     }
+    return values;
   }
 
-  /*****************************************************************************
-   * count conservation for the j'th column of the alignment
+  /**
+   * Counts conservation and gaps for a column of the alignment
    * 
-   * @return { gap count, conserved residue count}
+   * @return { 1 if fully conserved, else 0, gap count }
    */
-  public int[] countConsNGaps(int j)
+  public int[] countConservationAndGaps(int column)
   {
-    int count = 0;
-    int cons = 0;
-    int nres = 0;
-    int[] r = new int[2];
-    char f = '$';
-    int i, iSize = sequences.length;
-    char c;
+    int gapCount = 0;
+    boolean fullyConserved = true;
+    int iSize = sequences.length;
 
-    for (i = 0; i < iSize; i++)
+    if (iSize == 0)
+    {
+      return new int[] { 0, 0 };
+    }
+
+    char lastRes = '0';
+    for (int i = 0; i < iSize; i++)
     {
-      if (j >= sequences[i].getLength())
+      if (column >= sequences[i].getLength())
       {
-        count++;
+        gapCount++;
         continue;
       }
 
-      c = sequences[i].getCharAt(j); // gaps do not have upper/lower case
+      char c = sequences[i].getCharAt(column); // gaps do not have upper/lower case
 
-      if (jalview.util.Comparison.isGap((c)))
+      if (Comparison.isGap((c)))
       {
-        count++;
+        gapCount++;
       }
       else
       {
         c = toUpperCase(c);
-        nres++;
-
-        if (nres == 1)
+        if (lastRes == '0')
         {
-          f = c;
-          cons++;
+          lastRes = c;
         }
-        else if (f == c)
+        if (c != lastRes)
         {
-          cons++;
+          fullyConserved = false;
         }
       }
     }
 
-    r[0] = (nres == cons) ? 1 : 0;
-    r[1] = count;
-
+    int[] r = new int[] { fullyConserved ? 1 : 0, gapCount };
     return r;
   }
 
@@ -355,7 +419,7 @@ public class Conservation
   {
     if ('a' <= c && c <= 'z')
     {
-      c -= (32); // 32 = 'a' - 'A'
+      c -= TOUPPERCASE;
     }
     return c;
   }
@@ -363,22 +427,18 @@ public class Conservation
   /**
    * Calculates the conservation sequence
    * 
-   * @param consflag
-   *          if true, poitiveve conservation; false calculates negative
-   *          conservation
-   * @param percentageGaps
-   *          commonly used value is 25
+   * @param positiveOnly
+   *          if true, calculate positive conservation; else calculate both
+   *          positive and negative conservation
+   * @param maxPercentageGaps
+   *          the percentage of gaps in a column, at or above which no
+   *          conservation is asserted
    */
-  public void verdict(boolean consflag, float percentageGaps)
+  public void verdict(boolean positiveOnly, float maxPercentageGaps)
   {
-    StringBuffer consString = new StringBuffer();
-    String type;
-    Integer result;
-    int[] gapcons;
-    int totGaps, count;
-    float pgaps;
-    Hashtable resultHash;
-    Enumeration enumeration;
+    // TODO call this at the end of calculate(), should not be a public method
+
+    StringBuilder consString = new StringBuilder(end);
 
     // NOTE THIS SHOULD CHECK IF THE CONSEQUENCE ALREADY
     // EXISTS AND NOT OVERWRITE WITH '-', BUT THIS CASE
@@ -390,50 +450,50 @@ public class Conservation
     consSymbs = new String[end - start + 1];
     for (int i = start; i <= end; i++)
     {
-      gapcons = countConsNGaps(i);
-      totGaps = gapcons[1];
-      pgaps = ((float) totGaps * 100) / sequences.length;
-      consSymbs[i - start] = new String();
+      int[] gapcons = countConservationAndGaps(i);
+      boolean fullyConserved = gapcons[0] == 1;
+      int totGaps = gapcons[1];
+      float pgaps = (totGaps * 100f) / sequences.length;
 
-      if (percentageGaps > pgaps)
+      if (maxPercentageGaps > pgaps)
       {
-        resultHash = total[i - start];
-        // Now find the verdict
-        count = 0;
-        enumeration = resultHash.keys();
-
-        while (enumeration.hasMoreElements())
+        Map<String, Integer> resultHash = total[i - start];
+        int count = 0;
+        StringBuilder positives = new StringBuilder(64);
+        StringBuilder negatives = new StringBuilder(32);
+        for (String type : resultHash.keySet())
         {
-          type = (String) enumeration.nextElement();
-          result = (Integer) resultHash.get(type);
-          // Do we want to count +ve conservation or +ve and -ve cons.?
-          if (consflag)
+          int result = resultHash.get(type).intValue();
+          if (result == -1)
+          {
+            /*
+             * not conserved (present or absent)
+             */
+            continue;
+          }
+          count++;
+          if (result == 1)
           {
-            if (result.intValue() == 1)
-            {
-              consSymbs[i - start] = type + " " + consSymbs[i - start];
-              count++;
-            }
+            /*
+             * positively conserved property (all residues have it)
+             */
+            positives.append(positives.length() == 0 ? "" : " ");
+            positives.append(type);
           }
-          else
+          if (result == 0 && !positiveOnly)
           {
-            if (result.intValue() != -1)
-            {
-              {
-                if (result.intValue() == 0)
-                {
-                  consSymbs[i - start] = consSymbs[i - start] + " !" + type;
-                }
-                else
-                {
-                  consSymbs[i - start] = type + " " + consSymbs[i - start];
-                }
-              }
-
-              count++;
-            }
+            /*
+             * absense of property is conserved (all residues lack it)
+             */
+            negatives.append(negatives.length() == 0 ? "" : " ");
+            negatives.append("!").append(type);
           }
         }
+        if (negatives.length() > 0)
+        {
+          positives.append(" ").append(negatives);
+        }
+        consSymbs[i - start] = positives.toString();
 
         if (count < 10)
         {
@@ -441,7 +501,7 @@ public class Conservation
         }
         else
         {
-          consString.append((gapcons[0] == 1) ? "*" : "+");
+          consString.append(fullyConserved ? "*" : "+");
         }
       }
       else
@@ -474,7 +534,7 @@ public class Conservation
    */
   private void percentIdentity2()
   {
-    seqNums = new Vector();
+    seqNums = new Vector<int[]>();
     // calcSeqNum(s);
     int i = 0, iSize = sequences.length;
     // Do we need to calculate this again?
@@ -501,7 +561,7 @@ public class Conservation
 
       while (j < sequences.length)
       {
-        sqnum = (int[]) seqNums.elementAt(j);
+        sqnum = seqNums.elementAt(j);
 
         for (i = 1; i < sqnum.length; i++)
         {
@@ -531,17 +591,17 @@ public class Conservation
   /**
    * Calculates the quality of the set of sequences
    * 
-   * @param start
+   * @param startRes
    *          Start residue
-   * @param end
+   * @param endRes
    *          End residue
    */
-  public void findQuality(int start, int end)
+  public void findQuality(int startRes, int endRes)
   {
-    quality = new Vector();
+    quality = new Vector<Double>();
 
     double max = -10000;
-    int[][] BLOSUM62 = jalview.schemes.ResidueProperties.getBLOSUM62();
+    int[][] BLOSUM62 = ResidueProperties.getBLOSUM62();
 
     // Loop over columns // JBPNote Profiling info
     // long ts = System.currentTimeMillis();
@@ -556,10 +616,10 @@ public class Conservation
 
     for (l = 0; l < size; l++)
     {
-      lengths[l] = ((int[]) seqNums.elementAt(l)).length - 1;
+      lengths[l] = seqNums.elementAt(l).length - 1;
     }
 
-    for (j = start; j <= end; j++)
+    for (j = startRes; j <= endRes; j++)
     {
       bigtot = 0;
 
@@ -583,8 +643,10 @@ public class Conservation
       {
         tot = 0;
         xx = new double[24];
-        seqNum = (j < lengths[k]) ? ((int[]) seqNums.elementAt(k))[j + 1]
-                : 23; // Sequence, or gap at the end
+        seqNum = (j < lengths[k]) ? seqNums.elementAt(k)[j + 1] : 23; // Sequence,
+                                                                      // or gap
+                                                                      // at the
+                                                                      // end
 
         // This is a loop over r
         for (i = 0; i < 23; i++)
@@ -617,9 +679,9 @@ public class Conservation
 
     double newmax = -10000;
 
-    for (j = start; j <= end; j++)
+    for (j = startRes; j <= endRes; j++)
     {
-      tmp = ((Double) quality.elementAt(j)).doubleValue();
+      tmp = quality.elementAt(j).doubleValue();
       tmp = ((max - tmp) * (size - cons2[j][23])) / size;
 
       // System.out.println(tmp+ " " + j);
@@ -632,12 +694,12 @@ public class Conservation
     }
 
     // System.out.println("Quality " + s);
-    qualityRange[0] = new Double(0);
-    qualityRange[1] = new Double(newmax);
+    qualityRange[0] = 0D;
+    qualityRange[1] = newmax;
   }
 
   /**
-   * complete the given consensus and quuality annotation rows. Note: currently
+   * Complete the given consensus and quuality annotation rows. Note: currently
    * this method will enlarge the given annotation row if it is too small,
    * otherwise will leave its length unchanged.
    * 
@@ -675,7 +737,7 @@ public class Conservation
 
     char c;
 
-    if (conservation.annotations != null
+    if (conservation != null && conservation.annotations != null
             && conservation.annotations.length < alWidth)
     {
       conservation.annotations = new Annotation[alWidth];
@@ -683,14 +745,14 @@ public class Conservation
 
     if (quality2 != null)
     {
-      quality2.graphMax = qualityRange[1].floatValue();
+      quality2.graphMax = (float) qualityRange[1];
       if (quality2.annotations != null
               && quality2.annotations.length < alWidth)
       {
         quality2.annotations = new Annotation[alWidth];
       }
-      qmin = qualityRange[0].floatValue();
-      qmax = qualityRange[1].floatValue();
+      qmin = (float) qualityRange[0];
+      qmax = (float) qualityRange[1];
     }
 
     for (int i = istart; i < alWidth; i++)
@@ -712,20 +774,23 @@ public class Conservation
         value = 10;
       }
 
-      float vprop = value - min;
-      vprop /= max;
-      int consp = i - start;
-      String conssym = (value > 0 && consp > -1 && consp < consSymbs.length) ? consSymbs[consp]
-              : "";
-      conservation.annotations[i] = new Annotation(String.valueOf(c),
-              conssym, ' ', value, new Color(minR + (maxR * vprop), minG
-                      + (maxG * vprop), minB + (maxB * vprop)));
+      if (conservation != null)
+      {
+        float vprop = value - min;
+        vprop /= max;
+        int consp = i - start;
+        String conssym = (value > 0 && consp > -1 && consp < consSymbs.length) ? consSymbs[consp]
+                : "";
+        conservation.annotations[i] = new Annotation(String.valueOf(c),
+                conssym, ' ', value, new Color(minR + (maxR * vprop), minG
+                        + (maxG * vprop), minB + (maxB * vprop)));
+      }
 
       // Quality calc
       if (quality2 != null)
       {
-        value = ((Double) quality.elementAt(i)).floatValue();
-        vprop = value - qmin;
+        value = quality.elementAt(i).floatValue();
+        float vprop = value - qmin;
         vprop /= qmax;
         quality2.annotations[i] = new Annotation(" ",
                 String.valueOf(value), ' ', value, new Color(minR
@@ -740,49 +805,27 @@ public class Conservation
    * 
    * @param name
    *          - name of conservation
-   * @param consHash
-   *          - hash table of properties for each amino acid (normally
-   *          ResidueProperties.propHash)
-   * @param threshold
-   *          - minimum number of conserved residues needed to indicate
-   *          conservation (typically 3)
    * @param seqs
    * @param start
    *          first column in calculation window
    * @param end
    *          last column in calculation window
-   * @param posOrNeg
-   *          positive (true) or negative (false) conservation
-   * @param consPercGaps
+   * @param positiveOnly
+   *          calculate positive (true) or positive and negative (false)
+   *          conservation
+   * @param maxPercentGaps
    *          percentage of gaps tolerated in column
    * @param calcQuality
    *          flag indicating if alignment quality should be calculated
    * @return Conservation object ready for use in visualization
    */
   public static Conservation calculateConservation(String name,
-          Hashtable consHash, int threshold, List<SequenceI> seqs,
-          int start, int end, boolean posOrNeg, int consPercGaps,
-          boolean calcQuality)
-  {
-    Conservation cons = new Conservation(name, consHash, threshold, seqs,
-            start, end);
-    return calculateConservation(cons, posOrNeg, consPercGaps, calcQuality);
-  }
-
-  /**
-   * @param b
-   *          positive (true) or negative (false) conservation
-   * @param consPercGaps
-   *          percentage of gaps tolerated in column
-   * @param calcQuality
-   *          flag indicating if alignment quality should be calculated
-   * @return Conservation object ready for use in visualization
-   */
-  public static Conservation calculateConservation(Conservation cons,
-          boolean b, int consPercGaps, boolean calcQuality)
+          List<SequenceI> seqs, int start, int end, boolean positiveOnly,
+          int maxPercentGaps, boolean calcQuality)
   {
+    Conservation cons = new Conservation(name, seqs, start, end);
     cons.calculate();
-    cons.verdict(b, consPercGaps);
+    cons.verdict(positiveOnly, maxPercentGaps);
 
     if (calcQuality)
     {
@@ -791,4 +834,24 @@ public class Conservation
 
     return cons;
   }
+
+  /**
+   * Returns the computed tooltip (annotation description) for a given column.
+   * The tip is empty if the conservation score is zero, otherwise holds the
+   * conserved properties (and, optionally, properties whose absence is
+   * conserved).
+   * 
+   * @param column
+   * @return
+   */
+  String getTooltip(int column)
+  {
+    char[] sequence = getConsSequence().getSequence();
+    char val = column < sequence.length ? sequence[column] : '-';
+    boolean hasConservation = val != '-' && val != '0';
+    int consp = column - start;
+    String tip = (hasConservation && consp > -1 && consp < consSymbs.length) ? consSymbs[consp]
+            : "";
+    return tip;
+  }
 }
index 288d60e..4ba7e41 100644 (file)
@@ -24,6 +24,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -106,6 +107,16 @@ public class CrossRef
         findXrefSourcesForSequence(seq, dna, sources);
       }
     }
+    sources.remove(DBRefSource.EMBL); // hack to prevent EMBL xrefs resulting in
+                                      // redundant datasets
+    if (dna)
+    {
+      sources.remove(DBRefSource.ENSEMBL); // hack to prevent Ensembl and
+                                           // EnsemblGenomes xref option shown
+                                           // from cdna panel
+      sources.remove(DBRefSource.ENSEMBLGENOMES);
+    }
+    // redundant datasets
     return sources;
   }
 
@@ -209,8 +220,7 @@ public class CrossRef
 
     rseqs = new ArrayList<SequenceI>();
     AlignedCodonFrame cf = new AlignedCodonFrame();
-    matcher = new SequenceIdMatcher(
-            dataset.getSequences());
+    matcher = new SequenceIdMatcher(dataset.getSequences());
 
     for (SequenceI seq : fromSeqs)
     {
@@ -222,6 +232,9 @@ public class CrossRef
       boolean found = false;
       DBRefEntry[] xrfs = DBRefUtils
               .selectDbRefs(!fromDna, dss.getDBRefs());
+      // ENST & ENSP comes in to both Protein and nucleotide, so we need to
+      // filter them
+      // out later.
       if ((xrfs == null || xrfs.length == 0) && dataset != null)
       {
         /*
@@ -249,11 +262,15 @@ public class CrossRef
       List<DBRefEntry> sourceRefs = DBRefUtils.searchRefsForSource(xrfs,
               source);
       Iterator<DBRefEntry> refIterator = sourceRefs.iterator();
+      // At this point, if we are retrieving Ensembl, we still don't filter out
+      // ENST when looking for protein crossrefs.
       while (refIterator.hasNext())
       {
         DBRefEntry xref = refIterator.next();
         found = false;
-        if (xref.hasMap())
+        // we're only interested in coding cross-references, not
+        // locus->transcript
+        if (xref.hasMap() && xref.getMap().getMap().isTripletMap())
         {
           SequenceI mappedTo = xref.getMap().getTo();
           if (mappedTo != null)
@@ -271,6 +288,18 @@ public class CrossRef
              * but findInDataset() matches ENSP when looking for Uniprot...
              */
             SequenceI matchInDataset = findInDataset(xref);
+            if (matchInDataset != null && xref.getMap().getTo() != null
+                    && matchInDataset != xref.getMap().getTo())
+            {
+              System.err
+                      .println("Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref."
+                              + "Found:"
+                              + matchInDataset
+                              + "\nExpected:"
+                              + xref.getMap().getTo()
+                              + "\nFor xref:"
+                              + xref);
+            }
             /*matcher.findIdMatch(mappedTo);*/
             if (matchInDataset != null)
             {
@@ -278,13 +307,34 @@ public class CrossRef
               {
                 rseqs.add(matchInDataset);
               }
+              // even if rseqs contained matchInDataset - check mappings between
+              // these seqs are added
+              // need to try harder to only add unique mappings
+              if (xref.getMap().getMap().isTripletMap()
+                      && dataset.getMapping(seq, matchInDataset) == null
+                      && cf.getMappingBetween(seq, matchInDataset) == null)
+              {
+                // materialise a mapping for highlighting between these
+                // sequences
+                if (fromDna)
+                {
+                  cf.addMap(dss, matchInDataset, xref.getMap().getMap(),
+                          xref.getMap().getMappedFromId());
+                }
+                else
+                {
+                  cf.addMap(matchInDataset, dss, xref.getMap().getMap()
+                          .getInverse(), xref.getMap().getMappedFromId());
+                }
+              }
+
               refIterator.remove();
               continue;
             }
+            // TODO: need to determine if this should be a deriveSequence
             SequenceI rsq = new Sequence(mappedTo);
             rseqs.add(rsq);
-            if (xref.getMap().getMap().getFromRatio() != xref.getMap()
-                    .getMap().getToRatio())
+            if (xref.getMap().getMap().isTripletMap())
             {
               // get sense of map correct for adding to product alignment.
               if (fromDna)
@@ -307,7 +357,9 @@ public class CrossRef
         {
           SequenceI matchedSeq = matcher.findIdMatch(xref.getSource() + "|"
                   + xref.getAccessionId());
-          if (matchedSeq != null)
+          // if there was a match, check it's at least the right type of
+          // molecule!
+          if (matchedSeq != null && matchedSeq.isProtein() == fromDna)
           {
             if (constructMapping(seq, matchedSeq, xref, cf, fromDna))
             {
@@ -356,6 +408,16 @@ public class CrossRef
     SequenceI[] retrieved = null;
     SequenceI dss = seq.getDatasetSequence() == null ? seq : seq
             .getDatasetSequence();
+    // first filter in case we are retrieving crossrefs that have already been
+    // retrieved. this happens for cases where a database record doesn't yield
+    // protein products for CDS
+    removeAlreadyRetrievedSeqs(sourceRefs, fromDna);
+    if (sourceRefs.size() == 0)
+    {
+      // no more work to do! We already had all requested sequence records in
+      // the dataset.
+      return;
+    }
     try
     {
       retrieved = sftch.getSequences(sourceRefs, !fromDna);
@@ -369,125 +431,241 @@ public class CrossRef
 
     if (retrieved != null)
     {
-      updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+      boolean addedXref = false;
+      List<SequenceI> newDsSeqs = new ArrayList<SequenceI>(), doNotAdd = new ArrayList<SequenceI>();
+
       for (SequenceI retrievedSequence : retrieved)
       {
         // dataset gets contaminated ccwith non-ds sequences. why ??!
         // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
         SequenceI retrievedDss = retrievedSequence.getDatasetSequence() == null ? retrievedSequence
                 : retrievedSequence.getDatasetSequence();
-        DBRefEntry[] dbr = retrievedSequence.getDBRefs();
-        if (dbr != null)
+        addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+                retrievedDss);
+      }
+      if (!addedXref)
+      {
+        // try again, after looking for matching IDs
+        // shouldn't need to do this unless the dbref mechanism has broken.
+        updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+        for (SequenceI retrievedSequence : retrieved)
+        {
+          // dataset gets contaminated ccwith non-ds sequences. why ??!
+          // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
+          SequenceI retrievedDss = retrievedSequence.getDatasetSequence() == null ? retrievedSequence
+                  : retrievedSequence.getDatasetSequence();
+          addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+                  retrievedDss);
+        }
+      }
+      for (SequenceI newToSeq : newDsSeqs)
+      {
+        if (!doNotAdd.contains(newToSeq)
+                && dataset.findIndex(newToSeq) == -1)
+        {
+          dataset.addSequence(newToSeq);
+          matcher.add(newToSeq);
+        }
+      }
+    }
+  }
+
+  /**
+   * Search dataset for sequences with a primary reference contained in
+   * sourceRefs.
+   * 
+   * @param sourceRefs
+   *          - list of references to filter.
+   * @param fromDna
+   *          - type of sequence to search for matching primary reference.
+   */
+  private void removeAlreadyRetrievedSeqs(List<DBRefEntry> sourceRefs,
+          boolean fromDna)
+  {
+    DBRefEntry[] dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
+    for (SequenceI sq : dataset.getSequences())
+    {
+      boolean dupeFound = false;
+      // !fromDna means we are looking only for nucleotide sequences, not
+      // protein
+      if (sq.isProtein() == fromDna)
+      {
+        for (DBRefEntry dbr : sq.getPrimaryDBRefs())
+        {
+          for (DBRefEntry found : DBRefUtils.searchRefs(dbrSourceSet, dbr))
+          {
+            sourceRefs.remove(found);
+            dupeFound = true;
+          }
+        }
+      }
+      if (dupeFound)
+      {
+        // rebuild the search array from the filtered sourceRefs list
+        dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
+      }
+    }
+  }
+
+  /**
+   * process sequence retrieved via a dbref on source sequence to resolve and
+   * transfer data
+   * 
+   * @param cf
+   * @param sourceSequence
+   * @param retrievedSequence
+   * @return true if retrieveSequence was imported
+   */
+  private boolean importCrossRefSeq(AlignedCodonFrame cf,
+          List<SequenceI> newDsSeqs, List<SequenceI> doNotAdd,
+          SequenceI sourceSequence, SequenceI retrievedSequence)
+  {
+    /**
+     * set when retrievedSequence has been verified as a crossreference for
+     * sourceSequence
+     */
+    boolean imported = false;
+    DBRefEntry[] dbr = retrievedSequence.getDBRefs();
+    if (dbr != null)
+    {
+      for (DBRefEntry dbref : dbr)
+      {
+        SequenceI matched = findInDataset(dbref);
+        if (matched == sourceSequence)
         {
-          for (DBRefEntry dbref : dbr)
+          // verified retrieved and source sequence cross-reference each other
+          imported = true;
+        }
+        // find any entry where we should put in the sequence being
+        // cross-referenced into the map
+        Mapping map = dbref.getMap();
+        if (map != null)
+        {
+          if (map.getTo() != null && map.getMap() != null)
           {
-            // find any entry where we should put in the sequence being
-            // cross-referenced into the map
-            Mapping map = dbref.getMap();
-            if (map != null)
+            if (map.getTo() == sourceSequence)
             {
-              if (map.getTo() != null && map.getMap() != null)
+              // already called to import once, and most likely this sequence
+              // already imported !
+              continue;
+            }
+            if (matched == null)
+            {
+              /*
+               * sequence is new to dataset, so save a reference so it can be added. 
+               */
+              newDsSeqs.add(map.getTo());
+              continue;
+            }
+
+            /*
+             * there was a matching sequence in dataset, so now, check to see if we can update the map.getTo() sequence to the existing one.
+             */
+
+            try
+            {
+              // compare ms with dss and replace with dss in mapping
+              // if map is congruent
+              SequenceI ms = map.getTo();
+              // TODO findInDataset requires exact sequence match but
+              // 'congruent' test is only for the mapped part
+              // maybe not a problem in practice since only ENA provide a
+              // mapping and it is to the full protein translation of CDS
+              // matcher.findIdMatch(map.getTo());
+              // TODO addendum: if matched is shorter than getTo, this will fail
+              // - when it should really succeed.
+              int sf = map.getMap().getToLowest();
+              int st = map.getMap().getToHighest();
+              SequenceI mappedrg = ms.getSubSequence(sf, st);
+              if (mappedrg.getLength() > 0
+                      && ms.getSequenceAsString().equals(
+                              matched.getSequenceAsString()))
               {
-                // TODO findInDataset requires exact sequence match but
-                // 'congruent' test is only for the mapped part
-                // maybe not a problem in practice since only ENA provide a
-                // mapping and it is to the full protein translation of CDS
-                SequenceI matched = findInDataset(dbref);
-                // matcher.findIdMatch(map.getTo());
-                if (matched != null)
+                /*
+                 * sequences were a match, 
+                 */
+                String msg = "Mapping updated from " + ms.getName()
+                        + " to retrieved crossreference "
+                        + matched.getName();
+                System.out.println(msg);
+
+                DBRefEntry[] toRefs = map.getTo().getDBRefs();
+                if (toRefs != null)
                 {
                   /*
-                   * already got an xref to this sequence; update this
-                   * map to point to the same sequence, and add
-                   * any new dbrefs to it
+                   * transfer database refs
                    */
-                  DBRefEntry[] toRefs = map.getTo().getDBRefs();
-                  if (toRefs != null)
+                  for (DBRefEntry ref : toRefs)
                   {
-                    for (DBRefEntry ref : toRefs)
+                    if (dbref.getSrcAccString().equals(
+                            ref.getSrcAccString()))
                     {
-                      matched.addDBRef(ref); // add or update mapping
+                      continue; // avoid overwriting the ref on source sequence
                     }
+                    matched.addDBRef(ref); // add or update mapping
                   }
-                  map.setTo(matched);
-                }
-                else
-                {
-                  matcher.add(map.getTo());
                 }
-                try
-                {
-                  // compare ms with dss and replace with dss in mapping
-                  // if map is congruent
-                  SequenceI ms = map.getTo();
-                  int sf = map.getMap().getToLowest();
-                  int st = map.getMap().getToHighest();
-                  SequenceI mappedrg = ms.getSubSequence(sf, st);
-                  // SequenceI loc = dss.getSubSequence(sf, st);
-                  if (mappedrg.getLength() > 0
-                          && ms.getSequenceAsString().equals(
-                                  dss.getSequenceAsString()))
-                  // && mappedrg.getSequenceAsString().equals(
-                  // loc.getSequenceAsString()))
-                  {
-                    String msg = "Mapping updated from " + ms.getName()
-                            + " to retrieved crossreference "
-                            + dss.getName();
-                    System.out.println(msg);
-                    map.setTo(dss);
+                doNotAdd.add(map.getTo());
+                map.setTo(matched);
 
-                    /*
-                     * give the reverse reference the inverse mapping 
-                     * (if it doesn't have one already)
-                     */
-                    setReverseMapping(dss, dbref, cf);
+                /*
+                 * give the reverse reference the inverse mapping 
+                 * (if it doesn't have one already)
+                 */
+                setReverseMapping(matched, dbref, cf);
 
+                /*
+                 * copy sequence features as well, avoiding
+                 * duplication (e.g. same variation from two 
+                 * transcripts)
+                 */
+                SequenceFeature[] sfs = ms.getSequenceFeatures();
+                if (sfs != null)
+                {
+                  for (SequenceFeature feat : sfs)
+                  {
                     /*
-                     * copy sequence features as well, avoiding
-                     * duplication (e.g. same variation from two 
-                     * transcripts)
+                     * make a flyweight feature object which ignores Parent
+                     * attribute in equality test; this avoids creating many
+                     * otherwise duplicate exon features on genomic sequence
                      */
-                    SequenceFeature[] sfs = ms.getSequenceFeatures();
-                    if (sfs != null)
+                    SequenceFeature newFeature = new SequenceFeature(feat)
                     {
-                      for (SequenceFeature feat : sfs)
+                      @Override
+                      public boolean equals(Object o)
                       {
-                        /*
-                         * make a flyweight feature object which ignores Parent
-                         * attribute in equality test; this avoids creating many
-                         * otherwise duplicate exon features on genomic sequence
-                         */
-                        SequenceFeature newFeature = new SequenceFeature(
-                                feat)
-                        {
-                          @Override
-                          public boolean equals(Object o)
-                          {
-                            return super.equals(o, true);
-                          }
-                        };
-                        dss.addSequenceFeature(newFeature);
+                        return super.equals(o, true);
                       }
-                    }
+                    };
+                    matched.addSequenceFeature(newFeature);
                   }
-                  cf.addMap(retrievedDss, map.getTo(), map.getMap());
-                } catch (Exception e)
-                {
-                  System.err
-                          .println("Exception when consolidating Mapped sequence set...");
-                  e.printStackTrace(System.err);
                 }
+
               }
+              cf.addMap(retrievedSequence, map.getTo(), map.getMap());
+            } catch (Exception e)
+            {
+              System.err
+                      .println("Exception when consolidating Mapped sequence set...");
+              e.printStackTrace(System.err);
             }
           }
         }
-        retrievedSequence.updatePDBIds();
-        rseqs.add(retrievedDss);
-        dataset.addSequence(retrievedDss);
-        matcher.add(retrievedDss);
       }
     }
+    if (imported)
+    {
+      retrievedSequence.updatePDBIds();
+      rseqs.add(retrievedSequence);
+      if (dataset.findIndex(retrievedSequence) == -1)
+      {
+        dataset.addSequence(retrievedSequence);
+        matcher.add(retrievedSequence);
+      }
+    }
+    return imported;
   }
+
   /**
    * Sets the inverse sequence mapping in the corresponding dbref of the mapped
    * to sequence (if any). This is used after fetching a cross-referenced
@@ -530,9 +708,12 @@ public class CrossRef
   }
 
   /**
-   * Returns the first identical sequence in the dataset if any, else null
+   * 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
    * 
    * @param xref
+   *          with map and mapped-to sequence
    * @return
    */
   SequenceI findInDataset(DBRefEntry xref)
@@ -546,22 +727,42 @@ public class CrossRef
     String name2 = xref.getSource() + "|" + name;
     SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo : mapsTo
             .getDatasetSequence();
+    // first check ds if ds is directly referenced
+    if (dataset.findIndex(dss) > -1)
+    {
+      return dss;
+    }
+    DBRefEntry template = new DBRefEntry(xref.getSource(), null,
+            xref.getAccessionId());
+    /**
+     * remember the first ID match - in case we don't find a match to template
+     */
+    SequenceI firstIdMatch = null;
     for (SequenceI seq : dataset.getSequences())
     {
+      // first check primary refs.
+      List<DBRefEntry> match = DBRefUtils.searchRefs(seq.getPrimaryDBRefs()
+              .toArray(new DBRefEntry[0]), template);
+      if (match != null && match.size() == 1 && sameSequence(seq, dss))
+      {
+        return seq;
+      }
       /*
        * clumsy alternative to using SequenceIdMatcher which currently
        * returns sequences with a dbref to the matched accession id 
        * which we don't want
        */
-      if (name.equals(seq.getName()) || seq.getName().startsWith(name2))
+      if (firstIdMatch == null
+              && (name.equals(seq.getName()) || seq.getName().startsWith(
+                      name2)))
       {
         if (sameSequence(seq, dss))
         {
-          return seq;
+          firstIdMatch = seq;
         }
       }
     }
-    return null;
+    return firstIdMatch;
   }
 
   /**
@@ -662,24 +863,28 @@ public class CrossRef
           DBRefEntry xref, AlignedCodonFrame mappings, boolean fromDna)
   {
     MapList mapping = null;
-
+    SequenceI dsmapFrom = mapFrom.getDatasetSequence() == null ? mapFrom
+            : mapFrom.getDatasetSequence();
+    SequenceI dsmapTo = mapTo.getDatasetSequence() == null ? mapTo : mapTo
+            .getDatasetSequence();
     /*
-     * look for a reverse mapping, if found make its inverse
+     * look for a reverse mapping, if found make its inverse. 
+     * Note - we do this on dataset sequences only.
      */
-    if (mapTo.getDBRefs() != null)
+    if (dsmapTo.getDBRefs() != null)
     {
-      for (DBRefEntry dbref : mapTo.getDBRefs())
+      for (DBRefEntry dbref : dsmapTo.getDBRefs())
       {
         String name = dbref.getSource() + "|" + dbref.getAccessionId();
-        if (dbref.hasMap() && mapFrom.getName().startsWith(name))
+        if (dbref.hasMap() && dsmapFrom.getName().startsWith(name))
         {
           /*
            * looks like we've found a map from 'mapTo' to 'mapFrom'
            * - invert it to make the mapping the other way 
            */
           MapList reverse = dbref.getMap().getMap().getInverse();
-          xref.setMap(new Mapping(mapTo, reverse));
-          mappings.addMap(mapFrom, mapTo, reverse);
+          xref.setMap(new Mapping(dsmapTo, reverse));
+          mappings.addMap(mapFrom, dsmapTo, reverse);
           return true;
         }
       }
@@ -706,14 +911,16 @@ public class CrossRef
     /*
      * and add a reverse DbRef with the inverse mapping
      */
-    if (mapFrom.getDatasetSequence() != null
-            && mapFrom.getDatasetSequence().getSourceDBRef() != null)
+    if (mapFrom.getDatasetSequence() != null && false)
+    // && mapFrom.getDatasetSequence().getSourceDBRef() != null)
     {
-      DBRefEntry dbref = new DBRefEntry(mapFrom.getDatasetSequence()
-              .getSourceDBRef());
-      dbref.setMap(new Mapping(mapFrom.getDatasetSequence(), mapping
-              .getInverse()));
-      mapTo.addDBRef(dbref);
+      // possible need to search primary references... except, why doesn't xref
+      // == getSourceDBRef ??
+      // DBRefEntry dbref = new DBRefEntry(mapFrom.getDatasetSequence()
+      // .getSourceDBRef());
+      // dbref.setMap(new Mapping(mapFrom.getDatasetSequence(), mapping
+      // .getInverse()));
+      // mapTo.addDBRef(dbref);
     }
 
     if (fromDna)
@@ -789,8 +996,8 @@ public class CrossRef
    *          </ul>
    * @return true if relationship found and sequence added.
    */
-  boolean searchDataset(boolean fromDna, SequenceI fromSeq,
-          DBRefEntry xrf, List<SequenceI> foundSeqs, AlignedCodonFrame mappings,
+  boolean searchDataset(boolean fromDna, SequenceI fromSeq, DBRefEntry xrf,
+          List<SequenceI> foundSeqs, AlignedCodonFrame mappings,
           boolean direct)
   {
     boolean found = false;
@@ -851,37 +1058,38 @@ public class CrossRef
           // }
           if (!cands.isEmpty())
           {
-            if (!foundSeqs.contains(nxt))
+            if (foundSeqs.contains(nxt))
             {
-              found = true;
-              foundSeqs.add(nxt);
-              if (mappings != null && !direct)
+              continue;
+            }
+            found = true;
+            foundSeqs.add(nxt);
+            if (mappings != null && !direct)
+            {
+              /*
+               * if the matched sequence has mapped dbrefs to
+               * protein product / cdna, add equivalent mappings to
+               * our source sequence
+               */
+              for (DBRefEntry candidate : cands)
               {
-                /*
-                 * if the matched sequence has mapped dbrefs to
-                 * protein product / cdna, add equivalent mappings to
-                 * our source sequence
-                 */
-                for (DBRefEntry candidate : cands)
+                Mapping mapping = candidate.getMap();
+                if (mapping != null)
                 {
-                  Mapping mapping = candidate.getMap();
-                  if (mapping != null)
+                  MapList map = mapping.getMap();
+                  if (mapping.getTo() != null
+                          && map.getFromRatio() != map.getToRatio())
                   {
-                    MapList map = mapping.getMap();
-                    if (mapping.getTo() != null
-                            && map.getFromRatio() != map.getToRatio())
+                    /*
+                     * add a mapping, as from dna to peptide sequence
+                     */
+                    if (map.getFromRatio() == 3)
                     {
-                      /*
-                       * add a mapping, as from dna to peptide sequence
-                       */
-                      if (map.getFromRatio() == 3)
-                      {
-                        mappings.addMap(nxt, fromSeq, map);
-                      }
-                      else
-                      {
-                        mappings.addMap(nxt, fromSeq, map.getInverse());
-                      }
+                      mappings.addMap(nxt, fromSeq, map);
+                    }
+                    else
+                    {
+                      mappings.addMap(nxt, fromSeq, map.getInverse());
                     }
                   }
                 }
index 800cef2..799a8ed 100644 (file)
@@ -878,7 +878,8 @@ public class Dna
   public static char getComplement(char c)
   {
     char result = c;
-    switch (c) {
+    switch (c)
+    {
     case '-':
     case '.':
     case ' ':
index 72097e0..25ee7d2 100644 (file)
 package jalview.analysis;
 
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
-import jalview.datamodel.Sequence;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 
+import com.stevesoft.pat.Regex;
+
 public class Finder
 {
   /**
    * Implements the search algorithms for the Find dialog box.
    */
-  SearchResults searchResults;
+  SearchResultsI searchResults;
 
   AlignmentI alignment;
 
-  jalview.datamodel.SequenceGroup selection = null;
+  SequenceGroup selection = null;
 
-  Vector idMatch = null;
+  Vector<SequenceI> idMatch = null;
 
   boolean caseSensitive = false;
 
@@ -46,10 +53,10 @@ public class Finder
 
   boolean findAll = false;
 
-  com.stevesoft.pat.Regex regex = null;
+  Regex regex = null;
 
   /**
-   * hold's last-searched position between calles to find(false)
+   * holds last-searched position between calls to find(false)
    */
   int seqIndex = 0, resIndex = -1;
 
@@ -83,11 +90,10 @@ public class Finder
     {
       searchString = searchString.toUpperCase();
     }
-    regex = new com.stevesoft.pat.Regex(searchString);
+    regex = new Regex(searchString);
     regex.setIgnoreCase(!caseSensitive);
     searchResults = new SearchResults();
-    idMatch = new Vector();
-    Sequence seq;
+    idMatch = new Vector<SequenceI>();
     String item = null;
     boolean found = false;
     int end = alignment.getHeight();
@@ -102,10 +108,11 @@ public class Finder
         selection = null;
       }
     }
+    SearchResultMatchI lastm = null;
 
     while (!found && (seqIndex < end))
     {
-      seq = (Sequence) alignment.getSequenceAt(seqIndex);
+      SequenceI seq = alignment.getSequenceAt(seqIndex);
 
       if ((selection != null && selection.getSize() > 0)
               && !selection.getSequences(null).contains(seq))
@@ -140,7 +147,7 @@ public class Finder
         {
         }
 
-        if (regex.search(seq.getName()))
+        if (regex.search(seq.getName()) && !idMatch.contains(seq))
         {
           idMatch.addElement(seq);
           hasResults = true;
@@ -153,7 +160,8 @@ public class Finder
         }
 
         if (isIncludeDescription() && seq.getDescription() != null
-                && regex.search(seq.getDescription()))
+                && regex.search(seq.getDescription())
+                && !idMatch.contains(seq))
         {
           idMatch.addElement(seq);
           hasResults = true;
@@ -174,16 +182,16 @@ public class Finder
       }
 
       // /Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
-      StringBuffer noGapsSB = new StringBuffer();
+      StringBuilder noGapsSB = new StringBuilder();
       int insertCount = 0;
-      Vector spaces = new Vector();
+      List<Integer> spaces = new ArrayList<Integer>();
 
       for (int j = 0; j < item.length(); j++)
       {
-        if (!jalview.util.Comparison.isGap(item.charAt(j)))
+        if (!Comparison.isGap(item.charAt(j)))
         {
           noGapsSB.append(item.charAt(j));
-          spaces.addElement(new Integer(insertCount));
+          spaces.add(Integer.valueOf(insertCount));
         }
         else
         {
@@ -192,7 +200,6 @@ public class Finder
       }
 
       String noGaps = noGapsSB.toString();
-
       for (int r = resIndex; r < noGaps.length(); r++)
       {
 
@@ -201,22 +208,22 @@ public class Finder
           resIndex = regex.matchedFrom();
 
           if ((selection != null && selection.getSize() > 0)
-                  && ((resIndex + Integer.parseInt(spaces.elementAt(
-                          resIndex).toString())) < selection.getStartRes()))
+                  && (resIndex + spaces.get(resIndex) < selection
+                          .getStartRes()))
           {
             continue;
           }
           // if invalid string used, then regex has no matched to/from
-          int sres = seq
-                  .findPosition(resIndex
-                          + Integer.parseInt(spaces.elementAt(resIndex)
-                                  .toString()));
-          int eres = seq.findPosition(regex.matchedTo()
-                  - 1
-                  + Integer.parseInt(spaces
-                          .elementAt(regex.matchedTo() - 1).toString()));
-
-          searchResults.addResult(seq, sres, eres);
+          int sres = seq.findPosition(resIndex + spaces.get(resIndex));
+          int eres = seq.findPosition(regex.matchedTo() - 1
+                  + (spaces.get(regex.matchedTo() - 1)));
+          // only add result if not contained in previous result
+          if (lastm == null
+                  || (lastm.getSequence() != seq || (!(lastm.getStart() <= sres && lastm
+                          .getEnd() >= eres))))
+          {
+            lastm = searchResults.addResult(seq, sres, eres);
+          }
           hasResults = true;
           if (!findAll)
           {
@@ -320,9 +327,12 @@ public class Finder
   }
 
   /**
-   * @return the idMatch
+   * Returns the (possibly empty) list of matching sequences (when search
+   * includes searching sequence names)
+   * 
+   * @return
    */
-  public Vector getIdMatch()
+  public Vector<SequenceI> getIdMatch()
   {
     return idMatch;
   }
@@ -338,7 +348,7 @@ public class Finder
   /**
    * @return the searchResults
    */
-  public SearchResults getSearchResults()
+  public SearchResultsI getSearchResults()
   {
     return searchResults;
   }
index 4489783..e0e50fb 100644 (file)
@@ -44,7 +44,7 @@ import java.util.Vector;
  */
 public class NJTree
 {
-  Vector cluster;
+  Vector<Cluster> cluster;
 
   SequenceI[] sequence;
 
@@ -68,7 +68,7 @@ public class NJTree
 
   float rj;
 
-  Vector groups = new Vector();
+  Vector<SequenceNode> groups = new Vector<SequenceNode>();
 
   SequenceNode maxdist;
 
@@ -80,7 +80,7 @@ public class NJTree
 
   int ycount;
 
-  Vector node;
+  Vector<SequenceNode> node;
 
   String type;
 
@@ -88,8 +88,6 @@ public class NJTree
 
   Object found = null;
 
-  Object leaves = null;
-
   boolean hasDistances = true; // normal case for jalview trees
 
   boolean hasBootstrap = false; // normal case for jalview trees
@@ -151,8 +149,7 @@ public class NJTree
 
     SequenceIdMatcher algnIds = new SequenceIdMatcher(seqs);
 
-    Vector leaves = new Vector();
-    findLeaves(top, leaves);
+    Vector<SequenceNode> leaves = findLeaves(top);
 
     int i = 0;
     int namesleft = seqs.length;
@@ -160,11 +157,11 @@ public class NJTree
     SequenceNode j;
     SequenceI nam;
     String realnam;
-    Vector one2many = new Vector();
+    Vector<SequenceI> one2many = new Vector<SequenceI>();
     int countOne2Many = 0;
     while (i < leaves.size())
     {
-      j = (SequenceNode) leaves.elementAt(i++);
+      j = leaves.elementAt(i++);
       realnam = j.getName();
       nam = null;
 
@@ -221,7 +218,7 @@ public class NJTree
           String pwtype, ScoreModelI sm, int start, int end)
   {
     this.sequence = sequence;
-    this.node = new Vector();
+    this.node = new Vector<SequenceNode>();
     this.type = type;
     this.pwtype = pwtype;
     if (seqData != null)
@@ -282,6 +279,7 @@ public class NJTree
    * 
    * @return Newick File with all tree data available
    */
+  @Override
   public String toString()
   {
     jalview.io.NewickFile fout = new jalview.io.NewickFile(getTopNode());
@@ -299,8 +297,7 @@ public class NJTree
    */
   public void UpdatePlaceHolders(List<SequenceI> list)
   {
-    Vector leaves = new Vector();
-    findLeaves(top, leaves);
+    Vector<SequenceNode> leaves = findLeaves(top);
 
     int sz = leaves.size();
     SequenceIdMatcher seqmatcher = null;
@@ -308,7 +305,7 @@ public class NJTree
 
     while (i < sz)
     {
-      SequenceNode leaf = (SequenceNode) leaves.elementAt(i++);
+      SequenceNode leaf = leaves.elementAt(i++);
 
       if (list.contains(leaf.element()))
       {
@@ -369,12 +366,12 @@ public class NJTree
     {
 
       @Override
-      public void transform(BinaryNode node)
+      public void transform(BinaryNode nd)
       {
-        Object el = node.element();
+        Object el = nd.element();
         if (el != null && el instanceof SequenceI)
         {
-          node.setName(((SequenceI) el).getName());
+          nd.setName(((SequenceI) el).getName());
         }
       }
     });
@@ -428,7 +425,7 @@ public class NJTree
     }
 
     joinClusters(one, two);
-    top = (SequenceNode) (node.elementAt(one));
+    top = (node.elementAt(one));
 
     reCount(top);
     findHeight(top);
@@ -449,19 +446,19 @@ public class NJTree
   {
     float dist = distance[i][j];
 
-    int noi = ((Cluster) cluster.elementAt(i)).value.length;
-    int noj = ((Cluster) cluster.elementAt(j)).value.length;
+    int noi = cluster.elementAt(i).value.length;
+    int noj = cluster.elementAt(j).value.length;
 
     int[] value = new int[noi + noj];
 
     for (int ii = 0; ii < noi; ii++)
     {
-      value[ii] = ((Cluster) cluster.elementAt(i)).value[ii];
+      value[ii] = cluster.elementAt(i).value[ii];
     }
 
     for (int ii = noi; ii < (noi + noj); ii++)
     {
-      value[ii] = ((Cluster) cluster.elementAt(j)).value[ii - noi];
+      value[ii] = cluster.elementAt(j).value[ii - noi];
     }
 
     Cluster c = new Cluster(value);
@@ -480,11 +477,11 @@ public class NJTree
 
     SequenceNode sn = new SequenceNode();
 
-    sn.setLeft((SequenceNode) (node.elementAt(i)));
-    sn.setRight((SequenceNode) (node.elementAt(j)));
+    sn.setLeft((node.elementAt(i)));
+    sn.setRight((node.elementAt(j)));
 
-    SequenceNode tmpi = (SequenceNode) (node.elementAt(i));
-    SequenceNode tmpj = (SequenceNode) (node.elementAt(j));
+    SequenceNode tmpi = (node.elementAt(i));
+    SequenceNode tmpj = (node.elementAt(j));
 
     if (type.equals("NJ"))
     {
@@ -576,8 +573,8 @@ public class NJTree
    */
   public void findClusterDistance(int i, int j)
   {
-    int noi = ((Cluster) cluster.elementAt(i)).value.length;
-    int noj = ((Cluster) cluster.elementAt(j)).value.length;
+    int noi = cluster.elementAt(i).value.length;
+    int noj = cluster.elementAt(j).value.length;
 
     // New distances from cluster to others
     float[] newdist = new float[noseqs];
@@ -733,7 +730,7 @@ public class NJTree
   public float[][] findDistances(ScoreModelI _pwmatrix)
   {
 
-    float[][] distance = new float[noseqs][noseqs];
+    float[][] dist = new float[noseqs][noseqs];
     if (_pwmatrix == null)
     {
       // Resolve substitution model
@@ -743,8 +740,8 @@ public class NJTree
         _pwmatrix = ResidueProperties.getScoreMatrix("BLOSUM62");
       }
     }
-    distance = _pwmatrix.findDistances(seqData);
-    return distance;
+    dist = _pwmatrix.findDistances(seqData);
+    return dist;
 
   }
 
@@ -753,7 +750,7 @@ public class NJTree
    */
   public void makeLeaves()
   {
-    cluster = new Vector();
+    cluster = new Vector<Cluster>();
 
     for (int i = 0; i < noseqs; i++)
     {
@@ -772,26 +769,42 @@ public class NJTree
   }
 
   /**
+   * Search for leaf nodes below (or at) the given node
+   * 
+   * @param nd
+   *          root node to search from
+   * 
+   * @return
+   */
+  public Vector<SequenceNode> findLeaves(SequenceNode nd)
+  {
+    Vector<SequenceNode> leaves = new Vector<SequenceNode>();
+    findLeaves(nd, leaves);
+    return leaves;
+  }
+
+  /**
    * Search for leaf nodes.
    * 
-   * @param node
+   * @param nd
    *          root node to search from
    * @param leaves
    *          Vector of leaves to add leaf node objects too.
    * 
    * @return Vector of leaf nodes on binary tree
    */
-  public Vector findLeaves(SequenceNode node, Vector leaves)
+  Vector<SequenceNode> findLeaves(SequenceNode nd,
+          Vector<SequenceNode> leaves)
   {
-    if (node == null)
+    if (nd == null)
     {
       return leaves;
     }
 
-    if ((node.left() == null) && (node.right() == null)) // Interior node
+    if ((nd.left() == null) && (nd.right() == null)) // Interior node
     // detection
     {
-      leaves.addElement(node);
+      leaves.addElement(nd);
 
       return leaves;
     }
@@ -801,8 +814,8 @@ public class NJTree
        * TODO: Identify internal nodes... if (node.isSequenceLabel()) {
        * leaves.addElement(node); }
        */
-      findLeaves((SequenceNode) node.left(), leaves);
-      findLeaves((SequenceNode) node.right(), leaves);
+      findLeaves((SequenceNode) nd.left(), leaves);
+      findLeaves((SequenceNode) nd.right(), leaves);
     }
 
     return leaves;
@@ -811,16 +824,16 @@ public class NJTree
   /**
    * Find the leaf node with a particular ycount
    * 
-   * @param node
+   * @param nd
    *          initial point on tree to search from
    * @param count
    *          value to search for
    * 
    * @return null or the node with ycound=count
    */
-  public Object findLeaf(SequenceNode node, int count)
+  public Object findLeaf(SequenceNode nd, int count)
   {
-    found = _findLeaf(node, count);
+    found = _findLeaf(nd, count);
 
     return found;
   }
@@ -828,23 +841,23 @@ public class NJTree
   /*
    * #see findLeaf(SequenceNode node, count)
    */
-  public Object _findLeaf(SequenceNode node, int count)
+  public Object _findLeaf(SequenceNode nd, int count)
   {
-    if (node == null)
+    if (nd == null)
     {
       return null;
     }
 
-    if (node.ycount == count)
+    if (nd.ycount == count)
     {
-      found = node.element();
+      found = nd.element();
 
       return found;
     }
     else
     {
-      _findLeaf((SequenceNode) node.left(), count);
-      _findLeaf((SequenceNode) node.right(), count);
+      _findLeaf((SequenceNode) nd.left(), count);
+      _findLeaf((SequenceNode) nd.right(), count);
     }
 
     return found;
@@ -853,58 +866,57 @@ public class NJTree
   /**
    * printNode is mainly for debugging purposes.
    * 
-   * @param node
+   * @param nd
    *          SequenceNode
    */
-  public void printNode(SequenceNode node)
+  public void printNode(SequenceNode nd)
   {
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
 
-    if ((node.left() == null) && (node.right() == null))
+    if ((nd.left() == null) && (nd.right() == null))
     {
-      System.out
-              .println("Leaf = " + ((SequenceI) node.element()).getName());
-      System.out.println("Dist " + node.dist);
-      System.out.println("Boot " + node.getBootstrap());
+      System.out.println("Leaf = " + ((SequenceI) nd.element()).getName());
+      System.out.println("Dist " + nd.dist);
+      System.out.println("Boot " + nd.getBootstrap());
     }
     else
     {
-      System.out.println("Dist " + node.dist);
-      printNode((SequenceNode) node.left());
-      printNode((SequenceNode) node.right());
+      System.out.println("Dist " + nd.dist);
+      printNode((SequenceNode) nd.left());
+      printNode((SequenceNode) nd.right());
     }
   }
 
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    */
-  public void findMaxDist(SequenceNode node)
+  public void findMaxDist(SequenceNode nd)
   {
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
 
-    if ((node.left() == null) && (node.right() == null))
+    if ((nd.left() == null) && (nd.right() == null))
     {
-      float dist = node.dist;
+      float dist = nd.dist;
 
       if (dist > maxDistValue)
       {
-        maxdist = node;
+        maxdist = nd;
         maxDistValue = dist;
       }
     }
     else
     {
-      findMaxDist((SequenceNode) node.left());
-      findMaxDist((SequenceNode) node.right());
+      findMaxDist((SequenceNode) nd.left());
+      findMaxDist((SequenceNode) nd.right());
     }
   }
 
@@ -913,7 +925,7 @@ public class NJTree
    * 
    * @return DOCUMENT ME!
    */
-  public Vector getGroups()
+  public Vector<SequenceNode> getGroups()
   {
     return groups;
   }
@@ -931,51 +943,51 @@ public class NJTree
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    * @param threshold
    *          DOCUMENT ME!
    */
-  public void groupNodes(SequenceNode node, float threshold)
+  public void groupNodes(SequenceNode nd, float threshold)
   {
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
 
-    if ((node.height / maxheight) > threshold)
+    if ((nd.height / maxheight) > threshold)
     {
-      groups.addElement(node);
+      groups.addElement(nd);
     }
     else
     {
-      groupNodes((SequenceNode) node.left(), threshold);
-      groupNodes((SequenceNode) node.right(), threshold);
+      groupNodes((SequenceNode) nd.left(), threshold);
+      groupNodes((SequenceNode) nd.right(), threshold);
     }
   }
 
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    * 
    * @return DOCUMENT ME!
    */
-  public float findHeight(SequenceNode node)
+  public float findHeight(SequenceNode nd)
   {
-    if (node == null)
+    if (nd == null)
     {
       return maxheight;
     }
 
-    if ((node.left() == null) && (node.right() == null))
+    if ((nd.left() == null) && (nd.right() == null))
     {
-      node.height = ((SequenceNode) node.parent()).height + node.dist;
+      nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
 
-      if (node.height > maxheight)
+      if (nd.height > maxheight)
       {
-        return node.height;
+        return nd.height;
       }
       else
       {
@@ -984,18 +996,18 @@ public class NJTree
     }
     else
     {
-      if (node.parent() != null)
+      if (nd.parent() != null)
       {
-        node.height = ((SequenceNode) node.parent()).height + node.dist;
+        nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
       }
       else
       {
         maxheight = 0;
-        node.height = (float) 0.0;
+        nd.height = (float) 0.0;
       }
 
-      maxheight = findHeight((SequenceNode) (node.left()));
-      maxheight = findHeight((SequenceNode) (node.right()));
+      maxheight = findHeight((SequenceNode) (nd.left()));
+      maxheight = findHeight((SequenceNode) (nd.right()));
     }
 
     return maxheight;
@@ -1078,43 +1090,42 @@ public class NJTree
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    */
-  public void printN(SequenceNode node)
+  public void printN(SequenceNode nd)
   {
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
 
-    if ((node.left() != null) && (node.right() != null))
+    if ((nd.left() != null) && (nd.right() != null))
     {
-      printN((SequenceNode) node.left());
-      printN((SequenceNode) node.right());
+      printN((SequenceNode) nd.left());
+      printN((SequenceNode) nd.right());
     }
     else
     {
-      System.out.println(" name = "
-              + ((SequenceI) node.element()).getName());
+      System.out.println(" name = " + ((SequenceI) nd.element()).getName());
     }
 
-    System.out.println(" dist = " + node.dist + " " + node.count + " "
-            + node.height);
+    System.out.println(" dist = " + nd.dist + " " + nd.count + " "
+            + nd.height);
   }
 
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    */
-  public void reCount(SequenceNode node)
+  public void reCount(SequenceNode nd)
   {
     ycount = 0;
     _lycount = 0;
     // _lylimit = this.node.size();
-    _reCount(node);
+    _reCount(nd);
   }
 
   private long _lycount = 0, _lylimit = 0;
@@ -1122,37 +1133,37 @@ public class NJTree
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    */
-  public void _reCount(SequenceNode node)
+  public void _reCount(SequenceNode nd)
   {
     // if (_lycount<_lylimit)
     // {
     // System.err.println("Warning: depth of _recount greater than number of nodes.");
     // }
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
     _lycount++;
 
-    if ((node.left() != null) && (node.right() != null))
+    if ((nd.left() != null) && (nd.right() != null))
     {
 
-      _reCount((SequenceNode) node.left());
-      _reCount((SequenceNode) node.right());
+      _reCount((SequenceNode) nd.left());
+      _reCount((SequenceNode) nd.right());
 
-      SequenceNode l = (SequenceNode) node.left();
-      SequenceNode r = (SequenceNode) node.right();
+      SequenceNode l = (SequenceNode) nd.left();
+      SequenceNode r = (SequenceNode) nd.right();
 
-      node.count = l.count + r.count;
-      node.ycount = (l.ycount + r.ycount) / 2;
+      nd.count = l.count + r.count;
+      nd.ycount = (l.ycount + r.ycount) / 2;
     }
     else
     {
-      node.count = 1;
-      node.ycount = ycount++;
+      nd.count = 1;
+      nd.ycount = ycount++;
     }
     _lycount--;
   }
@@ -1160,80 +1171,80 @@ public class NJTree
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    */
-  public void swapNodes(SequenceNode node)
+  public void swapNodes(SequenceNode nd)
   {
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
 
-    SequenceNode tmp = (SequenceNode) node.left();
+    SequenceNode tmp = (SequenceNode) nd.left();
 
-    node.setLeft(node.right());
-    node.setRight(tmp);
+    nd.setLeft(nd.right());
+    nd.setRight(tmp);
   }
 
   /**
    * DOCUMENT ME!
    * 
-   * @param node
+   * @param nd
    *          DOCUMENT ME!
    * @param dir
    *          DOCUMENT ME!
    */
-  public void changeDirection(SequenceNode node, SequenceNode dir)
+  public void changeDirection(SequenceNode nd, SequenceNode dir)
   {
-    if (node == null)
+    if (nd == null)
     {
       return;
     }
 
-    if (node.parent() != top)
+    if (nd.parent() != top)
     {
-      changeDirection((SequenceNode) node.parent(), node);
+      changeDirection((SequenceNode) nd.parent(), nd);
 
-      SequenceNode tmp = (SequenceNode) node.parent();
+      SequenceNode tmp = (SequenceNode) nd.parent();
 
-      if (dir == node.left())
+      if (dir == nd.left())
       {
-        node.setParent(dir);
-        node.setLeft(tmp);
+        nd.setParent(dir);
+        nd.setLeft(tmp);
       }
-      else if (dir == node.right())
+      else if (dir == nd.right())
       {
-        node.setParent(dir);
-        node.setRight(tmp);
+        nd.setParent(dir);
+        nd.setRight(tmp);
       }
     }
     else
     {
-      if (dir == node.left())
+      if (dir == nd.left())
       {
-        node.setParent(node.left());
+        nd.setParent(nd.left());
 
-        if (top.left() == node)
+        if (top.left() == nd)
         {
-          node.setRight(top.right());
+          nd.setRight(top.right());
         }
         else
         {
-          node.setRight(top.left());
+          nd.setRight(top.left());
         }
       }
       else
       {
-        node.setParent(node.right());
+        nd.setParent(nd.right());
 
-        if (top.left() == node)
+        if (top.left() == nd)
         {
-          node.setLeft(top.right());
+          nd.setLeft(top.right());
         }
         else
         {
-          node.setLeft(top.left());
+          nd.setLeft(top.left());
         }
       }
     }
@@ -1289,8 +1300,9 @@ public class NJTree
    */
   public void applyToNodes(NodeTransformI nodeTransformI)
   {
-    for (Enumeration nodes = node.elements(); nodes.hasMoreElements(); nodeTransformI
-            .transform((BinaryNode) nodes.nextElement()))
+    for (Enumeration<SequenceNode> nodes = node.elements(); nodes
+            .hasMoreElements(); nodeTransformI.transform(nodes
+            .nextElement()))
     {
       ;
     }
index e3d999a..89c5c30 100644 (file)
@@ -359,8 +359,8 @@ public class Rna
   }
 
   /**
-   * Answers true if the base-pair is either a canonical (A-T/U, C-G) or a
-   * wobble (G-T/U) pair (either way round), else false
+   * Answers true if the base-pair is either a Watson-Crick (A:T/U, C:G) or a
+   * wobble (G:T/U) pair (either way round), else false
    * 
    * @param first
    * @param second
@@ -376,7 +376,7 @@ public class Rna
     {
       second -= 32;
     }
-  
+
     switch (first)
     {
     case 'A':
@@ -417,6 +417,62 @@ public class Rna
   }
 
   /**
+   * Answers true if the base-pair is Watson-Crick - (A:T/U or C:G, either way
+   * round), else false
+   * 
+   * @param first
+   * @param second
+   * @return
+   */
+  public static boolean isCanonicalPair(char first, char second)
+  {
+
+    if (first > 'Z')
+    {
+      first -= 32;
+    }
+    if (second > 'Z')
+    {
+      second -= 32;
+    }
+
+    switch (first)
+    {
+    case 'A':
+      switch (second)
+      {
+      case 'T':
+      case 'U':
+        return true;
+      }
+      break;
+    case 'G':
+      switch (second)
+      {
+      case 'C':
+        return true;
+      }
+      break;
+    case 'C':
+      switch (second)
+      {
+      case 'G':
+        return true;
+      }
+      break;
+    case 'T':
+    case 'U':
+      switch (second)
+      {
+      case 'A':
+        return true;
+      }
+      break;
+    }
+    return false;
+  }
+
+  /**
    * Returns the matching close pair symbol for the given opening symbol.
    * Currently returns a-z for A-Z, or )]}> for ([{<, or the input symbol if it
    * is not a valid opening symbol.
index b0ecfde..21ad1cc 100755 (executable)
@@ -63,14 +63,14 @@ public class SeqsetUtils
     {
       sqinfo.put("SeqFeatures", sfeat);
       sqinfo.put("PdbId",
-            (seq.getAllPDBEntries() != null) ? seq.getAllPDBEntries()
-                    : new Vector<PDBEntry>());
+              (seq.getAllPDBEntries() != null) ? seq.getAllPDBEntries()
+                      : new Vector<PDBEntry>());
     }
     else
     {
       sqinfo.put("datasetSequence",
-            (seq.getDatasetSequence() != null) ? seq.getDatasetSequence()
-                    : new Sequence("THISISAPLACEHOLDER", ""));
+              (seq.getDatasetSequence() != null) ? seq.getDatasetSequence()
+                      : new Sequence("THISISAPLACEHOLDER", ""));
     }
     return sqinfo;
   }
@@ -135,7 +135,7 @@ public class SeqsetUtils
             && !(seqds.getName().equals("THISISAPLACEHOLDER") && seqds
                     .getLength() == 0))
     {
-      if (sfeatures!=null)
+      if (sfeatures != null)
       {
         System.err
                 .println("Implementation error: setting dataset sequence for a sequence which has sequence features.\n\tDataset sequence features will not be visible.");
index 479c856..7b0858d 100644 (file)
@@ -112,8 +112,9 @@ public class StructureFrequency
 
     for (int i = start; i < end; i++) // foreach column
     {
-      int canonicalOrWobblePairCount = 0;
+      int canonicalOrWobblePairCount = 0, canonical = 0;
       int otherPairCount = 0;
+      int nongap = 0;
       maxResidue = "-";
       values = new int[255];
       pairs = new int[255][255];
@@ -161,7 +162,7 @@ public class StructureFrequency
               values['-']++;
               continue;
             }
-
+            nongap++;
             /*
              * ensure upper-case for counting purposes
              */
@@ -175,20 +176,19 @@ public class StructureFrequency
             }
             if (Rna.isCanonicalOrWobblePair(c, cEnd))
             {
-              values['(']++;
-              maxResidue = "(";
               canonicalOrWobblePairCount++;
+              if (Rna.isCanonicalPair(c, cEnd))
+              {
+                canonical++;
+              }
             }
             else
             {
-              values['[']++;
-              maxResidue = "[";
               otherPairCount++;
             }
             pairs[c][cEnd]++;
           }
         }
-        // nonGap++;
       }
 
       residueHash = new Hashtable();
@@ -200,7 +200,9 @@ public class StructureFrequency
 
         residueHash.put(PAIRPROFILE, pairs);
       }
-
+      values['('] = canonicalOrWobblePairCount;
+      values['['] = canonical;
+      values['{'] = otherPairCount;
       /*
        * the count is the number of valid pairs (as a percentage, determines
        * the relative size of the profile logo)
@@ -208,13 +210,20 @@ public class StructureFrequency
       int count = canonicalOrWobblePairCount;
 
       /*
-       * currently displaying as '(' if most pairs are valid, or as
-       * '[' if there are more invalid than valid pairs 
+       * display '(' if most pairs are canonical, or as
+       * '[' if there are more wobble pairs. 
        */
-      if (!maxResidue.equals("-"))
+      if (canonicalOrWobblePairCount > 0 || otherPairCount > 0)
       {
-        maxResidue = canonicalOrWobblePairCount >= otherPairCount ? "("
-                : "[";
+        if (canonicalOrWobblePairCount >= otherPairCount)
+        {
+          maxResidue = (canonicalOrWobblePairCount - canonical) < canonical ? "("
+                  : "[";
+        }
+        else
+        {
+          maxResidue = "{";
+        }
       }
       residueHash.put(MAXCOUNT, new Integer(count));
       residueHash.put(MAXRESIDUE, maxResidue);
@@ -222,8 +231,9 @@ public class StructureFrequency
       percentage = ((float) count * 100) / jSize;
       residueHash.put(PID_GAPS, new Float(percentage));
 
-      // percentage = ((float) count * 100) / (float) nongap;
-      // residueHash.put(PID_NOGAPS, new Float(percentage));
+      percentage = ((float) count * 100) / nongap;
+      residueHash.put(PID_NOGAPS, new Float(percentage));
+
       if (result[i] == null)
       {
         result[i] = residueHash;
@@ -232,9 +242,12 @@ public class StructureFrequency
       {
         values[')'] = values['('];
         values[']'] = values['['];
+        values['}'] = values['{'];
         values['('] = 0;
         values['['] = 0;
-        maxResidue = maxResidue.equals("(") ? ")" : "]";
+        values['{'] = 0;
+        maxResidue = maxResidue.equals("(") ? ")"
+                : maxResidue.equals("[") ? "]" : "}";
 
         residueHash = new Hashtable();
         if (profile)
@@ -251,6 +264,9 @@ public class StructureFrequency
         percentage = ((float) count * 100) / jSize;
         residueHash.put(PID_GAPS, new Float(percentage));
 
+        percentage = ((float) count * 100) / nongap;
+        residueHash.put(PID_NOGAPS, new Float(percentage));
+
         result[bpEnd] = residueHash;
       }
     }
index b868ee5..a7ec69e 100644 (file)
@@ -99,4 +99,16 @@ public interface AlignViewControllerI
   public boolean parseFeaturesFile(String file, DataSourceType sourceType,
           boolean relaxedIdMatching);
 
+  /**
+   * mark columns containing highlighted regions (e.g. from search, structure
+   * highlight, or a mouse over event in another viewer)
+   * 
+   * @param invert
+   * @param extendCurrent
+   * @param toggle
+   * @return
+   */
+  boolean markHighlightedColumns(boolean invert, boolean extendCurrent,
+          boolean toggle);
+
 }
index 8343f0b..72542b3 100644 (file)
@@ -26,6 +26,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ProfilesI;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -53,6 +55,18 @@ public interface AlignViewportI extends ViewStyleI
    */
   public int calcPanelHeight();
 
+  /**
+   * Answers true if the viewport has at least one column selected
+   * 
+   * @return
+   */
+  boolean hasSelectedColumns();
+
+  /**
+   * Answers true if the viewport has at least one hidden column
+   * 
+   * @return
+   */
   boolean hasHiddenColumns();
 
   boolean isValidCharWidth();
@@ -69,7 +83,7 @@ public interface AlignViewportI extends ViewStyleI
 
   ColumnSelection getColumnSelection();
 
-  Hashtable[] getSequenceConsensusHash();
+  ProfilesI getSequenceConsensusHash();
 
   /**
    * Get consensus data table for the cDNA complement of this alignment (if any)
@@ -110,6 +124,11 @@ public interface AlignViewportI extends ViewStyleI
   boolean isClosed();
 
   /**
+   * Dispose of all references or resources held by the viewport
+   */
+  void dispose();
+
+  /**
    * get the associated calculation thread manager for the view
    * 
    * @return
@@ -127,7 +146,7 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @param hconsensus
    */
-  void setSequenceConsensusHash(Hashtable[] hconsensus);
+  void setSequenceConsensusHash(ProfilesI hconsensus);
 
   /**
    * Set the cDNA complement consensus for the viewport
@@ -243,7 +262,7 @@ public interface AlignViewportI extends ViewStyleI
    * @return String[]
    */
   String[] getViewAsString(boolean selectedRegionOnly);
-  
+
   /**
    * This method returns the visible alignment as text, as seen on the GUI, ie
    * if columns are hidden they will not be returned in the result. Use this for
@@ -258,7 +277,8 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @return String[]
    */
-  String[] getViewAsString(boolean selectedRegionOnly, boolean isExportHiddenSeqs);
+  String[] getViewAsString(boolean selectedRegionOnly,
+          boolean isExportHiddenSeqs);
 
   void setSelectionGroup(SequenceGroup sg);
 
@@ -395,6 +415,34 @@ public interface AlignViewportI extends ViewStyleI
    */
   void setFollowHighlight(boolean b);
 
-
   public void applyFeaturesStyle(FeatureSettingsModelI featureSettings);
+
+  /**
+   * check if current selection group is defined on the view, or is simply a
+   * temporary group.
+   * 
+   * @return true if group is defined on the alignment
+   */
+  boolean isSelectionDefinedGroup();
+
+  /**
+   * 
+   * @return true if there are search results on the view
+   */
+  boolean hasSearchResults();
+
+  /**
+   * set the search results for the view
+   * 
+   * @param results
+   *          - or null to clear current results
+   */
+  void setSearchResults(SearchResultsI results);
+
+  /**
+   * get search results for this view (if any)
+   * 
+   * @return search results or null
+   */
+  SearchResultsI getSearchResults();
 }
index 32245b3..51c35c5 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.api;
 
 import jalview.datamodel.Mapping;
@@ -70,4 +90,25 @@ public interface DBRefEntryI
    * @return
    */
   public boolean updateFrom(DBRefEntryI otherEntry);
+
+  /**
+   * Answers true if the ref looks like a primary (direct) database reference. <br>
+   * The only way a dbref's mappings can be fully verified is via the local
+   * sequence frame, so rather than use isPrimaryCandidate directly, please use
+   * SequenceI.getPrimaryDbRefs(). <br>
+   * Primary references indicate the local sequence data directly corresponds
+   * with the database record. All other references are secondary. Direct
+   * references indicate that part or all of the local sequence data can be
+   * mapped with another sequence, enabling annotation transfer.
+   * Cross-references indicate the local sequence data can be corresponded to
+   * some other linear coordinate system via a transformation. <br>
+   * This method is also sufficient to distinguish direct DBRefEntry mappings
+   * from other relationships - e.g. coding relationships (imply a 1:3/3:1
+   * mapping), but not transcript relationships, which imply a (possibly
+   * non-contiguous) 1:1 mapping.
+   *
+   * @return true if this reference provides a primary accession for the
+   *         associated sequence object
+   */
+  public boolean isPrimaryCandidate();
 }
index 1fcbfd0..01eb7fa 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.api;
 
 import jalview.datamodel.SequenceFeature;
index dbc9880..f54231e 100644 (file)
@@ -132,7 +132,8 @@ public interface FeatureRenderer
   void setGroupVisibility(String group, boolean visible);
 
   /**
-   * locate features at a particular position on the given sequence
+   * Returns features at the specified position on the given sequence.
+   * Non-positional features are not included.
    * 
    * @param sequence
    * @param res
index 8f8d8c1..dd8e721 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.api;
 
 /**
index dad434a..c795f3f 100644 (file)
@@ -47,7 +47,6 @@ public interface SiftsClientI
    */
   public String getDbCoordSys();
 
-
   /**
    * Get DB Source for the SIFTs Entry
    * 
@@ -117,7 +116,7 @@ public interface SiftsClientI
    */
   public StructureMapping getSiftsStructureMapping(SequenceI seq,
           String pdbFile, String chain) throws SiftsException;
-  
+
   /**
    * Get residue by residue mapping for a given Sequence and SIFTs entity
    * 
@@ -129,6 +128,5 @@ public interface SiftsClientI
    * @throws Exception
    */
   public HashMap<Integer, int[]> getGreedyMapping(String entityId,
-          SequenceI seq,
-          java.io.PrintStream os) throws SiftsException;
+          SequenceI seq, java.io.PrintStream os) throws SiftsException;
 }
\ No newline at end of file
index fbdf241..015734f 100644 (file)
@@ -30,7 +30,6 @@ import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -46,7 +45,6 @@ import jalview.schemes.HelixColourScheme;
 import jalview.schemes.HydrophobicColourScheme;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.PIDColourScheme;
-import jalview.schemes.ResidueProperties;
 import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
@@ -63,6 +61,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -256,122 +255,9 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
     if (links != null && links.size() > 0)
     {
-      Menu linkMenu = new Menu(MessageManager.getString("action.link"));
-      for (int i = 0; i < links.size(); i++)
-      {
-        String link = links.elementAt(i);
-        UrlLink urlLink = new UrlLink(link);
-        if (!urlLink.isValid())
-        {
-          System.err.println(urlLink.getInvalidMessage());
-          continue;
-        }
-        final String target = urlLink.getTarget(); // link.substring(0,
-        // link.indexOf("|"));
-        final String label = urlLink.getLabel();
-        if (seq != null && urlLink.isDynamic())
-        {
-
-          // collect matching db-refs
-          DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs(
-                  seq.getDBRefs(), new String[] { target });
-          // collect id string too
-          String id = seq.getName();
-          String descr = seq.getDescription();
-          if (descr != null && descr.length() < 1)
-          {
-            descr = null;
-          }
-          if (dbr != null)
-          {
-            for (int r = 0; r < dbr.length; r++)
-            {
-              if (id != null && dbr[r].getAccessionId().equals(id))
-              {
-                // suppress duplicate link creation for the bare sequence ID
-                // string with this link
-                id = null;
-              }
-              // create Bare ID link for this RUL
-              String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(),
-                      true);
-              if (urls != null)
-              {
-                for (int u = 0; u < urls.length; u += 2)
-                {
-                  addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
-                }
-              }
-            }
-          }
-          if (id != null)
-          {
-            // create Bare ID link for this RUL
-            String[] urls = urlLink.makeUrls(id, true);
-            if (urls != null)
-            {
-              for (int u = 0; u < urls.length; u += 2)
-              {
-                addshowLink(linkMenu, label, urls[u + 1]);
-              }
-            }
-            // addshowLink(linkMenu, target, url_pref + id + url_suff);
-          }
-          // Now construct URLs from description but only try to do it for regex
-          // URL links
-          if (descr != null && urlLink.getRegexReplace() != null)
-          {
-            // create link for this URL from description only if regex matches
-            String[] urls = urlLink.makeUrls(descr, true);
-            if (urls != null)
-            {
-              for (int u = 0; u < urls.length; u += 2)
-              {
-                addshowLink(linkMenu, label, urls[u + 1]);
-              }
-            }
-          }
-        }
-        else
-        {
-          addshowLink(linkMenu, target, urlLink.getUrl_prefix()); // link.substring(link.lastIndexOf("|")+1));
-        }
-        /*
-         * final String url;
-         * 
-         * if (link.indexOf("$SEQUENCE_ID$") > -1) { // Substitute SEQUENCE_ID
-         * string and any matching database reference accessions String url_pref
-         * = link.substring(link.indexOf("|") + 1,
-         * link.indexOf("$SEQUENCE_ID$"));
-         * 
-         * String url_suff = link.substring(link.indexOf("$SEQUENCE_ID$") + 13);
-         * // collect matching db-refs DBRefEntry[] dbr =
-         * jalview.util.DBRefUtils.selectRefs(seq.getDBRef(), new
-         * String[]{target}); // collect id string too String id =
-         * seq.getName(); if (id.indexOf("|") > -1) { id =
-         * id.substring(id.lastIndexOf("|") + 1); } if (dbr!=null) { for (int
-         * r=0;r<dbr.length; r++) { if (dbr[r].getAccessionId().equals(id)) { //
-         * suppress duplicate link creation for the bare sequence ID string with
-         * this link id = null; } addshowLink(linkMenu,
-         * dbr[r].getSource()+"|"+dbr[r].getAccessionId(), target,
-         * url_pref+dbr[r].getAccessionId()+url_suff); } } if (id!=null) { //
-         * create Bare ID link for this RUL addshowLink(linkMenu, target,
-         * url_pref + id + url_suff); } } else { addshowLink(linkMenu, target,
-         * link.substring(link.lastIndexOf("|")+1)); }
-         */
-      }
-      if (linkMenu.getItemCount() > 0)
-      {
-        if (seq != null)
-        {
-          seqMenu.add(linkMenu);
-        }
-        else
-        {
-          add(linkMenu);
-        }
-      }
+      addFeatureLinks(seq, links);
     }
+
     // TODO: add group link menu entry here
     if (seq != null)
     {
@@ -417,6 +303,71 @@ public class APopupMenu extends java.awt.PopupMenu implements
   }
 
   /**
+   * Adds a 'Link' menu item with a sub-menu item for each hyperlink provided.
+   * 
+   * @param seq
+   * @param links
+   */
+  void addFeatureLinks(final SequenceI seq, List<String> links)
+  {
+    Menu linkMenu = new Menu(MessageManager.getString("action.link"));
+    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+
+    for (String link : links)
+    {
+      UrlLink urlLink = null;
+      try
+      {
+        urlLink = new UrlLink(link);
+      } catch (Exception foo)
+      {
+        System.err.println("Exception for URLLink '" + link + "': "
+                + foo.getMessage());
+        continue;
+      }
+
+      if (!urlLink.isValid())
+      {
+        System.err.println(urlLink.getInvalidMessage());
+        continue;
+      }
+
+      urlLink.createLinksFromSeq(seq, linkset);
+    }
+
+    addshowLinks(linkMenu, linkset.values());
+
+    // disable link menu if there are no valid entries
+    if (linkMenu.getItemCount() > 0)
+    {
+      linkMenu.setEnabled(true);
+    }
+    else
+    {
+      linkMenu.setEnabled(false);
+    }
+
+    if (seq != null)
+    {
+      seqMenu.add(linkMenu);
+    }
+    else
+    {
+      add(linkMenu);
+    }
+
+  }
+
+  private void addshowLinks(Menu linkMenu, Collection<List<String>> linkset)
+  {
+    for (List<String> linkstrset : linkset)
+    {
+      // split linkstr into label and url
+      addshowLink(linkMenu, linkstrset.get(1), linkstrset.get(3));
+    }
+  }
+
+  /**
    * Build menus for annotation types that may be shown or hidden, and for
    * 'reference annotations' that may be added to the alignment.
    */
@@ -854,7 +805,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, ap.alignFrame);
 
-    StringBuffer contents = new StringBuffer();
+    StringBuilder contents = new StringBuilder(128);
     for (SequenceI seq : sequences)
     {
       contents.append(MessageManager.formatMessage(
@@ -865,7 +816,6 @@ public class APopupMenu extends java.awt.PopupMenu implements
               seq,
               true,
               true,
-              false,
               (ap.seqPanel.seqCanvas.fr != null) ? ap.seqPanel.seqCanvas.fr
                       .getMinMax() : null);
       contents.append("</p>");
@@ -896,9 +846,10 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
   void addPDB()
   {
-    if (seq.getAllPDBEntries() != null)
+    Vector<PDBEntry> pdbs = seq.getAllPDBEntries();
+    if (pdbs != null&& !pdbs.isEmpty())
     {
-      PDBEntry entry = seq.getAllPDBEntries().firstElement();
+      PDBEntry entry = pdbs.firstElement();
 
       if (ap.av.applet.jmolAvailable)
       {
@@ -1210,11 +1161,10 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
     if (conservationMenuItem.getState())
     {
-
-      sg.cs.setConservation(Conservation.calculateConservation("Group",
-              ResidueProperties.propHash, 3, sg.getSequences(ap.av
-                      .getHiddenRepSequences()), 0, ap.av.getAlignment()
-                      .getWidth(), false, ap.av.getConsPercGaps(), false));
+      sg.cs.setConservation(Conservation.calculateConservation("Group", sg
+              .getSequences(ap.av.getHiddenRepSequences()), 0, ap.av
+              .getAlignment().getWidth(), false, ap.av.getConsPercGaps(),
+              false));
       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
       SliderPanel.showConservationSlider();
     }
index fcdf9d2..f830fe6 100644 (file)
@@ -104,7 +104,6 @@ import java.net.URLEncoder;
 import java.util.Arrays;
 import java.util.Deque;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
@@ -358,14 +357,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
    * 
    * @param file
    *          file URL, content, or other resolvable path
-   * @param paste
+   * @param sourceType
    *          is protocol for accessing data referred to by file
    * @param autoenabledisplay
    *          when true, display features flag will be automatically enabled if
    *          features are loaded
    * @return true if data parsed as a features file
    */
-  public boolean parseFeaturesFile(String file, DataSourceType paste,
+  public boolean parseFeaturesFile(String file, DataSourceType sourceType,
           boolean autoenabledisplay)
   {
     boolean featuresFile = false;
@@ -375,7 +374,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
               .getFeatureRenderer().getFeatureColours();
       boolean relaxedIdMatching = viewport.applet.getDefaultParameter(
               "relaxedidmatch", false);
-      featuresFile = new FeaturesFile(file, paste).parse(
+      featuresFile = new FeaturesFile(file, sourceType).parse(
               viewport.getAlignment(), colours, true, relaxedIdMatching);
     } catch (Exception ex)
     {
@@ -705,9 +704,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       // Hide everything by the current selection - this is a hack - we do the
       // invert and then hide
       // first check that there will be visible columns after the invert.
-      if ((viewport.getColumnSelection() != null
-              && viewport.getColumnSelection().getSelected() != null && viewport
-              .getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns()
               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
                       .getEndRes()))
       {
@@ -735,8 +732,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
         hide = true;
         viewport.hideAllSelectedSeqs();
       }
-      else if (!(toggleCols && viewport.getColumnSelection().getSelected()
-              .size() > 0))
+      else if (!(toggleCols && viewport.hasSelectedColumns()))
       {
         viewport.showAllHiddenSeqs();
       }
@@ -744,7 +740,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     if (toggleCols)
     {
-      if (viewport.getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns())
       {
         viewport.hideSelectedColumns();
         if (!toggleSeqs)
@@ -931,11 +927,11 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     if (alignPanel.getAlignment().getAlignmentAnnotation() != null)
     {
       for (AlignmentAnnotation aa : alignPanel.getAlignment()
-            .getAlignmentAnnotation())
-    {
-      boolean visible = (aa.sequenceRef == null ? showForAlignment
-              : showForSequences);
-      aa.visible = visible;
+              .getAlignmentAnnotation())
+      {
+        boolean visible = (aa.sequenceRef == null ? showForAlignment
+                : showForSequences);
+        aa.visible = visible;
       }
     }
     alignPanel.validateAnnotationDimensions(true);
@@ -1420,9 +1416,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     FeaturesFile formatter = new FeaturesFile();
     if (format.equalsIgnoreCase("Jalview"))
     {
-      features = formatter.printJalviewFormat(viewport
-              .getAlignment().getSequencesArray(),
-              getDisplayedFeatureCols());
+      features = formatter.printJalviewFormat(viewport.getAlignment()
+              .getSequencesArray(), getDisplayedFeatureCols());
     }
     else
     {
@@ -4029,12 +4024,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       }
       if (needtoadd)
       {
-        // make a note of the access mode and add
-        if (pdbentry.getProperty() == null)
-        {
-          pdbentry.setProperty(new Hashtable<String, String>());
-        }
-        pdbentry.getProperty().put("protocol", protocol.toString());
+        pdbentry.setProperty("protocol", protocol);
         toaddpdb.addPDBId(pdbentry);
         alignPanel.getStructureSelectionManager()
                 .registerPDBEntry(pdbentry);
@@ -4084,7 +4074,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     }
     if (protocol == null)
     {
-      String sourceType = pdb.getProperty().get("protocol");
+      String sourceType = (String) pdb.getProperty("protocol");
       try
       {
         protocol = DataSourceType.valueOf(sourceType);
index e5178cb..4bd77b6 100644 (file)
@@ -28,6 +28,7 @@ import jalview.commands.CommandI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -433,7 +434,7 @@ public class AlignViewport extends AlignmentViewport implements
      * there is no complement, or it is not following highlights, or no mapping
      * is found, the result will be empty.
      */
-    SearchResults sr = new SearchResults();
+    SearchResultsI sr = new SearchResults();
     int seqOffset = findComplementScrollTarget(sr);
     if (!sr.isEmpty())
     {
index 34e0cc0..e97c347 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.JalviewLite;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 import jalview.structure.StructureSelectionManager;
 
@@ -68,7 +68,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   // this value is set false when selection area being dragged
   boolean fastPaint = true;
 
-  public void finalize()
+  @Override
+  public void finalize() throws Throwable
   {
     alignFrame = null;
     av = null;
@@ -80,6 +81,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     annotationPanel = null;
     annotationPanelHolder = null;
     annotationSpaceFillerHolder = null;
+    super.finalize();
   }
 
   public AlignmentPanel(AlignFrame af, final AlignViewport av)
@@ -121,6 +123,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
     addComponentListener(new ComponentAdapter()
     {
+      @Override
       public void componentResized(ComponentEvent evt)
       {
         setScrollValues(av.getStartRes(), av.getStartSeq());
@@ -146,6 +149,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     final AlignmentPanel ap = this;
     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
     {
+      @Override
       public void propertyChange(java.beans.PropertyChangeEvent evt)
       {
         if (evt.getPropertyName().equals("alignment"))
@@ -289,7 +293,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    * Highlight the given results on the alignment.
    * 
    */
-  public void highlightSearchResults(SearchResults results)
+  public void highlightSearchResults(SearchResultsI results)
   {
     scrollToPosition(results);
     seqPanel.seqCanvas.highlightSearchResults(results);
@@ -302,7 +306,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    * @param results
    * @return false if results were not found
    */
-  public boolean scrollToPosition(SearchResults results)
+  public boolean scrollToPosition(SearchResultsI results)
   {
     return scrollToPosition(results, true);
   }
@@ -316,10 +320,10 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    *          - when set, the overview will be recalculated (takes longer)
    * @return false if results were not found
    */
-  public boolean scrollToPosition(SearchResults results,
+  public boolean scrollToPosition(SearchResultsI results,
           boolean redrawOverview)
   {
-    return scrollToPosition(results, redrawOverview, false);
+    return scrollToPosition(results, 0, redrawOverview, false);
   }
 
   /**
@@ -331,7 +335,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    *          - when set, the overview will be recalculated (takes longer)
    * @return false if results were not found
    */
-  public boolean scrollToPosition(SearchResults results,
+  public boolean scrollToPosition(SearchResultsI results,
+          int verticalOffset,
           boolean redrawOverview, boolean centre)
   {
     // do we need to scroll the panel?
@@ -343,6 +348,10 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       {
         return false;
       }
+      /*
+       * allow for offset of target sequence (actually scroll to one above it)
+       */
+
       SequenceI seq = alignment.getSequenceAt(seqIndex);
       int[] r = results.getResults(seq, 0, alignment.getWidth());
       if (r == null)
@@ -387,6 +396,11 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       {
         return false;
       }
+
+      /*
+       * allow for offset of target sequence (actually scroll to one above it)
+       */
+      seqIndex = Math.max(0, seqIndex - verticalOffset);
       return scrollTo(start, end, seqIndex, false, redrawOverview);
     }
     return true;
@@ -415,6 +429,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     {
       start = ostart;
     }
+
     if (!av.getWrapAlignment())
     {
       /*
@@ -538,6 +553,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    * automatically adjust annotation panel height for new annotation whilst
    * ensuring the alignment is still visible.
    */
+  @Override
   public void adjustAnnotationHeight()
   {
     // TODO: display vertical annotation scrollbar if necessary
@@ -770,6 +786,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     int oldX = av.getStartRes();
@@ -896,14 +913,14 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
    * @param seqOffset
    *          the number of visible sequences to show above the mapped region
    */
-  protected void scrollToCentre(SearchResults sr, int seqOffset)
+  protected void scrollToCentre(SearchResultsI sr, int seqOffset)
   {
     /*
      * To avoid jumpy vertical scrolling (if some sequences are gapped or not
      * mapped), we can make the scroll-to location a sequence above the one
      * actually mapped.
      */
-    SequenceI mappedTo = sr.getResultSequence(0);
+    SequenceI mappedTo = sr.getResults().get(0).getSequence();
     List<SequenceI> seqs = av.getAlignment().getSequences();
 
     /*
@@ -925,16 +942,14 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     {
       return; // failsafe, shouldn't happen
     }
-    sequenceIndex = Math.max(0, sequenceIndex - seqOffset);
-    sr.getResults().get(0)
-            .setSequence(av.getAlignment().getSequenceAt(sequenceIndex));
 
     /*
      * Scroll to position but centring the target residue. Also set a state flag
      * to prevent adjustmentValueChanged performing this recursively.
      */
     setFollowingComplementScroll(true);
-    scrollToPosition(sr, true, true);
+    // this should be scrollToPosition(sr,verticalOffset,
+    scrollToPosition(sr, seqOffset, true, true);
   }
 
   private void sendViewPosition()
@@ -947,6 +962,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   /**
    * Repaint the alignment and annotations, and, optionally, any overview window
    */
+  @Override
   public void paintAlignment(boolean updateOverview)
   {
     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
@@ -969,11 +985,13 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     }
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     invalidate();
index 5a9cd55..79d2f1f 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.appletgui;
 
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceGroup;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
@@ -96,7 +97,8 @@ public class AnnotationColourChooser extends Panel implements
     slider.addAdjustmentListener(this);
     slider.addMouseListener(this);
 
-    if (av.getAlignment().getAlignmentAnnotation() == null)
+    AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
+    if (anns == null)
     {
       return;
     }
@@ -117,11 +119,15 @@ public class AnnotationColourChooser extends Panel implements
       // seqAssociated.setState(acg.isSeqAssociated());
     }
 
-    Vector list = new Vector();
+    Vector<String> list = new Vector<String>();
     int index = 1;
-    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
+    for (int i = 0; i < anns.length; i++)
     {
-      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
+      String label = anns[i].label;
+      if (anns[i].sequenceRef != null)
+      {
+        label = label + "_" + anns[i].sequenceRef.getName();
+      }
       if (!list.contains(label))
       {
         list.addElement(label);
@@ -309,6 +315,7 @@ public class AnnotationColourChooser extends Panel implements
 
   Checkbox thresholdIsMin = new Checkbox();
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     if (evt.getSource() == thresholdValue)
@@ -351,6 +358,7 @@ public class AnnotationColourChooser extends Panel implements
     }
   }
 
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     if (evt.getSource() == currentColours)
@@ -368,6 +376,7 @@ public class AnnotationColourChooser extends Panel implements
     changeColour();
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     if (!adjusting)
@@ -552,23 +561,28 @@ public class AnnotationColourChooser extends Panel implements
 
   }
 
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
+  @Override
   public void mousePressed(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     ap.paintAlignment(true);
   }
 
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseExited(MouseEvent evt)
   {
   }
index e3def25..a8dff62 100644 (file)
@@ -135,17 +135,22 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     slider.addAdjustmentListener(this);
     slider.addMouseListener(this);
 
-    if (av.getAlignment().getAlignmentAnnotation() == null)
+    AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
+    if (anns == null)
     {
       return;
     }
     setOldColumnSelection(av.getColumnSelection());
     adjusting = true;
-    Vector list = new Vector();
+    Vector<String> list = new Vector<String>();
     int index = 1;
-    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
+    for (int i = 0; i < anns.length; i++)
     {
-      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
+      String label = anns[i].label;
+      if (anns[i].sequenceRef != null)
+      {
+        label = label + "_" + anns[i].sequenceRef.getName();
+      }
       if (!list.contains(label))
       {
         list.addElement(label);
@@ -273,6 +278,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     this.validate();
   }
 
+  @Override
   @SuppressWarnings("unchecked")
   public void reset()
   {
@@ -302,6 +308,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
 
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     if (!adjusting)
@@ -343,6 +350,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     });
   }
 
+  @Override
   public void valueChanged(boolean updateAllAnnotation)
   {
     if (slider.isEnabled())
@@ -866,6 +874,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     }
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     if (evt.getSource() == thresholdValue)
index fc49de5..8d67d71 100644 (file)
@@ -85,45 +85,6 @@ public abstract class AnnotationRowFilter extends Panel
 
   }
 
-  public Vector getAnnotationItems(boolean isSeqAssociated)
-  {
-    Vector list = new Vector();
-    int index = 1;
-    int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
-    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
-    {
-      if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
-      {
-        if (isSeqAssociated)
-        {
-          continue;
-        }
-      }
-      else
-      {
-        enableSeqAss = true;
-      }
-      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
-      if (!list.contains(label))
-      {
-        anmap[list.size()] = i;
-        list.add(label);
-
-      }
-      else
-      {
-        if (!isSeqAssociated)
-        {
-          anmap[list.size()] = i;
-          list.add(label + "_" + (index++));
-        }
-      }
-    }
-    this.annmap = new int[list.size()];
-    System.arraycopy(anmap, 0, this.annmap, 0, this.annmap.length);
-    return list;
-  }
-
   protected int getSelectedThresholdItem(int indexValue)
   {
     int selectedThresholdItem = -1;
index 18e7d1a..9d4779c 100644 (file)
@@ -61,7 +61,6 @@ import java.awt.event.KeyListener;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Vector;
 
@@ -182,7 +181,7 @@ public class AppletJmol extends EmbmenuFrame implements
     this.ap = ap;
     jmb = new AppletJmolBinding(this, ap.getStructureSelectionManager(),
             new PDBEntry[] { pdbentry }, new SequenceI[][] { seq },
-            new String[][] { chains }, protocol);
+            protocol);
     jmb.setColourBySequence(true);
     if (pdbentry.getId() == null || pdbentry.getId().length() < 1)
     {
@@ -291,12 +290,9 @@ public class AppletJmol extends EmbmenuFrame implements
         closeViewer();
       }
     });
-    if (pdbentry.getProperty() == null)
-    {
-      pdbentry.setProperty(new Hashtable<String, String>());
-      pdbentry.getProperty().put("protocol", protocol.toString());
-    }
+    pdbentry.setProperty("protocol", protocol);
     if (pdbentry.getFile() != null)
+    
     {
       // import structure data from pdbentry.getFile based on given protocol
       if (protocol == DataSourceType.PASTE)
@@ -374,7 +370,7 @@ public class AppletJmol extends EmbmenuFrame implements
     jmb.loadInline(string);
   }
 
-  void setChainMenuItems(Vector<String> chains)
+  void setChainMenuItems(List<String> chains)
   {
     chainMenu.removeAll();
 
@@ -593,7 +589,7 @@ public class AppletJmol extends EmbmenuFrame implements
       repaint();
       return;
     }
-    setChainMenuItems(jmb.chainNames);
+    setChainMenuItems(jmb.getChainNames());
     jmb.colourBySequence(ap);
 
     setTitle(jmb.getViewerTitle());
index 92dff7b..f938cad 100644 (file)
@@ -30,8 +30,6 @@ import jalview.structure.StructureSelectionManager;
 import java.awt.Container;
 import java.util.Map;
 
-import javajs.awt.Dimension;
-
 import org.jmol.api.JmolAppConsoleInterface;
 import org.jmol.console.AppletConsole;
 import org.jmol.java.BS;
@@ -46,9 +44,9 @@ class AppletJmolBinding extends JalviewJmolBinding
 
   public AppletJmolBinding(AppletJmol appletJmol,
           StructureSelectionManager sSm, PDBEntry[] pdbentry,
-          SequenceI[][] seq, String[][] chains, DataSourceType protocol)
+          SequenceI[][] seq, DataSourceType protocol)
   {
-    super(sSm, pdbentry, seq, chains, protocol);
+    super(sSm, pdbentry, seq, protocol);
     appletJmolBinding = appletJmol;
   }
 
@@ -187,7 +185,7 @@ class AppletJmolBinding extends JalviewJmolBinding
   }
 
   @Override
-  public Dimension resizeInnerPanel(String data)
+  public int[] resizeInnerPanel(String data)
   {
     // TODO Auto-generated method stub
     return null;
index a402ae0..189fe88 100644 (file)
@@ -50,11 +50,11 @@ public class ExtJmol extends JalviewJmolBinding
   private AlignmentPanel ap;
 
   protected ExtJmol(AlignFrame alframe,
-          PDBEntry[] pdbentry, SequenceI[][] seq, String[][] chains,
+          PDBEntry[] pdbentry, SequenceI[][] seq,
           DataSourceType protocol)
   {
     super(alframe.alignPanel.getStructureSelectionManager(), pdbentry, seq,
-            chains, protocol);
+            protocol);
   }
 
   public ExtJmol(Viewer viewer, AlignmentPanel alignPanel,
index 82736d7..2fca07d 100644 (file)
@@ -22,6 +22,7 @@ package jalview.appletgui;
 
 import jalview.api.FeatureColourI;
 import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.FeaturesFile;
@@ -225,7 +226,7 @@ public class FeatureRenderer extends
             start.setText(features[index].getBegin() + "");
             end.setText(features[index].getEnd() + "");
 
-            SearchResults highlight = new SearchResults();
+            SearchResultsI highlight = new SearchResults();
             highlight.addResult(sequences[0], features[index].getBegin(),
                     features[index].getEnd());
 
index 9733c86..2c454a4 100755 (executable)
@@ -185,8 +185,7 @@ public class FeatureSettings extends Panel implements ItemListener,
   }
 
   protected void popupSort(final MyCheckbox check,
-          final Map<String, float[][]> minmax,
-          int x, int y)
+          final Map<String, float[][]> minmax, int x, int y)
   {
     final String type = check.type;
     final FeatureColourI typeCol = fr.getFeatureStyle(type);
@@ -804,11 +803,10 @@ public class FeatureSettings extends Panel implements ItemListener,
    * @param type
    * @param columnsContaining
    */
-  void hideFeatureColumns(final String type,
-          boolean columnsContaining)
+  void hideFeatureColumns(final String type, boolean columnsContaining)
   {
-    if (ap.alignFrame.avc.markColumnsContainingFeatures(
-            columnsContaining, false, false, type))
+    if (ap.alignFrame.avc.markColumnsContainingFeatures(columnsContaining,
+            false, false, type))
     {
       if (ap.alignFrame.avc.markColumnsContainingFeatures(
               !columnsContaining, false, false, type))
index 75d9b9e..d2fe69c 100644 (file)
@@ -20,7 +20,8 @@
  */
 package jalview.appletgui;
 
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
@@ -50,7 +51,7 @@ public class Finder extends Panel implements ActionListener
 
   Frame frame;
 
-  SearchResults searchResults;
+  SearchResultsI searchResults;
 
   int seqIndex = 0;
 
@@ -76,6 +77,7 @@ public class Finder extends Panel implements ActionListener
     frame.repaint();
     frame.addWindowListener(new WindowAdapter()
     {
+      @Override
       public void windowClosing(WindowEvent evt)
       {
         ap.highlightSearchResults(null);
@@ -84,6 +86,7 @@ public class Finder extends Panel implements ActionListener
     textfield.requestFocus();
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     if (evt.getSource() == textfield)
@@ -114,13 +117,15 @@ public class Finder extends Panel implements ActionListener
     SequenceFeature[] features = new SequenceFeature[searchResults
             .getSize()];
 
-    for (int i = 0; i < searchResults.getSize(); i++)
+    int i = 0;
+    for (SearchResultMatchI match : searchResults.getResults())
     {
-      seqs[i] = searchResults.getResultSequence(i);
+      seqs[i] = match.getSequence().getDatasetSequence();
 
       features[i] = new SequenceFeature(textfield.getText().trim(),
-              "Search Results", null, searchResults.getResultStart(i),
-              searchResults.getResultEnd(i), "Search Results");
+              "Search Results", null, match.getStart(), match.getEnd(),
+              "Search Results");
+      i++;
     }
 
     if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
@@ -152,7 +157,7 @@ public class Finder extends Panel implements ActionListener
     seqIndex = finder.getSeqIndex();
     resIndex = finder.getResIndex();
     searchResults = finder.getSearchResults();
-    Vector idMatch = finder.getIdMatch();
+    Vector<SequenceI> idMatch = finder.getIdMatch();
     boolean haveResults = false;
     // set or reset the GUI
     if ((idMatch.size() > 0))
@@ -246,6 +251,7 @@ public class Finder extends Panel implements ActionListener
     textfield.setBounds(new Rectangle(40, 17, 133, 21));
     textfield.addKeyListener(new java.awt.event.KeyAdapter()
     {
+      @Override
       public void keyTyped(KeyEvent e)
       {
         textfield_keyTyped(e);
index 36c2199..182f20e 100755 (executable)
@@ -20,6 +20,9 @@
  */
 package jalview.appletgui;
 
+import static jalview.util.UrlConstants.EMBLEBI_STRING;
+import static jalview.util.UrlConstants.SRS_STRING;
+
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -82,19 +85,16 @@ public class IdPanel extends Panel implements MouseListener,
     }
     {
       // upgrade old SRS link
-      int srsPos = links
-              .indexOf("SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry");
+      int srsPos = links.indexOf(SRS_STRING);
       if (srsPos > -1)
       {
-        links.setElementAt(
-                "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$",
-                srsPos);
+        links.setElementAt(EMBLEBI_STRING, srsPos);
       }
     }
     if (links.size() < 1)
     {
       links = new java.util.Vector();
-      links.addElement("EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$");
+      links.addElement(EMBLEBI_STRING);
     }
   }
 
@@ -246,7 +246,14 @@ public class IdPanel extends Panel implements MouseListener,
         url = null;
         continue;
       }
-      ;
+
+      if (urlLink.usesDBAccession())
+      {
+        // this URL requires an accession id, not the name of a sequence
+        url = null;
+        continue;
+      }
+
       if (!urlLink.isValid())
       {
         System.err.println(urlLink.getInvalidMessage());
@@ -352,8 +359,7 @@ public class IdPanel extends Panel implements MouseListener,
 
     if ((av.getSelectionGroup() == null)
             || ((!jalview.util.Platform.isControlDown(e) && !e
-                    .isShiftDown()) && av
-                    .getSelectionGroup() != null))
+                    .isShiftDown()) && av.getSelectionGroup() != null))
     {
       av.setSelectionGroup(new SequenceGroup());
       av.getSelectionGroup().setStartRes(0);
index d2c1693..5a156fa 100755 (executable)
@@ -152,8 +152,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     PopupMenu pop = new PopupMenu();
     if (reveal != null)
     {
-      MenuItem item = new MenuItem(
-              MessageManager.getString("label.reveal"));
+      MenuItem item = new MenuItem(MessageManager.getString("label.reveal"));
       item.addActionListener(new ActionListener()
       {
         @Override
@@ -205,8 +204,8 @@ public class ScalePanel extends Panel implements MouseMotionListener,
         {
           av.hideColumns(res, res);
           if (av.getSelectionGroup() != null
-                  && av.getSelectionGroup().getSize() == av
-                          .getAlignment().getHeight())
+                  && av.getSelectionGroup().getSize() == av.getAlignment()
+                          .getHeight())
           {
             av.setSelectionGroup(null);
           }
@@ -495,8 +494,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
           gg.fillPolygon(new int[] {
               -1 + res * avCharWidth - avcharHeight / 4,
               -1 + res * avCharWidth + avcharHeight / 4,
-              -1 + res * avCharWidth },
-                  new int[] { y, y, y + 2 * yOf }, 3);
+              -1 + res * avCharWidth }, new int[] { y, y, y + 2 * yOf }, 3);
         }
       }
     }
index 22849f1..5d6bb07 100755 (executable)
@@ -21,7 +21,7 @@
 package jalview.appletgui;
 
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
@@ -50,8 +50,6 @@ public class SeqCanvas extends Panel
 
   AlignViewport av;
 
-  SearchResults searchResults = null;
-
   boolean fastPaint = false;
 
   int cursorX = 0;
@@ -113,8 +111,7 @@ public class SeqCanvas extends Panel
         }
         g.drawLine((mpos * avcharWidth) + (avcharWidth / 2), (ypos + 2)
                 - (avcharHeight / 2), (mpos * avcharWidth)
-                + (avcharWidth / 2),
-                ypos - 2);
+                + (avcharWidth / 2), ypos - 2);
       }
     }
   }
@@ -633,9 +630,10 @@ public class SeqCanvas extends Panel
 
       // / Highlight search Results once all sequences have been drawn
       // ////////////////////////////////////////////////////////
-      if (searchResults != null)
+      if (av.hasSearchResults())
       {
-        int[] visibleResults = searchResults.getResults(nextSeq, startRes,
+        int[] visibleResults = av.getSearchResults().getResults(nextSeq,
+                startRes,
                 endRes);
         if (visibleResults != null)
         {
@@ -844,10 +842,9 @@ public class SeqCanvas extends Panel
     }
   }
 
-  public void highlightSearchResults(SearchResults results)
+  public void highlightSearchResults(SearchResultsI results)
   {
-    searchResults = results;
-
+    av.setSearchResults(results);
     repaint();
   }
 
index 02172d6..8d6e683 100644 (file)
@@ -25,8 +25,9 @@ import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
-import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -458,7 +459,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
    * @param results
    * @return true if results were matched, false if not
    */
-  private boolean setStatusMessage(SearchResults results)
+  private boolean setStatusMessage(SearchResultsI results)
   {
     AlignmentI al = this.av.getAlignment();
     int sequenceIndex = al.findIndex(results);
@@ -467,7 +468,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       return false;
     }
     SequenceI ds = al.getSequenceAt(sequenceIndex).getDatasetSequence();
-    for (Match m : results.getResults())
+    for (SearchResultMatchI m : results.getResults())
     {
       SequenceI seq = m.getSequence();
       if (seq.getDatasetSequence() != null)
@@ -559,7 +560,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
       if (features != null && features.length > 0)
       {
-        SearchResults highlight = new SearchResults();
+        SearchResultsI highlight = new SearchResults();
         highlight.addResult(sequence, features[0].getBegin(),
                 features[0].getEnd());
         seqCanvas.highlightSearchResults(highlight);
@@ -731,7 +732,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
   }
 
   @Override
-  public void highlightSequence(SearchResults results)
+  public void highlightSequence(SearchResultsI results)
   {
     if (av.isFollowHighlight())
     {
@@ -927,13 +928,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
    */
   private boolean needOverviewUpdate; // TODO: refactor to avcontroller
 
-  /**
-   * set if av.getSelectionGroup() refers to a group that is defined on the
-   * alignment view, rather than a transient selection
-   */
-  private boolean editingDefinedGroup = false; // TODO: refactor to avcontroller
-                                               // or viewModel
-
   @Override
   public void mouseDragged(MouseEvent evt)
   {
@@ -1436,12 +1430,10 @@ public class SeqPanel extends Panel implements MouseMotionListener,
               && res < stretchGroup.getEndRes())
       {
         av.setSelectionGroup(stretchGroup);
-        editingDefinedGroup = true;
       }
       else
       {
         stretchGroup = null;
-        editingDefinedGroup = false;
       }
     }
 
@@ -1461,7 +1453,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
                   && allGroups[i].getEndRes() >= res)
           {
             stretchGroup = allGroups[i];
-            editingDefinedGroup = true;
             break;
           }
         }
@@ -1517,7 +1508,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       sg.setEndRes(res);
       sg.addSequence(sequence, false);
       av.setSelectionGroup(sg);
-      editingDefinedGroup = false;
       stretchGroup = sg;
 
       if (av.getConservationSelected())
@@ -1543,7 +1533,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     // always do this - annotation has own state
     // but defer colourscheme update until hidden sequences are passed in
     boolean vischange = stretchGroup.recalcConservation(true);
-    needOverviewUpdate |= vischange && editingDefinedGroup;
+    // here we rely on stretchGroup == av.getSelection()
+    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
     if (stretchGroup.cs != null)
     {
       stretchGroup.cs.alignmentChanged(stretchGroup,
@@ -1562,8 +1553,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
     PaintRefresher.Refresh(ap, av.getSequenceSetId());
     ap.paintAlignment(needOverviewUpdate);
-    needOverviewUpdate =false;
-    editingDefinedGroup = false;
+    needOverviewUpdate = false;
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
@@ -1618,7 +1608,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       if (res > (stretchGroup.getStartRes() - 1))
       {
         stretchGroup.setEndRes(res);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
     else if (changeStartRes)
@@ -1626,7 +1616,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       if (res < (stretchGroup.getEndRes() + 1))
       {
         stretchGroup.setStartRes(res);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1660,7 +1650,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       if (stretchGroup.getSequences(null).contains(nextSeq))
       {
         stretchGroup.deleteSequence(seq, false);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
       else
       {
@@ -1670,7 +1660,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
 
         stretchGroup.addSequence(nextSeq, false);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
index 2c53c08..35c2a22 100644 (file)
@@ -131,8 +131,9 @@ public class SliderPanel extends Panel implements ActionListener,
       pid = (SliderPanel) PIDSlider.getComponent(0);
       pid.cs = cs;
     }
-    PIDSlider.setTitle(MessageManager
-            .formatMessage("label.percentage_identity_threshold",
+    PIDSlider
+            .setTitle(MessageManager.formatMessage(
+                    "label.percentage_identity_threshold",
                     new String[] { source }));
 
     if (ap.av.getAlignment().getGroups() != null)
index edcd961..8292a5a 100755 (executable)
@@ -29,7 +29,6 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequenceNode;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 import jalview.util.Format;
 import jalview.util.MappingUtils;
@@ -122,13 +121,13 @@ public class TreeCanvas extends Panel implements MouseListener,
     tree.findHeight(tree.getTopNode());
 
     // Now have to calculate longest name based on the leaves
-    Vector leaves = tree.findLeaves(tree.getTopNode(), new Vector());
+    Vector<SequenceNode> leaves = tree.findLeaves(tree.getTopNode());
     boolean has_placeholders = false;
     longestName = "";
 
     for (int i = 0; i < leaves.size(); i++)
     {
-      SequenceNode lf = (SequenceNode) leaves.elementAt(i);
+      SequenceNode lf = leaves.elementAt(i);
 
       if (lf.isPlaceholder())
       {
@@ -525,13 +524,11 @@ public class TreeCanvas extends Panel implements MouseListener,
       }
       else
       {
-        Vector leaves = new Vector();
-        tree.findLeaves(highlightNode, leaves);
+        Vector<SequenceNode> leaves = tree.findLeaves(highlightNode);
 
         for (int i = 0; i < leaves.size(); i++)
         {
-          SequenceI seq = (SequenceI) ((SequenceNode) leaves.elementAt(i))
-                  .element();
+          SequenceI seq = (SequenceI) leaves.elementAt(i).element();
           treeSelectionChanged(seq);
         }
       }
@@ -628,16 +625,15 @@ public class TreeCanvas extends Panel implements MouseListener,
 
       Color col = new Color((int) (Math.random() * 255),
               (int) (Math.random() * 255), (int) (Math.random() * 255));
-      setColor((SequenceNode) tree.getGroups().elementAt(i), col.brighter());
+      setColor(tree.getGroups().elementAt(i), col.brighter());
 
-      Vector l = tree.findLeaves(
-              (SequenceNode) tree.getGroups().elementAt(i), new Vector());
+      Vector<SequenceNode> l = tree.findLeaves(tree.getGroups()
+              .elementAt(i));
 
-      Vector sequences = new Vector();
+      Vector<SequenceI> sequences = new Vector<SequenceI>();
       for (int j = 0; j < l.size(); j++)
       {
-        SequenceI s1 = (SequenceI) ((SequenceNode) l.elementAt(j))
-                .element();
+        SequenceI s1 = (SequenceI) l.elementAt(j).element();
         if (!sequences.contains(s1))
         {
           sequences.addElement(s1);
@@ -680,8 +676,7 @@ public class TreeCanvas extends Panel implements MouseListener,
       if (av.getGlobalColourScheme() != null
               && av.getGlobalColourScheme().conservationApplied())
       {
-        Conservation c = new Conservation("Group",
-                ResidueProperties.propHash, 3, sg.getSequences(null),
+        Conservation c = new Conservation("Group", sg.getSequences(null),
                 sg.getStartRes(), sg.getEndRes());
 
         c.calculate();
index 9c8d0df..c927f1f 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.bin;
 
 import java.net.URLDecoder;
@@ -94,4 +114,4 @@ public class ArgsParser
     return vargs.size();
   }
 
-}
\ No newline at end of file
+}
index df71ccc..8412dab 100755 (executable)
@@ -228,11 +228,11 @@ public class Cache
   private final static String DEFAULT_CACHE_THRESHOLD_IN_DAYS = "2";
 
   private final static String DEFAULT_FAIL_SAFE_PID_THRESHOLD = "30";
-  
+
   /**
    * Allowed values are PDB or mmCIF
    */
-  private final static String DEFAULT_STRUCTURE_FORMAT = PDBEntry.Type.MMCIF
+  private final static String PDB_DOWNLOAD_FORMAT = PDBEntry.Type.MMCIF
           .toString();
 
   private final static String DEFAULT_PDB_FILE_PARSER = StructureImportSettings.StructureParser.JMOL_PARSER
@@ -444,11 +444,12 @@ public class Cache
             .println("Jalview Version: " + codeVersion + codeInstallation);
 
     StructureImportSettings.setDefaultStructureFileFormat(jalview.bin.Cache
-            .getDefault(
-            "DEFAULT_STRUCTURE_FORMAT", DEFAULT_STRUCTURE_FORMAT));
+            .getDefault("PDB_DOWNLOAD_FORMAT", PDB_DOWNLOAD_FORMAT));
     StructureImportSettings
-            .setDefaultPDBFileParser(jalview.bin.Cache.getDefault(
-                    "DEFAULT_PDB_FILE_PARSER", DEFAULT_PDB_FILE_PARSER));
+            .setDefaultPDBFileParser(DEFAULT_PDB_FILE_PARSER);
+    // StructureImportSettings
+    // .setDefaultPDBFileParser(jalview.bin.Cache.getDefault(
+    // "DEFAULT_PDB_FILE_PARSER", DEFAULT_PDB_FILE_PARSER));
     // jnlpVersion will be null if we're using InstallAnywhere
     // Dont do this check if running in headless mode
     if (jnlpVersion == null
@@ -894,7 +895,7 @@ public class Cache
   {
     setProperty(property, jalview.util.Format.getHexString(colour));
   }
-  
+
   /**
    * Stores a formatted date in a jalview property, using a fixed locale.
    * 
index 1ab837f..39c0a5b 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.bin;
 import groovy.lang.Binding;
 import groovy.util.GroovyScriptEngine;
 
+import jalview.ext.so.SequenceOntology;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.PromptUserConfig;
@@ -36,6 +37,7 @@ import jalview.io.FileLoader;
 import jalview.io.HtmlSvgOutput;
 import jalview.io.IdentifyFile;
 import jalview.io.NewickFile;
+import jalview.io.gff.SequenceOntologyFactory;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
 import jalview.schemes.UserColourScheme;
@@ -52,6 +54,7 @@ import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.security.AllPermission;
 import java.security.CodeSource;
@@ -291,6 +294,15 @@ public class Jalview
       }
     }
 
+    /*
+     * configure 'full' SO model if preferences say to, 
+     * else use the default (SO Lite)
+     */
+    if (Cache.getDefault("USE_FULL_SO", false))
+    {
+      SequenceOntologyFactory.setInstance(new SequenceOntology());
+    }
+
     if (!headless)
     {
       desktop = new Desktop();
@@ -650,10 +662,33 @@ public class Jalview
           {
             File imageFile = new File(file);
             imageName = imageFile.getName();
-            new HtmlSvgOutput(new File(file), af.alignPanel);
+            HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
+            htmlSVG.exportHTML(file);
+
             System.out.println("Creating HTML image: " + file);
             continue;
           }
+          else if (outputFormat.equalsIgnoreCase("biojsmsa"))
+          {
+            if (file == null)
+            {
+              System.err.println("The output html file must not be null");
+              return;
+            }
+            try
+            {
+              BioJsHTMLOutput
+                      .refreshVersionInfo(BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+            } catch (URISyntaxException e)
+            {
+              e.printStackTrace();
+            }
+            BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
+            bjs.exportHTML(file);
+            System.out.println("Creating BioJS MSA Viwer HTML file: "
+                    + file);
+            continue;
+          }
           else if (outputFormat.equalsIgnoreCase("imgMap"))
           {
             af.createImageMap(new File(file), imageName);
@@ -795,6 +830,7 @@ public class Jalview
                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
                     + "-html FILE\tCreate HTML file from alignment.\n"
+                    + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
index 7f15b3e..9fd8a90 100644 (file)
@@ -470,7 +470,7 @@ public class JalviewLite extends Applet implements
         SequenceI rs = sel.getSequenceAt(0);
         start = rs.findIndex(start);
         end = rs.findIndex(end);
-        List<Integer> cs = csel.getSelected();
+        List<Integer> cs = new ArrayList<Integer>(csel.getSelected());
         csel.clear();
         for (Integer selectedCol : cs)
         {
index dc6c424..655657e 100644 (file)
@@ -68,7 +68,6 @@ public class TrimRegionCommand extends EditCommand
       setEdit(new Edit(Action.CUT, seqs, column + 1, width, al));
     }
 
-
     performEdit(0, null);
   }
 
index 7d60dc8..bc7f212 100644 (file)
@@ -244,10 +244,6 @@ public class AlignViewController implements AlignViewControllerI
         SequenceFeature[] sfs = sq.getSequenceFeatures();
         if (sfs != null)
         {
-          /*
-           * check whether the feature start/end (base 1) 
-           * overlaps the selection start/end
-           */
           int ist = sq.findIndex(sq.getStart());
           int iend = sq.findIndex(sq.getEnd());
           if (iend < startPosition || ist > endPosition)
@@ -265,29 +261,54 @@ public class AlignViewController implements AlignViewControllerI
               // - findIndex wastes time by starting from first character and
               // counting
 
-              int i = sq.findIndex(sf.getBegin());
-              int j = sq.findIndex(sf.getEnd());
-              if (j < startPosition || i > endPosition)
+              int sfStartCol = sq.findIndex(sf.getBegin());
+              int sfEndCol = sq.findIndex(sf.getEnd());
+
+              if (sf.isContactFeature())
+              {
+                /*
+                 * 'contact' feature - check for 'start' or 'end'
+                 * position within the selected region
+                 */
+                if (sfStartCol >= startPosition
+                        && sfStartCol <= endPosition)
+                {
+                  bs.set(sfStartCol - 1);
+                  sequenceHasFeature = true;
+                }
+                if (sfEndCol >= startPosition && sfEndCol <= endPosition)
+                {
+                  bs.set(sfEndCol - 1);
+                  sequenceHasFeature = true;
+                }
+                continue;
+              }
+
+              /*
+               * contiguous feature - select feature positions (if any) 
+               * within the selected region
+               */
+              if (sfStartCol > endPosition || sfEndCol < startPosition)
               {
                 // feature is outside selected region
                 continue;
               }
               sequenceHasFeature = true;
-              if (i < startPosition)
+              if (sfStartCol < startPosition)
               {
-                i = startPosition;
+                sfStartCol = startPosition;
               }
-              if (i < ist)
+              if (sfStartCol < ist)
               {
-                i = ist;
+                sfStartCol = ist;
               }
-              if (j > endPosition)
+              if (sfEndCol > endPosition)
               {
-                j = endPosition;
+                sfEndCol = endPosition;
               }
-              for (; i <= j; i++)
+              for (; sfStartCol <= sfEndCol; sfStartCol++)
               {
-                bs.set(i - 1); // convert to base 0
+                bs.set(sfStartCol - 1); // convert to base 0
               }
             }
           }
@@ -382,4 +403,66 @@ public class AlignViewController implements AlignViewControllerI
     return featuresFile;
 
   }
+
+  @Override
+  public boolean markHighlightedColumns(boolean invert,
+          boolean extendCurrent, boolean toggle)
+  {
+    if (!viewport.hasSearchResults())
+    {
+      // do nothing if no selection exists
+      return false;
+    }
+    // JBPNote this routine could also mark rows, not just columns.
+    BitSet bs = new BitSet();
+    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null || extendCurrent) ? viewport
+            .getAlignment() : viewport.getSelectionGroup();
+
+    // this could be a lambda... - the remains of the method is boilerplate,
+    // except for the different messages for reporting selection.
+    int nseq = viewport.getSearchResults().markColumns(sqcol, bs);
+
+    ColumnSelection cs = viewport.getColumnSelection();
+    if (cs == null)
+    {
+      cs = new ColumnSelection();
+    }
+
+    if (bs.cardinality() > 0 || invert)
+    {
+      boolean changed = cs.markColumns(bs, sqcol.getStartRes(),
+              sqcol.getEndRes(), invert, extendCurrent, toggle);
+      if (changed)
+      {
+        viewport.setColumnSelection(cs);
+        alignPanel.paintAlignment(true);
+        int columnCount = invert ? (sqcol.getEndRes() - sqcol.getStartRes() + 1)
+                - bs.cardinality()
+                : bs.cardinality();
+        avcg.setStatus(MessageManager.formatMessage(
+                "label.view_controller_toggled_marked",
+                new String[] {
+                    toggle ? MessageManager.getString("label.toggled")
+                            : MessageManager.getString("label.marked"),
+                    String.valueOf(columnCount),
+                    invert ? MessageManager
+                            .getString("label.not_containing")
+                            : MessageManager.getString("label.containing"),
+                    "Highlight", Integer.valueOf(nseq).toString() }));
+        return true;
+      }
+    }
+    else
+    {
+      avcg.setStatus(MessageManager
+              .formatMessage("No highlighted regions marked"));
+      if (!extendCurrent)
+      {
+        cs.clear();
+        alignPanel.paintAlignment(true);
+      }
+    }
+    return false;
+  }
+
 }
index 326cc4e..4fbfd62 100644 (file)
@@ -93,8 +93,8 @@ public class AlignedCodonFrame
       return (this.fromSeq == that.fromSeq || (this.fromSeq != null
               && that.fromSeq != null
               && this.fromSeq.getDatasetSequence() != null && this.fromSeq
-              .getDatasetSequence() == that.fromSeq
-              .getDatasetSequence())) && this.mapping.equals(that.mapping);
+              .getDatasetSequence() == that.fromSeq.getDatasetSequence()))
+              && this.mapping.equals(that.mapping);
     }
 
     public SequenceI getFromSeq()
@@ -301,7 +301,7 @@ public class AlignedCodonFrame
    *          where highlighted regions go
    */
   public void markMappedRegion(SequenceI seq, int index,
-          SearchResults results)
+          SearchResultsI results)
   {
     int[] codon;
     SequenceI ds = seq.getDatasetSequence();
@@ -719,8 +719,8 @@ public class AlignedCodonFrame
   }
 
   /**
-   * Returns the first mapping found that is between 'fromSeq' and 'toSeq', or null
-   * if none found
+   * Returns the first mapping found that is between 'fromSeq' and 'toSeq', or
+   * null if none found
    * 
    * @param fromSeq
    *          aligned or dataset sequence
index 286e284..d651c1d 100755 (executable)
 package jalview.datamodel;
 
 import jalview.analysis.AlignmentUtils;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.io.FastaFile;
 import jalview.util.Comparison;
+import jalview.util.LinkedIdentityHashSet;
 import jalview.util.MessageManager;
 
 import java.util.ArrayList;
@@ -225,18 +227,21 @@ public class Alignment implements AlignmentI
   {
     if (dataset != null)
     {
+
       // maintain dataset integrity
-      if (snew.getDatasetSequence() != null)
-      {
-        getDataset().addSequence(snew.getDatasetSequence());
-      }
-      else
+      SequenceI dsseq = snew.getDatasetSequence();
+      if (dsseq == null)
       {
         // derive new sequence
         SequenceI adding = snew.deriveSequence();
-        getDataset().addSequence(adding.getDatasetSequence());
         snew = adding;
+        dsseq = snew.getDatasetSequence();
       }
+      if (getDataset().findIndex(dsseq) == -1)
+      {
+        getDataset().addSequence(dsseq);
+      }
+
     }
     if (sequences == null)
     {
@@ -255,18 +260,22 @@ public class Alignment implements AlignmentI
     }
   }
 
-  /**
-   * Adds a sequence to the alignment. Recalculates maxLength and size.
-   * 
-   * @param snew
-   */
   @Override
-  public void setSequenceAt(int i, SequenceI snew)
+  public SequenceI replaceSequenceAt(int i, SequenceI snew)
   {
     synchronized (sequences)
     {
-      deleteSequence(i);
-      sequences.set(i, snew);
+      if (sequences.size() > i)
+      {
+        return sequences.set(i, snew);
+
+      }
+      else
+      {
+        sequences.add(snew);
+        hiddenSequences.adjustHeightSequenceAdded();
+      }
+      return null;
     }
   }
 
@@ -282,13 +291,23 @@ public class Alignment implements AlignmentI
   }
 
   @Override
-  public void finalize()
+  public void finalize() throws Throwable
   {
     if (getDataset() != null)
     {
       getDataset().removeAlignmentRef();
     }
 
+    nullReferences();
+    super.finalize();
+  }
+
+  /**
+   * Defensively nulls out references in case this object is not garbage
+   * collected
+   */
+  void nullReferences()
+  {
     dataset = null;
     sequences = null;
     groups = null;
@@ -297,14 +316,16 @@ public class Alignment implements AlignmentI
   }
 
   /**
-   * decrement the alignmentRefs counter by one and call finalize if it goes to
-   * zero.
+   * decrement the alignmentRefs counter by one and null references if it goes
+   * to zero.
+   * 
+   * @throws Throwable
    */
-  private void removeAlignmentRef()
+  private void removeAlignmentRef() throws Throwable
   {
     if (--alignmentRefs == 0)
     {
-      finalize();
+      nullReferences();
     }
   }
 
@@ -640,7 +661,7 @@ public class Alignment implements AlignmentI
    * jalview.datamodel.AlignmentI#findIndex(jalview.datamodel.SearchResults)
    */
   @Override
-  public int findIndex(SearchResults results)
+  public int findIndex(SearchResultsI results)
   {
     int i = 0;
 
@@ -1029,6 +1050,70 @@ public class Alignment implements AlignmentI
   }
 
   /**
+   * add dataset sequences to seq for currentSeq and any sequences it references
+   */
+  private void resolveAndAddDatasetSeq(SequenceI currentSeq,
+          Set<SequenceI> seqs, boolean createDatasetSequence)
+  {
+    SequenceI alignedSeq = currentSeq;
+    if (currentSeq.getDatasetSequence() != null)
+    {
+      currentSeq = currentSeq.getDatasetSequence();
+    }
+    else
+    {
+      if (createDatasetSequence)
+      {
+        currentSeq = currentSeq.createDatasetSequence();
+      }
+    }
+    if (seqs.contains(currentSeq))
+    {
+      return;
+    }
+    List<SequenceI> toProcess = new ArrayList<SequenceI>();
+    toProcess.add(currentSeq);
+    while (toProcess.size() > 0)
+    {
+      // use a queue ?
+      SequenceI curDs = toProcess.remove(0);
+      if (seqs.contains(curDs))
+      {
+        continue;
+      }
+      seqs.add(curDs);
+      // iterate over database references, making sure we add forward referenced
+      // sequences
+      if (curDs.getDBRefs() != null)
+      {
+        for (DBRefEntry dbr : curDs.getDBRefs())
+        {
+          if (dbr.getMap() != null && dbr.getMap().getTo() != null)
+          {
+            if (dbr.getMap().getTo() == alignedSeq)
+            {
+              /*
+               * update mapping to be to the newly created dataset sequence
+               */
+              dbr.getMap().setTo(currentSeq);
+            }
+            if (dbr.getMap().getTo().getDatasetSequence() != null)
+            {
+              throw new Error(
+                      "Implementation error: Map.getTo() for dbref " + dbr
+                              + " from " + curDs.getName()
+                              + " is not a dataset sequence.");
+            }
+            // we recurse to add all forward references to dataset sequences via
+            // DBRefs/etc
+            toProcess.add(dbr.getMap().getTo());
+          }
+        }
+      }
+    }
+  }
+
+  /**
    * Creates a new dataset for this alignment. Can only be done once - if
    * dataset is not null this will not be performed.
    */
@@ -1038,22 +1123,32 @@ public class Alignment implements AlignmentI
     {
       return;
     }
-    SequenceI[] seqs = new SequenceI[getHeight()];
-    SequenceI currentSeq;
+    // try to avoid using SequenceI.equals at this stage, it will be expensive
+    Set<SequenceI> seqs = new LinkedIdentityHashSet<SequenceI>();
+
     for (int i = 0; i < getHeight(); i++)
     {
-      currentSeq = getSequenceAt(i);
-      if (currentSeq.getDatasetSequence() != null)
-      {
-        seqs[i] = currentSeq.getDatasetSequence();
-      }
-      else
+      SequenceI currentSeq = getSequenceAt(i);
+      resolveAndAddDatasetSeq(currentSeq, seqs, true);
+    }
+
+    // verify all mappings are in dataset
+    for (AlignedCodonFrame cf : codonFrameList)
+    {
+      for (SequenceToSequenceMapping ssm : cf.getMappings())
       {
-        seqs[i] = currentSeq.createDatasetSequence();
+        if (!seqs.contains(ssm.getFromSeq()))
+        {
+          resolveAndAddDatasetSeq(ssm.getFromSeq(), seqs, false);
+        }
+        if (!seqs.contains(ssm.getMapping().getTo()))
+        {
+          resolveAndAddDatasetSeq(ssm.getMapping().getTo(), seqs, false);
+        }
       }
     }
-
-    dataset = new Alignment(seqs);
+    // finally construct dataset
+    dataset = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
     // move mappings to the dataset alignment
     dataset.codonFrameList = this.codonFrameList;
     this.codonFrameList = null;
index 2a89fa1..05688cb 100755 (executable)
@@ -1307,8 +1307,7 @@ public class AlignmentAnnotation
    *       already
    */
   public void remap(SequenceI newref, HashMap<Integer, int[]> mapping,
-          int from, int to,
-          int idxoffset)
+          int from, int to, int idxoffset)
   {
     if (mapping != null)
     {
index f1db4c0..7274e5f 100755 (executable)
@@ -108,11 +108,14 @@ public interface AlignmentI extends AnnotatedCollectionI
    * Used to set a particular index of the alignment with the given sequence.
    * 
    * @param i
-   *          Index of sequence to be updated.
+   *          Index of sequence to be updated. if i>length, sequence will be
+   *          added to end, with no intervening positions.
    * @param seq
-   *          New sequence to be inserted.
+   *          New sequence to be inserted. The existing sequence at position i
+   *          will be replaced.
+   * @return existing sequence (or null if i>current length)
    */
-  void setSequenceAt(int i, SequenceI seq);
+  SequenceI replaceSequenceAt(int i, SequenceI seq);
 
   /**
    * Deletes a sequence from the alignment
@@ -423,7 +426,7 @@ public interface AlignmentI extends AnnotatedCollectionI
    * @param results
    * @return -1 or index of sequence in alignment
    */
-  int findIndex(SearchResults results);
+  int findIndex(SearchResultsI results);
 
   /**
    * append sequences and annotation from another alignment object to this one.
index 7ef2a68..d651c0b 100644 (file)
@@ -45,19 +45,52 @@ public class ColumnSelection
     /*
      * list of selected columns (ordered by selection order, not column order)
      */
-    private List<Integer> order = new ArrayList<Integer>();
+    private List<Integer> order;
+
+    /*
+     * an unmodifiable view of the selected columns list
+     */
+    private List<Integer> _uorder;
 
     /**
      * bitfield for column selection - allows quick lookup
      */
-    private BitSet selected = new BitSet();
+    private BitSet selected;
+
+    /**
+     * Constructor
+     */
+    IntList()
+    {
+      order = new ArrayList<Integer>();
+      _uorder = Collections.unmodifiableList(order);
+      selected = new BitSet();
+    }
+
+    /**
+     * Copy constructor
+     * 
+     * @param other
+     */
+    IntList(IntList other)
+    {
+      this();
+      if (other != null)
+      {
+        int j = other.size();
+        for (int i = 0; i < j; i++)
+        {
+          add(other.elementAt(i));
+        }
+      }
+    }
 
     /**
      * adds a new column i to the selection - only if i is not already selected
      * 
      * @param i
      */
-    public void add(int i)
+    void add(int i)
     {
       if (!selected.get(i))
       {
@@ -66,13 +99,13 @@ public class ColumnSelection
       }
     }
 
-    public void clear()
+    void clear()
     {
       order.clear();
       selected.clear();
     }
 
-    public void remove(int col)
+    void remove(int col)
     {
 
       Integer colInt = new Integer(col);
@@ -87,22 +120,27 @@ public class ColumnSelection
       }
     }
 
-    public boolean contains(Integer colInt)
+    boolean contains(Integer colInt)
     {
       return selected.get(colInt);
     }
 
-    public boolean isEmpty()
+    boolean isEmpty()
     {
       return order.isEmpty();
     }
 
-    public List<Integer> getList()
+    /**
+     * Returns a read-only view of the selected columns list
+     * 
+     * @return
+     */
+    List<Integer> getList()
     {
-      return order;
+      return _uorder;
     }
 
-    public int size()
+    int size()
     {
       return order.size();
     }
@@ -113,7 +151,7 @@ public class ColumnSelection
      * @param i
      * @return
      */
-    public int elementAt(int i)
+    int elementAt(int i)
     {
       return order.get(i);
     }
@@ -156,7 +194,7 @@ public class ColumnSelection
      * @param change
      *          - delta for shift
      */
-    public void compensateForEdits(int start, int change)
+    void compensateForEdits(int start, int change)
     {
       BitSet mask = new BitSet();
       for (int i = 0; i < order.size(); i++)
@@ -175,17 +213,17 @@ public class ColumnSelection
       selected.or(mask);
     }
 
-    public boolean isSelected(int column)
+    boolean isSelected(int column)
     {
       return selected.get(column);
     }
 
-    public int getMaxColumn()
+    int getMaxColumn()
     {
       return selected.length() - 1;
     }
 
-    public int getMinColumn()
+    int getMinColumn()
     {
       return selected.get(0) ? 0 : selected.nextSetBit(0);
     }
@@ -193,7 +231,7 @@ public class ColumnSelection
     /**
      * @return a series of selection intervals along the range
      */
-    public List<int[]> getRanges()
+    List<int[]> getRanges()
     {
       List<int[]> rlist = new ArrayList<int[]>();
       if (selected.isEmpty())
@@ -288,14 +326,18 @@ public class ColumnSelection
   }
 
   /**
-   * Returns a list of selected columns. The list contains no duplicates but is
-   * not necessarily ordered. It also may include columns hidden from the
-   * current view. This returns a copy of the actual list, and changes to the
-   * copy will not affect the selection.
+   * Returns a read-only view of the (possibly empty) list of selected columns
+   * <p>
+   * The list contains no duplicates but is not necessarily ordered. It also may
+   * include columns hidden from the current view. To modify (for example sort)
+   * the list, you should first make a copy.
+   * <p>
+   * The list is not thread-safe: iterating over it could result in
+   * ConcurrentModificationException if it is modified by another thread.
    */
   public List<Integer> getSelected()
   {
-    return new ArrayList<Integer>(selection.getList());
+    return selection.getList();
   }
 
   /**
@@ -949,14 +991,7 @@ public class ColumnSelection
   {
     if (copy != null)
     {
-      if (copy.selection != null)
-      {
-        selection = new IntList();
-        for (int i = 0, j = copy.selection.size(); i < j; i++)
-        {
-          selection.add(copy.selection.elementAt(i));
-        }
-      }
+      selection = new IntList(copy.selection);
       if (copy.hiddenColumns != null)
       {
         hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
@@ -1113,9 +1148,9 @@ public class ColumnSelection
    */
   public int[] locateVisibleBoundsOfSequence(SequenceI seq)
   {
-    int fpos=seq.getStart(),lpos= seq.getEnd();
+    int fpos = seq.getStart(), lpos = seq.getEnd();
     int start = 0;
-    
+
     if (hiddenColumns == null || hiddenColumns.size() == 0)
     {
       int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
index a641b1b..ec6dcf8 100755 (executable)
@@ -22,9 +22,13 @@ package jalview.datamodel;
 
 import jalview.api.DBRefEntryI;
 
+import java.util.Arrays;
+import java.util.List;
+
 public class DBRefEntry implements DBRefEntryI
 {
   String source = "", version = "", accessionId = "";
+
   /**
    * maps from associated sequence to the database sequence's coordinate system
    */
@@ -35,7 +39,6 @@ public class DBRefEntry implements DBRefEntryI
 
   }
 
-
   public DBRefEntry(String source, String version, String accessionId)
   {
     this(source, version, accessionId, null);
@@ -138,7 +141,8 @@ public class DBRefEntry implements DBRefEntryI
     String otherAccession = other.getAccessionId();
     if ((accessionId == null && otherAccession != null)
             || (accessionId != null && otherAccession == null)
-            || (accessionId != null && !accessionId.equalsIgnoreCase(otherAccession)))
+            || (accessionId != null && !accessionId
+                    .equalsIgnoreCase(otherAccession)))
     {
       return false;
     }
@@ -148,7 +152,7 @@ public class DBRefEntry implements DBRefEntryI
      * otherwise the versions have to match
      */
     String otherVersion = other.getVersion();
-      
+
     if ((version == null || version.equals("0") || version.endsWith(":0"))
             && otherVersion != null)
     {
@@ -223,28 +227,24 @@ public class DBRefEntry implements DBRefEntryI
     return accessionId;
   }
 
-
   @Override
   public void setAccessionId(String accessionId)
   {
     this.accessionId = accessionId;
   }
 
-
   @Override
   public void setSource(String source)
   {
     this.source = source;
   }
 
-
   @Override
   public void setVersion(String version)
   {
     this.version = version;
   }
 
-
   @Override
   public Mapping getMap()
   {
@@ -280,4 +280,56 @@ public class DBRefEntry implements DBRefEntryI
   {
     return getSrcAccString();
   }
+
+  @Override
+  public boolean isPrimaryCandidate()
+  {
+    /*
+     * if a map is present, unless it is 1:1 and has no SequenceI mate, it cannot be a primary reference.  
+     */
+    if (map != null)
+    {
+      if (map.getTo() != null)
+      {
+        return false;
+      }
+      if (map.getMap().getFromRatio() != map.getMap().getToRatio()
+              || map.getMap().getFromRatio() != 1)
+      {
+        return false;
+      }
+      // check map is between identical single contiguous ranges
+      List<int[]> fromRanges = map.getMap().getFromRanges();
+      List<int[]> toRanges = map.getMap().getToRanges();
+      if (fromRanges.size() != 1 || toRanges.size() != 1)
+      {
+        return false;
+      }
+      if (fromRanges.get(0)[0] != toRanges.get(0)[0]
+              || fromRanges.get(0)[1] != toRanges.get(0)[1])
+      {
+        return false;
+      }
+    }
+    if (version == null)
+    {
+      // no version string implies the reference has not been verified at all.
+      return false;
+    }
+    // tricky - this test really needs to search the sequence's set of dbrefs to
+    // see if there is a primary reference that derived this reference.
+    String ucv = version.toUpperCase();
+    for (String primsrc : Arrays.asList(DBRefSource.allSources()))
+    {
+      if (ucv.startsWith(primsrc.toUpperCase()))
+      {
+        // by convention, many secondary references inherit the primary
+        // reference's
+        // source string as a prefix for any version information from the
+        // secondary reference.
+        return false;
+      }
+    }
+    return true;
+  }
 }
index fba9211..0ac14e5 100755 (executable)
  */
 package jalview.datamodel;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Defines internal constants for unambiguous annotation of DbRefEntry source
  * strings and describing the data retrieved from external database sources (see
@@ -36,12 +40,12 @@ public class DBRefSource
   /**
    * UNIPROT Accession Number
    */
-  public static String UNIPROT = "UNIPROT";
+  public static final String UNIPROT = "UNIPROT";
 
   /**
    * UNIPROT Entry Name
    */
-  public static String UP_NAME = "UNIPROT_NAME".toUpperCase();
+  public static final String UP_NAME = "UNIPROT_NAME".toUpperCase();
 
   /**
    * Uniprot Knowledgebase/TrEMBL as served from EMBL protein products.
@@ -54,27 +58,27 @@ public class DBRefSource
   /**
    * PDB Entry Code
    */
-  public static String PDB = "PDB";
+  public static final String PDB = "PDB";
 
   /**
    * EMBL ID
    */
-  public static String EMBL = "EMBL";
+  public static final String EMBL = "EMBL";
 
   /**
    * EMBLCDS ID
    */
-  public static String EMBLCDS = "EMBLCDS";
+  public static final String EMBLCDS = "EMBLCDS";
 
   /**
    * PFAM ID
    */
-  public static String PFAM = "PFAM";
+  public static final String PFAM = "PFAM";
 
   /**
    * RFAM ID
    */
-  public static String RFAM = "RFAM";
+  public static final String RFAM = "RFAM";
 
   /**
    * GeneDB ID
@@ -96,6 +100,25 @@ public class DBRefSource
 
   public static final String[] CODINGDBS = { EMBLCDS, GENEDB, ENSEMBL };
 
-  public static final String[] PROTEINDBS = { UNIPROT, PDB, UNIPROTKB,
+  public static final String[] PROTEINDBS = { UNIPROT, UNIPROTKB,
       EMBLCDSProduct, ENSEMBL }; // Ensembl ENSP* entries are protein
+
+  public static String[] allSources()
+  {
+    List<String> src = new ArrayList<String>();
+    for (Field f : DBRefSource.class.getFields())
+    {
+      if (String.class.equals(f.getType()))
+      {
+        try
+        {
+          src.add((String) f.get(null));
+        } catch (Exception x)
+        {
+          x.printStackTrace();
+        }
+      }
+    }
+    return src.toArray(new String[0]);
+  }
 }
index 8ca3c5a..9e2cf72 100755 (executable)
@@ -296,6 +296,7 @@ public class HiddenSequences
    * makes a copy of the alignment with hidden sequences included. Using the
    * copy for anything other than simple output is not recommended. Note - this
    * method DOES NOT USE THE AlignmentI COPY CONSTRUCTOR!
+   * 
    * @return
    */
   public AlignmentI getFullAlignment()
index c0c69aa..551e5d8 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.datamodel;
 
 /**
index 37dfdbf..97fb08d 100755 (executable)
  */
 package jalview.datamodel;
 
+import jalview.util.CaseInsensitiveString;
+
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.Hashtable;
 
 public class PDBEntry
 {
+
+  /**
+   * constant for storing chain code in properties table
+   */
+  private static final String CHAIN_ID = "chain_code";
+
+  private Hashtable<String, Object> properties;
+
+  private static final int PDB_ID_LENGTH = 4;
+
   private String file;
 
   private String type;
 
   private String id;
 
-  private String chainCode;
-
   public enum Type
   {
     // TODO is FILE needed; if not is this needed or can we
@@ -55,14 +67,40 @@ public class PDBEntry
     {
       return ext;
     }
-  }
 
-  Hashtable<String, String> properties;
+    /**
+     * case insensitive matching for Type enum
+     * 
+     * @param value
+     * @return
+     */
+    public static Type getType(String value)
+    {
+      for (Type t : Type.values())
+      {
+        if (t.toString().equalsIgnoreCase(value))
+        {
+          return t;
+        }
+      }
+      return null;
+    }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.lang.Object#equals(java.lang.Object)
+    /**
+     * case insensitive equivalence for strings resolving to PDBEntry type
+     * 
+     * @param t
+     * @return
+     */
+    public boolean matches(String t)
+    {
+      return (this.toString().equalsIgnoreCase(t));
+    }
+  }
+
+  /**
+   * Answers true if obj is a PDBEntry with the same id and chain code (both
+   * ignoring case), file, type and properties
    */
   @Override
   public boolean equals(Object obj)
@@ -76,17 +114,24 @@ public class PDBEntry
       return true;
     }
     PDBEntry o = (PDBEntry) obj;
-    return (type == o.type || (type != null && o.type != null && o.type
-            .equals(type)))
-            && (id == o.id || (id != null && o.id != null && o.id
-                    .equalsIgnoreCase(id)))
-            && (chainCode == o.chainCode || (chainCode != null
-                    && o.chainCode != null && o.chainCode
-                      .equalsIgnoreCase(chainCode)))
-            && (properties == o.properties || (properties != null
-                    && o.properties != null && properties
-                      .equals(o.properties)));
 
+    /*
+     * note that chain code is stored as a property wrapped by a 
+     * CaseInsensitiveString, so we are in effect doing a 
+     * case-insensitive comparison of chain codes
+     */
+    boolean idMatches = id == o.id
+            || (id != null && id.equalsIgnoreCase(o.id));
+    boolean fileMatches = file == o.file
+            || (file != null && file.equals(o.file));
+    boolean typeMatches = type == o.type
+            || (type != null && type.equals(o.type));
+    if (idMatches && fileMatches && typeMatches)
+    {
+      return properties == o.properties
+              || (properties != null && properties.equals(o.properties));
+    }
+    return false;
   }
 
   /**
@@ -96,24 +141,25 @@ public class PDBEntry
   {
   }
 
-  /**
-   * Constructor given file path and PDB id.
-   * 
-   * @param filePath
-   */
-  // public PDBEntry(String filePath, String pdbId)
-  // {
-  // this.file = filePath;
-  // this.id = pdbId;
-  // }
 
   public PDBEntry(String pdbId, String chain, PDBEntry.Type type,
           String filePath)
   {
+    init(pdbId, chain, type, filePath);
+  }
+
+  /**
+   * @param pdbId
+   * @param chain
+   * @param entryType
+   * @param filePath
+   */
+  void init(String pdbId, String chain, PDBEntry.Type entryType, String filePath)
+  {
     this.id = pdbId;
-    this.chainCode = chain;
-    this.type = type == null ? null : type.toString();
+    this.type = entryType == null ? null : entryType.toString();
     this.file = filePath;
+    setChainCode(chain);
   }
 
   /**
@@ -126,16 +172,44 @@ public class PDBEntry
     file = entry.file;
     type = entry.type;
     id = entry.id;
-    chainCode = entry.chainCode;
     if (entry.properties != null)
     {
-      properties = (Hashtable) entry.properties.clone();
+      properties = (Hashtable<String, Object>) entry.properties.clone();
     }
   }
 
-  public void setFile(String file)
+  /**
+   * Make a PDBEntry from a DBRefEntry. The accession code is used for the PDB
+   * id, but if it is 5 characters in length, the last character is removed and
+   * set as the chain code instead.
+   * 
+   * @param dbr
+   */
+  public PDBEntry(DBRefEntry dbr)
   {
-    this.file = file;
+    if (!DBRefSource.PDB.equals(dbr.getSource()))
+    {
+      throw new IllegalArgumentException("Invalid source: "
+              + dbr.getSource());
+    }
+
+    String pdbId = dbr.getAccessionId();
+    String chainCode = null;
+    if (pdbId.length() == PDB_ID_LENGTH + 1)
+    {
+      char chain = pdbId.charAt(PDB_ID_LENGTH);
+      if (('a' <= chain && chain <= 'z') || ('A' <= chain && chain <= 'Z'))
+      {
+        pdbId = pdbId.substring(0, PDB_ID_LENGTH);
+        chainCode = String.valueOf(chain);
+      }
+    }
+    init(pdbId, chainCode, null, null);
+  }
+
+  public void setFile(String f)
+  {
+    this.file = f;
   }
 
   public String getFile()
@@ -168,24 +242,76 @@ public class PDBEntry
     return id;
   }
 
-  public void setProperty(Hashtable property)
+  public void setProperty(String key, Object value)
   {
-    this.properties = property;
+    if (this.properties == null)
+    {
+      this.properties = new Hashtable<String, Object>();
+    }
+    properties.put(key, value);
   }
 
-  public Hashtable<String, String> getProperty()
+  public Object getProperty(String key)
   {
-    return properties;
+    return properties == null ? null : properties.get(key);
   }
 
+  /**
+   * Returns an enumeration of the keys of this object's properties (or an empty
+   * enumeration if it has no properties)
+   * 
+   * @return
+   */
+  public Enumeration<String> getProperties()
+  {
+    if (properties == null)
+    {
+      return Collections.emptyEnumeration();
+    }
+    return properties.keys();
+  }
+
+  /**
+   * 
+   * @return null or a string for associated chain IDs
+   */
   public String getChainCode()
   {
-    return chainCode;
+    return (properties == null || properties.get(CHAIN_ID) == null) ? null
+            : properties.get(CHAIN_ID).toString();
   }
 
+  /**
+   * Sets a non-case-sensitive property for the given chain code. Two PDBEntry
+   * objects which differ only in the case of their chain code are considered
+   * equal. This avoids duplication of objects in lists of PDB ids.
+   * 
+   * @param chainCode
+   */
   public void setChainCode(String chainCode)
   {
-    this.chainCode = chainCode;
+    if (chainCode == null)
+    {
+      deleteProperty(CHAIN_ID);
+    }
+    else
+    {
+      setProperty(CHAIN_ID, new CaseInsensitiveString(chainCode));
+    }
+  }
+
+  /**
+   * Deletes the property with the given key, and returns the deleted value (or
+   * null)
+   */
+  Object deleteProperty(String key)
+  {
+    Object result = null;
+    if (properties != null)
+    {
+      result = properties.remove(key);
+    }
+    return result;
   }
 
   @Override
@@ -193,4 +319,134 @@ public class PDBEntry
   {
     return id;
   }
+
+  /**
+   * Getter provided for Castor binding only. Application code should call
+   * getProperty() or getProperties() instead.
+   * 
+   * @deprecated
+   * @see #getProperty(String)
+   * @see #getProperties()
+   * @see jalview.ws.dbsources.Uniprot#getUniprotEntries
+   * @return
+   */
+  @Deprecated
+  public Hashtable<String, Object> getProps()
+  {
+    return properties;
+  }
+
+  /**
+   * Setter provided for Castor binding only. Application code should call
+   * setProperty() instead.
+   * 
+   * @deprecated
+   * @return
+   */
+  @Deprecated
+  public void setProps(Hashtable<String, Object> props)
+  {
+    properties = props;
+  }
+
+  /**
+   * Answers true if this object is either equivalent to, or can be 'improved'
+   * by, the given entry.
+   * <p>
+   * If newEntry has the same id (ignoring case), and doesn't have a conflicting
+   * file spec or chain code, then update this entry from its file and/or chain
+   * code.
+   * 
+   * @param newEntry
+   * @return true if modifications were made
+   */
+  public boolean updateFrom(PDBEntry newEntry)
+  {
+    if (this.equals(newEntry))
+    {
+      return true;
+    }
+
+    String newId = newEntry.getId();
+    if (newId == null || getId() == null)
+    {
+      return false; // shouldn't happen
+    }
+
+    /*
+     * id has to match (ignoring case)
+     */
+    if (!getId().equalsIgnoreCase(newId))
+    {
+      return false;
+    }
+
+    /*
+     * Don't update if associated with different structure files
+     */
+    String newFile = newEntry.getFile();
+    if (newFile != null && getFile() != null && !newFile.equals(getFile()))
+    {
+      return false;
+    }
+
+    /*
+     * Don't update if associated with different chains (ignoring case)
+     */
+    String newChain = newEntry.getChainCode();
+    if (newChain != null && newChain.length() > 0 && getChainCode() != null
+            && getChainCode().length() > 0
+            && !getChainCode().equalsIgnoreCase(newChain))
+    {
+      return false;
+    }
+
+    /*
+     * set file path if not already set
+     */
+    String newType = newEntry.getType();
+    if (getFile() == null && newFile != null)
+    {
+      setFile(newFile);
+      setType(newType);
+    }
+
+    /*
+     * set file type if new entry has it and we don't
+     * (for the case where file was not updated)
+     */
+    if (getType() == null && newType != null)
+    {
+      setType(newType);
+    }
+
+    /*
+     * set chain if not already set (we excluded differing 
+     * chains earlier) (ignoring case change only)
+     */
+    if (newChain != null && newChain.length() > 0
+            && !newChain.equalsIgnoreCase(getChainCode()))
+    {
+      setChainCode(newChain);
+    }
+
+    /*
+     * copy any new or modified properties
+     */
+    Enumeration<String> newProps = newEntry.getProperties();
+    while (newProps.hasMoreElements())
+    {
+      /*
+       * copy properties unless value matches; this defends against changing
+       * the case of chain_code which is wrapped in a CaseInsensitiveString
+       */
+      String key = newProps.nextElement();
+      Object value = newEntry.getProperty(key);
+      if (!value.equals(getProperty(key)))
+      {
+        setProperty(key, value);
+      }
+    }
+    return true;
+  }
 }
diff --git a/src/jalview/datamodel/Profile.java b/src/jalview/datamodel/Profile.java
new file mode 100644 (file)
index 0000000..1501808
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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.datamodel;
+
+
+/**
+ * A profile for one column of an alignment
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class Profile implements ProfileI
+{
+  /*
+   * an object holding counts of symbols in the profile
+   */
+  private ResidueCount counts;
+
+  /*
+   * the number of sequences (gapped or not) in the profile
+   */
+  private int height;
+
+  /*
+   * the number of non-gapped sequences in the profile
+   */
+  private int gapped;
+
+  /*
+   * the highest count for any residue in the profile
+   */
+  private int maxCount;
+
+  /*
+   * the residue (e.g. K) or residues (e.g. KQW) with the
+   * highest count in the profile
+   */
+  private String modalResidue;
+
+  /**
+   * Constructor which allows derived data to be stored without having to store
+   * the full profile
+   * 
+   * @param seqCount
+   *          the number of sequences in the profile
+   * @param gaps
+   *          the number of gapped sequences
+   * @param max
+   *          the highest count for any residue
+   * @param modalres
+   *          the residue (or concatenated residues) with the highest count
+   */
+  public Profile(int seqCount, int gaps, int max, String modalRes)
+  {
+    this.height = seqCount;
+    this.gapped = gaps;
+    this.maxCount = max;
+    this.modalResidue = modalRes;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#setCounts(jalview.datamodel.ResidueCount)
+   */
+  @Override
+  public void setCounts(ResidueCount residueCounts)
+  {
+    this.counts = residueCounts;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getPercentageIdentity(boolean)
+   */
+  @Override
+  public float getPercentageIdentity(boolean ignoreGaps)
+  {
+    if (height == 0)
+    {
+      return 0f;
+    }
+    float pid = 0f;
+    if (ignoreGaps && gapped < height)
+    {
+      pid = (maxCount * 100f) / (height - gapped);
+    }
+    else
+    {
+      pid = (maxCount * 100f) / height;
+    }
+    return pid;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getCounts()
+   */
+  @Override
+  public ResidueCount getCounts()
+  {
+    return counts;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getHeight()
+   */
+  @Override
+  public int getHeight()
+  {
+    return height;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getGapped()
+   */
+  @Override
+  public int getGapped()
+  {
+    return gapped;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getMaxCount()
+   */
+  @Override
+  public int getMaxCount()
+  {
+    return maxCount;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getModalResidue()
+   */
+  @Override
+  public String getModalResidue()
+  {
+    return modalResidue;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.datamodel.ProfileI#getNonGapped()
+   */
+  @Override
+  public int getNonGapped()
+  {
+    return height - gapped;
+  }
+}
diff --git a/src/jalview/datamodel/ProfileI.java b/src/jalview/datamodel/ProfileI.java
new file mode 100644 (file)
index 0000000..65a5c0d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.datamodel;
+
+public interface ProfileI
+{
+
+  /**
+   * Set the full profile of counts
+   * 
+   * @param residueCounts
+   */
+  public abstract void setCounts(ResidueCount residueCounts);
+
+  /**
+   * Returns the percentage identity of the profile, i.e. the highest proportion
+   * of conserved (equal) symbols. The percentage is as a fraction of all
+   * sequences, or only ungapped sequences if flag ignoreGaps is set true.
+   * 
+   * @param ignoreGaps
+   * @return
+   */
+  public abstract float getPercentageIdentity(boolean ignoreGaps);
+
+  /**
+   * Returns the full symbol counts for this profile
+   * 
+   * @return
+   */
+  public abstract ResidueCount getCounts();
+
+  /**
+   * Returns the number of sequences in the profile
+   * 
+   * @return
+   */
+  public abstract int getHeight();
+
+  /**
+   * Returns the number of sequences in the profile which had a gap character
+   * (or were too short to be included in this column's profile)
+   * 
+   * @return
+   */
+  public abstract int getGapped();
+
+  /**
+   * Returns the highest count for any symbol(s) in the profile
+   * 
+   * @return
+   */
+  public abstract int getMaxCount();
+
+  /**
+   * Returns the symbol (or concatenated symbols) which have the highest count
+   * in the profile, or an empty string if there were no symbols counted
+   * 
+   * @return
+   */
+  public abstract String getModalResidue();
+
+  /**
+   * Answers the number of non-gapped sequences in the profile
+   * 
+   * @return
+   */
+  public abstract int getNonGapped();
+
+}
\ No newline at end of file
diff --git a/src/jalview/datamodel/Profiles.java b/src/jalview/datamodel/Profiles.java
new file mode 100644 (file)
index 0000000..f65830a
--- /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.
+ */
+package jalview.datamodel;
+
+public class Profiles implements ProfilesI
+{
+
+  private ProfileI[] profiles;
+
+  public Profiles(ProfileI[] p)
+  {
+    profiles = p;
+  }
+
+  /**
+   * Returns the profile for the given column, or null if none found
+   * 
+   * @param col
+   */
+  @Override
+  public ProfileI get(int col)
+  {
+    return profiles != null && col >= 0 && col < profiles.length ? profiles[col]
+            : null;
+  }
+
+  /**
+   * Returns the first column (base 0) covered by the profiles
+   */
+  @Override
+  public int getStartColumn()
+  {
+    return 0;
+  }
+
+  /**
+   * Returns the last column (base 0) covered by the profiles
+   */
+  @Override
+  public int getEndColumn()
+  {
+    return profiles == null ? 0 : profiles.length - 1;
+  }
+
+}
diff --git a/src/jalview/datamodel/ProfilesI.java b/src/jalview/datamodel/ProfilesI.java
new file mode 100644 (file)
index 0000000..82398d9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.datamodel;
+
+public interface ProfilesI
+{
+
+  ProfileI get(int i);
+
+  int getStartColumn();
+
+  int getEndColumn();
+
+}
diff --git a/src/jalview/datamodel/ResidueCount.java b/src/jalview/datamodel/ResidueCount.java
new file mode 100644 (file)
index 0000000..3e3a966
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * 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.datamodel;
+
+import jalview.util.Comparison;
+import jalview.util.Format;
+import jalview.util.QuickSort;
+import jalview.util.SparseCount;
+
+/**
+ * A class to count occurrences of residues in a profile, optimised for speed
+ * and memory footprint.
+ * @author gmcarstairs
+ *
+ */
+public class ResidueCount
+{
+  /**
+   * A data bean to hold the results of counting symbols
+   */
+  public class SymbolCounts
+  {
+    /**
+     * the symbols seen (as char values), in no particular order
+     */
+    public final char[] symbols;
+
+    /**
+     * the counts for each symbol, in the same order as the symbols
+     */
+    public final int[] values;
+
+    SymbolCounts(char[] s, int[] v)
+    {
+      symbols = s;
+      values = v;
+    }
+  }
+
+  private static final int TOUPPERCASE = 'A' - 'a';
+
+  /*
+   * nucleotide symbols to count (including N unknown)
+   */
+  private static final String NUCS = "ACGNTU";
+
+  /*
+   * amino acid symbols to count (including X unknown)
+   * NB we also include U so as to support counting of RNA bases
+   * in the "don't know" case of nucleotide / peptide
+   */
+  private static final String AAS = "ACDEFGHIKLMNPQRSTUVWXY";
+
+  private static final int GAP_COUNT = 0;
+
+  /*
+   * fast lookup tables holding the index into our count
+   * arrays of each symbol; index 0 is reserved for gap counting
+   */
+  private static int[] NUC_INDEX = new int[26];
+
+  private static int[] AA_INDEX = new int[26];
+  static
+  {
+    for (int i = 0; i < NUCS.length(); i++)
+    {
+      NUC_INDEX[NUCS.charAt(i) - 'A'] = i + 1;
+    }
+    for (int i = 0; i < AAS.length(); i++)
+    {
+      AA_INDEX[AAS.charAt(i) - 'A'] = i + 1;
+    }
+  }
+
+  /*
+   * counts array, just big enough for the nucleotide or peptide
+   * character set (plus gap counts in position 0)
+   */
+  private short[] counts;
+
+  /*
+   * alternative array of int counts for use if any count 
+   * exceeds the maximum value of short (32767)
+   */
+  private int[] intCounts;
+
+  /*
+   * flag set if we switch from short to int counts
+   */
+  private boolean useIntCounts;
+
+  /*
+   * general-purpose counter, only for use for characters
+   * that are not in the expected alphabet
+   */
+  private SparseCount otherData;
+
+  /*
+   * keeps track of the maximum count value recorded
+   * (if this class ever allows decrements, would need to
+   * calculate this on request instead) 
+   */
+  int maxCount;
+
+  /*
+   * if we think we are counting nucleotide, can get by with smaller
+   * array to hold counts
+   */
+  private boolean isNucleotide;
+
+  /**
+   * Default constructor allocates arrays able to count either nucleotide or
+   * peptide bases. Use this constructor if not sure which the data is.
+   */
+  public ResidueCount()
+  {
+    this(false);
+  }
+
+  /**
+   * Constructor that allocates an array just big enough for the anticipated
+   * characters, plus one position to count gaps
+   */
+  public ResidueCount(boolean nucleotide)
+  {
+    isNucleotide = nucleotide;
+    int charsToCount = nucleotide ? NUCS.length() : AAS.length();
+    counts = new short[charsToCount + 1];
+  }
+
+  /**
+   * Increments the count for the given character. The supplied character may be
+   * upper or lower case but counts are for the upper case only. Gap characters
+   * (space, ., -) are all counted together.
+   * 
+   * @param c
+   * @return the new value of the count for the character
+   */
+  public int add(final char c)
+  {
+    char u = toUpperCase(c);
+    int newValue = 0;
+    int offset = getOffset(u);
+
+    /*
+     * offset 0 is reserved for gap counting, so 0 here means either
+     * an unexpected character, or a gap character passed in error
+     */
+    if (offset == 0)
+    {
+      if (Comparison.isGap(u))
+      {
+        newValue = addGap();
+      }
+      else
+      {
+        newValue = addOtherCharacter(u);
+      }
+    }
+    else
+    {
+      newValue = increment(offset);
+    }
+    return newValue;
+  }
+
+  /**
+   * Increment the count at the specified offset. If this would result in short
+   * overflow, promote to counting int values instead.
+   * 
+   * @param offset
+   * @return the new value of the count at this offset
+   */
+  int increment(int offset)
+  {
+    int newValue = 0;
+    if (useIntCounts)
+    {
+      newValue = intCounts[offset];
+      intCounts[offset] = ++newValue;
+    }
+    else
+    {
+      if (counts[offset] == Short.MAX_VALUE)
+      {
+        handleOverflow();
+        newValue = intCounts[offset];
+        intCounts[offset] = ++newValue;
+      }
+      else
+      {
+        newValue = counts[offset];
+        counts[offset] = (short) ++newValue;
+      }
+    }
+    maxCount = Math.max(maxCount, newValue);
+    return newValue;
+  }
+
+  /**
+   * Switch from counting in short to counting in int
+   */
+  synchronized void handleOverflow()
+  {
+    intCounts = new int[counts.length];
+    for (int i = 0; i < counts.length; i++)
+    {
+      intCounts[i] = counts[i];
+    }
+    counts = null;
+    useIntCounts = true;
+  }
+
+  /**
+   * Returns this character's offset in the count array
+   * 
+   * @param c
+   * @return
+   */
+  int getOffset(char c)
+  {
+    int offset = 0;
+    if ('A' <= c && c <= 'Z')
+    {
+      offset = isNucleotide ? NUC_INDEX[c - 'A'] : AA_INDEX[c - 'A'];
+    }
+    return offset;
+  }
+
+  /**
+   * @param c
+   * @return
+   */
+  protected char toUpperCase(final char c)
+  {
+    char u = c;
+    if ('a' <= c && c <= 'z')
+    {
+      u = (char) (c + TOUPPERCASE);
+    }
+    return u;
+  }
+
+  /**
+   * Increment count for some unanticipated character. The first time this
+   * called, a SparseCount is instantiated to hold these 'extra' counts.
+   * 
+   * @param c
+   * @return the new value of the count for the character
+   */
+  int addOtherCharacter(char c)
+  {
+    if (otherData == null)
+    {
+      otherData = new SparseCount();
+    }
+    int newValue = otherData.add(c, 1);
+    maxCount = Math.max(maxCount, newValue);
+    return newValue;
+  }
+
+  /**
+   * Set count for some unanticipated character. The first time this called, a
+   * SparseCount is instantiated to hold these 'extra' counts.
+   * 
+   * @param c
+   * @param value
+   */
+  void setOtherCharacter(char c, int value)
+  {
+    if (otherData == null)
+    {
+      otherData = new SparseCount();
+    }
+    otherData.put(c, value);
+  }
+
+  /**
+   * Increment count of gap characters
+   * 
+   * @return the new count of gaps
+   */
+  public int addGap()
+  {
+    int newValue;
+    if (useIntCounts)
+    {
+      newValue = ++intCounts[GAP_COUNT];
+    }
+    else
+    {
+      newValue = ++counts[GAP_COUNT];
+    }
+    return newValue;
+  }
+
+  /**
+   * Answers true if we are counting ints (only after overflow of short counts)
+   * 
+   * @return
+   */
+  boolean isCountingInts()
+  {
+    return useIntCounts;
+  }
+
+  /**
+   * Sets the count for the given character. The supplied character may be upper
+   * or lower case but counts are for the upper case only.
+   * 
+   * @param c
+   * @param count
+   */
+  public void put(char c, int count)
+  {
+    char u = toUpperCase(c);
+    int offset = getOffset(u);
+
+    /*
+     * offset 0 is reserved for gap counting, so 0 here means either
+     * an unexpected character, or a gap character passed in error
+     */
+    if (offset == 0)
+    {
+      if (Comparison.isGap(u))
+      {
+        set(0, count);
+      }
+      else
+      {
+        setOtherCharacter(u, count);
+        maxCount = Math.max(maxCount, count);
+      }
+    }
+    else
+    {
+      set(offset, count);
+      maxCount = Math.max(maxCount, count);
+    }
+  }
+
+  /**
+   * Sets the count at the specified offset. If this would result in short
+   * overflow, promote to counting int values instead.
+   * 
+   * @param offset
+   * @param value
+   */
+  void set(int offset, int value)
+  {
+    if (useIntCounts)
+    {
+      intCounts[offset] = value;
+    }
+    else
+    {
+      if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
+      {
+        handleOverflow();
+        intCounts[offset] = value;
+      }
+      else
+      {
+        counts[offset] = (short) value;
+      }
+    }
+  }
+
+  /**
+   * Returns the count for the given character, or zero if no count held
+   * 
+   * @param c
+   * @return
+   */
+  public int getCount(char c)
+  {
+    char u = toUpperCase(c);
+    int offset = getOffset(u);
+    if (offset == 0)
+    {
+      if (!Comparison.isGap(u))
+      {
+        // should have called getGapCount()
+        return otherData == null ? 0 : otherData.get(u);
+      }
+    }
+    return useIntCounts ? intCounts[offset] : counts[offset];
+  }
+
+  public int getGapCount()
+  {
+    return useIntCounts ? intCounts[0] : counts[0];
+  }
+
+  /**
+   * Answers true if this object wraps a counter for unexpected characters
+   * 
+   * @return
+   */
+  boolean isUsingOtherData()
+  {
+    return otherData != null;
+  }
+
+  /**
+   * Returns the character (or concatenated characters) for the symbol(s) with
+   * the given count in the profile. Can be used to get the modal residue by
+   * supplying the modal count value. Returns an empty string if no symbol has
+   * the given count. The symbols are in alphabetic order of standard peptide or
+   * nucleotide characters, followed by 'other' symbols if any.
+   * 
+   * @return
+   */
+  public String getResiduesForCount(int count)
+  {
+    if (count == 0)
+    {
+      return "";
+    }
+
+    /*
+     * find counts for the given value and append the
+     * corresponding symbol
+     */
+    StringBuilder modal = new StringBuilder();
+    if (useIntCounts)
+    {
+      for (int i = 1; i < intCounts.length; i++)
+      {
+        if (intCounts[i] == count)
+        {
+          modal.append(isNucleotide ? NUCS.charAt(i - 1) : AAS
+                  .charAt(i - 1));
+        }
+      }
+    }
+    else
+    {
+      for (int i = 1; i < counts.length; i++)
+      {
+        if (counts[i] == count)
+        {
+          modal.append(isNucleotide ? NUCS.charAt(i - 1) : AAS
+                  .charAt(i - 1));
+        }
+      }
+    }
+    if (otherData != null)
+    {
+      for (int i = 0; i < otherData.size(); i++)
+      {
+        if (otherData.valueAt(i) == count)
+        {
+          modal.append((char) otherData.keyAt(i));
+        }
+      }
+    }
+    return modal.toString();
+  }
+
+  /**
+   * Returns the highest count for any symbol(s) in the profile (excluding gap)
+   * 
+   * @return
+   */
+  public int getModalCount()
+  {
+    return maxCount;
+  }
+
+  /**
+   * Returns the number of distinct symbols with a non-zero count (excluding the
+   * gap symbol)
+   * 
+   * @return
+   */
+  public int size() {
+    int size = 0;
+    if (useIntCounts)
+    {
+      for (int i = 1; i < intCounts.length; i++)
+      {
+        if (intCounts[i] > 0)
+        {
+          size++;
+        }
+      }
+    }
+    else
+    {
+      for (int i = 1; i < counts.length; i++)
+      {
+        if (counts[i] > 0)
+        {
+          size++;
+        }
+      }
+    }
+
+    /*
+     * include 'other' characters recorded (even if count is zero
+     * though that would be a strange use case)
+     */
+    if (otherData != null)
+    {
+      size += otherData.size();
+    }
+
+    return size;
+  }
+
+  /**
+   * Returns a data bean holding those symbols that have a non-zero count
+   * (excluding the gap symbol), with their counts.
+   * 
+   * @return
+   */
+  public SymbolCounts getSymbolCounts()
+  {
+    int size = size();
+    char[] symbols = new char[size];
+    int[] values = new int[size];
+    int j = 0;
+
+    if (useIntCounts)
+    {
+      for (int i = 1; i < intCounts.length; i++)
+      {
+        if (intCounts[i] > 0)
+        {
+          char symbol = isNucleotide ? NUCS.charAt(i - 1) : AAS
+                  .charAt(i - 1);
+          symbols[j] = symbol;
+          values[j] = intCounts[i];
+          j++;
+        }
+      }
+    }
+    else
+    {
+      for (int i = 1; i < counts.length; i++)
+      {
+        if (counts[i] > 0)
+        {
+          char symbol = isNucleotide ? NUCS.charAt(i - 1) : AAS
+                  .charAt(i - 1);
+          symbols[j] = symbol;
+          values[j] = counts[i];
+          j++;
+        }
+      }
+    }
+    if (otherData != null)
+    {
+      for (int i = 0; i < otherData.size(); i++)
+      {
+        symbols[j] = (char) otherData.keyAt(i);
+        values[j] = otherData.valueAt(i);
+        j++;
+      }
+    }
+
+    return new SymbolCounts(symbols, values);
+  }
+
+  /**
+   * Returns a tooltip string showing residues in descending order of their
+   * percentage frequency in the profile
+   * 
+   * @param normaliseBy
+   *          the divisor for residue counts (may or may not include gapped
+   *          sequence count)
+   * @param percentageDecPl
+   *          the number of decimal places to show in percentages
+   * @return
+   */
+  public String getTooltip(int normaliseBy, int percentageDecPl)
+  {
+    SymbolCounts symbolCounts = getSymbolCounts();
+    char[] ca = symbolCounts.symbols;
+    int[] vl = symbolCounts.values;
+
+    /*
+     * sort characters into ascending order of their counts
+     */
+    QuickSort.sort(vl, ca);
+
+    /*
+     * traverse in reverse order (highest count first) to build tooltip
+     */
+    boolean first = true;
+    StringBuilder sb = new StringBuilder(64);
+    for (int c = ca.length - 1; c >= 0; c--)
+    {
+      final char residue = ca[c];
+      // TODO combine residues which share a percentage
+      // (see AAFrequency.completeCdnaConsensus)
+      float tval = (vl[c] * 100f) / normaliseBy;
+      sb.append(first ? "" : "; ").append(residue).append(" ");
+      Format.appendPercentage(sb, tval, percentageDecPl);
+      sb.append("%");
+      first = false;
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Returns a string representation of the symbol counts, for debug purposes.
+   */
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append("[ ");
+    SymbolCounts sc = getSymbolCounts();
+    for (int i = 0; i < sc.symbols.length; i++)
+    {
+      sb.append(sc.symbols[i]).append(":").append(sc.values[i]).append(" ");
+    }
+    sb.append("]");
+    return sb.toString();
+  }
+}
diff --git a/src/jalview/datamodel/SearchResultMatchI.java b/src/jalview/datamodel/SearchResultMatchI.java
new file mode 100644 (file)
index 0000000..a47ca8b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.datamodel;
+
+/**
+ * An interface that describes one matched region of an alignment, as one
+ * contiguous portion of a single dataset sequence
+ */
+public interface SearchResultMatchI
+{
+  /**
+   * Returns the matched sequence
+   * 
+   * @return
+   */
+  SequenceI getSequence();
+
+  /**
+   * Returns the start position of the match in the sequence (base 1)
+   * 
+   * @return
+   */
+  int getStart();
+
+  /**
+   * Returns the end position of the match in the sequence (base 1)
+   * 
+   * @return
+   */
+  int getEnd();
+
+}
\ No newline at end of file
index b9db461..1bf5475 100755 (executable)
 package jalview.datamodel;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.BitSet;
 import java.util.List;
 
 /**
  * Holds a list of search result matches, where each match is a contiguous
  * stretch of a single sequence.
  * 
- * @author gmcarstairs
+ * @author gmcarstairs amwaterhouse
  *
  */
-public class SearchResults
+public class SearchResults implements SearchResultsI
 {
 
-  private List<Match> matches = new ArrayList<Match>();
+  private List<SearchResultMatchI> matches = new ArrayList<SearchResultMatchI>();
 
   /**
    * One match consists of a sequence reference, start and end positions.
    * Discontiguous ranges in a sequence require two or more Match objects.
    */
-  public class Match
+  public class Match implements SearchResultMatchI
   {
     SequenceI sequence;
 
@@ -55,7 +55,10 @@ public class SearchResults
     int end;
 
     /**
-     * Constructor
+     * create a Match on a range of sequence. Match always holds region in
+     * forwards order, even if given in reverse order (such as from a mapping to
+     * a reverse strand); this avoids trouble for routines that highlight search
+     * results etc
      * 
      * @param seq
      *          a sequence
@@ -80,48 +83,54 @@ public class SearchResults
       }
       else
       {
+        // TODO: JBP could mark match as being specified in reverse direction
+        // for use
+        // by caller ? e.g. visualizing reverse strand highlight
         this.start = end;
         this.end = start;
       }
     }
 
+    /* (non-Javadoc)
+     * @see jalview.datamodel.SearchResultMatchI#getSequence()
+     */
+    @Override
     public SequenceI getSequence()
     {
       return sequence;
     }
 
+    /* (non-Javadoc)
+     * @see jalview.datamodel.SearchResultMatchI#getStart()
+     */
+    @Override
     public int getStart()
     {
       return start;
     }
 
+    /* (non-Javadoc)
+     * @see jalview.datamodel.SearchResultMatchI#getEnd()
+     */
+    @Override
     public int getEnd()
     {
       return end;
     }
 
     /**
-     * Returns the string of characters in the matched region, prefixed by the
-     * start position, e.g. "12CGT" or "208K"
+     * Returns a representation as "seqid/start-end"
      */
     @Override
     public String toString()
     {
-      final int from = Math.max(start - 1, 0);
-      String startPosition = String.valueOf(from);
-      return startPosition + getCharacters();
-    }
-
-    /**
-     * Returns the string of characters in the matched region.
-     */
-    public String getCharacters()
-    {
-      char[] chars = sequence.getSequence();
-      // convert start/end to base 0 (with bounds check)
-      final int from = Math.max(start - 1, 0);
-      final int to = Math.min(end, chars.length + 1);
-      return String.valueOf(Arrays.copyOfRange(chars, from, to));
+      StringBuilder sb = new StringBuilder();
+      if (sequence != null)
+      {
+        sb.append(sequence.getName()).append("/");
+      }
+      sb.append(start).append("-").append(end);
+      return sb.toString();
     }
 
     public void setSequence(SequenceI seq)
@@ -150,46 +159,38 @@ public class SearchResults
     @Override
     public boolean equals(Object obj)
     {
-      if (obj == null || !(obj instanceof Match))
+      if (obj == null || !(obj instanceof SearchResultMatchI))
       {
         return false;
       }
-      Match m = (Match) obj;
-      return (this.sequence == m.sequence && this.start == m.start && this.end == m.end);
+      SearchResultMatchI m = (SearchResultMatchI) obj;
+      return (sequence == m.getSequence() && start == m.getStart() && end == m
+              .getEnd());
     }
   }
 
-  /**
-   * This method replaces the old search results which merely held an alignment
-   * index of search matches. This broke when sequences were moved around the
-   * alignment
-   * 
-   * @param seq
-   *          Sequence
-   * @param start
-   *          int
-   * @param end
-   *          int
+  /* (non-Javadoc)
+   * @see jalview.datamodel.SearchResultsI#addResult(jalview.datamodel.SequenceI, int, int)
    */
-  public void addResult(SequenceI seq, int start, int end)
+  @Override
+  public SearchResultMatchI addResult(SequenceI seq, int start, int end)
   {
-    matches.add(new Match(seq, start, end));
+    Match m = new Match(seq, start, end);
+    matches.add(m);
+    return m;
   }
 
-  /**
-   * Quickly check if the given sequence is referred to in the search results
-   * 
-   * @param sequence
-   *          (specific alignment sequence or a dataset sequence)
-   * @return true if the results involve sequence
+  /* (non-Javadoc)
+   * @see jalview.datamodel.SearchResultsI#involvesSequence(jalview.datamodel.SequenceI)
    */
+  @Override
   public boolean involvesSequence(SequenceI sequence)
   {
     SequenceI ds = sequence.getDatasetSequence();
-    for (Match m : matches)
+    for (SearchResultMatchI _m : matches)
     {
-      if (m.sequence != null
-              && (m.sequence == sequence || m.sequence == ds))
+      SequenceI matched = _m.getSequence();
+      if (matched != null && (matched == sequence || matched == ds))
       {
         return true;
       }
@@ -197,11 +198,10 @@ public class SearchResults
     return false;
   }
 
-  /**
-   * This Method returns the search matches which lie between the start and end
-   * points of the sequence in question. It is optimised for returning objects
-   * for drawing on SequenceCanvas
+  /* (non-Javadoc)
+   * @see jalview.datamodel.SearchResultsI#getResults(jalview.datamodel.SequenceI, int, int)
    */
+  @Override
   public int[] getResults(SequenceI sequence, int start, int end)
   {
     if (matches.isEmpty())
@@ -213,8 +213,11 @@ public class SearchResults
     int[] tmp = null;
     int resultLength, matchStart = 0, matchEnd = 0;
     boolean mfound;
-    for (Match m : matches)
+    Match m;
+    for (SearchResultMatchI _m : matches)
     {
+      m = (Match) _m;
+
       mfound = false;
       if (m.sequence == sequence)
       {
@@ -269,97 +272,76 @@ public class SearchResults
     return result;
   }
 
-  public int getSize()
-  {
-    return matches.size();
-  }
-
-  public SequenceI getResultSequence(int index)
-  {
-    return matches.get(index).sequence;
-  }
-
-  /**
-   * Returns the start position of the i'th match in the search results.
-   * 
-   * @param i
-   * @return
-   */
-  public int getResultStart(int i)
+  @Override
+  public int markColumns(SequenceCollectionI sqcol, BitSet bs)
   {
-    return matches.get(i).start;
+    int count = 0;
+    BitSet mask = new BitSet();
+    for (SequenceI s : sqcol.getSequences())
+    {
+      int[] cols = getResults(s, sqcol.getStartRes(), sqcol.getEndRes());
+      if (cols != null)
+      {
+        for (int pair = 0; pair < cols.length; pair += 2)
+        {
+          mask.set(cols[pair], cols[pair + 1] + 1);
+        }
+      }
+    }
+    // compute columns that were newly selected
+    BitSet original = (BitSet) bs.clone();
+    original.and(mask);
+    count = mask.cardinality() - original.cardinality();
+    // and mark ranges not already marked
+    bs.or(mask);
+    return count;
   }
 
-  /**
-   * Returns the end position of the i'th match in the search results.
-   * 
-   * @param i
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.SearchResultsI#getSize()
    */
-  public int getResultEnd(int i)
+  @Override
+  public int getSize()
   {
-    return matches.get(i).end;
+    return matches.size();
   }
 
-  /**
-   * Returns true if no search result matches are held.
-   * 
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.SearchResultsI#isEmpty()
    */
+  @Override
   public boolean isEmpty()
   {
     return matches.isEmpty();
   }
 
-  /**
-   * Returns the list of matches.
-   * 
-   * @return
+  /* (non-Javadoc)
+   * @see jalview.datamodel.SearchResultsI#getResults()
    */
-  public List<Match> getResults()
+  @Override
+  public List<SearchResultMatchI> getResults()
   {
     return matches;
   }
 
   /**
-   * Return the results as a string of characters (bases) prefixed by start
-   * position(s). Meant for use when the context ensures that all matches are to
-   * regions of the same sequence (otherwise the result is meaningless).
+   * Return the results as a list of matches [seq1/from-to, seq2/from-to, ...]
    * 
    * @return
    */
   @Override
   public String toString()
   {
-    StringBuilder result = new StringBuilder(256);
-    for (Match m : matches)
-    {
-      result.append(m.toString());
-    }
-    return result.toString();
-  }
-
-  /**
-   * Return the results as a string of characters (bases). Meant for use when
-   * the context ensures that all matches are to regions of the same sequence
-   * (otherwise the result is meaningless).
-   * 
-   * @return
-   */
-  public String getCharacters()
-  {
-    StringBuilder result = new StringBuilder(256);
-    for (Match m : matches)
-    {
-      result.append(m.getCharacters());
-    }
-    return result.toString();
+    return matches == null ? "" : matches.toString();
   }
 
   /**
-   * Hashcode is has derived from the list of matches. This ensures that when
-   * two SearchResults objects satisfy the test for equals(), then they have the
+   * Hashcode is derived from the list of matches. This ensures that when two
+   * SearchResults objects satisfy the test for equals(), then they have the
    * same hashcode.
+   * 
+   * @see Match#hashCode()
+   * @see java.util.AbstractList#hashCode()
    */
   @Override
   public int hashCode()
@@ -374,11 +356,11 @@ public class SearchResults
   @Override
   public boolean equals(Object obj)
   {
-    if (obj == null || !(obj instanceof SearchResults))
+    if (obj == null || !(obj instanceof SearchResultsI))
     {
       return false;
     }
-    SearchResults sr = (SearchResults) obj;
-    return ((ArrayList<Match>) this.matches).equals(sr.matches);
+    SearchResultsI sr = (SearchResultsI) obj;
+    return matches.equals(sr.getResults());
   }
 }
diff --git a/src/jalview/datamodel/SearchResultsI.java b/src/jalview/datamodel/SearchResultsI.java
new file mode 100644 (file)
index 0000000..52a0467
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.datamodel;
+
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * An interface describing the result of a search or other operation which
+ * highlights matched regions of an alignment
+ */
+public interface SearchResultsI
+{
+
+  /**
+   * Adds one region to the results
+   * 
+   * @param seq
+   *          Sequence
+   * @param start
+   *          int
+   * @param end
+   *          int
+   * @return
+   */
+  SearchResultMatchI addResult(SequenceI seq, int start, int end);
+
+  /**
+   * Answers true if the search results include the given sequence (or its
+   * dataset sequence), else false
+   * 
+   * @param sequence
+   * @return
+   */
+  boolean involvesSequence(SequenceI sequence);
+
+  /**
+   * Returns an array of [from, to, from, to..] matched columns (base 0) between
+   * the given start and end columns of the given sequence. Returns null if no
+   * matches overlap the specified region.
+   * <p>
+   * Implementations should provide an optimised method to return locations to
+   * highlight on a visible portion of an alignment.
+   * 
+   * @param sequence
+   * @param start
+   *          first column of range (base 0, inclusive)
+   * @param end
+   *          last column of range base 0, inclusive)
+   * @return int[]
+   */
+  int[] getResults(SequenceI sequence, int start, int end);
+
+  /**
+   * Returns the number of matches found
+   * 
+   * @return
+   */
+  int getSize();
+
+  /**
+   * Returns true if no search result matches are held.
+   * 
+   * @return
+   */
+  boolean isEmpty();
+
+  /**
+   * Returns the list of matches.
+   * 
+   * @return
+   */
+  List<SearchResultMatchI> getResults();
+
+  /**
+   * Set bits in a bitfield for all columns in the given sequence collection
+   * that are highlighted
+   * 
+   * @param sqcol
+   *          the set of sequences to search for highlighted regions
+   * @param bs
+   *          bitset to set
+   * @return number of bits set
+   */
+  int markColumns(SequenceCollectionI sqcol, BitSet bs);
+}
\ No newline at end of file
index a857712..c8b94ce 100755 (executable)
@@ -22,10 +22,14 @@ package jalview.datamodel;
 
 import jalview.analysis.AlignSeq;
 import jalview.api.DBRefEntryI;
+import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
+import jalview.util.MapList;
 import jalview.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.Vector;
@@ -57,8 +61,6 @@ public class Sequence extends ASequence implements SequenceI
 
   String vamsasId;
 
-  DBRefEntryI sourceDBRef;
-
   DBRefEntry[] dbrefs;
 
   RNA rna;
@@ -231,12 +233,9 @@ public class Sequence extends ASequence implements SequenceI
     {
       char[] oseq = seq.getSequence();
       initSeqAndName(seq.getName(), Arrays.copyOf(oseq, oseq.length),
-              seq.getStart(),
-            seq.getEnd());
+              seq.getStart(), seq.getEnd());
     }
     description = seq.getDescription();
-    sourceDBRef = seq.getSourceDBRef() == null ? null : new DBRefEntry(
-            seq.getSourceDBRef());
     if (seq != datasetSequence)
     {
       setDatasetSequence(seq.getDatasetSequence());
@@ -293,7 +292,6 @@ public class Sequence extends ASequence implements SequenceI
     }
   }
 
-
   @Override
   public void setSequenceFeatures(SequenceFeature[] features)
   {
@@ -307,8 +305,9 @@ public class Sequence extends ASequence implements SequenceI
               && datasetSequence.getSequenceFeatures() != null
               && datasetSequence.getSequenceFeatures().length > 0)
       {
-        System.err
-              .println("Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment");
+        new Exception(
+                "Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment")
+                .printStackTrace();
       }
       datasetSequence.setSequenceFeatures(features);
     }
@@ -317,7 +316,7 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public synchronized void addSequenceFeature(SequenceFeature sf)
   {
-    if (sequenceFeatures==null && datasetSequence != null)
+    if (sequenceFeatures == null && datasetSequence != null)
     {
       datasetSequence.addSequenceFeature(sf);
       return;
@@ -347,8 +346,9 @@ public class Sequence extends ASequence implements SequenceI
   {
     if (sequenceFeatures == null)
     {
-      if (datasetSequence!=null) {
-         datasetSequence.deleteFeature(sf);
+      if (datasetSequence != null)
+      {
+        datasetSequence.deleteFeature(sf);
       }
       return;
     }
@@ -412,28 +412,24 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
-  public void addPDBId(PDBEntry entry)
+  public boolean addPDBId(PDBEntry entry)
   {
     if (pdbIds == null)
     {
       pdbIds = new Vector<PDBEntry>();
+      pdbIds.add(entry);
+      return true;
     }
-    if (pdbIds.contains(entry))
-    {
-      updatePDBEntry(pdbIds.get(pdbIds.indexOf(entry)), entry);
-    }
-    else
-    {
-      pdbIds.addElement(entry);
-    }
-  }
 
-  private static void updatePDBEntry(PDBEntry oldEntry, PDBEntry newEntry)
-  {
-    if (newEntry.getFile() != null)
+    for (PDBEntry pdbe : pdbIds)
     {
-      oldEntry.setFile(newEntry.getFile());
+      if (pdbe.updateFrom(entry))
+      {
+        return false;
+      }
     }
+    pdbIds.addElement(entry);
+    return true;
   }
 
   /**
@@ -948,7 +944,17 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public void setDBRefs(DBRefEntry[] dbref)
   {
+    if (dbrefs == null && datasetSequence != null
+            && this != datasetSequence)
+    {
+      datasetSequence.setDBRefs(dbref);
+      return;
+    }
     dbrefs = dbref;
+    if (dbrefs != null)
+    {
+      DBRefUtils.ensurePrimaries(this);
+    }
   }
 
   @Override
@@ -965,7 +971,12 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public void addDBRef(DBRefEntry entry)
   {
-    // TODO add to dataset sequence instead if there is one?
+    if (datasetSequence != null)
+    {
+      datasetSequence.addDBRef(entry);
+      return;
+    }
+
     if (dbrefs == null)
     {
       dbrefs = new DBRefEntry[0];
@@ -993,12 +1004,23 @@ public class Sequence extends ASequence implements SequenceI
     temp[temp.length - 1] = entry;
 
     dbrefs = temp;
+
+    DBRefUtils.ensurePrimaries(this);
   }
 
   @Override
   public void setDatasetSequence(SequenceI seq)
   {
-    // TODO check for circular reference before setting?
+    if (seq == this)
+    {
+      throw new IllegalArgumentException(
+              "Implementation Error: self reference passed to SequenceI.setDatasetSequence");
+    }
+    if (seq != null && seq.getDatasetSequence() != null)
+    {
+      throw new IllegalArgumentException(
+              "Implementation error: cascading dataset sequences are not allowed.");
+    }
     datasetSequence = seq;
   }
 
@@ -1071,7 +1093,7 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public SequenceI deriveSequence()
   {
-    Sequence seq=null;
+    Sequence seq = null;
     if (datasetSequence == null)
     {
       if (isValidDatasetSequence())
@@ -1085,7 +1107,7 @@ public class Sequence extends ASequence implements SequenceI
       else
       {
         // Create a new, valid dataset sequence
-       createDatasetSequence();
+        createDatasetSequence();
       }
     }
     return new Sequence(this);
@@ -1095,6 +1117,10 @@ public class Sequence extends ASequence implements SequenceI
 
   private long _seqhash = 0;
 
+  /**
+   * Answers false if the sequence is more than 85% nucleotide (ACGTU), else
+   * true
+   */
   @Override
   public boolean isProtein()
   {
@@ -1105,7 +1131,7 @@ public class Sequence extends ASequence implements SequenceI
     if (_seqhash != sequence.hashCode())
     {
       _seqhash = sequence.hashCode();
-      _isNa=jalview.util.Comparison.isNucleotide(new SequenceI[] { this });
+      _isNa = Comparison.isNucleotide(this);
     }
     return !_isNa;
   };
@@ -1129,9 +1155,9 @@ public class Sequence extends ASequence implements SequenceI
       dsseq.setDescription(description);
       // move features and database references onto dataset sequence
       dsseq.sequenceFeatures = sequenceFeatures;
-      sequenceFeatures=null;
+      sequenceFeatures = null;
       dsseq.dbrefs = dbrefs;
-      dbrefs=null;
+      dbrefs = null;
       // TODO: search and replace any references to this sequence with
       // references to the dataset sequence in Mappings on dbref
       dsseq.pdbIds = pdbIds;
@@ -1225,46 +1251,22 @@ public class Sequence extends ASequence implements SequenceI
     {
       return false;
     }
-    Vector newpdb = new Vector();
-    for (int i = 0; i < dbrefs.length; i++)
+    boolean added = false;
+    for (DBRefEntry dbr : dbrefs)
     {
-      if (DBRefSource.PDB.equals(dbrefs[i].getSource()))
+      if (DBRefSource.PDB.equals(dbr.getSource()))
       {
-        PDBEntry pdbe = new PDBEntry();
-        pdbe.setId(dbrefs[i].getAccessionId());
-        if (pdbIds == null || pdbIds.size() == 0)
-        {
-          newpdb.addElement(pdbe);
-        }
-        else
-        {
-          Enumeration en = pdbIds.elements();
-          boolean matched = false;
-          while (!matched && en.hasMoreElements())
-          {
-            PDBEntry anentry = (PDBEntry) en.nextElement();
-            if (anentry.getId().equals(pdbe.getId()))
-            {
-              matched = true;
-            }
-          }
-          if (!matched)
-          {
-            newpdb.addElement(pdbe);
-          }
-        }
-      }
-    }
-    if (newpdb.size() > 0)
-    {
-      Enumeration en = newpdb.elements();
-      while (en.hasMoreElements())
-      {
-        addPDBId((PDBEntry) en.nextElement());
+        /*
+         * 'Add' any PDB dbrefs as a PDBEntry - add is only performed if the
+         * PDB id is not already present in a 'matching' PDBEntry
+         * Constructor parses out a chain code if appended to the accession id
+         * (a fudge used to 'store' the chain code in the DBRef)
+         */
+        PDBEntry pdbe = new PDBEntry(dbr);
+        added |= addPDBId(pdbe);
       }
-      return true;
     }
-    return false;
+    return added;
   }
 
   @Override
@@ -1394,12 +1396,15 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public PDBEntry getPDBEntry(String pdbIdStr)
   {
-    if (getDatasetSequence() == null
-            || getDatasetSequence().getAllPDBEntries() == null)
+    if (getDatasetSequence() != null)
+    {
+      return getDatasetSequence().getPDBEntry(pdbIdStr);
+    }
+    if (pdbIds == null)
     {
       return null;
     }
-    List<PDBEntry> entries = getDatasetSequence().getAllPDBEntries();
+    List<PDBEntry> entries = getAllPDBEntries();
     for (PDBEntry entry : entries)
     {
       if (entry.getId().equalsIgnoreCase(pdbIdStr))
@@ -1411,15 +1416,63 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   @Override
-  public void setSourceDBRef(DBRefEntryI dbRef)
-  {
-    this.sourceDBRef = dbRef;
-  }
-
-  @Override
-  public DBRefEntryI getSourceDBRef()
+  public List<DBRefEntry> getPrimaryDBRefs()
   {
-    return this.sourceDBRef;
+    if (datasetSequence != null)
+    {
+      return datasetSequence.getPrimaryDBRefs();
+    }
+    if (dbrefs == null || dbrefs.length == 0)
+    {
+      return Collections.emptyList();
+    }
+    synchronized (dbrefs)
+    {
+      List<DBRefEntry> primaries = new ArrayList<DBRefEntry>();
+      DBRefEntry[] tmp = new DBRefEntry[1];
+      for (DBRefEntry ref : dbrefs)
+      {
+        if (!ref.isPrimaryCandidate())
+        {
+          continue;
+        }
+        if (ref.hasMap())
+        {
+          MapList mp = ref.getMap().getMap();
+          if (mp.getFromLowest() > start || mp.getFromHighest() < end)
+          {
+            // map only involves a subsequence, so cannot be primary
+            continue;
+          }
+        }
+        // whilst it looks like it is a primary ref, we also sanity check type
+        if (DBRefUtils.getCanonicalName(DBRefSource.PDB).equals(
+                DBRefUtils.getCanonicalName(ref.getSource())))
+        {
+          // PDB dbrefs imply there should be a PDBEntry associated
+          // TODO: tighten PDB dbrefs
+          // formally imply Jalview has actually downloaded and
+          // parsed the pdb file. That means there should be a cached file
+          // handle on the PDBEntry, and a real mapping between sequence and
+          // extracted sequence from PDB file
+          PDBEntry pdbentry = getPDBEntry(ref.getAccessionId());
+          if (pdbentry != null && pdbentry.getFile() != null)
+          {
+            primaries.add(ref);
+          }
+          continue;
+        }
+        // check standard protein or dna sources
+        tmp[0] = ref;
+        DBRefEntry[] res = DBRefUtils.selectDbRefs(!isProtein(), tmp);
+        if (res != null && res[0] == tmp[0])
+        {
+          primaries.add(ref);
+          continue;
+        }
+      }
+      return primaries;
+    }
   }
 
 }
index c75d6f2..15f54b9 100755 (executable)
@@ -208,7 +208,9 @@ public class SequenceFeature
     }
 
     SequenceFeature sf = (SequenceFeature) o;
-    if (begin != sf.begin || end != sf.end || score != sf.score)
+    boolean sameScore = Float.isNaN(score) ? Float.isNaN(sf.score)
+            : score == sf.score;
+    if (begin != sf.begin || end != sf.end || !sameScore)
     {
       return false;
     }
@@ -530,4 +532,20 @@ public class SequenceFeature
     return s.hashCode() + getBegin() + getEnd() + (int) getScore()
             + getStrand();
   }
+
+  /**
+   * Answers true if the feature's start/end values represent two related
+   * positions, rather than ends of a range. Such features may be visualised or
+   * reported differently to features on a range.
+   */
+  public boolean isContactFeature()
+  {
+    // TODO abstract one day to a FeatureType class
+    if ("disulfide bond".equalsIgnoreCase(type)
+            || "disulphide bond".equalsIgnoreCase(type))
+    {
+      return true;
+    }
+    return false;
+  }
 }
index 22c537a..9245761 100755 (executable)
@@ -23,14 +23,11 @@ package jalview.datamodel;
 import jalview.analysis.AAFrequency;
 import jalview.analysis.Conservation;
 import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ResidueProperties;
 
 import java.awt.Color;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
 
 /**
  * Collects a set contiguous ranges on a set of sequences
@@ -46,8 +43,6 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   Conservation conserve;
 
-  Vector aaFrequency;
-
   boolean displayBoxes = true;
 
   boolean displayText = true;
@@ -529,24 +524,26 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
     // TODO: try harder to detect changes in state in order to minimise
     // recalculation effort
+    boolean upd = false;
     try
     {
-      Hashtable cnsns[] = AAFrequency.calculate(sequences, startRes,
+      ProfilesI cnsns = AAFrequency.calculate(sequences, startRes,
               endRes + 1, showSequenceLogo);
       if (consensus != null)
       {
         _updateConsensusRow(cnsns, sequences.size());
+        upd = true;
       }
       if (cs != null)
       {
         cs.setConsensus(cnsns);
+        upd = true;
       }
 
       if ((conservation != null)
               || (cs != null && cs.conservationApplied()))
       {
-        Conservation c = new Conservation(groupName,
-                ResidueProperties.propHash, 3, sequences, startRes,
+        Conservation c = new Conservation(groupName, sequences, startRes,
                 endRes + 1);
         c.calculate();
         c.verdict(false, consPercGaps);
@@ -561,6 +558,8 @@ public class SequenceGroup implements AnnotatedCollectionI
             cs.setConservation(c);
           }
         }
+        // eager update - will cause a refresh of overview regardless
+        upd = true;
       }
       if (cs != null && !defer)
       {
@@ -570,14 +569,14 @@ public class SequenceGroup implements AnnotatedCollectionI
       }
       else
       {
-        return false;
+        return upd;
       }
     } catch (java.lang.OutOfMemoryError err)
     {
       // TODO: catch OOM
       System.out.println("Out of memory loading groups: " + err);
     }
-    return false;
+    return upd;
   }
 
   private void _updateConservationRow(Conservation c)
@@ -600,9 +599,9 @@ public class SequenceGroup implements AnnotatedCollectionI
     c.completeAnnotations(conservation, null, startRes, endRes + 1);
   }
 
-  public Hashtable[] consensusData = null;
+  public ProfilesI consensusData = null;
 
-  private void _updateConsensusRow(Hashtable[] cnsns, long nseq)
+  private void _updateConsensusRow(ProfilesI cnsns, long nseq)
   {
     if (consensus == null)
     {
index 45a767c..aec68ab 100755 (executable)
@@ -20,8 +20,6 @@
  */
 package jalview.datamodel;
 
-import jalview.api.DBRefEntryI;
-
 import java.util.List;
 import java.util.Vector;
 
@@ -219,8 +217,11 @@ public interface SequenceI extends ASequenceI
   public int[] findPositionMap();
 
   /**
+   * Answers true if the sequence is composed of amino acid characters. Note
+   * that implementations may use heuristic methods which are not guaranteed to
+   * give the biologically 'right' answer.
    * 
-   * @return true if sequence is composed of amino acid characters
+   * @return
    */
   public boolean isProtein();
 
@@ -291,11 +292,18 @@ public interface SequenceI extends ASequenceI
   public Vector<PDBEntry> getAllPDBEntries();
 
   /**
-   * add entry to the vector of PDBIds, if it isn't in the list already
+   * Adds the entry to the *normalised* list of PDBIds.
+   * 
+   * If a PDBEntry is passed with the same entry.getID() string as one already
+   * in the list, or one is added that appears to be the same but has a chain ID
+   * appended, then the existing PDBEntry will be updated with the new
+   * attributes instead, unless the entries have distinct chain codes or
+   * associated structure files.
    * 
    * @param entry
+   * @return true if the entry was added, false if updated
    */
-  public void addPDBId(PDBEntry entry);
+  public boolean addPDBId(PDBEntry entry);
 
   /**
    * update the list of PDBEntrys to include any DBRefEntrys citing structural
@@ -309,6 +317,14 @@ public interface SequenceI extends ASequenceI
 
   public void setVamsasId(String id);
 
+  /**
+   * set the array of Database references for the sequence.
+   * 
+   * @param dbs
+   * @deprecated - use is discouraged since side-effects may occur if DBRefEntry
+   *             set are not normalised.
+   */
+  @Deprecated
   public void setDBRefs(DBRefEntry[] dbs);
 
   public DBRefEntry[] getDBRefs();
@@ -444,20 +460,12 @@ public interface SequenceI extends ASequenceI
   public PDBEntry getPDBEntry(String pdbId);
 
   /**
-   * Set the distinct source database, and accession number from which a
-   * sequence and its start-end data were derived from. This is very important
-   * for SIFTS mappings and must be set prior to performing SIFTS mapping.
+   * Get all primary database/accessions for this sequence's data. These
+   * DBRefEntry are expected to resolve to a valid record in the associated
+   * external database, either directly or via a provided 1:1 Mapping.
    * 
-   * @param dbRef
-   *          the source dbRef for the sequence
-   */
-  public void setSourceDBRef(DBRefEntryI dbRef);
-
-  /**
-   * Get the distinct source database, and accession number from which a
-   * sequence and its start-end data were derived from.
-   * 
-   * @return
+   * @return just the primary references (if any) for this sequence, or an empty
+   *         list
    */
-  public DBRefEntryI getSourceDBRef();
+  public List<DBRefEntry> getPrimaryDBRefs();
 }
index 06e929d..4d09bdc 100644 (file)
@@ -48,8 +48,7 @@ import java.util.regex.Pattern;
  * Data model for one entry returned from an EMBL query, as marshalled by a
  * Castor binding file
  * 
- * For example:
- * http://www.ebi.ac.uk/ena/data/view/J03321&display=xml
+ * For example: http://www.ebi.ac.uk/ena/data/view/J03321&display=xml
  * 
  * @see embl_mapping.xml
  */
@@ -195,13 +194,11 @@ public class EmblEntry
     DBRefEntry retrievedref = new DBRefEntry(sourceDb,
             getSequenceVersion(), accession);
     dna.addDBRef(retrievedref);
-    dna.setSourceDBRef(retrievedref);
     // add map to indicate the sequence is a valid coordinate frame for the
     // dbref
     retrievedref.setMap(new Mapping(null, new int[] { 1, dna.getLength() },
             new int[] { 1, dna.getLength() }, 1, 1));
 
-
     /*
      * transform EMBL Database refs to canonical form
      */
@@ -299,7 +296,8 @@ public class EmblEntry
         if (qname.equals("translation"))
         {
           // remove all spaces (precompiled String.replaceAll(" ", ""))
-          translation = SPACE_PATTERN.matcher(q.getValues()[0]).replaceAll("");
+          translation = SPACE_PATTERN.matcher(q.getValues()[0]).replaceAll(
+                  "");
         }
         else if (qname.equals("protein_id"))
         {
@@ -470,13 +468,14 @@ public class EmblEntry
          */
         String source = DBRefUtils.getCanonicalName(ref.getSource());
         ref.setSource(source);
-        DBRefEntry proteinDbRef = new DBRefEntry(ref.getSource(), ref.getVersion(), ref
-                .getAccessionId());
+        DBRefEntry proteinDbRef = new DBRefEntry(ref.getSource(),
+                ref.getVersion(), ref.getAccessionId());
         if (source.equals(DBRefSource.UNIPROT))
         {
           String proteinSeqName = DBRefSource.UNIPROT + "|"
                   + ref.getAccessionId();
-          if (dnaToProteinMapping != null && dnaToProteinMapping.getTo() != null)
+          if (dnaToProteinMapping != null
+                  && dnaToProteinMapping.getTo() != null)
           {
             if (mappingUsed)
             {
@@ -504,7 +503,6 @@ public class EmblEntry
             dnaToProteinMapping.setTo(proteinSeq);
             dnaToProteinMapping.setMappedFromId(proteinId);
             proteinSeq.addDBRef(proteinDbRef);
-            proteinSeq.setSourceDBRef(proteinDbRef);
             ref.setMap(dnaToProteinMapping);
           }
           hasUniprotDbref = true;
@@ -549,7 +547,6 @@ public class EmblEntry
                 DBRefSource.EMBLCDSProduct, getSequenceVersion(), proteinId);
       }
       product.addDBRef(proteinToEmblProteinRef);
-      product.setSourceDBRef(proteinToEmblProteinRef);
 
       if (dnaToProteinMapping != null
               && dnaToProteinMapping.getTo() != null)
index 69870b6..1dd854a 100644 (file)
@@ -46,6 +46,8 @@ public class EmblFile
 
   Vector<EmblError> errors;
 
+  String text;
+
   /**
    * @return the entries
    */
@@ -152,6 +154,10 @@ public class EmblFile
    */
   static void canonicaliseDbRefs(EmblFile record)
   {
+    if (record.getEntries() == null)
+    {
+      return;
+    }
     for (EmblEntry entry : record.getEntries())
     {
       if (entry.getDbRefs() != null)
@@ -183,4 +189,14 @@ public class EmblFile
       }
     }
   }
+
+  public String getText()
+  {
+    return text;
+  }
+
+  public void setText(String text)
+  {
+    this.text = text;
+  }
 }
diff --git a/src/jalview/ext/android/ContainerHelpers.java b/src/jalview/ext/android/ContainerHelpers.java
new file mode 100644 (file)
index 0000000..4033dcc
--- /dev/null
@@ -0,0 +1,108 @@
+package jalview.ext.android;
+
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copied to Jalview September 2016.
+ * Only the members of this class required for SparseIntArray were copied.
+ * Method binarySearch(short[] array, int size, short value) added to support
+ * SparseShortArray.
+ */
+class ContainerHelpers
+{
+  static final boolean[] EMPTY_BOOLEANS = new boolean[0];
+
+  static final int[] EMPTY_INTS = new int[0];
+
+  static final long[] EMPTY_LONGS = new long[0];
+
+  static final Object[] EMPTY_OBJECTS = new Object[0];
+
+  // This is Arrays.binarySearch(), but doesn't do any argument validation.
+  static int binarySearch(int[] array, int size, int value)
+  {
+    int lo = 0;
+    int hi = size - 1;
+    while (lo <= hi)
+    {
+      final int mid = (lo + hi) >>> 1;
+      final int midVal = array[mid];
+      if (midVal < value)
+      {
+        lo = mid + 1;
+      }
+      else if (midVal > value)
+      {
+        hi = mid - 1;
+      }
+      else
+      {
+        return mid; // value found
+      }
+    }
+    return ~lo; // value not present
+  }
+
+  static int binarySearch(long[] array, int size, long value)
+  {
+    int lo = 0;
+    int hi = size - 1;
+    while (lo <= hi)
+    {
+      final int mid = (lo + hi) >>> 1;
+      final long midVal = array[mid];
+      if (midVal < value)
+      {
+        lo = mid + 1;
+      }
+      else if (midVal > value)
+      {
+        hi = mid - 1;
+      }
+      else
+      {
+        return mid; // value found
+      }
+    }
+    return ~lo; // value not present
+  }
+
+  // This is Arrays.binarySearch(), but doesn't do any argument validation.
+  static int binarySearch(short[] array, int size, short value)
+  {
+    int lo = 0;
+    int hi = size - 1;
+    while (lo <= hi)
+    {
+      final int mid = (lo + hi) >>> 1;
+      final short midVal = array[mid];
+      if (midVal < value)
+      {
+        lo = mid + 1;
+      }
+      else if (midVal > value)
+      {
+        hi = mid - 1;
+      }
+      else
+      {
+        return mid; // value found
+      }
+    }
+    return ~lo; // value not present
+  }
+}
diff --git a/src/jalview/ext/android/SparseIntArray.java b/src/jalview/ext/android/SparseIntArray.java
new file mode 100644 (file)
index 0000000..fcd4f1f
--- /dev/null
@@ -0,0 +1,432 @@
+package jalview.ext.android;
+
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * SparseIntArrays map integers to integers. Unlike a normal array of integers,
+ * there can be gaps in the indices. It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Integers, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra
+ * entry object for each mapping.
+ *
+ * <p>
+ * Note that this container keeps its mappings in an array data structure, using
+ * a binary search to find keys. The implementation is not intended to be
+ * appropriate for data structures that may contain large numbers of items. It
+ * is generally slower than a traditional HashMap, since lookups require a
+ * binary search and adds and removes require inserting and deleting entries in
+ * the array. For containers holding up to hundreds of items, the performance
+ * difference is not significant, less than 50%.
+ * </p>
+ *
+ * <p>
+ * It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.
+ * </p>
+ */
+
+/*
+ * Imported into Jalview September 2016
+ * Change log:
+ *   Sep 2016 method add(int, int) added for more efficient increment of counts
+ *            (a single binary search, rather than one on read and one on write)
+ */
+public class SparseIntArray implements Cloneable
+{
+  private int[] mKeys;
+
+  private int[] mValues;
+
+  private int mSize;
+
+  /**
+   * Creates a new SparseIntArray containing no mappings.
+   */
+  public SparseIntArray()
+  {
+    this(10);
+  }
+
+  /**
+   * Creates a new SparseIntArray containing no mappings that will not require
+   * any additional memory allocation to store the specified number of mappings.
+   * If you supply an initial capacity of 0, the sparse array will be
+   * initialized with a light-weight representation not requiring any additional
+   * array allocations.
+   */
+  public SparseIntArray(int initialCapacity)
+  {
+    if (initialCapacity == 0)
+    {
+      mKeys = ContainerHelpers.EMPTY_INTS;
+      mValues = ContainerHelpers.EMPTY_INTS;
+    }
+    else
+    {
+      initialCapacity = idealIntArraySize(initialCapacity);
+      mKeys = new int[initialCapacity];
+      mValues = new int[initialCapacity];
+    }
+    mSize = 0;
+  }
+
+  @Override
+  public SparseIntArray clone()
+  {
+    SparseIntArray clone = null;
+    try
+    {
+      clone = (SparseIntArray) super.clone();
+      clone.mKeys = mKeys.clone();
+      clone.mValues = mValues.clone();
+    } catch (CloneNotSupportedException cnse)
+    {
+      /* ignore */
+    }
+    return clone;
+  }
+
+  /**
+   * Gets the int mapped from the specified key, or <code>0</code> if no such
+   * mapping has been made.
+   */
+  public int get(int key)
+  {
+    return get(key, 0);
+  }
+
+  /**
+   * Gets the int mapped from the specified key, or the specified value if no
+   * such mapping has been made.
+   */
+  public int get(int key, int valueIfKeyNotFound)
+  {
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+    if (i < 0)
+    {
+      return valueIfKeyNotFound;
+    }
+    else
+    {
+      return mValues[i];
+    }
+  }
+
+  /**
+   * Removes the mapping from the specified key, if there was any.
+   */
+  public void delete(int key)
+  {
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+    if (i >= 0)
+    {
+      removeAt(i);
+    }
+  }
+
+  /**
+   * Removes the mapping at the given index.
+   */
+  public void removeAt(int index)
+  {
+    System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+    System.arraycopy(mValues, index + 1, mValues, index, mSize
+            - (index + 1));
+    mSize--;
+  }
+
+  /**
+   * Adds a mapping from the specified key to the specified value, replacing the
+   * previous mapping from the specified key if there was one.
+   */
+  public void put(int key, int value)
+  {
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+    if (i >= 0)
+    {
+      mValues[i] = value;
+    }
+    else
+    {
+      i = ~i;
+      if (mSize >= mKeys.length)
+      {
+        int n = idealIntArraySize(mSize + 1);
+        int[] nkeys = new int[n];
+        int[] nvalues = new int[n];
+        // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
+        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+        mKeys = nkeys;
+        mValues = nvalues;
+      }
+      if (mSize - i != 0)
+      {
+        // Log.e("SparseIntArray", "move " + (mSize - i));
+        System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+        System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+      }
+      mKeys[i] = key;
+      mValues[i] = value;
+      mSize++;
+    }
+  }
+
+  /**
+   * Returns the number of key-value mappings that this SparseIntArray currently
+   * stores.
+   */
+  public int size()
+  {
+    return mSize;
+  }
+
+  /**
+   * Given an index in the range <code>0...size()-1</code>, returns the key from
+   * the <code>index</code>th key-value mapping that this SparseIntArray stores.
+   *
+   * <p>
+   * The keys corresponding to indices in ascending order are guaranteed to be
+   * in ascending order, e.g., <code>keyAt(0)</code> will return the smallest
+   * key and <code>keyAt(size()-1)</code> will return the largest key.
+   * </p>
+   */
+  public int keyAt(int index)
+  {
+    return mKeys[index];
+  }
+
+  /**
+   * Given an index in the range <code>0...size()-1</code>, returns the value
+   * from the <code>index</code>th key-value mapping that this SparseIntArray
+   * stores.
+   *
+   * <p>
+   * The values corresponding to indices in ascending order are guaranteed to be
+   * associated with keys in ascending order, e.g., <code>valueAt(0)</code> will
+   * return the value associated with the smallest key and
+   * <code>valueAt(size()-1)</code> will return the value associated with the
+   * largest key.
+   * </p>
+   */
+  public int valueAt(int index)
+  {
+    return mValues[index];
+  }
+
+  /**
+   * Returns the index for which {@link #keyAt} would return the specified key,
+   * or a negative number if the specified key is not mapped.
+   */
+  public int indexOfKey(int key)
+  {
+    return ContainerHelpers.binarySearch(mKeys, mSize, key);
+  }
+
+  /**
+   * Returns an index for which {@link #valueAt} would return the specified key,
+   * or a negative number if no keys map to the specified value. Beware that
+   * this is a linear search, unlike lookups by key, and that multiple keys can
+   * map to the same value and this will find only one of them.
+   */
+  public int indexOfValue(int value)
+  {
+    for (int i = 0; i < mSize; i++)
+    {
+      if (mValues[i] == value)
+      {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Removes all key-value mappings from this SparseIntArray.
+   */
+  public void clear()
+  {
+    mSize = 0;
+  }
+
+  /**
+   * Puts a key/value pair into the array, optimizing for the case where the key
+   * is greater than all existing keys in the array.
+   */
+  public void append(int key, int value)
+  {
+    if (mSize != 0 && key <= mKeys[mSize - 1])
+    {
+      put(key, value);
+      return;
+    }
+    int pos = mSize;
+    if (pos >= mKeys.length)
+    {
+      int n = idealIntArraySize(pos + 1);
+      int[] nkeys = new int[n];
+      int[] nvalues = new int[n];
+      // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
+      System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+      System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+      mKeys = nkeys;
+      mValues = nvalues;
+    }
+    mKeys[pos] = key;
+    mValues[pos] = value;
+    mSize = pos + 1;
+  }
+
+  /**
+   * Inlined here by copying from com.android.internal.util.ArrayUtils
+   * 
+   * @param i
+   * @return
+   */
+  public static int idealIntArraySize(int need)
+  {
+    return idealByteArraySize(need * 4) / 4;
+  }
+
+  /**
+   * Inlined here by copying from com.android.internal.util.ArrayUtils
+   * 
+   * @param i
+   * @return
+   */
+  public static int idealByteArraySize(int need)
+  {
+    for (int i = 4; i < 32; i++)
+    {
+      if (need <= (1 << i) - 12)
+      {
+        return (1 << i) - 12;
+      }
+    }
+
+    return need;
+  }
+
+  /**
+   * {@inheritDoc}
+   *
+   * <p>
+   * This implementation composes a string by iterating over its mappings.
+   */
+  @Override
+  public String toString()
+  {
+    if (size() <= 0)
+    {
+      return "{}";
+    }
+    StringBuilder buffer = new StringBuilder(mSize * 28);
+    buffer.append('{');
+    for (int i = 0; i < mSize; i++)
+    {
+      if (i > 0)
+      {
+        buffer.append(", ");
+      }
+      int key = keyAt(i);
+      buffer.append(key);
+      buffer.append('=');
+      int value = valueAt(i);
+      buffer.append(value);
+    }
+    buffer.append('}');
+    return buffer.toString();
+  }
+
+  /**
+   * Method (copied from put) added for Jalview to efficiently increment a key's
+   * value if present, else add it with the given value. This avoids a double
+   * binary search (once to get the value, again to put the updated value).
+   * 
+   * @param key
+   * @oparam toAdd
+   * @return the new value of the count for the key
+   * @throw ArithmeticException if the result would exceed the maximum value of
+   *        an int
+   */
+  public int add(int key, int toAdd)
+  {
+    int newValue = toAdd;
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+    if (i >= 0)
+    {
+      checkOverflow(mValues[i], toAdd);
+      mValues[i] += toAdd;
+      newValue = mValues[i];
+    }
+    else
+    {
+      i = ~i;
+      if (mSize >= mKeys.length)
+      {
+        int n = idealIntArraySize(mSize + 1);
+        int[] nkeys = new int[n];
+        int[] nvalues = new int[n];
+        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+        mKeys = nkeys;
+        mValues = nvalues;
+      }
+      if (mSize - i != 0)
+      {
+        System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+        System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+      }
+      mKeys[i] = key;
+      mValues[i] = toAdd;
+      mSize++;
+    }
+    return newValue;
+  }
+
+  /**
+   * Throws ArithmeticException if adding addend to value would exceed the range
+   * of int
+   * 
+   * @param value
+   * @param addend
+   */
+  static void checkOverflow(int value, int addend)
+  {
+    /*
+     * test cases being careful to avoid overflow while testing!
+     */
+    if (addend > 0)
+    {
+      if (value > 0 && Integer.MAX_VALUE - value < addend)
+      {
+        throw new ArithmeticException("Integer overflow adding " + addend
+                + " to  " + value);
+      }
+    }
+    else if (addend < 0)
+    {
+      if (value < 0 && Integer.MIN_VALUE - value > addend)
+      {
+        throw new ArithmeticException("Integer underflow adding " + addend
+                + " to  " + value);
+      }
+    }
+  }
+}
diff --git a/src/jalview/ext/android/SparseShortArray.java b/src/jalview/ext/android/SparseShortArray.java
new file mode 100644 (file)
index 0000000..f961f55
--- /dev/null
@@ -0,0 +1,442 @@
+package jalview.ext.android;
+
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * SparseShortArrays map shorts to shorts. Unlike a normal array of shorts,
+ * there can be gaps in the indices. It is intended to be more memory efficient
+ * than using a HashMap to map Shorts to Shorts, both because it avoids
+ * auto-boxing keys and values and its data structure doesn't rely on an extra
+ * entry object for each mapping.
+ *
+ * <p>
+ * Note that this container keeps its mappings in an array data structure, using
+ * a binary search to find keys. The implementation is not intended to be
+ * appropriate for data structures that may contain large numbers of items. It
+ * is generally slower than a traditional HashMap, since lookups require a
+ * binary search and adds and removes require inserting and deleting entries in
+ * the array. For containers holding up to hundreds of items, the performance
+ * difference is not significant, less than 50%.
+ * </p>
+ *
+ * <p>
+ * It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)<code>.
+ * </p>
+ */
+
+/*
+ * Added to Jalview September 2016. A copy of SparseIntArray designed to store
+ * short values (to minimise space usage).
+ * <p>
+ * Note that operations append, put, add throw ArithmeticException if either the
+ * key or the resulting value overflows the range of a short. Calling code
+ * should trap and handle this, for example by switching to using a
+ * SparseIntArray instead.
+ */
+public class SparseShortArray implements Cloneable
+{
+  private short[] mKeys;
+
+  private short[] mValues;
+
+  private int mSize;
+
+  /**
+   * Creates a new SparseShortArray containing no mappings.
+   */
+  public SparseShortArray()
+  {
+    this(10);
+  }
+
+  /**
+   * Creates a new SparseShortArray containing no mappings that will not require
+   * any additional memory allocation to store the specified number of mappings.
+   * If you supply an initial capacity of 0, the sparse array will be
+   * initialized with a light-weight representation not requiring any additional
+   * array allocations.
+   */
+  public SparseShortArray(int initialCapacity)
+  {
+    if (initialCapacity == 0)
+    {
+      mKeys = new short[0];
+      mValues = new short[0];
+    }
+    else
+    {
+      initialCapacity = idealShortArraySize(initialCapacity);
+      mKeys = new short[initialCapacity];
+      mValues = new short[initialCapacity];
+    }
+    mSize = 0;
+  }
+
+  @Override
+  public SparseShortArray clone()
+  {
+    SparseShortArray clone = null;
+    try
+    {
+      clone = (SparseShortArray) super.clone();
+      clone.mKeys = mKeys.clone();
+      clone.mValues = mValues.clone();
+    } catch (CloneNotSupportedException cnse)
+    {
+      /* ignore */
+    }
+    return clone;
+  }
+
+  /**
+   * Gets the int mapped from the specified key, or <code>0</code> if no such
+   * mapping has been made.
+   */
+  public int get(int key)
+  {
+    return get(key, 0);
+  }
+
+  /**
+   * Gets the int mapped from the specified key, or the specified value if no
+   * such mapping has been made.
+   * 
+   * @throws ArithmeticException
+   *           if key is outside the range of a short value
+   */
+  public int get(int key, int valueIfKeyNotFound)
+  {
+    checkOverflow(key);
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
+    if (i < 0)
+    {
+      return valueIfKeyNotFound;
+    }
+    else
+    {
+      return mValues[i];
+    }
+  }
+
+  /**
+   * Removes the mapping from the specified key, if there was any.
+   * 
+   * @throws ArithmeticException
+   *           if key is outside the range of a short value
+   */
+  public void delete(int key)
+  {
+    checkOverflow(key);
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
+    if (i >= 0)
+    {
+      removeAt(i);
+    }
+  }
+
+  /**
+   * Removes the mapping at the given index.
+   */
+  public void removeAt(int index)
+  {
+    System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+    System.arraycopy(mValues, index + 1, mValues, index, mSize
+            - (index + 1));
+    mSize--;
+  }
+
+  /**
+   * Adds a mapping from the specified key to the specified value, replacing the
+   * previous mapping from the specified key if there was one.
+   * 
+   * @throws ArithmeticException
+   *           if either argument is outside the range of a short value
+   */
+  public void put(int key, int value)
+  {
+    checkOverflow(key);
+    checkOverflow(value);
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
+    if (i >= 0)
+    {
+      mValues[i] = (short) value;
+    }
+    else
+    {
+      i = ~i;
+      if (mSize >= mKeys.length)
+      {
+        int n = idealShortArraySize(mSize + 1);
+        short[] nkeys = new short[n];
+        short[] nvalues = new short[n];
+        // Log.e("SparseShortArray", "grow " + mKeys.length + " to " + n);
+        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+        mKeys = nkeys;
+        mValues = nvalues;
+      }
+      if (mSize - i != 0)
+      {
+        // Log.e("SparseShortArray", "move " + (mSize - i));
+        System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+        System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+      }
+      mKeys[i] = (short) key;
+      mValues[i] = (short) value;
+      mSize++;
+    }
+  }
+
+  /**
+   * Returns the number of key-value mappings that this SparseShortArray
+   * currently stores.
+   */
+  public int size()
+  {
+    return mSize;
+  }
+
+  /**
+   * Given an index in the range <code>0...size()-1</code>, returns the key from
+   * the <code>index</code>th key-value mapping that this SparseShortArray
+   * stores.
+   *
+   * <p>
+   * The keys corresponding to indices in ascending order are guaranteed to be
+   * in ascending order, e.g., <code>keyAt(0)</code> will return the smallest
+   * key and <code>keyAt(size()-1)</code> will return the largest key.
+   * </p>
+   */
+  public short keyAt(int index)
+  {
+    return mKeys[index];
+  }
+
+  /**
+   * Given an index in the range <code>0...size()-1</code>, returns the value
+   * from the <code>index</code>th key-value mapping that this SparseShortArray
+   * stores.
+   *
+   * <p>
+   * The values corresponding to indices in ascending order are guaranteed to be
+   * associated with keys in ascending order, e.g., <code>valueAt(0)</code> will
+   * return the value associated with the smallest key and
+   * <code>valueAt(size()-1)</code> will return the value associated with the
+   * largest key.
+   * </p>
+   */
+  public short valueAt(int index)
+  {
+    return mValues[index];
+  }
+
+  /**
+   * Returns the index for which {@link #keyAt} would return the specified key,
+   * or a negative number if the specified key is not mapped.
+   * 
+   * @throws ArithmeticException
+   *           if key is outside the range of a short value
+   */
+  public int indexOfKey(int key)
+  {
+    checkOverflow(key);
+    return ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
+  }
+
+  /**
+   * Returns an index for which {@link #valueAt} would return the specified key,
+   * or a negative number if no keys map to the specified value. Beware that
+   * this is a linear search, unlike lookups by key, and that multiple keys can
+   * map to the same value and this will find only one of them.
+   */
+  public int indexOfValue(int value)
+  {
+    for (int i = 0; i < mSize; i++)
+    {
+      if (mValues[i] == value)
+      {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Removes all key-value mappings from this SparseShortArray.
+   */
+  public void clear()
+  {
+    mSize = 0;
+  }
+
+  /**
+   * Puts a key/value pair into the array, optimizing for the case where the key
+   * is greater than all existing keys in the array.
+   */
+  public void append(int key, int value)
+  {
+    if (mSize != 0 && key <= mKeys[mSize - 1])
+    {
+      put(key, value);
+      return;
+    }
+    int pos = mSize;
+    if (pos >= mKeys.length)
+    {
+      int n = idealShortArraySize(pos + 1);
+      short[] nkeys = new short[n];
+      short[] nvalues = new short[n];
+      // Log.e("SparseShortArray", "grow " + mKeys.length + " to " + n);
+      System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+      System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+      mKeys = nkeys;
+      mValues = nvalues;
+    }
+    checkOverflow(key);
+    checkOverflow(value);
+    mKeys[pos] = (short) key;
+    mValues[pos] = (short) value;
+    mSize = pos + 1;
+  }
+
+  /**
+   * Throws an exception if the value is outside the range of a short.
+   * 
+   * @param value
+   * @throws ArithmeticException
+   */
+  public static void checkOverflow(int value)
+  {
+    if (value > Short.MAX_VALUE || value < Short.MIN_VALUE)
+    {
+      throw new ArithmeticException(String.valueOf(value));
+    }
+  }
+
+  /**
+   * Inlined here by copying from com.android.internal.util.ArrayUtils
+   * 
+   * @param i
+   * @return
+   */
+  public static int idealShortArraySize(int need)
+  {
+    return idealByteArraySize(need * 2) / 2;
+  }
+
+  /**
+   * Inlined here by copying from com.android.internal.util.ArrayUtils
+   * 
+   * @param i
+   * @return
+   */
+  public static int idealByteArraySize(int need)
+  {
+    for (int i = 4; i < 32; i++)
+    {
+      if (need <= (1 << i) - 12)
+      {
+        return (1 << i) - 12;
+      }
+    }
+
+    return need;
+  }
+
+  /**
+   * {@inheritDoc}
+   *
+   * <p>
+   * This implementation composes a string by iterating over its mappings.
+   */
+  @Override
+  public String toString()
+  {
+    if (size() <= 0)
+    {
+      return "{}";
+    }
+    StringBuilder buffer = new StringBuilder(mSize * 28);
+    buffer.append('{');
+    for (int i = 0; i < mSize; i++)
+    {
+      if (i > 0)
+      {
+        buffer.append(", ");
+      }
+      int key = keyAt(i);
+      buffer.append(key);
+      buffer.append('=');
+      int value = valueAt(i);
+      buffer.append(value);
+    }
+    buffer.append('}');
+    return buffer.toString();
+  }
+
+  /**
+   * Method (copied from put) added for Jalview to efficiently increment a key's
+   * value if present, else add it with the given value. This avoids a double
+   * binary search (once to get the value, again to put the updated value).
+   * 
+   * @param key
+   * @oparam toAdd
+   * @return the new value of the count for the key
+   * @throws ArithmeticException
+   *           if key, or result of adding toAdd, is outside the range of a
+   *           short value
+   */
+  public int add(int key, int toAdd)
+  {
+    int newValue = toAdd;
+    checkOverflow(key);
+    int i = ContainerHelpers.binarySearch(mKeys, mSize, (short) key);
+    if (i >= 0)
+    {
+      checkOverflow(toAdd + mValues[i]);
+      mValues[i] += (short) toAdd;
+      newValue = mValues[i];
+    }
+    else
+    {
+      checkOverflow(toAdd);
+      i = ~i;
+      if (mSize >= mKeys.length)
+      {
+        int n = idealShortArraySize(mSize + 1);
+        short[] nkeys = new short[n];
+        short[] nvalues = new short[n];
+        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+        mKeys = nkeys;
+        mValues = nvalues;
+      }
+      if (mSize - i != 0)
+      {
+        System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+        System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+      }
+      mKeys[i] = (short) key;
+      mValues[i] = (short) toAdd;
+      mSize++;
+    }
+    return newValue;
+  }
+}
index e141db4..dc000c6 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.SequenceFeature;
@@ -23,7 +43,7 @@ public class EnsemblCdna extends EnsemblSeqProxy
    */
   private static final Regex ACCESSION_REGEX = new Regex(
           "(ENS([A-Z]{3}|)[TG][0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)");
-  
+
   /*
    * fetch exon features on genomic sequence (to identify the cdna regions)
    * and cds and variation features (to retain)
index 2086eba..8b2550d 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.SequenceFeature;
index 0547433..b28a37f 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.Alignment;
@@ -79,8 +99,7 @@ class EnsemblFeatures extends EnsemblRestClient
   protected URL getUrl(List<String> ids) throws MalformedURLException
   {
     StringBuffer urlstring = new StringBuffer(128);
-    urlstring.append(getDomain()).append("/overlap/id/")
-            .append(ids.get(0));
+    urlstring.append(getDomain()).append("/overlap/id/").append(ids.get(0));
 
     // @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
     urlstring.append("?content-type=text/x-gff3");
index b4d2783..24e3e95 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.api.FeatureColourI;
@@ -118,7 +138,10 @@ public class EnsemblGene extends EnsemblSeqProxy
        * fetch the gene sequence(s) with features and xrefs
        */
       AlignmentI geneAlignment = super.getSequenceRecords(geneId);
-
+      if (geneAlignment == null)
+      {
+        continue;
+      }
       if (geneAlignment.getHeight() == 1)
       {
         getTranscripts(geneAlignment, geneId);
@@ -174,7 +197,8 @@ public class EnsemblGene extends EnsemblSeqProxy
        */
       else
       {
-        List<String> ids = new EnsemblSymbol(getDomain()).getIds(acc);
+        List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
+                getDbVersion()).getIds(acc);
         for (String geneId : ids)
         {
           if (!geneIds.contains(geneId))
@@ -196,7 +220,8 @@ public class EnsemblGene extends EnsemblSeqProxy
    */
   protected String getGeneIdentifiersForName(String query)
   {
-    List<String> ids = new EnsemblSymbol(getDomain()).getIds(query);
+    List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
+            getDbVersion()).getIds(query);
     if (ids != null)
     {
       for (String id : ids)
@@ -257,8 +282,7 @@ public class EnsemblGene extends EnsemblSeqProxy
         }
       }
       gene.setSequenceFeatures(filtered
-              .toArray(new SequenceFeature[filtered
-              .size()]));
+              .toArray(new SequenceFeature[filtered.size()]));
     }
   }
 
@@ -524,6 +548,7 @@ public class EnsemblGene extends EnsemblSeqProxy
     return new FeatureSettingsAdapter()
     {
       SequenceOntologyI so = SequenceOntologyFactory.getInstance();
+
       @Override
       public boolean isFeatureDisplayed(String type)
       {
index 20987e1..458a233 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.SequenceFeature;
index 9ba2e1c..ef46a5b 100644 (file)
@@ -1,6 +1,25 @@
+/*
+ * 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.ext.ensembl;
 
-
 /**
  * A class to behave much like EnsemblGene but referencing the ensemblgenomes
  * domain and data
index 88b5ac4..3108194 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 /**
index c5945ae..eb8f90e 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.AlignmentI;
@@ -105,7 +125,7 @@ public class EnsemblLookup extends EnsemblRestClient
   public String getParent(String identifier)
   {
     List<String> ids = Arrays.asList(new String[] { identifier });
-  
+
     BufferedReader br = null;
     try
     {
index 0facbb5..1554a0b 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.AlignmentI;
index 653d5d5..8ee6aaf 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.io.DataSourceType;
@@ -31,14 +51,19 @@ import com.stevesoft.pat.Regex;
  */
 abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 {
+  private static final int DEFAULT_READ_TIMEOUT = 5 * 60 * 1000; // 5 minutes
+
+  private static final int CONNECT_TIMEOUT_MS = 10 * 1000; // 10 seconds
+
   /*
    * update these constants when Jalview has been checked / updated for
    * changes to Ensembl REST API
    * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
+   * @see http://rest.ensembl.org/info/rest?content-type=application/json
    */
   private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "4.6";
 
-  private static final String LATEST_ENSEMBL_REST_VERSION = "4.6";
+  private static final String LATEST_ENSEMBL_REST_VERSION = "4.7";
 
   private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
 
@@ -52,10 +77,10 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   private final static long VERSION_RETEST_INTERVAL = 1000L * 3600; // 1 hr
 
   private static final Regex TRANSCRIPT_REGEX = new Regex(
-            "(ENS)([A-Z]{3}|)T[0-9]{11}$");
+          "(ENS)([A-Z]{3}|)T[0-9]{11}$");
 
   private static final Regex GENE_REGEX = new Regex(
-            "(ENS)([A-Z]{3}|)G[0-9]{11}$");
+          "(ENS)([A-Z]{3}|)G[0-9]{11}$");
 
   static
   {
@@ -166,7 +191,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    */
   private boolean checkEnsembl()
   {
-    HttpURLConnection conn = null;
+    BufferedReader br = null;
     try
     {
       // note this format works for both ensembl and ensemblgenomes
@@ -176,8 +201,9 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
       /*
        * expect {"ping":1} if ok
+       * if ping takes more than 2 seconds to respond, treat as if unavailable
        */
-      BufferedReader br = getHttpResponse(ping, null);
+      br = getHttpResponse(ping, null, 2 * 1000);
       JSONParser jp = new JSONParser();
       JSONObject val = (JSONObject) jp.parse(br);
       String pingString = val.get("ping").toString();
@@ -188,9 +214,15 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
               + t.getMessage());
     } finally
     {
-      if (conn != null)
+      if (br != null)
       {
-        conn.disconnect();
+        try
+        {
+          br.close();
+        } catch (IOException e)
+        {
+          // ignore
+        }
       }
     }
     return false;
@@ -207,28 +239,50 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
           throws IOException
   {
     URL url = getUrl(ids);
-  
+
     BufferedReader reader = getHttpResponse(url, ids);
+    if (reader == null)
+    {
+      // request failed
+      return null;
+    }
     FileParse fp = new FileParse(reader, url.toString(), DataSourceType.URL);
     return fp;
   }
 
   /**
+   * Gets a reader to the HTTP response, using the default read timeout of 5
+   * minutes
+   * 
+   * @param url
+   * @param ids
+   * @return
+   * @throws IOException
+   */
+  protected BufferedReader getHttpResponse(URL url, List<String> ids)
+          throws IOException
+  {
+    return getHttpResponse(url, ids, DEFAULT_READ_TIMEOUT);
+  }
+
+  /**
    * Writes the HTTP request and gets the response as a reader.
    * 
    * @param url
    * @param ids
    *          written as Json POST body if more than one
+   * @param readTimeout
+   *          in milliseconds
    * @return
    * @throws IOException
    *           if response code was not 200, or other I/O error
    */
-  protected BufferedReader getHttpResponse(URL url, List<String> ids)
-          throws IOException
+  protected BufferedReader getHttpResponse(URL url, List<String> ids,
+          int readTimeout) throws IOException
   {
     // long now = System.currentTimeMillis();
     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-  
+
     /*
      * POST method allows multiple queries in one request; it is supported for
      * sequence queries, but not for overlap
@@ -244,29 +298,33 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     connection.setDoInput(true);
     connection.setDoOutput(multipleIds);
 
+    connection.setConnectTimeout(CONNECT_TIMEOUT_MS);
+    connection.setReadTimeout(readTimeout);
+
     if (multipleIds)
     {
       writePostBody(connection, ids);
     }
-  
-    InputStream response = connection.getInputStream();
+
     int responseCode = connection.getResponseCode();
-  
+
     if (responseCode != 200)
     {
       /*
        * note: a GET request for an invalid id returns an error code e.g. 415
        * but POST request returns 200 and an empty Fasta response 
        */
-      throw new IOException(
-              "Response code was not 200. Detected response was "
-                      + responseCode);
+      System.err.println("Response code " + responseCode + " for " + url);
+      return null;
     }
+    // get content
+    InputStream response = connection.getInputStream();
+
     // System.out.println(getClass().getName() + " took "
     // + (System.currentTimeMillis() - now) + "ms to fetch");
 
     checkRateLimits(connection);
-  
+
     BufferedReader reader = null;
     reader = new BufferedReader(new InputStreamReader(response, "UTF-8"));
     return reader;
@@ -319,7 +377,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
       // remaining, limit, reset));
     }
   }
-  
+
   /**
    * Rechecks if Ensembl is responding, unless the last check was successful and
    * the retest interval has not yet elapsed. Returns true if Ensembl is up,
index cc002e1..7aa7178 100644 (file)
@@ -1,10 +1,32 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.Dna;
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
@@ -158,6 +180,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
                 + " chunks. Unexpected problem (" + r.getLocalizedMessage()
                 + ")";
         System.err.println(msg);
+        r.printStackTrace();
         break;
       }
     }
@@ -271,23 +294,63 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
       proteinSeq.createDatasetSequence();
       querySeq.createDatasetSequence();
 
-      MapList mapList = AlignmentUtils.mapCdsToProtein(querySeq, proteinSeq);
+      MapList mapList = AlignmentUtils
+              .mapCdsToProtein(querySeq, proteinSeq);
       if (mapList != null)
       {
         // clunky: ensure Uniprot xref if we have one is on mapped sequence
         SequenceI ds = proteinSeq.getDatasetSequence();
-        ds.setSourceDBRef(proteinSeq.getSourceDBRef());
-
+        // TODO: Verify ensp primary ref is on proteinSeq.getDatasetSequence()
         Mapping map = new Mapping(ds, mapList);
         DBRefEntry dbr = new DBRefEntry(getDbSource(),
                 getEnsemblDataVersion(), proteinSeq.getName(), map);
         querySeq.getDatasetSequence().addDBRef(dbr);
-        
+        DBRefEntry[] uprots = DBRefUtils.selectRefs(ds.getDBRefs(),
+                new String[] { DBRefSource.UNIPROT });
+        DBRefEntry[] upxrefs = DBRefUtils.selectRefs(querySeq.getDBRefs(),
+                new String[] { DBRefSource.UNIPROT });
+        if (uprots != null)
+        {
+          for (DBRefEntry up : uprots)
+          {
+            // locate local uniprot ref and map
+            List<DBRefEntry> upx = DBRefUtils.searchRefs(upxrefs,
+                    up.getAccessionId());
+            DBRefEntry upxref;
+            if (upx.size() != 0)
+            {
+              upxref = upx.get(0);
+
+              if (upx.size() > 1)
+              {
+                Cache.log
+                        .warn("Implementation issue - multiple uniprot acc on product sequence.");
+              }
+            }
+            else
+            {
+              upxref = new DBRefEntry(DBRefSource.UNIPROT,
+                      getEnsemblDataVersion(), up.getAccessionId());
+            }
+
+            Mapping newMap = new Mapping(ds, mapList);
+            upxref.setVersion(getEnsemblDataVersion());
+            upxref.setMap(newMap);
+            if (upx.size() == 0)
+            {
+              // add the new uniprot ref
+              querySeq.getDatasetSequence().addDBRef(upxref);
+            }
+
+          }
+        }
+
         /*
          * copy exon features to protein, compute peptide variants from dna 
          * variants and add as features on the protein sequence ta-da
          */
-        AlignmentUtils.computeProteinFeatures(querySeq, proteinSeq, mapList);
+        AlignmentUtils
+                .computeProteinFeatures(querySeq, proteinSeq, mapList);
       }
     } catch (Exception e)
     {
@@ -309,7 +372,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
       seq = seq.getDatasetSequence();
     }
 
-    EnsemblXref xrefFetcher = new EnsemblXref(getDomain());
+    EnsemblXref xrefFetcher = new EnsemblXref(getDomain(), getDbSource(),
+            getEnsemblDataVersion());
     List<DBRefEntry> xrefs = xrefFetcher.getCrossReferences(seq.getName());
     for (DBRefEntry xref : xrefs)
     {
@@ -322,7 +386,6 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     DBRefEntry self = new DBRefEntry(getDbSource(),
             getEnsemblDataVersion(), seq.getName());
     seq.addDBRef(self);
-    seq.setSourceDBRef(self);
   }
 
   /**
@@ -344,6 +407,11 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
       throw new JalviewException("ENSEMBL Rest API not available.");
     }
     FileParse fp = getSequenceReader(ids);
+    if (fp == null)
+    {
+      return alignment;
+    }
+
     FastaFile fr = new FastaFile(fp);
     if (fr.hasWarningMessage())
     {
@@ -368,9 +436,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
 
     if (fr.getSeqs().size() > 0)
     {
-      AlignmentI seqal = new Alignment(
-              fr.getSeqsAsArray());
-      for (SequenceI sq:seqal.getSequences())
+      AlignmentI seqal = new Alignment(fr.getSeqsAsArray());
+      for (SequenceI sq : seqal.getSequences())
       {
         if (sq.getDescription() == null)
         {
@@ -382,7 +449,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
         {
           DBRefEntry dbref = DBRefUtils.parseToDbRef(sq, getDbSource(),
                   getEnsemblDataVersion(), name);
-          sq.setSourceDBRef(dbref);
+          sq.addDBRef(dbref);
         }
       }
       if (alignment == null)
@@ -502,7 +569,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     int mappedLength = 0;
     int direction = 1; // forward
     boolean directionSet = false;
-  
+
     for (SequenceFeature sf : sfs)
     {
       /*
@@ -519,20 +586,20 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
           // abort - mix of forward and backward
           System.err.println("Error: forward and backward strand for "
                   + accId);
-            return null;
-          }
-          direction = strand;
-          directionSet = true;
-  
-          /*
-           * add to CDS ranges, semi-sorted forwards/backwards
-           */
-          if (strand < 0)
-          {
-            regions.add(0, new int[] { sf.getEnd(), sf.getBegin() });
-          }
-          else
-          {
+          return null;
+        }
+        direction = strand;
+        directionSet = true;
+
+        /*
+         * add to CDS ranges, semi-sorted forwards/backwards
+         */
+        if (strand < 0)
+        {
+          regions.add(0, new int[] { sf.getEnd(), sf.getBegin() });
+        }
+        else
+        {
           regions.add(new int[] { sf.getBegin(), sf.getEnd() });
         }
         mappedLength += Math.abs(sf.getEnd() - sf.getBegin() + 1);
@@ -547,7 +614,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
         }
       }
     }
-  
+
     if (regions.isEmpty())
     {
       System.out.println("Failed to identify target sequence for " + accId
@@ -560,10 +627,10 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
      * (havana / ensembl_havana)
      */
     Collections.sort(regions, new RangeSorter(direction == 1));
-  
+
     List<int[]> to = Arrays.asList(new int[] { start,
         start + mappedLength - 1 });
-  
+
     return new MapList(regions, to, 1, 1);
   }
 
@@ -607,7 +674,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     int start = sf.getBegin();
     int end = sf.getEnd();
     int[] mappedRange = mapping.locateInTo(start, end);
-  
+
     if (mappedRange != null)
     {
       SequenceFeature copy = new SequenceFeature(sf);
@@ -717,8 +784,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
 
     // long start = System.currentTimeMillis();
     SequenceFeature[] sfs = sourceSequence.getSequenceFeatures();
-    MapList mapping = getGenomicRangesFromFeatures(sourceSequence, accessionId,
-            targetSequence.getStart());
+    MapList mapping = getGenomicRangesFromFeatures(sourceSequence,
+            accessionId, targetSequence.getStart());
     if (mapping == null)
     {
       return false;
@@ -849,11 +916,13 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
           String type, String parentId)
   {
     List<SequenceFeature> result = new ArrayList<SequenceFeature>();
-    
+
     SequenceFeature[] sfs = sequence.getSequenceFeatures();
-    if (sfs != null) {
+    if (sfs != null)
+    {
       SequenceOntologyI so = SequenceOntologyFactory.getInstance();
-      for (SequenceFeature sf :sfs) {
+      for (SequenceFeature sf : sfs)
+      {
         if (so.isA(sf.getType(), type))
         {
           String parent = (String) sf.getValue(PARENT);
index dd1739b..bd6335a 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.DBRefSource;
index 1c47f11..0d79864 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import java.io.BufferedReader;
@@ -25,11 +45,13 @@ public class EnsemblSymbol extends EnsemblXref
   /**
    * Constructor given the target domain to fetch data from
    * 
-   * @param d
+   * @param domain
+   * @param dbName
+   * @param dbVersion
    */
-  public EnsemblSymbol(String d)
+  public EnsemblSymbol(String domain, String dbName, String dbVersion)
   {
-    super(d);
+    super(domain, dbName, dbVersion);
   }
 
   /**
@@ -69,8 +91,7 @@ public class EnsemblSymbol extends EnsemblXref
   protected URL getUrl(String id, Species species)
   {
     String url = getDomain() + "/xrefs/symbol/" + species.toString() + "/"
-            + id
-            + "?content-type=application/json";
+            + id + "?content-type=application/json";
     try
     {
       return new URL(url);
@@ -92,7 +113,7 @@ public class EnsemblSymbol extends EnsemblXref
     List<String> result = new ArrayList<String>();
     List<String> ids = new ArrayList<String>();
     ids.add(identifier);
-  
+
     String[] queries = identifier.split(getAccessionSeparator());
     BufferedReader br = null;
     try
index fa86865..c0b00b1 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.AlignmentI;
@@ -29,20 +49,25 @@ class EnsemblXref extends EnsemblRestClient
 
   private static final String GO_GENE_ONTOLOGY = "GO";
 
+  private String dbName = "ENSEMBL (xref)";
+
   /**
    * Constructor given the target domain to fetch data from
    * 
    * @param d
    */
-  public EnsemblXref(String d)
+  public EnsemblXref(String d, String dbSource, String version)
   {
     super(d);
+    dbName = dbSource;
+    xrefVersion = dbSource + ":" + version;
+
   }
 
   @Override
   public String getDbName()
   {
-    return "ENSEMBL (xref)";
+    return dbName;
   }
 
   @Override
@@ -152,7 +177,7 @@ class EnsemblXref extends EnsemblRestClient
         if (dbName != null && id != null)
         {
           dbName = DBRefUtils.getCanonicalName(dbName);
-          DBRefEntry dbref = new DBRefEntry(dbName, "0", id);
+          DBRefEntry dbref = new DBRefEntry(dbName, getXRefVersion(), id);
           result.add(dbref);
         }
       }
@@ -163,6 +188,18 @@ class EnsemblXref extends EnsemblRestClient
     return result;
   }
 
+  private String xrefVersion = "ENSEMBL:0";
+
+  /**
+   * version string for Xrefs - for 2.10, hardwired for ENSEMBL:0
+   * 
+   * @return
+   */
+  public String getXRefVersion()
+  {
+    return xrefVersion;
+  }
+
   /**
    * Returns the URL for the REST endpoint to fetch all cross-references for an
    * identifier. Note this may return protein cross-references for nucleotide.
index d8a00a5..350d0d5 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 /**
index f3b5098..4357abd 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.htsjdk;
 
 import htsjdk.samtools.SAMSequenceDictionary;
@@ -59,18 +79,21 @@ public class HtsContigDb
 
   }
 
-
   SAMSequenceDictionary rrefDict = null;
-  private ReferenceSequenceFile initSequenceDictionaryFor(File dbLocation2) throws Exception
+
+  private ReferenceSequenceFile initSequenceDictionaryFor(File dbLocation2)
+          throws Exception
   {
     rrefDict = getDictionary(dbLocation2, true);
     if (rrefDict != null)
     {
-      ReferenceSequenceFile rrefFile = ReferenceSequenceFileFactory.getReferenceSequenceFile(dbLocation2, true);
+      ReferenceSequenceFile rrefFile = ReferenceSequenceFileFactory
+              .getReferenceSequenceFile(dbLocation2, true);
       return rrefFile;
     }
     return null;
   }
+
   /**
    * code below hacked out from picard ----
    * 
@@ -79,7 +102,6 @@ public class HtsContigDb
    * broadinstitute/picard/commit/270580d3e28123496576f0b91b3433179bb5d876
    */
 
-
   /*
    * The MIT License
    * 
index 3ee8a34..2d2d10e 100644 (file)
@@ -43,13 +43,12 @@ import java.awt.event.ComponentListener;
 import java.io.File;
 import java.net.URL;
 import java.security.AccessControlException;
+import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
-import javajs.awt.Dimension;
-
 import org.jmol.adapter.smarter.SmarterJmolAdapter;
 import org.jmol.api.JmolAppConsoleInterface;
 import org.jmol.api.JmolSelectionListener;
@@ -73,7 +72,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   Vector<String> atomsPicked = new Vector<String>();
 
-  public Vector<String> chainNames;
+  private List<String> chainNames;
 
   Hashtable<String, String> chainFile;
 
@@ -93,20 +92,15 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   boolean loadedInline;
 
-  /**
-   * current set of model filenames loaded in the Jmol instance
-   */
-  String[] modelFileNames = null;
-
   StringBuffer resetLastRes = new StringBuffer();
 
   public Viewer viewer;
 
   public JalviewJmolBinding(StructureSelectionManager ssm,
-          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
+          PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
           DataSourceType protocol)
   {
-    super(ssm, pdbentry, sequenceIs, chains, protocol);
+    super(ssm, pdbentry, sequenceIs, protocol);
     /*
      * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
      * "jalviewJmol", ap.av.applet .getDocumentBase(),
@@ -171,7 +165,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   {
     // remove listeners for all structures in viewer
     getSsm().removeStructureViewerListener(this, this.getPdbFile());
-     viewer.dispose();
+    viewer.dispose();
     lastCommand = null;
     viewer = null;
     releaseUIResources();
@@ -258,8 +252,12 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       } catch (InterruptedException i)
       {
       }
-      ;
     }
+
+    /*
+     * get the distinct structure files modelled
+     * (a file with multiple chains may map to multiple sequences)
+     */
     String[] files = getPdbFile();
     if (!waitForFileLoad(files))
     {
@@ -307,6 +305,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
        * 'matched' array will hold 'true' for visible alignment columns where
        * all sequences have a residue with a mapping to the PDB structure
        */
+      // TODO could use a BitSet for matched
       boolean matched[] = new boolean[alignment.getWidth()];
       for (int m = 0; m < matched.length; m++)
       {
@@ -352,6 +351,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
        * generate select statements to select regions to superimpose structures
        */
       {
+        // TODO extract method to construct selection statements
         for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
         {
           String chainCd = ":" + structures[pdbfnum].chain;
@@ -419,6 +419,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
         }
       }
       StringBuilder command = new StringBuilder(256);
+      // command.append("set spinFps 10;\n");
+
       for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
       {
         if (pdbfnum == refStructure || selcom[pdbfnum] == null
@@ -449,12 +451,13 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       }
       if (selectioncom.length() > 0)
       {
-        System.out.println("Select regions:\n" + selectioncom.toString());
+        // TODO is performing selectioncom redundant here? is done later on
+        // System.out.println("Select regions:\n" + selectioncom.toString());
         evalStateCommand("select *; cartoons off; backbone; select ("
                 + selectioncom.toString() + "); cartoons; ");
         // selcom.append("; ribbons; ");
         String cmdString = command.toString();
-        System.out.println("Superimpose command(s):\n" + cmdString);
+        // System.out.println("Superimpose command(s):\n" + cmdString);
 
         evalStateCommand(cmdString);
       }
@@ -465,7 +468,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       {
         selectioncom.setLength(selectioncom.length() - 1);
       }
-      System.out.println("Select regions:\n" + selectioncom.toString());
+      // System.out.println("Select regions:\n" + selectioncom.toString());
       evalStateCommand("select *; cartoons off; backbone; select ("
               + selectioncom.toString() + "); cartoons; ");
       // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
@@ -647,15 +650,15 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     }
     if (modelFileNames == null)
     {
-      String mset[] = new String[viewer.ms.mc];
-      _modelFileNameMap = new int[mset.length];
+      List<String> mset = new ArrayList<String>();
+      _modelFileNameMap = new int[viewer.ms.mc];
       String m = viewer.ms.getModelFileName(0);
       if (m != null)
       {
-        mset[0] = m;
+        String filePath = m;
         try
         {
-          mset[0] = new File(m).getAbsolutePath();
+          filePath = new File(m).getAbsolutePath();
         } catch (AccessControlException x)
         {
           // usually not allowed to do this in applet
@@ -663,39 +666,43 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
                   .println("jmolBinding: Using local file string from Jmol: "
                           + m);
         }
-        if (mset[0].indexOf("/file:") != -1)
+        if (filePath.indexOf("/file:") != -1)
         {
           // applet path with docroot - discard as format won't match pdbfile
-          mset[0] = m;
+          filePath = m;
         }
+        mset.add(filePath);
         _modelFileNameMap[0] = 0; // filename index for first model is always 0.
       }
       int j = 1;
-      for (int i = 1; i < mset.length; i++)
+      for (int i = 1; i < viewer.ms.mc; i++)
       {
         m = viewer.ms.getModelFileName(i);
-        mset[j] = m;
+        String filePath = m;
         if (m != null)
         {
           try
           {
-            mset[j] = new File(m).getAbsolutePath();
+            filePath = new File(m).getAbsolutePath();
           } catch (AccessControlException x)
           {
             // usually not allowed to do this in applet, so keep raw handle
             // System.err.println("jmolBinding: Using local file string from Jmol: "+m);
           }
         }
-        _modelFileNameMap[j] = i; // record the model index for the filename
-        // skip any additional models in the same file (NMR structures)
-        if ((mset[j] == null ? mset[j] != mset[j - 1]
-                : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))
+
+        /*
+         * add this model unless it is read from a structure file we have
+         * already seen (example: 2MJW is an NMR structure with 10 models)
+         */
+        if (!mset.contains(filePath))
         {
+          mset.add(filePath);
+          _modelFileNameMap[j] = i; // record the model index for the filename
           j++;
         }
       }
-      modelFileNames = new String[j];
-      System.arraycopy(mset, 0, modelFileNames, 0, j);
+      modelFileNames = mset.toArray(new String[mset.size()]);
     }
     return modelFileNames;
   }
@@ -1074,7 +1081,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     fileLoadingError = null;
     String[] oldmodels = modelFileNames;
     modelFileNames = null;
-    chainNames = new Vector<String>();
+    chainNames = new ArrayList<String>();
     chainFile = new Hashtable<String, String>();
     boolean notifyLoaded = false;
     String[] modelfilenames = getPdbFile();
@@ -1134,6 +1141,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       for (int pe = 0; pe < getPdbCount(); pe++)
       {
         boolean matches = false;
+        addSequence(pe, getSequence()[pe]);
         if (fileName == null)
         {
           if (false)
@@ -1185,7 +1193,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
             String chid = new String(pdb.getId() + ":"
                     + pdb.getChains().elementAt(i).id);
             chainFile.put(chid, fileName);
-            chainNames.addElement(chid);
+            chainNames.add(chid);
           }
           notifyLoaded = true;
         }
@@ -1233,6 +1241,12 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     setLoadingFromArchive(false);
   }
 
+  @Override
+  public List<String> getChainNames()
+  {
+    return chainNames;
+  }
+
   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
   {
     notifyAtomPicked(iatom, strMeasure, null);
@@ -1395,7 +1409,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   }
 
   @Override
-  public Dimension resizeInnerPanel(String data)
+  public int[] resizeInnerPanel(String data)
   {
     // Jalview doesn't honour resize panel requests
     return null;
index 858aac7..f08e40e 100644 (file)
@@ -22,12 +22,14 @@ package jalview.ext.jmol;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
 import jalview.io.FileParse;
 import jalview.io.StructureFile;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureImportSettings;
+import jalview.util.Format;
 import jalview.util.MessageManager;
 
 import java.io.IOException;
@@ -37,8 +39,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
-import javajs.awt.Dimension;
-
 import org.jmol.api.JmolStatusListener;
 import org.jmol.api.JmolViewer;
 import org.jmol.c.CBK;
@@ -60,15 +60,13 @@ public class JmolParser extends StructureFile implements JmolStatusListener
 {
   Viewer viewer = null;
 
-  public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
-          boolean externalSecStr, String inFile, DataSourceType sourceType)
+  public JmolParser(String inFile, DataSourceType sourceType)
           throws IOException
   {
     super(inFile, sourceType);
   }
 
-  public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
-          boolean externalSecStr, FileParse fp) throws IOException
+  public JmolParser(FileParse fp) throws IOException
   {
     super(fp);
   }
@@ -98,6 +96,18 @@ public class JmolParser extends StructureFile implements JmolStatusListener
      */
     if (jmolModel.ms.mc > 0)
     {
+      // ideally we do this
+      // try
+      // {
+      // setStructureFileType(jmolModel.evalString("show _fileType"));
+      // } catch (Exception q)
+      // {
+      // }
+      // ;
+      // instead, we distinguish .cif from non-.cif by filename
+      setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
+              .toString() : "PDB");
+
       transformJmolModelToJalview(jmolModel.ms);
     }
   }
@@ -113,6 +123,10 @@ public class JmolParser extends StructureFile implements JmolStatusListener
     {
       try
       {
+        /*
+         * params -o (output to sysout) -n (nodisplay) -x (exit when finished)
+         * see http://wiki.jmol.org/index.php/Jmol_Application
+         */
         viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
                 null, "-x -o -n", this);
         // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
@@ -136,7 +150,17 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       List<SequenceI> prot = new ArrayList<SequenceI>();
       PDBChain tmpchain;
       String pdbId = (String) ms.getInfo(0, "title");
-      setId(pdbId);
+
+      if (pdbId == null)
+      {
+        setId(safeName(getDataName()));
+        setPDBIdAvailable(false);
+      }
+      else
+      {
+        setId(pdbId);
+        setPDBIdAvailable(true);
+      }
       List<Atom> significantAtoms = convertSignificantAtoms(ms);
       for (Atom tmpatom : significantAtoms)
       {
@@ -151,7 +175,7 @@ public class JmolParser extends StructureFile implements JmolStatusListener
           tmpchain.atoms.addElement(tmpatom);
         } catch (Exception e)
         {
-          tmpchain = new PDBChain(pdbId, tmpatom.chain);
+          tmpchain = new PDBChain(getId(), tmpatom.chain);
           getChains().add(tmpchain);
           tmpchain.atoms.addElement(tmpatom);
         }
@@ -162,10 +186,6 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       makeResidueList();
       makeCaBondList();
 
-      if (getId() == null)
-      {
-        setId(safeName(getDataName()));
-      }
       for (PDBChain chain : getChains())
       {
         SequenceI chainseq = postProcessChain(chain);
@@ -218,8 +238,8 @@ public class JmolParser extends StructureFile implements JmolStatusListener
         curAtom.resNumber = atom.getResno();
         curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
                 .getIndex()] : Float.valueOf(atom.getOccupancy100());
-        curAtom.resNumIns = ("" + curAtom.resNumber + curAtom.insCode)
-                .trim();
+        String fmt = new Format("%4i").form(curAtom.resNumber);
+        curAtom.resNumIns = (fmt + curAtom.insCode);
         curAtom.tfactor = atom.getBfactor100() / 100f;
         curAtom.type = 0;
         // significantAtoms.add(curAtom);
@@ -258,6 +278,10 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       // diff < 5 then mark as valid and update termination Atom
       if (chainTerMap.containsKey(curAtomChId))
       {
+        if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
+        {
+          return false;
+        }
         if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
         {
           chainTerMap.put(curAtomChId, curAtom);
@@ -269,6 +293,10 @@ public class JmolParser extends StructureFile implements JmolStatusListener
     // atom with previously terminated chain encountered
     else if (chainTerMap.containsKey(curAtomChId))
     {
+      if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
+      {
+        return false;
+      }
       if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
       {
         chainTerMap.put(curAtomChId, curAtom);
@@ -332,9 +360,9 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       {
         try
         {
-        asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
-                secstrcode[p], Float.NaN);
-        ssFound = true;
+          asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
+                  secstrcode[p], Float.NaN);
+          ssFound = true;
         } catch (Exception e)
         {
           // e.printStackTrace();
@@ -598,7 +626,7 @@ public class JmolParser extends StructureFile implements JmolStatusListener
    * Not implemented - returns null
    */
   @Override
-  public Dimension resizeInnerPanel(String data)
+  public int[] resizeInnerPanel(String data)
   {
     return null;
   }
index dca7038..b009948 100644 (file)
@@ -41,6 +41,7 @@ import jalview.util.MessageManager;
 import java.awt.Color;
 import java.net.BindException;
 import java.util.ArrayList;
+import java.util.Hashtable;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -64,6 +65,10 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   private static final String ALPHACARBON = "CA";
 
+  private List<String> chainNames = new ArrayList<String>();
+
+  private Hashtable<String, String> chainFile = new Hashtable<String, String>();
+  
   /*
    * Object through which we talk to Chimera
    */
@@ -102,11 +107,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   private String lastCommand;
 
-  /*
-   * current set of model filenames loaded
-   */
-  String[] modelFileNames = null;
-
   String lastHighlightCommand;
 
   /*
@@ -193,14 +193,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    * @param ssm
    * @param pdbentry
    * @param sequenceIs
-   * @param chains
    * @param protocol
    */
   public JalviewChimeraBinding(StructureSelectionManager ssm,
-          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
-          DataSourceType protocol)
+          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol)
   {
-    super(ssm, pdbentry, sequenceIs, chains, protocol);
+    super(ssm, pdbentry, sequenceIs, protocol);
     viewer = new ChimeraManager(
             new ext.edu.ucsf.rbvi.strucviz2.StructureManager(true));
   }
@@ -250,11 +248,14 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     boolean first = true;
     for (String chain : toshow)
     {
+      int modelNumber = getModelNoForChain(chain);
+      String showChainCmd = modelNumber == -1 ? "" : modelNumber + ":."
+              + chain.split(":")[1];
       if (!first)
       {
         cmd.append(",");
       }
-      cmd.append(":.").append(chain);
+      cmd.append(showChainCmd);
       first = false;
     }
 
@@ -263,7 +264,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
      * window, but it looks more helpful not to (easier to relate chains to the
      * whole)
      */
-    final String command = "~display #*; ~ribbon #*; ribbon "
+    final String command = "~display #*; ~ribbon #*; ribbon :"
             + cmd.toString();
     sendChimeraCommand(command, false);
   }
@@ -764,18 +765,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     {
       return new String[0];
     }
-    // if (modelFileNames == null)
-    // {
-    // Collection<ChimeraModel> chimodels = viewer.getChimeraModels();
-    // _modelFileNameMap = new int[chimodels.size()];
-    // int j = 0;
-    // for (ChimeraModel chimodel : chimodels)
-    // {
-    // String mdlName = chimodel.getModelName();
-    // }
-    // modelFileNames = new String[j];
-    // // System.arraycopy(mset, 0, modelFileNames, 0, j);
-    // }
 
     return chimeraMaps.keySet().toArray(
             modelFileNames = new String[chimeraMaps.size()]);
@@ -1073,28 +1062,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    * 
    * @return
    */
-  public List<String> getChainNames()
-  {
-    List<String> names = new ArrayList<String>();
-    String[][] allNames = getChains();
-    if (allNames != null)
-    {
-      for (String[] chainsForPdb : allNames)
-      {
-        if (chainsForPdb != null)
-        {
-          for (String chain : chainsForPdb)
-          {
-            if (chain != null && !names.contains(chain))
-            {
-              names.add(chain);
-            }
-          }
-        }
-      }
-    }
-    return names;
-  }
 
   /**
    * Send a 'focus' command to Chimera to recentre the visible display
@@ -1131,4 +1098,31 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       sm.highlightStructure(this, seq, positions);
     }
   }
+
+
+  @Override
+  public List<String> getChainNames()
+  {
+    return chainNames;
+  }
+
+  public Hashtable<String, String> getChainFile()
+  {
+    return chainFile;
+  }
+
+  public List<ChimeraModel> getChimeraModelByChain(String chain)
+  {
+    return chimeraMaps.get(chainFile.get(chain));
+  }
+
+  public int getModelNoForChain(String chain)
+  {
+    List<ChimeraModel> foundModels = getChimeraModelByChain(chain);
+    if (foundModels != null && !foundModels.isEmpty())
+    {
+      return foundModels.get(0).getModelNumber();
+    }
+    return -1;
+  }
 }
index af80b7a..a4c195f 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.so;
 
 import jalview.io.gff.SequenceOntologyI;
@@ -77,11 +97,11 @@ public class SequenceOntology implements SequenceOntologyI
    */
   protected void loadOntologyZipFile(String ontologyFile)
   {
+    long now = System.currentTimeMillis();
     ZipInputStream zipStream = null;
     try
     {
       String zipFile = ontologyFile + ".zip";
-      System.out.println("Loading Sequence Ontology from " + zipFile);
       InputStream inStream = this.getClass().getResourceAsStream(
               "/" + zipFile);
       zipStream = new ZipInputStream(new BufferedInputStream(inStream));
@@ -93,6 +113,9 @@ public class SequenceOntology implements SequenceOntologyI
           loadOboFile(zipStream);
         }
       }
+      long elapsed = System.currentTimeMillis() - now;
+      System.out.println("Loaded Sequence Ontology from " + zipFile + " ("
+              + elapsed + "ms)");
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -172,9 +195,9 @@ public class SequenceOntology implements SequenceOntologyI
             }
             else
             {
-            System.err.println("Warning: " + term.getName()
-                    + " has replaced " + replaced.getName()
-                    + " for lookup of '" + description + "'");
+              System.err.println("Warning: " + term.getName()
+                      + " has replaced " + replaced.getName()
+                      + " for lookup of '" + description + "'");
             }
           }
           termsByDescription.put(description, term);
@@ -197,8 +220,8 @@ public class SequenceOntology implements SequenceOntologyI
     {
       try
       {
-      if (Boolean.TRUE.equals(ann.getProperty("is_obsolete")))
-      {
+        if (Boolean.TRUE.equals(ann.getProperty("is_obsolete")))
+        {
           return true;
         }
       } catch (NoSuchElementException e)
index 3701c76..33b0ed6 100644 (file)
@@ -74,7 +74,6 @@ public interface FTSRestClientI
   public FTSDataColumnI getDataColumnByNameOrCode(String nameOrCode)
           throws Exception;
 
-
   /**
    * Convert collection of FTSDataColumnI objects to a comma delimited string of
    * the 'code' values
@@ -87,7 +86,6 @@ public interface FTSRestClientI
   public String getDataColumnsFieldsAsCommaDelimitedString(
           Collection<FTSDataColumnI> wantedFields);
 
-
   /**
    * Fetch index of the primary key column for the dynamic table
    * 
@@ -102,7 +100,7 @@ public interface FTSRestClientI
   public int getPrimaryKeyColumIndex(
           Collection<FTSDataColumnI> wantedFields, boolean hasRefSeq)
           throws Exception;
-          
+
   /**
    * Fetch the primary key data column object
    * 
@@ -139,4 +137,3 @@ public interface FTSRestClientI
    */
   public int getDefaultResponsePageSize();
 }
-
index 3642721..a9e303c 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.fts.core;
 
 import java.awt.Component;
@@ -57,4 +77,4 @@ public class DecimalFormatTableCellRenderer extends
     return super.getTableCellRendererComponent(table, value, isSelected,
             hasFocus, row, column);
   }
-}
\ No newline at end of file
+}
index eb7455e..1a8f398 100644 (file)
@@ -40,7 +40,6 @@ import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
 
-
 @SuppressWarnings("serial")
 public class FTSDataColumnPreferences extends JScrollPane
 {
@@ -71,7 +70,7 @@ public class FTSDataColumnPreferences extends JScrollPane
     if (source.equals(PreferenceSource.STRUCTURE_CHOOSER)
             || source.equals(PreferenceSource.PREFERENCES))
     {
-    structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
+      structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
               .getAllDefaultDisplayedStructureDataColumns();
     }
     allFTSDataColumns.addAll(ftsRestClient.getAllFTSDataColumns());
@@ -111,19 +110,18 @@ public class FTSDataColumnPreferences extends JScrollPane
       {
       case SEARCH_SUMMARY:
         data[x++] = new Object[] {
-            ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
-                    .contains(field),
-            field.getName(), field.getGroup() };
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns().contains(
+                    field), field.getName(), field.getGroup() };
         break;
       case STRUCTURE_CHOOSER:
         data[x++] = new Object[] { structSummaryColumns.contains(field),
             field.getName(), field.getGroup() };
         break;
       case PREFERENCES:
-        data[x++] = new Object[] { field.getName(),
-            ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
-                    .contains(field),
-            structSummaryColumns.contains(field) };
+        data[x++] = new Object[] {
+            field.getName(),
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns().contains(
+                    field), structSummaryColumns.contains(field) };
         break;
       default:
         break;
@@ -131,7 +129,8 @@ public class FTSDataColumnPreferences extends JScrollPane
       map.put(field.getName(), field);
     }
 
-    FTSDataColumnPrefsTableModel model = new FTSDataColumnPrefsTableModel(columnNames, data);
+    FTSDataColumnPrefsTableModel model = new FTSDataColumnPrefsTableModel(
+            columnNames, data);
     tbl_FTSDataColumnPrefs.setModel(model);
 
     switch (source)
@@ -147,8 +146,7 @@ public class FTSDataColumnPreferences extends JScrollPane
       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(1).setMinWidth(150);
       tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2)
               .setPreferredWidth(150);
-      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2)
-.setMinWidth(150);
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2).setMinWidth(150);
 
       TableRowSorter<TableModel> sorter = new TableRowSorter<>(
               tbl_FTSDataColumnPrefs.getModel());
@@ -158,8 +156,7 @@ public class FTSDataColumnPreferences extends JScrollPane
       sortKeys.add(new RowSorter.SortKey(columnIndexToSort,
               SortOrder.ASCENDING));
       sorter.setSortKeys(sortKeys);
-      sorter.setComparator(
-              columnIndexToSort,
+      sorter.setComparator(columnIndexToSort,
               new Comparator<FTSDataColumnGroupI>()
               {
                 @Override
@@ -189,7 +186,8 @@ public class FTSDataColumnPreferences extends JScrollPane
   class FTSDataColumnPrefsTableModel extends AbstractTableModel
   {
 
-    public FTSDataColumnPrefsTableModel(String[] columnNames, Object[][] data)
+    public FTSDataColumnPrefsTableModel(String[] columnNames,
+            Object[][] data)
     {
       this.data = data;
       this.columnNames = columnNames;
@@ -301,9 +299,8 @@ public class FTSDataColumnPreferences extends JScrollPane
 
       if (currentSource == PreferenceSource.SEARCH_SUMMARY)
       {
-        updatePrefs(ftsRestClient
-                .getAllDefaultDisplayedFTSDataColumns(), ftsDataColumn,
-                selected);
+        updatePrefs(ftsRestClient.getAllDefaultDisplayedFTSDataColumns(),
+                ftsDataColumn, selected);
       }
       else if (currentSource == PreferenceSource.STRUCTURE_CHOOSER)
       {
@@ -313,9 +310,8 @@ public class FTSDataColumnPreferences extends JScrollPane
       {
         if (col == 1)
         {
-          updatePrefs(ftsRestClient
-                  .getAllDefaultDisplayedFTSDataColumns(), ftsDataColumn,
-                  selected);
+          updatePrefs(ftsRestClient.getAllDefaultDisplayedFTSDataColumns(),
+                  ftsDataColumn, selected);
         }
         else if (col == 2)
         {
@@ -324,8 +320,7 @@ public class FTSDataColumnPreferences extends JScrollPane
       }
     }
 
-    private void updatePrefs(
-            Collection<FTSDataColumnI> prefConfig,
+    private void updatePrefs(Collection<FTSDataColumnI> prefConfig,
             FTSDataColumnI dataColumn, boolean selected)
     {
       if (prefConfig.contains(dataColumn) && !selected)
index 00a081b..4899e38 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.fts.core;
 
 import jalview.fts.api.FTSDataColumnI;
@@ -45,9 +65,9 @@ public abstract class FTSRestClient implements FTSRestClientI
   public void parseDataColumnsConfigFile()
   {
     String fileName = getColumnDataConfigFileName();
-    
-    InputStream in = getClass().getResourceAsStream(fileName); 
-    
+
+    InputStream in = getClass().getResourceAsStream(fileName);
+
     try (BufferedReader br = new BufferedReader(new InputStreamReader(in)))
     {
       String line;
@@ -259,7 +279,6 @@ public abstract class FTSRestClient implements FTSRestClientI
                         this.getGroup());
               }
 
-
               @Override
               public boolean equals(Object otherObject)
               {
@@ -269,7 +288,6 @@ public abstract class FTSRestClient implements FTSRestClientI
                         && this.getGroup().equals(that.getGroup());
               }
 
-
             };
             dataColumns.add(dataCol);
 
@@ -345,7 +363,6 @@ public abstract class FTSRestClient implements FTSRestClientI
     return result;
   }
 
-
   @Override
   public Collection<FTSDataColumnI> getAllFTSDataColumns()
   {
@@ -432,10 +449,9 @@ public abstract class FTSRestClient implements FTSRestClientI
     switch (code)
     {
     case 400:
-      message = MessageManager
-              .getString("exception.bad_request");
+      message = MessageManager.getString("exception.bad_request");
       break;
-      
+
     case 410:
       message = MessageManager.formatMessage(
               "exception.fts_rest_service_no_longer_available", service);
@@ -451,7 +467,8 @@ public abstract class FTSRestClient implements FTSRestClientI
     case 502:
     case 504:
     case 505:
-      message = MessageManager.getString("exception.fts_server_error");
+      message = MessageManager.formatMessage("exception.fts_server_error",
+              service);
       break;
     case 503:
       message = MessageManager.getString("exception.service_not_available");
index 164b102..2e1c632 100644 (file)
@@ -107,8 +107,7 @@ public class FTSRestRequest
     return wantedFields;
   }
 
-  public void setWantedFields(
-          Collection<FTSDataColumnI> wantedFields)
+  public void setWantedFields(Collection<FTSDataColumnI> wantedFields)
   {
     this.wantedFields = wantedFields;
   }
index 92ea5f8..5d8fb96 100644 (file)
@@ -90,8 +90,8 @@ public class FTSRestResponse
   public static DefaultTableModel getTableModel(FTSRestRequest request,
           Collection<FTSData> summariesList)
   {
-    final FTSDataColumnI[] cols = request.getWantedFields()
-            .toArray(new FTSDataColumnI[0]);
+    final FTSDataColumnI[] cols = request.getWantedFields().toArray(
+            new FTSDataColumnI[0]);
     final int colOffset = request.getAssociatedSequence() == null ? 0 : 1;
     DefaultTableModel tableModel = new DefaultTableModel()
     {
@@ -118,8 +118,7 @@ public class FTSRestResponse
       tableModel.addColumn("Ref Sequence"); // Create sequence column header if
       // exists in the request
     }
-    for (FTSDataColumnI field : request
-            .getWantedFields())
+    for (FTSDataColumnI field : request.getWantedFields())
     {
       tableModel.addColumn(field.getName()); // Create sequence column header if
                                              // exists in the request
@@ -172,5 +171,4 @@ public class FTSRestResponse
     }
   }
 
-
 }
index 33fa020..a69d9f8 100644 (file)
@@ -35,6 +35,7 @@ import java.awt.CardLayout;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.awt.event.KeyAdapter;
@@ -84,7 +85,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   protected JInternalFrame mainFrame = new JInternalFrame(
           getFTSFrameTitle());
 
-  protected IProgressIndicator progressIdicator;
+  protected IProgressIndicator progressIndicator;
 
   protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<FTSDataColumnI>();
 
@@ -147,6 +148,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
 
   protected static final DecimalFormat totalNumberformatter = new DecimalFormat(
           "###,###");
+
   private JTable tbl_summary = new JTable()
   {
     private boolean inLayout;
@@ -224,6 +226,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       return toolTipText;
     }
   };
+
   protected JScrollPane scrl_searchResult = new JScrollPane(tbl_summary);
 
   public GFTSPanel()
@@ -231,6 +234,14 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     try
     {
       jbInit();
+      mainFrame.addFocusListener(new FocusAdapter()
+      {
+        @Override
+        public void focusGained(FocusEvent e)
+        {
+          txt_search.requestFocusInWindow();
+        }
+      });
       mainFrame.invalidate();
       mainFrame.pack();
     } catch (Exception e)
@@ -495,8 +506,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     });
 
     final DeferredTextInputListener listener = new DeferredTextInputListener(
-            1500,
-            new ActionListener()
+            1500, new ActionListener()
             {
               @Override
               public void actionPerformed(ActionEvent e)
@@ -521,7 +531,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       @Override
       public void focusLost(FocusEvent e)
       {
-//        listener.stop();
+        // listener.stop();
       }
     });
 
@@ -554,8 +564,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
           txt_search.setEnabled(false);
           cmb_searchTarget.setEnabled(false);
           previousWantedFields = getFTSRestClient()
-                  .getAllDefaultDisplayedFTSDataColumns()
-                  .toArray(new Object[0]);
+                  .getAllDefaultDisplayedFTSDataColumns().toArray(
+                          new Object[0]);
         }
         if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
         {
@@ -636,6 +646,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     getTempUserPrefs().put("FTSPanel.y", mainFrame.getY());
     mainFrame.dispose();
   }
+
   public class DeferredTextInputListener implements DocumentListener
   {
     private final Timer swingTimer;
@@ -685,9 +696,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     }
 
     return Arrays.equals(getFTSRestClient()
-            .getAllDefaultDisplayedFTSDataColumns()
-            .toArray(new Object[0]), previousWantedFields) ? false
-            : true;
+            .getAllDefaultDisplayedFTSDataColumns().toArray(new Object[0]),
+            previousWantedFields) ? false : true;
 
   }
 
@@ -757,7 +767,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
   protected void btn_back_ActionPerformed()
   {
     closeAction();
-    new SequenceFetcher(progressIdicator);
+    new SequenceFetcher(progressIndicator);
   }
 
   protected void disableActionButtons()
@@ -803,7 +813,6 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     }
   }
 
-
   public void transferToSequenceFetcher(String ids)
   {
     // mainFrame.dispose();
@@ -916,8 +925,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     int[] selectedRows = resultTable.getSelectedRows();
     for (int summaryRow : selectedRows)
     {
-      String idStr = resultTable.getValueAt(summaryRow,
-              primaryKeyColIndex).toString();
+      String idStr = resultTable.getValueAt(summaryRow, primaryKeyColIndex)
+              .toString();
       paginatorCart.add(idStr);
     }
     // System.out.println("Paginator shopping cart size : "
@@ -953,6 +962,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
     }
     validateSelection();
   }
+
   public void refreshPaginatorState()
   {
     // System.out.println("resultSet count : " + resultSetCount);
@@ -973,6 +983,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
       setPrevPageButtonEnabled(true);
     }
   }
+
   public void referesh()
   {
     mainFrame.setTitle(getFTSFrameTitle());
index 5f5c716..1dfabce 100644 (file)
@@ -45,13 +45,13 @@ public class PDBFTSPanel extends GFTSPanel
 
   public PDBFTSPanel(SequenceFetcher seqFetcher)
   {
+    super();
     pageLimit = PDBFTSRestClient.getInstance().getDefaultResponsePageSize();
     this.seqFetcher = seqFetcher;
-    this.progressIdicator = (seqFetcher == null) ? null : seqFetcher
+    this.progressIndicator = (seqFetcher == null) ? null : seqFetcher
             .getProgressIndicator();
   }
 
-
   @Override
   public void searchAction(boolean isFreshSearch)
   {
@@ -103,7 +103,7 @@ public class PDBFTSPanel extends GFTSPanel
           {
             getResultTable().setModel(
                     FTSRestResponse.getTableModel(request,
-                    resultList.getSearchSummary()));
+                            resultList.getSearchSummary()));
             FTSRestResponse.configureTableColumn(getResultTable(),
                     wantedFields, tempUserPrefs);
             getResultTable().setVisible(true);
@@ -116,10 +116,12 @@ public class PDBFTSPanel extends GFTSPanel
           String result = (resultSetCount > 0) ? MessageManager
                   .getString("label.results") : MessageManager
                   .getString("label.result");
-         
+
           if (isPaginationEnabled() && resultSetCount > 0)
           {
-            updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
+            updateSearchFrameTitle(defaultFTSFrameTitle
+                    + " - "
+                    + result
                     + " "
                     + totalNumberformatter.format((Number) (offSet + 1))
                     + " to "
@@ -127,8 +129,8 @@ public class PDBFTSPanel extends GFTSPanel
                             .format((Number) (offSet + resultSetCount))
                     + " of "
                     + totalNumberformatter
-                            .format((Number) totalResultSetCount)
-                    + " " + " (" + (endTime - startTime) + " milli secs)");
+                            .format((Number) totalResultSetCount) + " "
+                    + " (" + (endTime - startTime) + " milli secs)");
           }
           else
           {
@@ -136,7 +138,7 @@ public class PDBFTSPanel extends GFTSPanel
                     + resultSetCount + " " + result + " ("
                     + (endTime - startTime) + " milli secs)");
           }
-          
+
           setSearchInProgress(false);
           refreshPaginatorState();
           updateSummaryTableSelections();
@@ -192,8 +194,7 @@ public class PDBFTSPanel extends GFTSPanel
     try
     {
       primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
-              wantedFields,
-              false);
+              wantedFields, false);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -203,8 +204,7 @@ public class PDBFTSPanel extends GFTSPanel
     for (int summaryRow : selectedRows)
     {
       String idStr = getResultTable().getValueAt(summaryRow,
-              primaryKeyColIndex)
-              .toString();
+              primaryKeyColIndex).toString();
       selectedIdsSet.add(getPDBIdwithSpecifiedChain(idStr, searchTerm));
     }
 
@@ -226,7 +226,6 @@ public class PDBFTSPanel extends GFTSPanel
     delayAndEnableActionButtons();
   }
 
-
   public static String getPDBIdwithSpecifiedChain(String pdbId,
           String searchTerm)
   {
index 219d6d6..06bf55b 100644 (file)
@@ -140,8 +140,7 @@ public class PDBFTSRestClient extends FTSRestClient
                 .queryParam("wt", "json").queryParam("fl", wantedFields)
                 .queryParam("rows", String.valueOf(responseSize))
                 .queryParam("start", String.valueOf(offSet))
-                .queryParam("q", query)
-                .queryParam("sort", sortParam);
+                .queryParam("q", query).queryParam("sort", sortParam);
       }
       // Execute the REST request
       ClientResponse clientResponse = webResource.accept(
@@ -162,8 +161,8 @@ public class PDBFTSRestClient extends FTSRestClient
         }
         else
         {
-          errorMessage = getMessageByHTTPStatusCode(clientResponse
-.getStatus(), "PDB");
+          errorMessage = getMessageByHTTPStatusCode(
+                  clientResponse.getStatus(), "PDB");
           throw new Exception(errorMessage);
         }
       }
@@ -198,7 +197,6 @@ public class PDBFTSRestClient extends FTSRestClient
     }
   }
 
-
   /**
    * Process error response from PDB server if/when one occurs.
    * 
@@ -328,15 +326,13 @@ public class PDBFTSRestClient extends FTSRestClient
         {
           summaryRowData[colCounter++] = (field.getDataType()
                   .getDataTypeClass() == Integer.class) ? Integer
-                  .valueOf(fieldData)
- : (field.getDataType()
+                  .valueOf(fieldData) : (field.getDataType()
                   .getDataTypeClass() == Double.class) ? Double
-                          .valueOf(fieldData)
- : sanitiseData(fieldData);
+                  .valueOf(fieldData) : sanitiseData(fieldData);
         } catch (Exception e)
         {
           e.printStackTrace();
-            System.out.println("offending value:" + fieldData);
+          System.out.println("offending value:" + fieldData);
         }
       }
     }
@@ -405,7 +401,6 @@ public class PDBFTSRestClient extends FTSRestClient
     return "/fts/pdb_data_columns.txt";
   }
 
-
   public static FTSRestClientI getInstance()
   {
     if (instance == null)
index 5ee518b..27bfca8 100644 (file)
@@ -241,13 +241,12 @@ public class UniProtFTSRestClient extends FTSRestClient
             summaryRowData[colCounter++] = (field.getDataType()
                     .getDataTypeClass() == Integer.class) ? Integer
                     .valueOf(fieldData.replace(",", ""))
- : (field.getDataType()
-                    .getDataTypeClass() == Double.class) ? Double
+                    : (field.getDataType().getDataTypeClass() == Double.class) ? Double
                             .valueOf(fieldData) : fieldData;
           } catch (Exception e)
           {
             e.printStackTrace();
-              System.out.println("offending value:" + fieldData);
+            System.out.println("offending value:" + fieldData);
           }
         }
       } catch (Exception e)
@@ -306,7 +305,6 @@ public class UniProtFTSRestClient extends FTSRestClient
     };
   }
 
-
   public static FTSRestClientI getInstance()
   {
     if (instance == null)
index 9c2c5ce..f04e4fa 100644 (file)
@@ -46,10 +46,11 @@ public class UniprotFTSPanel extends GFTSPanel
 
   public UniprotFTSPanel(SequenceFetcher seqFetcher)
   {
+    super();
     pageLimit = UniProtFTSRestClient.getInstance()
             .getDefaultResponsePageSize();
     this.seqFetcher = seqFetcher;
-    this.progressIdicator = (seqFetcher == null) ? null : seqFetcher
+    this.progressIndicator = (seqFetcher == null) ? null : seqFetcher
             .getProgressIndicator();
   }
 
@@ -61,7 +62,7 @@ public class UniprotFTSPanel extends GFTSPanel
       offSet = 0;
     }
     new Thread()
-  {
+    {
       @Override
       public void run()
       {
@@ -119,7 +120,9 @@ public class UniprotFTSPanel extends GFTSPanel
                   .getString("label.result");
           if (isPaginationEnabled() && resultSetCount > 0)
           {
-            updateSearchFrameTitle(defaultFTSFrameTitle + " - " + result
+            updateSearchFrameTitle(defaultFTSFrameTitle
+                    + " - "
+                    + result
                     + " "
                     + totalNumberformatter.format((Number) (offSet + 1))
                     + " to "
@@ -127,8 +130,8 @@ public class UniprotFTSPanel extends GFTSPanel
                             .format((Number) (offSet + resultSetCount))
                     + " of "
                     + totalNumberformatter
-                            .format((Number) totalResultSetCount)
-                    + " " + " (" + (endTime - startTime) + " milli secs)");
+                            .format((Number) totalResultSetCount) + " "
+                    + " (" + (endTime - startTime) + " milli secs)");
           }
           else
           {
@@ -172,7 +175,6 @@ public class UniprotFTSPanel extends GFTSPanel
     return foundSearchTerms;
   }
 
-
   @Override
   public boolean isPaginationEnabled()
   {
index 8cc1dd5..f31a220 100644 (file)
@@ -32,7 +32,6 @@ import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsControllerI;
-import jalview.api.FeatureSettingsModelI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.ScoreModelI;
@@ -54,7 +53,6 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.DBRefSource;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
@@ -77,8 +75,8 @@ import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
+import jalview.io.StructureFile;
 import jalview.io.TCoffeeScoreFile;
-import jalview.io.gff.SequenceOntologyI;
 import jalview.jbgui.GAlignFrame;
 import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.BuriedColourScheme;
@@ -98,12 +96,10 @@ import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.schemes.UserColourScheme;
 import jalview.schemes.ZappoColourScheme;
-import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
-import jalview.ws.SequenceFetcher;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
@@ -117,6 +113,7 @@ import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.StringSelection;
 import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DropTargetDragEvent;
 import java.awt.dnd.DropTargetDropEvent;
 import java.awt.dnd.DropTargetEvent;
@@ -677,6 +674,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           toggleHiddenRegions(toggleSeqs, toggleCols);
           break;
         }
+        case KeyEvent.VK_B:
+        {
+          boolean toggleSel = evt.isControlDown() || evt.isMetaDown();
+          boolean modifyExisting = true; // always modify, don't clear
+                                         // evt.isShiftDown();
+          boolean invertHighlighted = evt.isAltDown();
+          avc.markHighlightedColumns(invertHighlighted, modifyExisting,
+                  toggleSel);
+          break;
+        }
         case KeyEvent.VK_PAGE_UP:
           if (viewport.getWrapAlignment())
           {
@@ -1345,14 +1352,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void htmlMenuItem_actionPerformed(ActionEvent e)
   {
-    new HtmlSvgOutput(null, alignPanel);
+    HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel);
+    htmlSVG.exportHTML(null);
   }
 
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
-    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel, this);
-    bjs.exportJalviewAlignmentAsBioJsHtmlFile();
+    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
+    bjs.exportHTML(null);
   }
 
   public void createImageMap(File file, String image)
@@ -2915,8 +2923,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setFollowHighlight(state);
     if (state)
     {
-      alignPanel.scrollToPosition(
-              alignPanel.getSeqPanel().seqCanvas.searchResults, false);
+      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
     }
   }
 
@@ -2986,9 +2993,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // Hide everything by the current selection - this is a hack - we do the
       // invert and then hide
       // first check that there will be visible columns after the invert.
-      if ((viewport.getColumnSelection() != null
-              && viewport.getColumnSelection().getSelected() != null && viewport
-              .getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns()
               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
                       .getEndRes()))
       {
@@ -3016,8 +3021,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         hideSelSequences_actionPerformed(null);
         hide = true;
       }
-      else if (!(toggleCols && viewport.getColumnSelection().getSelected()
-              .size() > 0))
+      else if (!(toggleCols && viewport.hasSelectedColumns()))
       {
         showAllSeqs_actionPerformed(null);
       }
@@ -3025,7 +3029,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (toggleCols)
     {
-      if (viewport.getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns())
       {
         hideSelColumns_actionPerformed(null);
         if (!toggleSeqs)
@@ -3629,34 +3633,50 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isPopupTrigger())
+            if (evt.isPopupTrigger()) // Mac
             {
-              radioItem.removeActionListener(radioItem.getActionListeners()[0]);
+              offerRemoval(radioItem);
+            }
+          }
 
-              int option = JOptionPane.showInternalConfirmDialog(
-                      jalview.gui.Desktop.desktop,
-                      MessageManager
-                              .getString("label.remove_from_default_list"),
-                      MessageManager
-                              .getString("label.remove_user_defined_colour"),
-                      JOptionPane.YES_NO_OPTION);
-              if (option == JOptionPane.YES_OPTION)
-              {
-                jalview.gui.UserDefinedColours
-                        .removeColourFromDefaults(radioItem.getText());
-                colourMenu.remove(radioItem);
-              }
-              else
+          @Override
+          public void mouseReleased(MouseEvent evt)
+          {
+            if (evt.isPopupTrigger()) // Windows
+            {
+              offerRemoval(radioItem);
+            }
+          }
+
+          /**
+           * @param radioItem
+           */
+          void offerRemoval(final JRadioButtonMenuItem radioItem)
+          {
+            radioItem.removeActionListener(radioItem.getActionListeners()[0]);
+
+            int option = JOptionPane.showInternalConfirmDialog(
+                    jalview.gui.Desktop.desktop, MessageManager
+                            .getString("label.remove_from_default_list"),
+                    MessageManager
+                            .getString("label.remove_user_defined_colour"),
+                    JOptionPane.YES_NO_OPTION);
+            if (option == JOptionPane.YES_OPTION)
+            {
+              jalview.gui.UserDefinedColours
+                      .removeColourFromDefaults(radioItem.getText());
+              colourMenu.remove(radioItem);
+            }
+            else
+            {
+              radioItem.addActionListener(new ActionListener()
               {
-                radioItem.addActionListener(new ActionListener()
+                @Override
+                public void actionPerformed(ActionEvent evt)
                 {
-                  @Override
-                  public void actionPerformed(ActionEvent evt)
-                  {
-                    userDefinedColour_actionPerformed(evt);
-                  }
-                });
-              }
+                  userDefinedColour_actionPerformed(evt);
+                }
+              });
             }
           }
         });
@@ -4630,14 +4650,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
     AlignmentI dataset = viewport.getAlignment().getDataset();
+
+    showProducts.removeAll();
+    final boolean dna = viewport.getAlignment().isNucleotide();
+
+    if (seqs == null || seqs.length == 0)
+    {
+      // nothing to see here.
+      return false;
+    }
+
     boolean showp = false;
     try
     {
-      showProducts.removeAll();
-      final boolean dna = viewport.getAlignment().isNucleotide();
-      List<String> ptypes = (seqs == null || seqs.length == 0) ? null
-              : new CrossRef(seqs, dataset)
-                      .findXrefSourcesForSequences(dna);
+      List<String> ptypes = new CrossRef(seqs, dataset)
+              .findXrefSourcesForSequences(dna);
 
       for (final String source : ptypes)
       {
@@ -4680,236 +4707,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showProductsFor(final SequenceI[] sel,
           final boolean _odna, final String source)
   {
-    Runnable foo = new Runnable()
-    {
-
-      @Override
-      public void run()
-      {
-        final long sttime = System.currentTimeMillis();
-        AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                "status.searching_for_sequences_from",
-                new Object[] { source }), sttime);
-        try
-        {
-          AlignmentI alignment = AlignFrame.this.getViewport()
-                  .getAlignment();
-          AlignmentI dataset = alignment.getDataset() == null ? alignment
-                  : alignment.getDataset();
-          boolean dna = alignment.isNucleotide();
-          if (_odna != dna)
-          {
-            System.err
-                    .println("Conflict: showProducts for alignment originally "
-                            + "thought to be "
-                            + (_odna ? "DNA" : "Protein")
-                            + " now searching for "
-                            + (dna ? "DNA" : "Protein") + " Context.");
-          }
-          AlignmentI xrefs = new CrossRef(sel, dataset).findXrefSequences(
-                  source, dna);
-          if (xrefs == null)
-          {
-            return;
-          }
-          /*
-           * get display scheme (if any) to apply to features
-           */
-          FeatureSettingsModelI featureColourScheme = new SequenceFetcher()
-                  .getFeatureColourScheme(source);
-
-          AlignmentI xrefsAlignment = makeCrossReferencesAlignment(dataset,
-                  xrefs);
-          if (!dna)
-          {
-            xrefsAlignment = AlignmentUtils.makeCdsAlignment(
-                    xrefsAlignment.getSequencesArray(), dataset, sel);
-            xrefsAlignment.alignAs(alignment);
-          }
-
-          /*
-           * If we are opening a splitframe, make a copy of this alignment (sharing the same dataset
-           * sequences). If we are DNA, drop introns and update mappings
-           */
-          AlignmentI copyAlignment = null;
-
-          if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
-          {
-            boolean copyAlignmentIsAligned = false;
-            if (dna)
-            {
-              copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset,
-                      xrefsAlignment.getSequencesArray());
-              if (copyAlignment.getHeight() == 0)
-              {
-                JOptionPane.showMessageDialog(AlignFrame.this,
-                        MessageManager.getString("label.cant_map_cds"),
-                        MessageManager.getString("label.operation_failed"),
-                        JOptionPane.OK_OPTION);
-                System.err.println("Failed to make CDS alignment");
-              }
-
-              /*
-               * pending getting Embl transcripts to 'align', 
-               * we are only doing this for Ensembl
-               */
-              // TODO proper criteria for 'can align as cdna'
-              if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
-                      || AlignmentUtils.looksLikeEnsembl(alignment))
-              {
-                copyAlignment.alignAs(alignment);
-                copyAlignmentIsAligned = true;
-              }
-            }
-            else
-            {
-              copyAlignment = AlignmentUtils.makeCopyAlignment(sel,
-                      xrefs.getSequencesArray(), dataset);
-            }
-            copyAlignment.setGapCharacter(AlignFrame.this.viewport
-                    .getGapCharacter());
-
-            StructureSelectionManager ssm = StructureSelectionManager
-                    .getStructureSelectionManager(Desktop.instance);
-
-            /*
-             * register any new mappings for sequence mouseover etc
-             * (will not duplicate any previously registered mappings)
-             */
-            ssm.registerMappings(dataset.getCodonFrames());
-
-            if (copyAlignment.getHeight() <= 0)
-            {
-              System.err.println("No Sequences generated for xRef type "
-                      + source);
-              return;
-            }
-            /*
-             * align protein to dna
-             */
-            if (dna && copyAlignmentIsAligned)
-            {
-              xrefsAlignment.alignAs(copyAlignment);
-            }
-            else
-            {
-              /*
-               * align cdna to protein - currently only if 
-               * fetching and aligning Ensembl transcripts!
-               */
-              // TODO: generalise for other sources of locus/transcript/cds data
-              if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source))
-              {
-                copyAlignment.alignAs(xrefsAlignment);
-              }
-            }
-          }
-          /*
-           * build AlignFrame(s) according to available alignment data
-           */
-          AlignFrame newFrame = new AlignFrame(xrefsAlignment,
-                  DEFAULT_WIDTH, DEFAULT_HEIGHT);
-          if (Cache.getDefault("HIDE_INTRONS", true))
-          {
-            newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false);
-          }
-          String newtitle = String.format("%s %s %s",
-                  dna ? MessageManager.getString("label.proteins")
-                          : MessageManager.getString("label.nucleotides"),
-                  MessageManager.getString("label.for"), getTitle());
-          newFrame.setTitle(newtitle);
-
-          if (copyAlignment == null)
-          {
-            /*
-             * split frame display is turned off in preferences file
-             */
-            Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH,
-                    DEFAULT_HEIGHT);
-            return; // via finally clause
-          }
-          AlignFrame copyThis = new AlignFrame(copyAlignment,
-                  AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
-          copyThis.setTitle(AlignFrame.this.getTitle());
-
-          boolean showSequenceFeatures = viewport.isShowSequenceFeatures();
-          newFrame.setShowSeqFeatures(showSequenceFeatures);
-          copyThis.setShowSeqFeatures(showSequenceFeatures);
-          FeatureRenderer myFeatureStyling = alignPanel.getSeqPanel().seqCanvas
-                  .getFeatureRenderer();
-
-          /*
-           * copy feature rendering settings to split frame
-           */
-          newFrame.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .transferSettings(myFeatureStyling);
-          copyThis.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .transferSettings(myFeatureStyling);
-
-          /*
-           * apply 'database source' feature configuration
-           * if any was found
-           */
-          // TODO is this the feature colouring for the original
-          // alignment or the fetched xrefs? either could be Ensembl
-          newFrame.getViewport().applyFeaturesStyle(featureColourScheme);
-          copyThis.getViewport().applyFeaturesStyle(featureColourScheme);
-
-          SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame,
-                  dna ? newFrame : copyThis);
-          newFrame.setVisible(true);
-          copyThis.setVisible(true);
-          String linkedTitle = MessageManager
-                  .getString("label.linked_view_title");
-          Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
-          sf.adjustDivider();
-        } catch (OutOfMemoryError e)
-        {
-          new OOMWarning("whilst fetching crossreferences", e);
-        } catch (Throwable e)
-        {
-          Cache.log.error("Error when finding crossreferences", e);
-        } finally
-        {
-          AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                  "status.finished_searching_for_sequences_from",
-                  new Object[] { source }), sttime);
-        }
-      }
-
-      /**
-       * Makes an alignment containing the given sequences, and adds them to the
-       * given dataset, which is also set as the dataset for the new alignment
-       * 
-       * TODO: refactor to DatasetI method
-       * 
-       * @param dataset
-       * @param seqs
-       * @return
-       */
-      protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset,
-              AlignmentI seqs)
-      {
-        SequenceI[] sprods = new SequenceI[seqs.getHeight()];
-        for (int s = 0; s < sprods.length; s++)
-        {
-          sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
-          if (dataset.getSequences() == null
-                  || !dataset.getSequences().contains(
-                          sprods[s].getDatasetSequence()))
-          {
-            dataset.addSequence(sprods[s].getDatasetSequence());
-          }
-          sprods[s].updatePDBIds();
-        }
-        Alignment al = new Alignment(sprods);
-        al.setDataset(dataset);
-        return al;
-      }
-
-    };
-    Thread frunner = new Thread(foo);
-    frunner.start();
+    new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this))
+            .start();
   }
 
   /**
@@ -5031,6 +4830,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void drop(DropTargetDropEvent evt)
   {
+    // JAL-1552 - acceptDrop required before getTransferable call for
+    // Java's Transferable for native dnd
+    evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
     List<String> files = new ArrayList<String>();
     List<DataSourceType> protocols = new ArrayList<DataSourceType>();
@@ -5099,7 +4901,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               }
               if (type != null)
               {
-                if (FileFormat.PDB.equals(type))
+                if (FileFormat.PDB.equals(type) || FileFormat.MMCif.equals(type))
                 {
                   filesmatched.add(new Object[] { file, protocol, mtch });
                   continue;
@@ -5119,14 +4921,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                   this,
                                   MessageManager
                                           .formatMessage(
-                                                  "label.automatically_associate_pdb_files_with_sequences_same_name",
+                                                  "label.automatically_associate_structure_files_with_sequences_same_name",
                                                   new Object[] { Integer
                                                           .valueOf(
                                                                   filesmatched
                                                                           .size())
                                                           .toString() }),
                                   MessageManager
-                                          .getString("label.automatically_associate_pdb_files_by_name"),
+                                          .getString("label.automatically_associate_structure_files_by_name"),
                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
 
           {
@@ -6145,6 +5947,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     return false;
   }
+
+  @Override
+  protected void selectHighlightedColumns_actionPerformed(
+          ActionEvent actionEvent)
+  {
+    // include key modifier check in case user selects from menu
+    avc.markHighlightedColumns(
+            (actionEvent.getModifiers() & ActionEvent.ALT_MASK) != 0,
+            true,
+            (actionEvent.getModifiers() & (ActionEvent.META_MASK | ActionEvent.CTRL_MASK)) != 0);
+  }
 }
 
 class PrintThread extends Thread
index d4d2054..fb2a8ef 100644 (file)
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-/*
- * Jalview - A Sequence Alignment Editor and Viewer
- * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
- *
- * This program 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 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
 package jalview.gui;
 
 import jalview.analysis.AlignmentUtils;
@@ -55,6 +37,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -419,10 +402,11 @@ public class AlignViewport extends AlignmentViewport implements
    * @param align
    *          DOCUMENT ME!
    */
+  @Override
   public void setAlignment(AlignmentI align)
   {
     replaceMappings(align);
-    this.alignment = align;
+    super.setAlignment(align);
   }
 
   /**
@@ -675,7 +659,8 @@ public class AlignViewport extends AlignmentViewport implements
       List<SequenceI> choosenSeqs = new ArrayList<SequenceI>();
       for (SequenceI sq : alignment.getSequences())
       {
-        Vector<PDBEntry> pdbRefEntries = sq.getDatasetSequence().getAllPDBEntries();
+        Vector<PDBEntry> pdbRefEntries = sq.getDatasetSequence()
+                .getAllPDBEntries();
         if (pdbRefEntries == null)
         {
           continue;
@@ -707,7 +692,8 @@ public class AlignViewport extends AlignmentViewport implements
           }
         }
       }
-      seqvectors.add(choosenSeqs.toArray(new SequenceI[choosenSeqs.size()]));
+      seqvectors
+              .add(choosenSeqs.toArray(new SequenceI[choosenSeqs.size()]));
     }
     return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
   }
@@ -1057,7 +1043,7 @@ public class AlignViewport extends AlignmentViewport implements
      * there is no complement, or it is not following highlights, or no mapping
      * is found, the result will be empty.
      */
-    SearchResults sr = new SearchResults();
+    SearchResultsI sr = new SearchResults();
     int verticalOffset = findComplementScrollTarget(sr);
     if (!sr.isEmpty())
     {
index 87d5933..e61b042 100644 (file)
@@ -25,7 +25,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -101,6 +101,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   private boolean dontScrollComplement;
 
+  private PropertyChangeListener propertyChangeListener;
+
   /**
    * Creates a new AlignmentPanel object.
    * 
@@ -135,7 +137,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     vscroll.addAdjustmentListener(this);
 
     final AlignmentPanel ap = this;
-    av.addPropertyChangeListener(new PropertyChangeListener()
+    propertyChangeListener = new PropertyChangeListener()
     {
       @Override
       public void propertyChange(PropertyChangeEvent evt)
@@ -146,7 +148,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
           alignmentChanged();
         }
       }
-    });
+    };
+    av.addPropertyChangeListener(propertyChangeListener);
     fontChanged();
     adjustAnnotationHeight();
     updateLayout();
@@ -294,7 +297,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * Highlight the given results on the alignment.
    * 
    */
-  public void highlightSearchResults(SearchResults results)
+  public void highlightSearchResults(SearchResultsI results)
   {
     scrollToPosition(results);
     getSeqPanel().seqCanvas.highlightSearchResults(results);
@@ -306,7 +309,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * 
    * @param results
    */
-  public boolean scrollToPosition(SearchResults results)
+  public boolean scrollToPosition(SearchResultsI results)
   {
     return scrollToPosition(results, 0, true, false);
   }
@@ -319,7 +322,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param redrawOverview
    * @return
    */
-  public boolean scrollToPosition(SearchResults searchResults,
+  public boolean scrollToPosition(SearchResultsI searchResults,
           boolean redrawOverview)
   {
     return scrollToPosition(searchResults, 0, redrawOverview, false);
@@ -339,7 +342,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    *          if true, try to centre the search results horizontally in the view
    * @return false if results were not found
    */
-  public boolean scrollToPosition(SearchResults results,
+  public boolean scrollToPosition(SearchResultsI results,
           int verticalOffset, boolean redrawOverview, boolean centre)
   {
     int startv, endv, starts, ends;
@@ -953,11 +956,11 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     if (av.getWrapAlignment())
     {
-      return printWrappedAlignment(pg, pwidth, pheight, pi);
+      return printWrappedAlignment(pwidth, pheight, pi, pg);
     }
     else
     {
-      return printUnwrapped(pg, pwidth, pheight, pi);
+      return printUnwrapped(pwidth, pheight, pi, pg, pg);
     }
   }
 
@@ -978,84 +981,103 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @throws PrinterException
    *           DOCUMENT ME!
    */
-  public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi)
+  /**
+   * Draws the alignment image, including sequence ids, sequences, and
+   * annotation labels and annotations if shown, on either one or two Graphics
+   * context.
+   * 
+   * @param pageWidth
+   * @param pageHeight
+   * @param pi
+   * @param idGraphics
+   *          the graphics context for sequence ids and annotation labels
+   * @param alignmentGraphics
+   *          the graphics context for sequences and annotations (may or may not
+   *          be the same context as idGraphics)
+   * @return
+   * @throws PrinterException
+   */
+  public int printUnwrapped(int pageWidth, int pageHeight, int pi,
+          Graphics idGraphics, Graphics alignmentGraphics)
           throws PrinterException
   {
-    int idWidth = getVisibleIdWidth(false);
-    FontMetrics fm = getFontMetrics(av.getFont());
-    int scaleHeight = av.getCharHeight() + fm.getDescent();
+    final int idWidth = getVisibleIdWidth(false);
 
-    pg.setColor(Color.white);
-    pg.fillRect(0, 0, pwidth, pheight);
-    pg.setFont(av.getFont());
-
-    // //////////////////////////////////
-    // / How many sequences and residues can we fit on a printable page?
-    int totalRes = (pwidth - idWidth) / av.getCharWidth();
+    /*
+     * Get the horizontal offset to where we draw the sequences.
+     * This is idWidth if using a single Graphics context, else zero.
+     */
+    final int alignmentGraphicsOffset = idGraphics != alignmentGraphics ? 0 : idWidth;
 
-    int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1;
+    FontMetrics fm = getFontMetrics(av.getFont());
+    int charHeight = av.getCharHeight();
+    int scaleHeight = charHeight + fm.getDescent();
 
-    int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1;
+    idGraphics.setColor(Color.white);
+    idGraphics.fillRect(0, 0, pageWidth, pageHeight);
+    idGraphics.setFont(av.getFont());
 
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int startRes;
+    /*
+     * How many sequences and residues can we fit on a printable page?
+     */
+    int totalRes = (pageWidth - idWidth) / av.getCharWidth();
 
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int endRes;
+    int totalSeq = (pageHeight - scaleHeight) / charHeight - 1;
 
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int startSeq;
+    int alignmentWidth = av.getAlignment().getWidth();
+    int pagesWide = (alignmentWidth / totalRes) + 1;
 
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int endSeq;
-    startRes = (pi % pagesWide) * totalRes;
-    endRes = (startRes + totalRes) - 1;
+    final int startRes = (pi % pagesWide) * totalRes;
+    int endRes = (startRes + totalRes) - 1;
 
-    if (endRes > (av.getAlignment().getWidth() - 1))
+    if (endRes > (alignmentWidth - 1))
     {
-      endRes = av.getAlignment().getWidth() - 1;
+      endRes = alignmentWidth - 1;
     }
 
-    startSeq = (pi / pagesWide) * totalSeq;
-    endSeq = startSeq + totalSeq;
+    final int startSeq = (pi / pagesWide) * totalSeq;
+    int endSeq = startSeq + totalSeq;
 
-    if (endSeq > av.getAlignment().getHeight())
+    int alignmentHeight = av.getAlignment().getHeight();
+    if (endSeq > alignmentHeight)
     {
-      endSeq = av.getAlignment().getHeight();
+      endSeq = alignmentHeight;
     }
 
-    int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1)
-            * pheight;
+    int pagesHigh = ((alignmentHeight / totalSeq) + 1)
+            * pageHeight;
 
     if (av.isShowAnnotation())
     {
       pagesHigh += getAnnotationPanel().adjustPanelHeight() + 3;
     }
 
-    pagesHigh /= pheight;
+    pagesHigh /= pageHeight;
 
     if (pi >= (pagesWide * pagesHigh))
     {
       return Printable.NO_SUCH_PAGE;
     }
+    final int alignmentDrawnHeight = (endSeq - startSeq) * charHeight
+            + 3;
 
-    // draw Scale
-    pg.translate(idWidth, 0);
-    getScalePanel().drawScale(pg, startRes, endRes, pwidth - idWidth,
-            scaleHeight);
-    pg.translate(-idWidth, scaleHeight);
+    /*
+     * draw the Scale at horizontal offset, then reset to top left (0, 0)
+     */
+    alignmentGraphics.translate(alignmentGraphicsOffset, 0);
+    getScalePanel().drawScale(alignmentGraphics, startRes, endRes,
+            pageWidth - idWidth, scaleHeight);
+    alignmentGraphics.translate(-alignmentGraphicsOffset, 0);
 
-    // //////////////
-    // Draw the ids
+    /*
+     * Draw the sequence ids, offset for scale height,
+     * then reset to top left (0, 0)
+     */
+    idGraphics.translate(0, scaleHeight);
+    idGraphics.setFont(getIdPanel().getIdCanvas().getIdfont());
     Color currentColor = null;
     Color currentTextColor = null;
 
-    pg.setFont(getIdPanel().getIdCanvas().getIdfont());
-
     SequenceI seq;
     for (int i = startSeq; i < endSeq; i++)
     {
@@ -1063,6 +1085,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
       if ((av.getSelectionGroup() != null)
               && av.getSelectionGroup().getSequences(null).contains(seq))
       {
+        /*
+         * gray out ids of sequences in selection group (if any)
+         */
         currentColor = Color.gray;
         currentTextColor = Color.black;
       }
@@ -1072,45 +1097,58 @@ public class AlignmentPanel extends GAlignmentPanel implements
         currentTextColor = Color.black;
       }
 
-      pg.setColor(currentColor);
-      pg.fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
-              av.getCharHeight());
+      idGraphics.setColor(currentColor);
+      idGraphics.fillRect(0, (i - startSeq) * charHeight, idWidth,
+              charHeight);
 
-      pg.setColor(currentTextColor);
+      idGraphics.setColor(currentTextColor);
 
       int xPos = 0;
+      String displayId = seq.getDisplayId(av.getShowJVSuffix());
       if (av.isRightAlignIds())
       {
-        fm = pg.getFontMetrics();
+        fm = idGraphics.getFontMetrics();
         xPos = idWidth
-                - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix()))
+                - fm.stringWidth(displayId)
                 - 4;
       }
 
-      pg.drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos,
-              (((i - startSeq) * av.getCharHeight()) + av.getCharHeight())
-                      - (av.getCharHeight() / 5));
+      idGraphics.drawString(displayId, xPos,
+              (((i - startSeq) * charHeight) + charHeight)
+                      - (charHeight / 5));
     }
+    idGraphics.setFont(av.getFont());
+    idGraphics.translate(0, -scaleHeight);
 
-    pg.setFont(av.getFont());
+    /*
+     * draw the sequences, offset for scale height, and id width (if using a
+     * single graphics context), then reset to (0, scale height)
+     */
+    alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight);
+    getSeqPanel().seqCanvas.drawPanel(alignmentGraphics, startRes, endRes,
+            startSeq, endSeq, 0);
+    alignmentGraphics.translate(-alignmentGraphicsOffset, 0);
 
-    // draw main sequence panel
-    pg.translate(idWidth, 0);
-    getSeqPanel().seqCanvas.drawPanel(pg, startRes, endRes, startSeq,
-            endSeq, 0);
-
-    if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight()))
-    {
-      // draw annotation - need to offset for current scroll position
-      int offset = -getAlabels().getScrollOffset();
-      pg.translate(0, offset);
-      pg.translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight()
-              + 3);
-      getAlabels().drawComponent(pg, idWidth);
-      pg.translate(idWidth + 3, 0);
+    if (av.isShowAnnotation() && (endSeq == alignmentHeight))
+    {
+      /*
+       * draw annotation labels; drawComponent() translates by
+       * getScrollOffset(), so compensate for that first;
+       * then reset to (0, scale height)
+       */
+      int offset = getAlabels().getScrollOffset();
+      idGraphics.translate(0, -offset);
+      idGraphics.translate(0, alignmentDrawnHeight);
+      getAlabels().drawComponent(idGraphics, idWidth);
+      idGraphics.translate(0, -alignmentDrawnHeight);
+
+      /*
+       * draw the annotations starting at 
+       * (idOffset, alignmentHeight) from (0, scaleHeight)
+       */
+      alignmentGraphics.translate(alignmentGraphicsOffset, alignmentDrawnHeight);
       getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av,
-              pg, -1, startRes, endRes + 1);
-      pg.translate(0, -offset);
+              alignmentGraphics, -1, startRes, endRes + 1);
     }
 
     return Printable.PAGE_EXISTS;
@@ -1133,8 +1171,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @throws PrinterException
    *           DOCUMENT ME!
    */
-  public int printWrappedAlignment(Graphics pg, int pwidth, int pheight,
-          int pi) throws PrinterException
+  public int printWrappedAlignment(int pwidth, int pheight, int pi,
+          Graphics pg) throws PrinterException
   {
     int annotationHeight = 0;
     AnnotationLabels labels = null;
@@ -1261,8 +1299,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     if (onscreen
             || (idwidth = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null)
     {
-      return (getIdPanel().getWidth() > 0 ? getIdPanel().getWidth()
-              : calculateIdWidth().width + 4);
+      int w = getIdPanel().getWidth();
+      return (w > 0 ? w : calculateIdWidth().width + 4);
     }
     return idwidth.intValue() + 4;
   }
@@ -1278,7 +1316,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       if (file != null)
       {
         alignFrame.setProgressBar(MessageManager.formatMessage(
-              "status.saving_file", new Object[] { type.getLabel() }),
+                "status.saving_file", new Object[] { type.getLabel() }),
                 pSessionId);
       }
     }
@@ -1307,23 +1345,25 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
         im = new jalview.util.ImageMaker(this, type, imageAction,
                 aDimension.getWidth(), aDimension.getHeight()
-                        + boarderBottomOffset, file,
-                imageTitle, alignFrame, pSessionId, headless);
+                        + boarderBottomOffset, file, imageTitle,
+                alignFrame, pSessionId, headless);
+        Graphics graphics = im.getGraphics();
         if (av.getWrapAlignment())
         {
-          if (im.getGraphics() != null)
+          if (graphics != null)
           {
-            printWrappedAlignment(im.getGraphics(), aDimension.getWidth(),
-                    aDimension.getHeight() + boarderBottomOffset, 0);
+            printWrappedAlignment(aDimension.getWidth(),
+                    aDimension.getHeight() + boarderBottomOffset, 0,
+                    graphics);
             im.writeImage();
           }
         }
         else
         {
-          if (im.getGraphics() != null)
+          if (graphics != null)
           {
-            printUnwrapped(im.getGraphics(), aDimension.getWidth(),
-                    aDimension.getHeight(), 0);
+            printUnwrapped(aDimension.getWidth(), aDimension.getHeight(),
+                    0, graphics, graphics);
             im.writeImage();
           }
         }
@@ -1408,7 +1448,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   public void makePNGImageMap(File imgMapFile, String imageName)
   {
-    // /////ONLY WORKS WITH NONE WRAPPED ALIGNMENTS
+    // /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS
     // ////////////////////////////////////////////
     int idWidth = getVisibleIdWidth(false);
     FontMetrics fm = getFontMetrics(av.getFont());
@@ -1422,7 +1462,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
       {
         int s, sSize = av.getAlignment().getHeight(), res, alwidth = av
                 .getAlignment().getWidth(), g, gSize, f, fSize, sy;
-        StringBuffer text = new StringBuffer();
         PrintWriter out = new PrintWriter(new FileWriter(imgMapFile));
         out.println(jalview.io.HTMLOutput.getImageMapHTML());
         out.println("<img src=\"" + imageName
@@ -1438,7 +1477,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           SequenceGroup[] groups = av.getAlignment().findAllGroups(seq);
           for (res = 0; res < alwidth; res++)
           {
-            text = new StringBuffer();
+            StringBuilder text = new StringBuilder();
             String triplet = null;
             if (av.getAlignment().isNucleotide())
             {
@@ -1462,18 +1501,20 @@ public class AlignmentPanel extends GAlignmentPanel implements
             {
               if (text.length() < 1)
               {
-                text.append("<area shape=\"rect\" coords=\""
-                        + (idWidth + res * av.getCharWidth()) + "," + sy
-                        + "," + (idWidth + (res + 1) * av.getCharWidth())
-                        + "," + (av.getCharHeight() + sy) + "\""
-                        + " onMouseOver=\"toolTip('" + alIndex + " "
-                        + triplet);
+                text.append("<area shape=\"rect\" coords=\"")
+                        .append((idWidth + res * av.getCharWidth()))
+                        .append(",").append(sy).append(",")
+                        .append((idWidth + (res + 1) * av.getCharWidth()))
+                        .append(",").append((av.getCharHeight() + sy))
+                        .append("\"").append(" onMouseOver=\"toolTip('")
+                        .append(alIndex).append(" ").append(triplet);
               }
 
               if (groups[g].getStartRes() < res
                       && groups[g].getEndRes() > res)
               {
-                text.append("<br><em>" + groups[g].getName() + "</em>");
+                text.append("<br><em>").append(groups[g].getName())
+                        .append("</em>");
               }
             }
 
@@ -1481,12 +1522,13 @@ public class AlignmentPanel extends GAlignmentPanel implements
             {
               if (text.length() < 1)
               {
-                text.append("<area shape=\"rect\" coords=\""
-                        + (idWidth + res * av.getCharWidth()) + "," + sy
-                        + "," + (idWidth + (res + 1) * av.getCharWidth())
-                        + "," + (av.getCharHeight() + sy) + "\""
-                        + " onMouseOver=\"toolTip('" + alIndex + " "
-                        + triplet);
+                text.append("<area shape=\"rect\" coords=\"")
+                        .append((idWidth + res * av.getCharWidth()))
+                        .append(",").append(sy).append(",")
+                        .append((idWidth + (res + 1) * av.getCharWidth()))
+                        .append(",").append((av.getCharHeight() + sy))
+                        .append("\"").append(" onMouseOver=\"toolTip('")
+                        .append(alIndex).append(" ").append(triplet);
               }
               fSize = features.length;
               for (f = 0; f < fSize; f++)
@@ -1495,15 +1537,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
                 if ((features[f].getBegin() <= seq.findPosition(res))
                         && (features[f].getEnd() >= seq.findPosition(res)))
                 {
-                  if (features[f].getType().equals("disulfide bond"))
+                  if (features[f].isContactFeature())
                   {
                     if (features[f].getBegin() == seq.findPosition(res)
                             || features[f].getEnd() == seq
                                     .findPosition(res))
                     {
-                      text.append("<br>disulfide bond "
-                              + features[f].getBegin() + ":"
-                              + features[f].getEnd());
+                      text.append("<br>").append(features[f].getType())
+                              .append(" ").append(features[f].getBegin())
+                              .append(":").append(features[f].getEnd());
                     }
                   }
                   else
@@ -1514,13 +1556,13 @@ public class AlignmentPanel extends GAlignmentPanel implements
                             && !features[f].getType().equals(
                                     features[f].getDescription()))
                     {
-                      text.append(" " + features[f].getDescription());
+                      text.append(" ").append(features[f].getDescription());
                     }
 
                     if (features[f].getValue("status") != null)
                     {
-                      text.append(" (" + features[f].getValue("status")
-                              + ")");
+                      text.append(" (").append(features[f].getValue("status"))
+                              .append(")");
                     }
                   }
                 }
@@ -1595,8 +1637,18 @@ public class AlignmentPanel extends GAlignmentPanel implements
     PaintRefresher.RemoveComponent(getSeqPanel().seqCanvas);
     PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas());
     PaintRefresher.RemoveComponent(this);
+
+    /*
+     * try to ensure references are nulled
+     */
+    if (annotationPanel != null)
+    {
+      annotationPanel.dispose();
+    }
+
     if (av != null)
     {
+      av.removePropertyChangeListener(propertyChangeListener);
       jalview.structure.StructureSelectionManager ssm = av
               .getStructureSelectionManager();
       ssm.removeStructureViewerListener(getSeqPanel(), null);
@@ -1604,7 +1656,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       ssm.removeCommandListener(av);
       ssm.removeStructureViewerListener(getSeqPanel(), null);
       ssm.removeSelectionListener(getSeqPanel());
-      av.setAlignment(null);
+      av.dispose();
       av = null;
     }
     else
@@ -1775,14 +1827,14 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param verticalOffset
    *          the number of visible sequences to show above the mapped region
    */
-  public void scrollToCentre(SearchResults sr, int verticalOffset)
+  public void scrollToCentre(SearchResultsI sr, int verticalOffset)
   {
     /*
      * To avoid jumpy vertical scrolling (if some sequences are gapped or not
      * mapped), we can make the scroll-to location a sequence above the one
      * actually mapped.
      */
-    SequenceI mappedTo = sr.getResultSequence(0);
+    SequenceI mappedTo = sr.getResults().get(0).getSequence();
     List<SequenceI> seqs = av.getAlignment().getSequences();
 
     /*
index 93c9a6b..39cde03 100644 (file)
@@ -210,7 +210,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        ok_actionPerformed(e);
+        ok_actionPerformed();
       }
     });
     cancel.setOpaque(false);
@@ -220,7 +220,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        cancel_actionPerformed(e);
+        cancel_actionPerformed();
       }
     });
     defColours.setOpaque(false);
@@ -233,7 +233,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
-        resetColours_actionPerformed(arg0);
+        resetColours_actionPerformed();
       }
     });
 
@@ -242,7 +242,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        annotations_actionPerformed(e);
+        annotations_actionPerformed();
       }
     });
     getThreshold().addActionListener(new ActionListener()
@@ -250,7 +250,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        threshold_actionPerformed(e);
+        threshold_actionPerformed();
       }
     });
     thresholdValue.addActionListener(new ActionListener()
@@ -258,7 +258,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        thresholdValue_actionPerformed(e);
+        thresholdValue_actionPerformed();
       }
     });
     slider.setPaintLabels(false);
@@ -278,7 +278,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        currentColours_actionPerformed(e);
+        currentColours_actionPerformed();
       }
     });
     thresholdIsMin.setBackground(Color.white);
@@ -290,7 +290,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent actionEvent)
       {
-        thresholdIsMin_actionPerformed(actionEvent);
+        thresholdIsMin_actionPerformed();
       }
     });
     seqAssociated.setBackground(Color.white);
@@ -303,7 +303,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
-        seqAssociated_actionPerformed(arg0, annotations, seqAssociated);
+        seqAssociated_actionPerformed(annotations);
       }
     });
 
@@ -332,7 +332,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     this.validate();
   }
 
-  protected void resetColours_actionPerformed(ActionEvent arg0)
+  protected void resetColours_actionPerformed()
   {
     setDefaultMinMax();
     updateView();
@@ -372,6 +372,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     updateView();
   }
 
+  @Override
   public void reset()
   {
     av.setGlobalColourScheme(oldcs);
@@ -385,6 +386,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     }
   }
 
+  @Override
   public void valueChanged(boolean updateAllAnnotation)
   {
     if (slider.isEnabled())
@@ -411,7 +413,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
     this.threshold = threshold;
   }
 
-  public void currentColours_actionPerformed(ActionEvent e)
+  public void currentColours_actionPerformed()
   {
     if (currentColours.isSelected())
     {
index c0d7084..1290d70 100644 (file)
@@ -178,7 +178,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        ok_actionPerformed(e);
+        ok_actionPerformed();
       }
     });
 
@@ -189,7 +189,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        cancel_actionPerformed(e);
+        cancel_actionPerformed();
       }
     });
 
@@ -201,7 +201,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        threshold_actionPerformed(e);
+        threshold_actionPerformed();
       }
     });
 
@@ -212,7 +212,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        thresholdValue_actionPerformed(e);
+        thresholdValue_actionPerformed();
       }
     });
 
@@ -288,14 +288,15 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     String defaultTtip = MessageManager
             .getString("info.change_threshold_mode_to_enable");
 
-    String threshold = getThreshold().getSelectedItem().toString();
-    if (threshold.equalsIgnoreCase("No Threshold"))
+    String thresh = getThreshold().getSelectedItem().toString();
+    if (thresh.equalsIgnoreCase("No Threshold"))
     {
       thresholdValue.setToolTipText(defaultTtip);
       slider.setToolTipText(defaultTtip);
     }
   }
 
+  @Override
   public void reset()
   {
     if (this.getOldColumnSelection() != null)
@@ -324,6 +325,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
 
   }
 
+  @Override
   public void valueChanged(boolean updateAllAnnotation)
   {
     if (slider.isEnabled())
index 469e495..0d47e36 100644 (file)
@@ -174,7 +174,8 @@ public class AnnotationExporter extends JPanel
       else
       {
         text = new FeaturesFile().printJalviewFormat(ap.av.getAlignment()
-                .getDataset().getSequencesArray(), displayedFeatureColours, true, ap.av.isShowNPFeats()); // ap.av.featuresDisplayed);
+                .getDataset().getSequencesArray(), displayedFeatureColours,
+                true, ap.av.isShowNPFeats()); // ap.av.featuresDisplayed);
         text = formatter.printJalviewFormat(sequences, featureColours,
                 true, includeNonPositional);
       }
index d497488..4b774d6 100755 (executable)
@@ -220,6 +220,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     AlignmentAnnotation[] aa = ap.av.getAlignment()
             .getAlignmentAnnotation();
 
+    boolean fullRepaint = false;
     if (evt.getActionCommand().equals(ADDNEW))
     {
       AlignmentAnnotation newAnnotation = new AlignmentAnnotation(null,
@@ -232,11 +233,16 @@ public class AnnotationLabels extends JPanel implements MouseListener,
 
       ap.av.getAlignment().addAnnotation(newAnnotation);
       ap.av.getAlignment().setAnnotationIndex(newAnnotation, 0);
+      fullRepaint = true;
     }
     else if (evt.getActionCommand().equals(EDITNAME))
     {
+      String name = aa[selectedRow].label;
       editLabelDescription(aa[selectedRow]);
-      repaint();
+      if (!name.equalsIgnoreCase(aa[selectedRow].label))
+      {
+        fullRepaint = true;
+      }
     }
     else if (evt.getActionCommand().equals(HIDE))
     {
@@ -246,6 +252,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     {
       ap.av.getAlignment().deleteAnnotation(aa[selectedRow]);
       ap.av.getCalcManager().removeWorkerForAnnotation(aa[selectedRow]);
+      fullRepaint = true;
     }
     else if (evt.getActionCommand().equals(SHOWALL))
     {
@@ -256,6 +263,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
           aa[i].visible = true;
         }
       }
+      fullRepaint = true;
     }
     else if (evt.getActionCommand().equals(OUTPUT_TEXT))
     {
@@ -284,18 +292,30 @@ public class AnnotationLabels extends JPanel implements MouseListener,
       aa[selectedRow].scaleColLabel = !aa[selectedRow].scaleColLabel;
     }
 
-    refresh();
+    refresh(fullRepaint);
 
   }
 
   /**
    * Redraw sensibly.
+   * 
+   * @adjustHeight if true, try to recalculate panel height for visible
+   *               annotations
    */
-  protected void refresh()
+  protected void refresh(boolean adjustHeight)
   {
-    ap.validateAnnotationDimensions(false);
+    ap.validateAnnotationDimensions(adjustHeight);
     ap.addNotify();
-    ap.repaint();
+    if (adjustHeight)
+    {
+      // sort, repaint, update overview
+      ap.paintAlignment(true);
+    }
+    else
+    {
+      // lightweight repaint
+      ap.repaint();
+    }
   }
 
   /**
@@ -306,6 +326,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
    */
   boolean editLabelDescription(AlignmentAnnotation annotation)
   {
+    // TODO i18n
     EditNameDialog dialog = new EditNameDialog(annotation.label,
             annotation.description, "       Annotation Name ",
             "Annotation Description ", "Edit Annotation Name/Description",
@@ -333,12 +354,20 @@ public class AnnotationLabels extends JPanel implements MouseListener,
   {
     getSelectedRow(evt.getY() - getScrollOffset());
     oldY = evt.getY();
-    if (!evt.isPopupTrigger())
+    if (evt.isPopupTrigger())
     {
-      return;
+      showPopupMenu(evt);
     }
+  }
+
+  /**
+   * Build and show the Pop-up menu at the right-click mouse position
+   * 
+   * @param evt
+   */
+  void showPopupMenu(MouseEvent evt)
+  {
     evt.consume();
-    // handle popup menu event
     final AlignmentAnnotation[] aa = ap.av.getAlignment()
             .getAlignmentAnnotation();
 
@@ -391,7 +420,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
             // ann.visible = false;
             // }
             // }
-            refresh();
+            refresh(true);
           }
         });
         pop.add(hideType);
@@ -453,6 +482,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
             {
               ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
             }
+            ap.alignmentChanged();
           }
         });
         pop.add(cbmi);
@@ -596,7 +626,6 @@ public class AnnotationLabels extends JPanel implements MouseListener,
       }
     }
     pop.show(this, evt.getX(), evt.getY());
-
   }
 
   /**
@@ -608,6 +637,12 @@ public class AnnotationLabels extends JPanel implements MouseListener,
   @Override
   public void mouseReleased(MouseEvent evt)
   {
+    if (evt.isPopupTrigger())
+    {
+      showPopupMenu(evt);
+      return;
+    }
+
     int start = selectedRow;
     getSelectedRow(evt.getY() - getScrollOffset());
     int end = selectedRow;
index 6a621ff..199c4e5 100755 (executable)
@@ -49,6 +49,7 @@ import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.awt.image.BufferedImage;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -122,8 +123,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
   boolean mouseDragging = false;
 
-  boolean MAC = false;
-
   // for editing cursor
   int cursorX = 0;
 
@@ -141,9 +140,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
    */
   public AnnotationPanel(AlignmentPanel ap)
   {
-
-    MAC = jalview.util.Platform.isAMac();
-
     ToolTipManager.sharedInstance().registerComponent(this);
     ToolTipManager.sharedInstance().setInitialDelay(0);
     ToolTipManager.sharedInstance().setDismissDelay(10000);
@@ -445,8 +441,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     StringBuilder collatedInput = new StringBuilder(64);
     String last = "";
     ColumnSelection viscols = av.getColumnSelection();
-    // TODO: refactor and save av.getColumnSelection for efficiency
-    List<Integer> selected = viscols.getSelected();
+
+    /*
+     * the selection list (read-only view) is in selection order, not
+     * column order; make a copy so we can sort it
+     */
+    List<Integer> selected = new ArrayList<Integer>(viscols.getSelected());
     Collections.sort(selected);
     for (int index : selected)
     {
@@ -458,8 +458,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       String tlabel = null;
       if (anots[index] != null)
       { // LML added stem code
-        if (type.equals(HELIX) || type.equals(SHEET)
-                || type.equals(STEM) || type.equals(LABEL))
+        if (type.equals(HELIX) || type.equals(SHEET) || type.equals(STEM)
+                || type.equals(LABEL))
         {
           tlabel = anots[index].description;
           if (tlabel == null || tlabel.length() < 1)
@@ -507,6 +507,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     int height = 0;
     activeRow = -1;
 
+    final int y = evt.getY();
     for (int i = 0; i < aa.length; i++)
     {
       if (aa[i].visible)
@@ -514,7 +515,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         height += aa[i].height;
       }
 
-      if (evt.getY() < height)
+      if (y < height)
       {
         if (aa[i].editable)
         {
@@ -524,58 +525,71 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         {
           // Stretch Graph
           graphStretch = i;
-          graphStretchY = evt.getY();
+          graphStretchY = y;
         }
 
         break;
       }
     }
 
+    /*
+     * isPopupTrigger fires in mousePressed on Mac,
+     * not until mouseRelease on Windows
+     */
     if (evt.isPopupTrigger() && activeRow != -1)
     {
-      if (av.getColumnSelection() == null
-              || av.getColumnSelection().isEmpty())
-      {
-        return;
-      }
+      showPopupMenu(y, evt.getX());
+      return;
+    }
 
-      JPopupMenu pop = new JPopupMenu(
-              MessageManager.getString("label.structure_type"));
-      JMenuItem item;
-      /*
-       * Just display the needed structure options
-       */
-      if (av.getAlignment().isNucleotide())
-      {
-        item = new JMenuItem(STEM);
-        item.addActionListener(this);
-        pop.add(item);
-      }
-      else
-      {
-        item = new JMenuItem(HELIX);
-        item.addActionListener(this);
-        pop.add(item);
-        item = new JMenuItem(SHEET);
-        item.addActionListener(this);
-        pop.add(item);
-      }
-      item = new JMenuItem(LABEL);
+    ap.getScalePanel().mousePressed(evt);
+  }
+
+  /**
+   * Construct and display a context menu at the right-click position
+   * 
+   * @param y
+   * @param x
+   */
+  void showPopupMenu(final int y, int x)
+  {
+    if (av.getColumnSelection() == null
+            || av.getColumnSelection().isEmpty())
+    {
+      return;
+    }
+
+    JPopupMenu pop = new JPopupMenu(
+            MessageManager.getString("label.structure_type"));
+    JMenuItem item;
+    /*
+     * Just display the needed structure options
+     */
+    if (av.getAlignment().isNucleotide())
+    {
+      item = new JMenuItem(STEM);
       item.addActionListener(this);
       pop.add(item);
-      item = new JMenuItem(COLOUR);
+    }
+    else
+    {
+      item = new JMenuItem(HELIX);
       item.addActionListener(this);
       pop.add(item);
-      item = new JMenuItem(REMOVE);
+      item = new JMenuItem(SHEET);
       item.addActionListener(this);
       pop.add(item);
-      pop.show(this, evt.getX(), evt.getY());
-
-      return;
     }
-
-    ap.getScalePanel().mousePressed(evt);
-
+    item = new JMenuItem(LABEL);
+    item.addActionListener(this);
+    pop.add(item);
+    item = new JMenuItem(COLOUR);
+    item.addActionListener(this);
+    pop.add(item);
+    item = new JMenuItem(REMOVE);
+    item.addActionListener(this);
+    pop.add(item);
+    pop.show(this, x, y);
   }
 
   /**
@@ -591,6 +605,16 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     graphStretchY = -1;
     mouseDragging = false;
     ap.getScalePanel().mouseReleased(evt);
+
+    /*
+     * isPopupTrigger is set in mouseReleased on Windows
+     * (in mousePressed on Mac)
+     */
+    if (evt.isPopupTrigger() && activeRow != -1)
+    {
+      showPopupMenu(evt.getY(), evt.getX());
+    }
+
   }
 
   /**
@@ -790,8 +814,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       {
         text.append(", ")
                 .append(MessageManager.getString("label.sequence"))
-                .append(" ")
-                .append(seqIndex + 1);
+                .append(" ").append(seqIndex + 1);
         char residue = seqref.getCharAt(column);
         if (!Comparison.isGap(residue))
         {
@@ -1110,4 +1133,25 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return null;
     }
   }
+
+  /**
+   * Try to ensure any references held are nulled
+   */
+  public void dispose()
+  {
+    av = null;
+    ap = null;
+    image = null;
+    fadedImage = null;
+    gg = null;
+    _mwl = null;
+
+    /*
+     * I created the renderer so I will dispose of it
+     */
+    if (renderer != null)
+    {
+      renderer.dispose();
+    }
+  }
 }
index f0bea60..c8bd69c 100644 (file)
@@ -26,7 +26,6 @@ import jalview.datamodel.SequenceGroup;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.util.MessageManager;
 
-import java.awt.event.ActionEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.Vector;
@@ -52,7 +51,7 @@ public abstract class AnnotationRowFilter extends JPanel
 
   protected boolean enableSeqAss = false;
 
-  private jalview.datamodel.AlignmentAnnotation currentAnnotation;
+  private AlignmentAnnotation currentAnnotation;
 
   protected boolean adjusting = false;
 
@@ -161,11 +160,20 @@ public abstract class AnnotationRowFilter extends JPanel
         enableSeqAss = true;
       }
       String label = av.getAlignment().getAlignmentAnnotation()[i].label;
+      // add associated sequence ID if available
+      if (!isSeqAssociated
+              && av.getAlignment().getAlignmentAnnotation()[i].sequenceRef != null)
+      {
+        label = label
+                + "_"
+                + av.getAlignment().getAlignmentAnnotation()[i].sequenceRef
+                        .getName();
+      }
+      // make label unique
       if (!list.contains(label))
       {
         anmap[list.size()] = i;
         list.add(label);
-
       }
       else
       {
@@ -200,7 +208,7 @@ public abstract class AnnotationRowFilter extends JPanel
     seqAssociated.setEnabled(enableSeqAss);
   }
 
-  public void ok_actionPerformed(ActionEvent e)
+  public void ok_actionPerformed()
   {
     try
     {
@@ -210,7 +218,7 @@ public abstract class AnnotationRowFilter extends JPanel
     }
   }
 
-  public void cancel_actionPerformed(ActionEvent e)
+  public void cancel_actionPerformed()
   {
     reset();
     ap.paintAlignment(true);
@@ -222,22 +230,22 @@ public abstract class AnnotationRowFilter extends JPanel
     }
   }
 
-  public void thresholdCheck_actionPerformed(ActionEvent e)
+  public void thresholdCheck_actionPerformed()
   {
     updateView();
   }
 
-  public void annotations_actionPerformed(ActionEvent e)
+  public void annotations_actionPerformed()
   {
     updateView();
   }
 
-  public void threshold_actionPerformed(ActionEvent e)
+  public void threshold_actionPerformed()
   {
     updateView();
   }
 
-  public void thresholdValue_actionPerformed(ActionEvent e)
+  public void thresholdValue_actionPerformed()
   {
     try
     {
@@ -249,7 +257,7 @@ public abstract class AnnotationRowFilter extends JPanel
     }
   }
 
-  public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
+  public void thresholdIsMin_actionPerformed()
   {
     updateView();
   }
@@ -264,8 +272,7 @@ public abstract class AnnotationRowFilter extends JPanel
             .getString("label.threshold_feature_below_threshold"));
   }
 
-  protected void seqAssociated_actionPerformed(ActionEvent arg0,
-          JComboBox<String> annotations, JCheckBox seqAssociated)
+  protected void seqAssociated_actionPerformed(JComboBox<String> annotations)
   {
     adjusting = true;
     String cursel = (String) annotations.getSelectedItem();
@@ -322,26 +329,25 @@ public abstract class AnnotationRowFilter extends JPanel
     }
   }
 
-  protected boolean colorAlignmContaining(
-          AlignmentAnnotation currentAnnotation, int selectedThresholdItem)
+  protected boolean colorAlignmContaining(AlignmentAnnotation currentAnn,
+          int selectedThresholdOption)
   {
 
     AnnotationColourGradient acg = null;
     if (currentColours.isSelected())
     {
-      acg = new AnnotationColourGradient(currentAnnotation,
-              av.getGlobalColourScheme(), selectedThresholdItem);
+      acg = new AnnotationColourGradient(currentAnn,
+              av.getGlobalColourScheme(), selectedThresholdOption);
     }
     else
     {
-      acg = new AnnotationColourGradient(currentAnnotation,
+      acg = new AnnotationColourGradient(currentAnn,
               minColour.getBackground(), maxColour.getBackground(),
-              selectedThresholdItem);
+              selectedThresholdOption);
     }
     acg.setSeqAssociated(seqAssociated.isSelected());
 
-    if (currentAnnotation.graphMin == 0f
-            && currentAnnotation.graphMax == 0f)
+    if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
     {
       acg.setPredefinedColours(true);
     }
@@ -362,17 +368,17 @@ public abstract class AnnotationRowFilter extends JPanel
 
         if (currentColours.isSelected())
         {
-          sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
-                  selectedThresholdItem);
+          sg.cs = new AnnotationColourGradient(currentAnn, sg.cs,
+                  selectedThresholdOption);
           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
                   .isSelected());
 
         }
         else
         {
-          sg.cs = new AnnotationColourGradient(currentAnnotation,
+          sg.cs = new AnnotationColourGradient(currentAnn,
                   minColour.getBackground(), maxColour.getBackground(),
-                  selectedThresholdItem);
+                  selectedThresholdOption);
           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
                   .isSelected());
         }
index a1846bc..d7e8305 100644 (file)
@@ -41,6 +41,7 @@ import jalview.schemes.ZappoColourScheme;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.ws.dbsources.Pdb;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -49,7 +50,6 @@ import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.io.BufferedReader;
@@ -66,10 +66,10 @@ import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JColorChooser;
 import javax.swing.JInternalFrame;
 import javax.swing.JMenu;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JSplitPane;
+import javax.swing.SwingUtilities;
 import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 import javax.swing.event.MenuEvent;
@@ -77,6 +77,13 @@ import javax.swing.event.MenuListener;
 
 public class AppJmol extends StructureViewerBase
 {
+  // ms to wait for Jmol to load files
+  private static final int JMOL_LOAD_TIMEOUT = 20000;
+
+  private static final String SPACE = " ";
+
+  private static final String BACKSLASH = "\"";
+
   AppJmolBinding jmb;
 
   JPanel scriptWindow;
@@ -122,7 +129,7 @@ public class AppJmol extends StructureViewerBase
     // / TODO: check if protocol is needed to be set, and if chains are
     // autodiscovered.
     jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
-            pdbentrys, seqs, null, null);
+            pdbentrys, seqs, null);
 
     jmb.setLoadingFromArchive(true);
     addAlignmentPanel(ap);
@@ -292,7 +299,7 @@ public class AppJmol extends StructureViewerBase
   {
     progressBar = ap.alignFrame;
     jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
-            pdbentrys, seqs, null, null);
+            pdbentrys, seqs, null);
     addAlignmentPanel(ap);
     useAlignmentPanelForColourbyseq(ap);
     if (pdbentrys.length > 1)
@@ -303,12 +310,10 @@ public class AppJmol extends StructureViewerBase
     jmb.setColourBySequence(true);
     setSize(400, 400); // probably should be a configurable/dynamic default here
     initMenus();
-    worker = null;
-    {
-      addingStructures = false;
-      worker = new Thread(this);
-      worker.start();
-    }
+    addingStructures = false;
+    worker = new Thread(this);
+    worker.start();
+
     this.addInternalFrameListener(new InternalFrameAdapter()
     {
       @Override
@@ -375,8 +380,8 @@ public class AppJmol extends StructureViewerBase
       scriptWindow.setVisible(false);
     }
 
-    jmb.allocateViewer(renderPanel, true, "", null, null, "", scriptWindow,
-            null);
+    jmb.allocateViewer(renderPanel, true, "", null, null, "",
+            scriptWindow, null);
     // jmb.newJmolPopup("Jmol");
     if (command == null)
     {
@@ -387,57 +392,12 @@ public class AppJmol extends StructureViewerBase
     jmb.setFinishedInit(true);
   }
 
-  void setChainMenuItems(Vector<String> chains)
-  {
-    chainMenu.removeAll();
-    if (chains == null)
-    {
-      return;
-    }
-    JMenuItem menuItem = new JMenuItem(
-            MessageManager.getString("label.all"));
-    menuItem.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent evt)
-      {
-        allChainsSelected = true;
-        for (int i = 0; i < chainMenu.getItemCount(); i++)
-        {
-          if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
-          {
-            ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
-          }
-        }
-        centerViewer();
-        allChainsSelected = false;
-      }
-    });
-
-    chainMenu.add(menuItem);
-
-    for (String chain : chains)
-    {
-      menuItem = new JCheckBoxMenuItem(chain, true);
-      menuItem.addItemListener(new ItemListener()
-      {
-        @Override
-        public void itemStateChanged(ItemEvent evt)
-        {
-          if (!allChainsSelected)
-          {
-            centerViewer();
-          }
-        }
-      });
 
-      chainMenu.add(menuItem);
-    }
-  }
 
   boolean allChainsSelected = false;
 
-  void centerViewer()
+  @Override
+  void showSelectedChains()
   {
     Vector<String> toshow = new Vector<String>();
     for (int i = 0; i < chainMenu.getItemCount(); i++)
@@ -475,15 +435,168 @@ public class AppJmol extends StructureViewerBase
   public void run()
   {
     _started = true;
+    try
+    {
+      List<String> files = fetchPdbFiles();
+      if (files.size() > 0)
+      {
+        showFilesInViewer(files);
+      }
+    } finally
+    {
+      _started = false;
+      worker = null;
+    }
+  }
+
+  /**
+   * Either adds the given files to a structure viewer or opens a new viewer to
+   * show them
+   * 
+   * @param files
+   *          list of absolute paths to structure files
+   */
+  void showFilesInViewer(List<String> files)
+  {
+    long lastnotify = jmb.getLoadNotifiesHandled();
+    StringBuilder fileList = new StringBuilder();
+    for (String s : files)
+    {
+      fileList.append(SPACE).append(BACKSLASH)
+              .append(Platform.escapeString(s)).append(BACKSLASH);
+    }
+    String filesString = fileList.toString();
+
+    if (!addingStructures)
+    {
+      try
+      {
+        initJmol("load FILES " + filesString);
+      } catch (OutOfMemoryError oomerror)
+      {
+        new OOMWarning("When trying to open the Jmol viewer!", oomerror);
+        Cache.log.debug("File locations are " + filesString);
+      } catch (Exception ex)
+      {
+        Cache.log.error("Couldn't open Jmol viewer!", ex);
+      }
+    }
+    else
+    {
+      StringBuilder cmd = new StringBuilder();
+      cmd.append("loadingJalviewdata=true\nload APPEND ");
+      cmd.append(filesString);
+      cmd.append("\nloadingJalviewdata=null");
+      final String command = cmd.toString();
+      lastnotify = jmb.getLoadNotifiesHandled();
+
+      try
+      {
+        jmb.evalStateCommand(command);
+      } catch (OutOfMemoryError oomerror)
+      {
+        new OOMWarning("When trying to add structures to the Jmol viewer!",
+                oomerror);
+        Cache.log.debug("File locations are " + filesString);
+      } catch (Exception ex)
+      {
+        Cache.log.error("Couldn't add files to Jmol viewer!", ex);
+      }
+    }
+
+    // need to wait around until script has finished
+    int waitMax = JMOL_LOAD_TIMEOUT;
+    int waitFor = 35;
+    int waitTotal = 0;
+    while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
+            : !(jmb.isFinishedInit() && jmb.getPdbFile() != null && jmb
+                    .getPdbFile().length == files.size()))
+    {
+      try
+      {
+        Cache.log.debug("Waiting around for jmb notify.");
+        Thread.sleep(waitFor);
+        waitTotal += waitFor;
+      } catch (Exception e)
+      {
+      }
+      if (waitTotal > waitMax)
+      {
+        System.err
+                .println("Timed out waiting for Jmol to load files after "
+                        + waitTotal + "ms");
+//        System.err.println("finished: " + jmb.isFinishedInit()
+//                + "; loaded: " + Arrays.toString(jmb.getPdbFile())
+//                + "; files: " + files.toString());
+        jmb.getPdbFile();
+        break;
+      }
+    }
+
+    // refresh the sequence colours for the new structure(s)
+    for (AlignmentPanel ap : _colourwith)
+    {
+      jmb.updateColours(ap);
+    }
+    // do superposition if asked to
+    if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures)
+    {
+      alignAddedStructures();
+    }
+    addingStructures = false;
+  }
+
+  /**
+   * Queues a thread to align structures with Jalview alignments
+   */
+  void alignAddedStructures()
+  {
+    javax.swing.SwingUtilities.invokeLater(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        if (jmb.viewer.isScriptExecuting())
+        {
+          SwingUtilities.invokeLater(this);
+          try
+          {
+            Thread.sleep(5);
+          } catch (InterruptedException q)
+          {
+          }
+          return;
+        }
+        else
+        {
+          alignStructs_withAllAlignPanels();
+        }
+      }
+    });
+    alignAddedStructures = false;
+  }
+
+  /**
+   * 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>();
     String pdbid = "";
-    // todo - record which pdbids were successfuly imported.
-    StringBuffer errormsgs = new StringBuffer(), files = new StringBuffer();
     try
     {
-      String[] curfiles = jmb.getPdbFile(); // files currently in viewer
+      String[] filesInViewer = jmb.getPdbFile();
       // TODO: replace with reference fetching/transfer code (validate PDBentry
       // as a DBRef?)
-      jalview.ws.dbsources.Pdb pdbclient = new jalview.ws.dbsources.Pdb();
+      Pdb pdbclient = new Pdb();
       for (int pi = 0; pi < jmb.getPdbCount(); pi++)
       {
         String file = jmb.getPdbEntry(pi).getFile();
@@ -507,12 +620,15 @@ public class AppJmol extends StructureViewerBase
           } catch (Exception ex)
           {
             ex.printStackTrace();
-            errormsgs.append("'" + pdbid + "'");
-          }
-          if (progressBar != null)
+            errormsgs.append("'").append(pdbid).append("'");
+          } finally
           {
-            progressBar.setProgressBar(
-                    MessageManager.getString("label.state_completed"), hdl);
+            if (progressBar != null)
+            {
+              progressBar.setProgressBar(
+                      MessageManager.getString("label.state_completed"),
+                      hdl);
+            }
           }
           if (pdbseq != null)
           {
@@ -521,22 +637,21 @@ public class AppJmol extends StructureViewerBase
             file = new File(pdbseq.getSequenceAt(0).getAllPDBEntries()
                     .elementAt(0).getFile()).getAbsolutePath();
             jmb.getPdbEntry(pi).setFile(file);
-
-            files.append(" \"" + Platform.escapeString(file) + "\"");
+            files.add(file);
           }
           else
           {
-            errormsgs.append("'" + pdbid + "' ");
+            errormsgs.append("'").append(pdbid).append("' ");
           }
         }
         else
         {
-          if (curfiles != null && curfiles.length > 0)
+          if (filesInViewer != null && filesInViewer.length > 0)
           {
             addingStructures = true; // already files loaded.
-            for (int c = 0; c < curfiles.length; c++)
+            for (int c = 0; c < filesInViewer.length; c++)
             {
-              if (curfiles[c].equals(file))
+              if (filesInViewer[c].equals(file))
               {
                 file = null;
                 break;
@@ -545,7 +660,7 @@ public class AppJmol extends StructureViewerBase
           }
           if (file != null)
           {
-            files.append(" \"" + Platform.escapeString(file) + "\"");
+            files.add(file);
           }
         }
       }
@@ -555,114 +670,18 @@ public class AppJmol extends StructureViewerBase
     } catch (Exception ex)
     {
       ex.printStackTrace();
-      errormsgs.append("When retrieving pdbfiles : current was: '" + pdbid
-              + "'");
+      errormsgs.append("When retrieving pdbfiles : current was: '")
+              .append(pdbid).append("'");
     }
     if (errormsgs.length() > 0)
     {
-
       JOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
               .formatMessage("label.pdb_entries_couldnt_be_retrieved",
                       new String[] { errormsgs.toString() }),
               MessageManager.getString("label.couldnt_load_file"),
               JOptionPane.ERROR_MESSAGE);
-
-    }
-    long lastnotify = jmb.getLoadNotifiesHandled();
-    if (files.length() > 0)
-    {
-      if (!addingStructures)
-      {
-
-        try
-        {
-          initJmol("load FILES " + files.toString());
-        } catch (OutOfMemoryError oomerror)
-        {
-          new OOMWarning("When trying to open the Jmol viewer!", oomerror);
-          Cache.log.debug("File locations are " + files);
-        } catch (Exception ex)
-        {
-          Cache.log.error("Couldn't open Jmol viewer!", ex);
-        }
-      }
-      else
-      {
-        StringBuffer cmd = new StringBuffer();
-        cmd.append("loadingJalviewdata=true\nload APPEND ");
-        cmd.append(files.toString());
-        cmd.append("\nloadingJalviewdata=null");
-        final String command = cmd.toString();
-        cmd = null;
-        lastnotify = jmb.getLoadNotifiesHandled();
-
-        try
-        {
-          jmb.evalStateCommand(command);
-        } catch (OutOfMemoryError oomerror)
-        {
-          new OOMWarning(
-                  "When trying to add structures to the Jmol viewer!",
-                  oomerror);
-          Cache.log.debug("File locations are " + files);
-        } catch (Exception ex)
-        {
-          Cache.log.error("Couldn't add files to Jmol viewer!", ex);
-        }
-      }
-
-      // need to wait around until script has finished
-      while (addingStructures ? lastnotify >= jmb.getLoadNotifiesHandled()
-              : (!jmb.isFinishedInit() && jmb.getPdbFile() != null && jmb
-                      .getPdbFile().length != jmb.getPdbCount()))
-      {
-        try
-        {
-          Cache.log.debug("Waiting around for jmb notify.");
-          Thread.sleep(35);
-        } catch (Exception e)
-        {
-        }
-      }
-
-      // refresh the sequence colours for the new structure(s)
-      for (AlignmentPanel ap : _colourwith)
-      {
-        jmb.updateColours(ap);
-      }
-      // do superposition if asked to
-      if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures)
-      {
-        javax.swing.SwingUtilities.invokeLater(new Runnable()
-        {
-          @Override
-          public void run()
-          {
-            if (jmb.viewer.isScriptExecuting())
-            {
-              javax.swing.SwingUtilities.invokeLater(this);
-              try
-              {
-                Thread.sleep(5);
-              } catch (InterruptedException q)
-              {
-              }
-              ;
-              return;
-            }
-            else
-            {
-              alignStructs_withAllAlignPanels();
-            }
-          }
-        });
-        alignAddedStructures = false;
-      }
-      addingStructures = false;
-
     }
-    _started = false;
-    worker = null;
+    return files;
   }
 
   @Override
@@ -1009,7 +1028,7 @@ public class AppJmol extends StructureViewerBase
       repaint();
       return;
     }
-    setChainMenuItems(jmb.chainNames);
+    setChainMenuItems(jmb.getChainNames());
 
     this.setTitle(jmb.getViewerTitle());
     if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1)
index 6e520e5..4d7f7cf 100644 (file)
@@ -42,10 +42,9 @@ public class AppJmolBinding extends JalviewJmolBinding
   private FeatureRenderer fr = null;
 
   public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
-          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
-          DataSourceType protocol)
+          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol)
   {
-    super(sSm, pdbentry, sequenceIs, chains, protocol);
+    super(sSm, pdbentry, sequenceIs, protocol);
     appJmolWindow = appJmol;
   }
 
index a114f31..ab23e62 100644 (file)
@@ -31,6 +31,7 @@ import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
+import jalview.io.StructureFile;
 import jalview.schemes.BuriedColourScheme;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.HelixColourScheme;
@@ -46,7 +47,6 @@ import jalview.util.Platform;
 import jalview.ws.dbsources.Pdb;
 
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.io.BufferedReader;
@@ -59,16 +59,13 @@ import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
-import java.util.Set;
 import java.util.Vector;
 
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JColorChooser;
 import javax.swing.JInternalFrame;
 import javax.swing.JMenu;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
@@ -196,7 +193,7 @@ public class ChimeraViewFrame extends StructureViewerBase
   public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq,
           String[] chains, final AlignmentPanel ap)
   {
-    super();
+    this();
     String pdbId = pdbentry.getId();
 
     /*
@@ -249,10 +246,9 @@ public class ChimeraViewFrame extends StructureViewerBase
           SequenceI[][] seqs)
   {
     createProgressBar();
-    String[][] chains = extractChains(seqs);
+    // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs
     jmb = new JalviewChimeraBindingModel(this,
-            ap.getStructureSelectionManager(), pdbentrys, seqs, chains,
-            null);
+            ap.getStructureSelectionManager(), pdbentrys, seqs, null);
     addAlignmentPanel(ap);
     useAlignmentPanelForColourbyseq(ap);
     if (pdbentrys.length > 1)
@@ -279,38 +275,7 @@ public class ChimeraViewFrame extends StructureViewerBase
 
   }
 
-  /**
-   * Retrieve chains for sequences by inspecting their PDB refs. The hope is
-   * that the first will be to the sequence's own chain. Really need a more
-   * managed way of doing this.
-   * 
-   * @param seqs
-   * @return
-   */
-  protected String[][] extractChains(SequenceI[][] seqs)
-  {
-    String[][] chains = new String[seqs.length][];
-    for (int i = 0; i < seqs.length; i++)
-    {
-      chains[i] = new String[seqs[i].length];
-      int seqno = 0;
-      for (SequenceI seq : seqs[i])
-      {
-        String chain = null;
-        if (seq.getDatasetSequence() != null)
-        {
-          Vector<PDBEntry> pdbrefs = seq.getDatasetSequence()
-                  .getAllPDBEntries();
-          if (pdbrefs != null && pdbrefs.size() > 0)
-          {
-            chain = pdbrefs.get(0).getChainCode();
-          }
-        }
-        chains[i][seqno++] = chain;
-      }
-    }
-    return chains;
-  }
+
 
   /**
    * Create a new viewer from saved session state data including Chimera session
@@ -329,7 +294,7 @@ public class ChimeraViewFrame extends StructureViewerBase
           SequenceI[][] seqsArray, boolean colourByChimera,
           boolean colourBySequence, String newViewId)
   {
-    super();
+    this();
     setViewId(newViewId);
     this.chimeraSessionFile = chimeraSessionFile;
     openNewChimera(alignPanel, pdbArray, seqsArray);
@@ -358,31 +323,22 @@ public class ChimeraViewFrame extends StructureViewerBase
   public ChimeraViewFrame(PDBEntry[] pe, SequenceI[][] seqs,
           AlignmentPanel ap)
   {
-    super();
+    this();
     openNewChimera(ap, pe, seqs);
   }
 
-  public ChimeraViewFrame(Map<PDBEntry, List<SequenceI>> toView,
-          AlignmentPanel alignPanel)
+  /**
+   * Default constructor
+   */
+  public ChimeraViewFrame()
   {
     super();
 
     /*
-     * Convert the map of sequences per pdb entry into the tied arrays expected
-     * by openNewChimera
-     * 
-     * TODO pass the Map down to openNewChimera and its callees instead
+     * closeViewer will decide whether or not to close this frame
+     * depending on whether user chooses to Cancel or not
      */
-    final Set<PDBEntry> pdbEntries = toView.keySet();
-    PDBEntry[] pdbs = pdbEntries.toArray(new PDBEntry[pdbEntries.size()]);
-    SequenceI[][] seqsForPdbs = new SequenceI[pdbEntries.size()][];
-    for (int i = 0; i < pdbs.length; i++)
-    {
-      final List<SequenceI> seqsForPdb = toView.get(pdbs[i]);
-      seqsForPdbs[i] = seqsForPdb.toArray(new SequenceI[seqsForPdb.size()]);
-    }
-
-    openNewChimera(alignPanel, pdbs, seqsForPdbs);
+    setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
   }
 
   /**
@@ -444,63 +400,11 @@ public class ChimeraViewFrame extends StructureViewerBase
     jmb.startChimeraListener();
   }
 
-  /**
-   * If the list is not empty, add menu items for 'All' and each individual
-   * chain to the "View | Show Chain" sub-menu. Multiple selections are allowed.
-   * 
-   * @param chainNames
-   */
-  void setChainMenuItems(List<String> chainNames)
-  {
-    chainMenu.removeAll();
-    if (chainNames == null || chainNames.isEmpty())
-    {
-      return;
-    }
-    JMenuItem menuItem = new JMenuItem(
-            MessageManager.getString("label.all"));
-    menuItem.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent evt)
-      {
-        allChainsSelected = true;
-        for (int i = 0; i < chainMenu.getItemCount(); i++)
-        {
-          if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
-          {
-            ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
-          }
-        }
-        showSelectedChains();
-        allChainsSelected = false;
-      }
-    });
-
-    chainMenu.add(menuItem);
-
-    for (String chainName : chainNames)
-    {
-      menuItem = new JCheckBoxMenuItem(chainName, true);
-      menuItem.addItemListener(new ItemListener()
-      {
-        @Override
-        public void itemStateChanged(ItemEvent evt)
-        {
-          if (!allChainsSelected)
-          {
-            showSelectedChains();
-          }
-        }
-      });
-
-      chainMenu.add(menuItem);
-    }
-  }
 
   /**
    * Show only the selected chain(s) in the viewer
    */
+  @Override
   void showSelectedChains()
   {
     List<String> toshow = new ArrayList<String>();
@@ -539,7 +443,15 @@ public class ChimeraViewFrame extends StructureViewerBase
         prompt = JvSwingUtils.wrapTooltip(true, prompt);
         int confirm = JOptionPane.showConfirmDialog(this, prompt,
                 MessageManager.getString("label.close_viewer"),
-                JOptionPane.YES_NO_OPTION);
+                JOptionPane.YES_NO_CANCEL_OPTION);
+        /*
+         * abort closure if user hits escape or Cancel
+         */
+        if (confirm == JOptionPane.CANCEL_OPTION
+                || confirm == JOptionPane.CLOSED_OPTION)
+        {
+          return;
+        }
         closeChimera = confirm == JOptionPane.YES_OPTION;
       }
       jmb.closeViewer(closeChimera);
@@ -551,6 +463,7 @@ public class ChimeraViewFrame extends StructureViewerBase
     // TODO: check for memory leaks where instance isn't finalised because jmb
     // holds a reference to the window
     jmb = null;
+    dispose();
   }
 
   /**
@@ -567,6 +480,7 @@ public class ChimeraViewFrame extends StructureViewerBase
     List<PDBEntry> filePDB = new ArrayList<PDBEntry>();
     List<Integer> filePDBpos = new ArrayList<Integer>();
     PDBEntry thePdbEntry = null;
+    StructureFile pdb = null;
     try
     {
       String[] curfiles = jmb.getPdbFile(); // files currently in viewer
@@ -656,7 +570,8 @@ public class ChimeraViewFrame extends StructureViewerBase
           {
             int pos = filePDBpos.get(num).intValue();
             long startTime = startProgressBar("Chimera "
-                    + MessageManager.getString("status.opening_file"));
+                    + MessageManager.getString("status.opening_file_for")
+                    + " " + pe.getId());
             jmb.openFile(pe);
             jmb.addSequence(pos, jmb.getSequence()[pos]);
             File fl = new File(pe.getFile());
@@ -674,8 +589,9 @@ public class ChimeraViewFrame extends StructureViewerBase
               stopProgressBar("", startTime);
             }
             // Explicitly map to the filename used by Chimera ;
-            jmb.getSsm().setMapping(jmb.getSequence()[pos],
+            pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
                     jmb.getChains()[pos], pe.getFile(), protocol);
+            stashFoundChains(pdb, pe.getFile());
           } catch (OutOfMemoryError oomerror)
           {
             new OOMWarning(
@@ -691,6 +607,7 @@ public class ChimeraViewFrame extends StructureViewerBase
           }
         }
       }
+      jmb.refreshGUI();
       jmb.setFinishedInit(true);
       jmb.setLoadingFromArchive(false);
 
@@ -726,8 +643,20 @@ public class ChimeraViewFrame extends StructureViewerBase
    * @return
    * @throws Exception
    */
+
+  private void stashFoundChains(StructureFile pdb, String file)
+  {
+    for (int i = 0; i < pdb.getChains().size(); i++)
+    {
+      String chid = new String(pdb.getId() + ":"
+              + pdb.getChains().elementAt(i).id);
+      jmb.getChainNames().add(chid);
+      jmb.getChainFile().put(chid, file);
+    }
+  }
   private String fetchPdbFile(PDBEntry processingEntry) throws Exception
   {
+    // FIXME: this is duplicated code with Jmol frame ?
     String filePath = null;
     Pdb pdbclient = new Pdb();
     AlignmentI pdbseq = null;
diff --git a/src/jalview/gui/CrossRefAction.java b/src/jalview/gui/CrossRefAction.java
new file mode 100644 (file)
index 0000000..32af226
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * 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;
+
+import jalview.analysis.AlignmentUtils;
+import jalview.analysis.CrossRef;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureSettingsModelI;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceI;
+import jalview.io.gff.SequenceOntologyI;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
+import jalview.ws.SequenceFetcher;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+/**
+ * Factory constructor and runnable for discovering and displaying
+ * cross-references for a set of aligned sequences
+ * 
+ * @author jprocter
+ *
+ */
+public class CrossRefAction implements Runnable
+{
+  private AlignFrame alignFrame;
+
+  private SequenceI[] sel;
+
+  private boolean _odna;
+
+  private String source;
+
+  List<AlignmentViewPanel> xrefViews = new ArrayList<AlignmentViewPanel>();
+
+  public List<jalview.api.AlignmentViewPanel> getXrefViews()
+  {
+    return xrefViews;
+  }
+
+  @Override
+  public void run()
+  {
+    final long sttime = System.currentTimeMillis();
+    alignFrame.setProgressBar(
+            MessageManager.formatMessage(
+                    "status.searching_for_sequences_from",
+                    new Object[] { source }), sttime);
+    try
+    {
+      AlignmentI alignment = alignFrame.getViewport().getAlignment();
+      AlignmentI dataset = alignment.getDataset() == null ? alignment
+              : alignment.getDataset();
+      boolean dna = alignment.isNucleotide();
+      if (_odna != dna)
+      {
+        System.err
+                .println("Conflict: showProducts for alignment originally "
+                        + "thought to be " + (_odna ? "DNA" : "Protein")
+                        + " now searching for " + (dna ? "DNA" : "Protein")
+                        + " Context.");
+      }
+      AlignmentI xrefs = new CrossRef(sel, dataset).findXrefSequences(
+              source, dna);
+      if (xrefs == null)
+      {
+        return;
+      }
+      /*
+       * get display scheme (if any) to apply to features
+       */
+      FeatureSettingsModelI featureColourScheme = new SequenceFetcher()
+              .getFeatureColourScheme(source);
+
+      AlignmentI xrefsAlignment = makeCrossReferencesAlignment(dataset,
+              xrefs);
+      if (!dna)
+      {
+        xrefsAlignment = AlignmentUtils.makeCdsAlignment(
+                xrefsAlignment.getSequencesArray(), dataset, sel);
+        xrefsAlignment.alignAs(alignment);
+      }
+
+      /*
+       * If we are opening a splitframe, make a copy of this alignment (sharing the same dataset
+       * sequences). If we are DNA, drop introns and update mappings
+       */
+      AlignmentI copyAlignment = null;
+
+      if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
+      {
+        boolean copyAlignmentIsAligned = false;
+        if (dna)
+        {
+          copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset,
+                  xrefsAlignment.getSequencesArray());
+          if (copyAlignment.getHeight() == 0)
+          {
+            JOptionPane.showMessageDialog(alignFrame,
+                    MessageManager.getString("label.cant_map_cds"),
+                    MessageManager.getString("label.operation_failed"),
+                    JOptionPane.OK_OPTION);
+            System.err.println("Failed to make CDS alignment");
+          }
+
+          /*
+           * pending getting Embl transcripts to 'align', 
+           * we are only doing this for Ensembl
+           */
+          // TODO proper criteria for 'can align as cdna'
+          if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
+                  || AlignmentUtils.looksLikeEnsembl(alignment))
+          {
+            copyAlignment.alignAs(alignment);
+            copyAlignmentIsAligned = true;
+          }
+        }
+        else
+        {
+          copyAlignment = AlignmentUtils.makeCopyAlignment(sel,
+                  xrefs.getSequencesArray(), dataset);
+        }
+        copyAlignment
+                .setGapCharacter(alignFrame.viewport.getGapCharacter());
+
+        StructureSelectionManager ssm = StructureSelectionManager
+                .getStructureSelectionManager(Desktop.instance);
+
+        /*
+         * register any new mappings for sequence mouseover etc
+         * (will not duplicate any previously registered mappings)
+         */
+        ssm.registerMappings(dataset.getCodonFrames());
+
+        if (copyAlignment.getHeight() <= 0)
+        {
+          System.err.println("No Sequences generated for xRef type "
+                  + source);
+          return;
+        }
+        /*
+         * align protein to dna
+         */
+        if (dna && copyAlignmentIsAligned)
+        {
+          xrefsAlignment.alignAs(copyAlignment);
+        }
+        else
+        {
+          /*
+           * align cdna to protein - currently only if 
+           * fetching and aligning Ensembl transcripts!
+           */
+          // TODO: generalise for other sources of locus/transcript/cds data
+          if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source))
+          {
+            copyAlignment.alignAs(xrefsAlignment);
+          }
+        }
+      }
+      /*
+       * build AlignFrame(s) according to available alignment data
+       */
+      AlignFrame newFrame = new AlignFrame(xrefsAlignment,
+              AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+      if (Cache.getDefault("HIDE_INTRONS", true))
+      {
+        newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false);
+      }
+      String newtitle = String.format("%s %s %s",
+              dna ? MessageManager.getString("label.proteins")
+                      : MessageManager.getString("label.nucleotides"),
+              MessageManager.getString("label.for"), alignFrame.getTitle());
+      newFrame.setTitle(newtitle);
+
+      if (copyAlignment == null)
+      {
+        /*
+         * split frame display is turned off in preferences file
+         */
+        Desktop.addInternalFrame(newFrame, newtitle,
+                AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+        xrefViews.add(newFrame.alignPanel);
+        return; // via finally clause
+      }
+      AlignFrame copyThis = new AlignFrame(copyAlignment,
+              AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+      copyThis.setTitle(alignFrame.getTitle());
+
+      boolean showSequenceFeatures = alignFrame.getViewport()
+              .isShowSequenceFeatures();
+      newFrame.setShowSeqFeatures(showSequenceFeatures);
+      copyThis.setShowSeqFeatures(showSequenceFeatures);
+      FeatureRenderer myFeatureStyling = alignFrame.alignPanel
+              .getSeqPanel().seqCanvas.getFeatureRenderer();
+
+      /*
+       * copy feature rendering settings to split frame
+       */
+      newFrame.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
+              .transferSettings(myFeatureStyling);
+      copyThis.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
+              .transferSettings(myFeatureStyling);
+
+      /*
+       * apply 'database source' feature configuration
+       * if any was found
+       */
+      // TODO is this the feature colouring for the original
+      // alignment or the fetched xrefs? either could be Ensembl
+      newFrame.getViewport().applyFeaturesStyle(featureColourScheme);
+      copyThis.getViewport().applyFeaturesStyle(featureColourScheme);
+
+      SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame,
+              dna ? newFrame : copyThis);
+      newFrame.setVisible(true);
+      copyThis.setVisible(true);
+      String linkedTitle = MessageManager
+              .getString("label.linked_view_title");
+      Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
+      sf.adjustDivider();
+
+      // finally add the top, then bottom frame to the view list
+      xrefViews.add(dna ? copyThis.alignPanel : newFrame.alignPanel);
+      xrefViews.add(!dna ? copyThis.alignPanel : newFrame.alignPanel);
+
+    } catch (OutOfMemoryError e)
+    {
+      new OOMWarning("whilst fetching crossreferences", e);
+    } catch (Throwable e)
+    {
+      Cache.log.error("Error when finding crossreferences", e);
+    } finally
+    {
+      alignFrame.setProgressBar(MessageManager.formatMessage(
+              "status.finished_searching_for_sequences_from",
+              new Object[] { source }), sttime);
+    }
+  }
+
+  /**
+   * Makes an alignment containing the given sequences, and adds them to the
+   * given dataset, which is also set as the dataset for the new alignment
+   * 
+   * TODO: refactor to DatasetI method
+   * 
+   * @param dataset
+   * @param seqs
+   * @return
+   */
+  protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset,
+          AlignmentI seqs)
+  {
+    SequenceI[] sprods = new SequenceI[seqs.getHeight()];
+    for (int s = 0; s < sprods.length; s++)
+    {
+      sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
+      if (dataset.getSequences() == null
+              || !dataset.getSequences().contains(
+                      sprods[s].getDatasetSequence()))
+      {
+        dataset.addSequence(sprods[s].getDatasetSequence());
+      }
+      sprods[s].updatePDBIds();
+    }
+    Alignment al = new Alignment(sprods);
+    al.setDataset(dataset);
+    return al;
+  }
+
+  public CrossRefAction(AlignFrame alignFrame, SequenceI[] sel,
+          boolean _odna, String source)
+  {
+    this.alignFrame = alignFrame;
+    this.sel = sel;
+    this._odna = _odna;
+    this.source = source;
+  }
+
+  public static CrossRefAction showProductsFor(final SequenceI[] sel,
+          final boolean _odna, final String source,
+          final AlignFrame alignFrame)
+  {
+    return new CrossRefAction(alignFrame, sel, _odna, source);
+  }
+
+}
index 65d8670..dae83d1 100644 (file)
@@ -228,6 +228,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
   @Override
   public void textarea_mousePressed(MouseEvent e)
   {
+    // isPopupTrigger is on mousePressed (Mac) or mouseReleased (Windows)
     if (e.isPopupTrigger())
     {
       JPopupMenu popup = new JPopupMenu(
index 8b21058..ca79a83 100644 (file)
@@ -365,6 +365,10 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
   @Override
   public void textarea_mousePressed(MouseEvent e)
   {
+    /*
+     * isPopupTrigger is checked in mousePressed on Mac,
+     * in mouseReleased on Windows
+     */
     if (e.isPopupTrigger())
     {
       JPopupMenu popup = new JPopupMenu(
index 3fa5387..2e8644e 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.gui;
 
+import static jalview.util.UrlConstants.EMBLEBI_STRING;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
@@ -67,12 +70,10 @@ import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
-import java.beans.PropertyVetoException;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -80,6 +81,7 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.concurrent.ExecutorService;
@@ -87,9 +89,12 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Semaphore;
 
 import javax.swing.AbstractAction;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
 import javax.swing.DefaultDesktopManager;
 import javax.swing.DesktopManager;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JDesktopPane;
@@ -105,6 +110,8 @@ import javax.swing.KeyStroke;
 import javax.swing.SwingUtilities;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkEvent.EventType;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
 import javax.swing.event.MenuEvent;
 import javax.swing.event.MenuListener;
 
@@ -385,6 +392,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
     showNews.setVisible(false);
 
+    checkURLLinks();
+
     this.addWindowListener(new WindowAdapter()
     {
       @Override
@@ -400,7 +409,16 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       @Override
       public void mousePressed(MouseEvent evt)
       {
-        if (evt.isPopupTrigger())
+        if (evt.isPopupTrigger()) // Mac
+        {
+          showPasteMenu(evt.getX(), evt.getY());
+        }
+      }
+
+      @Override
+      public void mouseReleased(MouseEvent evt)
+      {
+        if (evt.isPopupTrigger()) // Windows
         {
           showPasteMenu(evt.getX(), evt.getY());
         }
@@ -808,32 +826,53 @@ public class Desktop extends jalview.jbgui.GDesktop implements
               * ((openFrameCount - 1) % 10) + yOffset);
     }
 
+    /*
+     * 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 javax.swing.event.InternalFrameAdapter()
+    frame.addInternalFrameListener(new InternalFrameAdapter()
     {
       @Override
-      public void internalFrameActivated(
-              javax.swing.event.InternalFrameEvent evt)
+      public void internalFrameActivated(InternalFrameEvent evt)
       {
         JInternalFrame itf = desktop.getSelectedFrame();
         if (itf != null)
         {
           itf.requestFocus();
         }
-
       }
 
       @Override
-      public void internalFrameClosed(
-              javax.swing.event.InternalFrameEvent evt)
+      public void internalFrameClosed(InternalFrameEvent evt)
       {
         PaintRefresher.RemoveComponent(frame);
-        openFrameCount--;
+
+        /*
+         * defensive check to prevent frames being
+         * added half off the window
+         */
+        if (openFrameCount > 0)
+        {
+          openFrameCount--;
+        }
+
+        /*
+         * ensure no reference to alignFrame retained by menu item listener
+         */
+        if (menuItem.getActionListeners().length > 0)
+        {
+          menuItem.removeActionListener(menuItem.getActionListeners()[0]);
+        }
         windowMenu.remove(menuItem);
         JInternalFrame itf = desktop.getSelectedFrame();
         if (itf != null)
         {
           itf.requestFocus();
+          if (itf instanceof AlignFrame)
+          {
+            Jalview.setCurrentAlignFrame((AlignFrame) itf);
+          }
         }
         System.gc();
       };
@@ -854,47 +893,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
         }
       }
     });
-    menuItem.addMouseListener(new MouseListener()
-    {
-
-      @Override
-      public void mouseReleased(MouseEvent e)
-      {
-      }
-
-      @Override
-      public void mousePressed(MouseEvent e)
-      {
-      }
-
-      @Override
-      public void mouseExited(MouseEvent e)
-      {
-        try
-        {
-          frame.setSelected(false);
-        } catch (PropertyVetoException e1)
-        {
-        }
-      }
-
-      @Override
-      public void mouseEntered(MouseEvent e)
-      {
-        try
-        {
-          frame.setSelected(true);
-        } catch (PropertyVetoException e1)
-        {
-        }
-      }
-
-      @Override
-      public void mouseClicked(MouseEvent e)
-      {
-
-      }
-    });
 
     windowMenu.add(menuItem);
 
@@ -955,6 +953,9 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   public void drop(DropTargetDropEvent evt)
   {
     boolean success = true;
+    // JAL-1552 - acceptDrop required before getTransferable call for
+    // Java's Transferable for native dnd
+    evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
     List<String> files = new ArrayList<String>();
     List<DataSourceType> protocols = new ArrayList<DataSourceType>();
@@ -1064,11 +1065,9 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    * 
    * @param e
    *          DOCUMENT ME!
-   * @throws FileFormatException
    */
   @Override
   public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
-  // throws FileFormatException
   {
     // This construct allows us to have a wider textfield
     // for viewing
@@ -1333,6 +1332,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   @Override
   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++)
     {
@@ -1343,6 +1343,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       {
       }
     }
+    Jalview.setCurrentAlignFrame(null);
     System.out.println("ALL CLOSED");
     if (v_client != null)
     {
@@ -1359,6 +1360,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     {
       ssm.resetAll();
     }
+    System.gc();
   }
 
   @Override
@@ -2189,7 +2191,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     if (v_client != null)
     {
       JalviewFileChooser chooser = new JalviewFileChooser(
-              Cache.getProperty("LAST_DIRECTORY"), "vdj",
+              Cache.getProperty("LAST_DIRECTORY"), "vdj",// TODO: VAMSAS DOCUMENT EXTENSION is VDJ
               "Vamsas Document", "Vamsas Document");
 
       chooser.setFileView(new JalviewFileView());
@@ -2246,7 +2248,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   public void setVamsasUpdate(boolean b)
   {
-    jalview.bin.Cache.log.debug("Setting gui for Vamsas update "
+    Cache.log.debug("Setting gui for Vamsas update "
             + (b ? "in progress" : "finished"));
 
     if (vamUpdate != null)
@@ -2281,6 +2283,84 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     new Thread(jvq).start();
   }
 
+  public void checkURLLinks()
+  {
+    // Thread off the URL link checker
+    addDialogThread(new Runnable()
+    {
+      @Override
+      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
+          Vector<String> links = Preferences.sequenceURLLinks;
+
+          // 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<JLabel>();
+          while (li.hasNext())
+          {
+            String link = li.next();
+            if (link.contains(SEQUENCE_ID) && !link.equals(EMBLEBI_STRING))
+            {
+              check = true;
+              int barPos = link.indexOf("|");
+              String urlMsg = barPos == -1 ? link : link.substring(0,
+                      barPos) + ": " + link.substring(barPos + 1);
+              urls.add(new JLabel(urlMsg));
+            }
+          }
+          if (!check)
+          {
+            return;
+          }
+
+          // ask user to check in case URL links use old style tokens
+          // ($SEQUENCE_ID$ for sequence id _or_ accession id)
+          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"));
+          msgPanel.add(msg);
+          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()
+          {
+            @Override
+            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());
+            }
+          });
+          msgPanel.add(jcb);
+
+          JOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
+                  MessageManager
+                          .getString("label.SEQUENCE_ID_no_longer_used"),
+                  JOptionPane.WARNING_MESSAGE);
+        }
+      }
+    });
+    }
+
   /**
    * Proxy class for JDesktopPane which optionally displays the current memory
    * usage and highlights the desktop area with a red bar if free memory runs
@@ -2542,8 +2622,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   {
     getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
             KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit
-                    .getDefaultToolkit().getMenuShortcutKeyMask()),
-            "Quit");
+                    .getDefaultToolkit().getMenuShortcutKeyMask()), "Quit");
     getRootPane().getActionMap().put("Quit", new AbstractAction()
     {
       @Override
@@ -3210,11 +3289,10 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     {
       // Works on Windows and MacOSX
       Cache.log.debug("Drop handled as javaFileListFlavor");
-      evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
       for (Object file : (List) t
               .getTransferData(DataFlavor.javaFileListFlavor))
       {
-        files.add(((File)file).toString());
+        files.add(((File) file).toString());
         protocols.add(DataSourceType.FILE);
       }
     }
@@ -3227,7 +3305,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       {
         Cache.log.debug("Drop handled as uriListFlavor");
         // This is used by Unix drag system
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
         data = (String) t.getTransferData(uriListFlavor);
       }
       if (data == null)
@@ -3282,7 +3359,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
           {
             Cache.log.debug("Supported transfer dataflavor: "
                     + fl.toString());
-            evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
             Object df = t.getTransferData(fl);
             if (df != null)
             {
index 426ea32..83d1612 100644 (file)
@@ -22,6 +22,7 @@ package jalview.gui;
 
 import jalview.api.FeatureColourI;
 import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.FeatureColour;
@@ -200,7 +201,7 @@ public class FeatureRenderer extends
             start.setValue(new Integer(features[index].getBegin()));
             end.setValue(new Integer(features[index].getEnd()));
 
-            SearchResults highlight = new SearchResults();
+            SearchResultsI highlight = new SearchResults();
             highlight.addResult(sequences[0], features[index].getBegin(),
                     features[index].getEnd());
 
index 6dc5cb3..c8b6531 100644 (file)
@@ -174,8 +174,7 @@ public class FeatureSettings extends JPanel implements
       public void mousePressed(MouseEvent evt)
       {
         selectedRow = table.rowAtPoint(evt.getPoint());
-        boolean ctrlDown = Platform.isControlDown(evt);
-        if (SwingUtilities.isRightMouseButton(evt) && !ctrlDown)
+        if (evt.isPopupTrigger())
         {
           popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
                   table.getValueAt(selectedRow, 1), fr.getMinMax(),
@@ -184,7 +183,7 @@ public class FeatureSettings extends JPanel implements
         else if (evt.getClickCount() == 2)
         {
           boolean invertSelection = evt.isAltDown();
-          boolean toggleSelection = ctrlDown;
+          boolean toggleSelection = Platform.isControlDown(evt);
           boolean extendSelection = evt.isShiftDown();
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
                   invertSelection, extendSelection, toggleSelection,
@@ -192,7 +191,7 @@ public class FeatureSettings extends JPanel implements
         }
       }
 
-      // isPopupTrigger fires on mouseReleased on Mac
+      // isPopupTrigger fires on mouseReleased on Windows
       @Override
       public void mouseReleased(MouseEvent evt)
       {
index 6bff69a..a8dbc38 100755 (executable)
@@ -20,7 +20,8 @@
  */
 package jalview.gui;
 
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.jbgui.GFinder;
@@ -67,7 +68,7 @@ public class Finder extends GFinder
 
   int resIndex = -1;
 
-  SearchResults searchResults;
+  SearchResultsI searchResults;
 
   /**
    * Creates a new Finder object with no associated viewport or panel.
@@ -109,6 +110,7 @@ public class Finder extends GFinder
             KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel");
     getRootPane().getActionMap().put("Cancel", new AbstractAction()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         escapeActionPerformed();
@@ -130,6 +132,7 @@ public class Finder extends GFinder
    * 
    * @param e
    */
+  @Override
   public void findNext_actionPerformed(ActionEvent e)
   {
     if (getFocusedViewport())
@@ -143,6 +146,7 @@ public class Finder extends GFinder
    * 
    * @param e
    */
+  @Override
   public void findAll_actionPerformed(ActionEvent e)
   {
     if (getFocusedViewport())
@@ -198,19 +202,22 @@ public class Finder extends GFinder
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void createNewGroup_actionPerformed(ActionEvent e)
   {
     SequenceI[] seqs = new SequenceI[searchResults.getSize()];
     SequenceFeature[] features = new SequenceFeature[searchResults
             .getSize()];
 
-    for (int i = 0; i < searchResults.getSize(); i++)
+    int i = 0;
+    for (SearchResultMatchI match : searchResults.getResults())
     {
-      seqs[i] = searchResults.getResultSequence(i).getDatasetSequence();
+      seqs[i] = match.getSequence().getDatasetSequence();
 
       features[i] = new SequenceFeature(textfield.getText().trim(),
-              "Search Results", null, searchResults.getResultStart(i),
-              searchResults.getResultEnd(i), "Search Results");
+              "Search Results", null, match.getStart(), match.getEnd(),
+              "Search Results");
+      i++;
     }
 
     if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
@@ -256,7 +263,7 @@ public class Finder extends GFinder
 
     searchResults = finder.getSearchResults(); // find(regex,
     // caseSensitive.isSelected(), )
-    Vector idMatch = finder.getIdMatch();
+    Vector<SequenceI> idMatch = finder.getIdMatch();
     boolean haveResults = false;
     // set or reset the GUI
     if ((idMatch.size() > 0))
index 8f16e77..f2d8113 100644 (file)
@@ -37,8 +37,8 @@ public class Help
 {
   public enum HelpId
   {
-    Home("home"), SequenceFeatureSettings("seqfeatures.settings"), StructureViewer(
-            "viewingpdbs");
+    Home("home"), SequenceFeatureSettings("seqfeatures.settings"),
+    StructureViewer("viewingpdbs");
 
     private String id;
 
index 61ddafb..6a20872 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.io.SequenceAnnotationReport;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.util.UrlLink;
 import jalview.viewmodel.AlignmentViewport;
 
@@ -108,8 +109,8 @@ public class IdPanel extends JPanel implements MouseListener,
     if (seq > -1 && seq < av.getAlignment().getHeight())
     {
       SequenceI sequence = av.getAlignment().getSequenceAt(seq);
-      StringBuffer tip = new StringBuffer(64);
-      seqAnnotReport.createSequenceAnnotationReport(tip, sequence,
+      StringBuilder tip = new StringBuilder(64);
+      seqAnnotReport.createTooltipAnnotationReport(tip, sequence,
               av.isShowDBRefs(), av.isShowNPFeats(),
               sp.seqCanvas.fr.getMinMax());
       setToolTipText(JvSwingUtils.wrapTooltip(true,
@@ -224,7 +225,14 @@ public class IdPanel extends JPanel implements MouseListener,
         url = null;
         continue;
       }
-      ;
+
+      if (urlLink.usesDBAccession())
+      {
+        // this URL requires an accession id, not the name of a sequence
+        url = null;
+        continue;
+      }
+
       if (!urlLink.isValid())
       {
         jalview.bin.Cache.log.error(urlLink.getInvalidMessage());
@@ -316,48 +324,32 @@ public class IdPanel extends JPanel implements MouseListener,
       return;
     }
 
-    int seq = alignPanel.getSeqPanel().findSeq(e);
-
-    if (e.isPopupTrigger())
+    if (e.isPopupTrigger()) // Mac reports this in mousePressed
     {
-      Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq);
-      // build a new links menu based on the current links + any non-positional
-      // features
-      Vector<String> nlinks = new Vector<String>(
-              Preferences.sequenceURLLinks);
-      SequenceFeature sfs[] = sq == null ? null : sq.getSequenceFeatures();
-      if (sfs != null)
-      {
-        for (SequenceFeature sf : sfs)
-        {
-          if (sf.begin == sf.end && sf.begin == 0)
-          {
-            if (sf.links != null && sf.links.size() > 0)
-            {
-              for (int l = 0, lSize = sf.links.size(); l < lSize; l++)
-              {
-                nlinks.addElement(sf.links.elementAt(l));
-              }
-            }
-          }
-        }
-      }
-
-      PopupMenu pop = new PopupMenu(alignPanel, sq, nlinks,
-              Preferences.getGroupURLLinks());
-      pop.show(this, e.getX(), e.getY());
+      showPopupMenu(e);
+      return;
+    }
 
+    /*
+     * defer right-mouse click handling to mouseReleased on Windows
+     * (where isPopupTrigger() will answer true)
+     * NB isRightMouseButton is also true for Cmd-click on Mac
+     */
+    if (SwingUtilities.isRightMouseButton(e) && !Platform.isAMac())
+    {
       return;
     }
+
     if ((av.getSelectionGroup() == null)
-            || (!jalview.util.Platform.isControlDown(e)
-                    && !e.isShiftDown() && av.getSelectionGroup() != null))
+            || (!jalview.util.Platform.isControlDown(e) && !e.isShiftDown() && av
+                    .getSelectionGroup() != null))
     {
       av.setSelectionGroup(new SequenceGroup());
       av.getSelectionGroup().setStartRes(0);
       av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
     }
 
+    int seq = alignPanel.getSeqPanel().findSeq(e);
     if (e.isShiftDown() && (lastid != -1))
     {
       selectSeqs(lastid, seq);
@@ -366,13 +358,48 @@ public class IdPanel extends JPanel implements MouseListener,
     {
       selectSeq(seq);
     }
-    // TODO is this addition ok here?
+
     av.isSelectionGroupChanged(true);
 
     alignPanel.paintAlignment(true);
   }
 
   /**
+   * Build and show the popup-menu at the right-click mouse position
+   * 
+   * @param e
+   */
+  void showPopupMenu(MouseEvent e)
+  {
+    int seq2 = alignPanel.getSeqPanel().findSeq(e);
+    Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq2);
+    // build a new links menu based on the current links + any non-positional
+    // features
+    Vector<String> nlinks = new Vector<String>(Preferences.sequenceURLLinks);
+    SequenceFeature sfs[] = sq == null ? null : sq.getSequenceFeatures();
+    if (sfs != null)
+    {
+      for (SequenceFeature sf : sfs)
+      {
+        if (sf.begin == sf.end && sf.begin == 0)
+        {
+          if (sf.links != null && sf.links.size() > 0)
+          {
+            for (int l = 0, lSize = sf.links.size(); l < lSize; l++)
+            {
+              nlinks.addElement(sf.links.elementAt(l));
+            }
+          }
+        }
+      }
+    }
+
+    PopupMenu pop = new PopupMenu(alignPanel, sq, nlinks,
+            Preferences.getGroupURLLinks());
+    pop.show(this, e.getX(), e.getY());
+  }
+
+  /**
    * Toggle whether the sequence is part of the current selection group.
    * 
    * @param seq
@@ -439,6 +466,11 @@ public class IdPanel extends JPanel implements MouseListener,
     PaintRefresher.Refresh(this, av.getSequenceSetId());
     // always send selection message when mouse is released
     av.sendSelection();
+
+    if (e.isPopupTrigger()) // Windows reports this in mouseReleased
+    {
+      showPopupMenu(e);
+    }
   }
 
   /**
index 8294d2b..2a3d788 100644 (file)
@@ -33,6 +33,8 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -168,6 +170,19 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
         _setSelectionState();
       }
     });
+    dbviews.addMouseListener(new MouseAdapter()
+    {
+
+      @Override
+      public void mousePressed(MouseEvent e)
+      {
+        if (e.getClickCount() == 2)
+        {
+          okPressed();
+          closeDialog();
+        }
+      }
+    });
     JPanel jc = new JPanel(new BorderLayout()), j = new JPanel(
             new FlowLayout());
     jc.add(svp, BorderLayout.CENTER);
@@ -308,7 +323,6 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
   protected void okPressed()
   {
     _setSelectionState();
-    closeDialog();
   }
 
   @Override
@@ -557,6 +571,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     {
       action = arg0.getKeyCode();
       okPressed();
+      closeDialog();
     }
     if (!arg0.isConsumed() && arg0.getKeyChar() == KeyEvent.VK_ESCAPE)
     {
index 35d4685..d09e7c2 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.analysis.Conservation;
 import jalview.api.FeatureColourI;
 import jalview.api.ViewStyleI;
 import jalview.api.structures.JalviewStructureDisplayI;
@@ -315,6 +316,7 @@ public class Jalview2XML
       }
       return sq;
     }
+
     /**
      * @return true if the forward reference was fully resolved
      */
@@ -367,6 +369,12 @@ public class Jalview2XML
       public jalview.datamodel.Mapping mp = _jmap;
 
       @Override
+      public boolean isResolvable()
+      {
+        return super.isResolvable() && mp.getTo() != null;
+      };
+
+      @Override
       boolean resolve()
       {
         SequenceI seq = getSrefDatasetSeq();
@@ -383,35 +391,44 @@ public class Jalview2XML
 
   public void resolveFrefedSequences()
   {
-    Iterator<SeqFref> nextFref=frefedSequence.iterator();
-    int toresolve=frefedSequence.size();
-    int unresolved=0,failedtoresolve=0;
-    while (nextFref.hasNext()) {
+    Iterator<SeqFref> nextFref = frefedSequence.iterator();
+    int toresolve = frefedSequence.size();
+    int unresolved = 0, failedtoresolve = 0;
+    while (nextFref.hasNext())
+    {
       SeqFref ref = nextFref.next();
       if (ref.isResolvable())
       {
-        try {
+        try
+        {
           if (ref.resolve())
           {
             nextFref.remove();
-          } else {
+          }
+          else
+          {
             failedtoresolve++;
           }
-        } catch (Exception x) {
-          System.err.println("IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "+ref.getSref());
+        } catch (Exception x)
+        {
+          System.err
+                  .println("IMPLEMENTATION ERROR: Failed to resolve forward reference for sequence "
+                          + ref.getSref());
           x.printStackTrace();
           failedtoresolve++;
-        } 
-      } else {
+        }
+      }
+      else
+      {
         unresolved++;
       }
     }
-    if (unresolved>0)
+    if (unresolved > 0)
     {
       System.err.println("Jalview Project Import: There were " + unresolved
               + " forward references left unresolved on the stack.");
     }
-    if (failedtoresolve>0)
+    if (failedtoresolve > 0)
     {
       System.err.println("SERIOUS! " + failedtoresolve
               + " resolvable forward references failed to resolve.");
@@ -789,37 +806,42 @@ public class Jalview2XML
 
     JSeq jseq;
     Set<String> calcIdSet = new HashSet<String>();
-
+    // record the set of vamsas sequence XML POJO we create.
+    HashMap<String, Sequence> vamsasSetIds = new HashMap<String, Sequence>();
     // SAVE SEQUENCES
     for (final SequenceI jds : rjal.getSequences())
     {
       final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
               : jds.getDatasetSequence();
       String id = seqHash(jds);
-
-      if (seqRefIds.get(id) != null)
-      {
-        // This happens for two reasons: 1. multiple views are being serialised.
-        // 2. the hashCode has collided with another sequence's code. This DOES
-        // HAPPEN! (PF00072.15.stk does this)
-        // JBPNote: Uncomment to debug writing out of files that do not read
-        // back in due to ArrayOutOfBoundExceptions.
-        // System.err.println("vamsasSeq backref: "+id+"");
-        // System.err.println(jds.getName()+"
-        // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
-        // System.err.println("Hashcode: "+seqHash(jds));
-        // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
-        // System.err.println(rsq.getName()+"
-        // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
-        // System.err.println("Hashcode: "+seqHash(rsq));
-      }
-      else
-      {
-        vamsasSeq = createVamsasSequence(id, jds);
-        vamsasSet.addSequence(vamsasSeq);
-        seqRefIds.put(id, jds);
+      if (vamsasSetIds.get(id) == null)
+      {
+        if (seqRefIds.get(id) != null && !storeDS)
+        {
+          // This happens for two reasons: 1. multiple views are being
+          // serialised.
+          // 2. the hashCode has collided with another sequence's code. This
+          // DOES
+          // HAPPEN! (PF00072.15.stk does this)
+          // JBPNote: Uncomment to debug writing out of files that do not read
+          // back in due to ArrayOutOfBoundExceptions.
+          // System.err.println("vamsasSeq backref: "+id+"");
+          // System.err.println(jds.getName()+"
+          // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString());
+          // System.err.println("Hashcode: "+seqHash(jds));
+          // SequenceI rsq = (SequenceI) seqRefIds.get(id + "");
+          // System.err.println(rsq.getName()+"
+          // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString());
+          // System.err.println("Hashcode: "+seqHash(rsq));
+        }
+        else
+        {
+          vamsasSeq = createVamsasSequence(id, jds);
+          vamsasSet.addSequence(vamsasSeq);
+          vamsasSetIds.put(id, vamsasSeq);
+          seqRefIds.put(id, jds);
+        }
       }
-
       jseq = new JSeq();
       jseq.setStart(jds.getStart());
       jseq.setEnd(jds.getEnd());
@@ -838,8 +860,7 @@ public class Jalview2XML
           if (av.isHiddenRepSequence(jds))
           {
             jalview.datamodel.SequenceI[] reps = av
-                    .getRepresentedSequences(jds)
-                    .getSequencesInOrder(rjal);
+                    .getRepresentedSequences(jds).getSequencesInOrder(rjal);
 
             for (int h = 0; h < reps.length; h++)
             {
@@ -973,17 +994,16 @@ public class Jalview2XML
             }
           }
 
-          if (entry.getProperty() != null && !entry.getProperty().isEmpty())
+          Enumeration<String> props = entry.getProperties();
+          if (props.hasMoreElements())
           {
             PdbentryItem item = new PdbentryItem();
-            Hashtable<String, String> properties = entry.getProperty();
-            Enumeration<String> en2 = properties.keys();
-            while (en2.hasMoreElements())
+            while (props.hasMoreElements())
             {
               Property prop = new Property();
-              String key = en2.nextElement();
+              String key = props.nextElement();
               prop.setName(key);
-              prop.setValue(properties.get(key));
+              prop.setValue(entry.getProperty(key).toString());
               item.addProperty(prop);
             }
             pdb.addPdbentryItem(item);
@@ -1331,8 +1351,7 @@ public class Jalview2XML
           for (String featureType : renderOrder)
           {
             FeatureColourI fcol = ap.getSeqPanel().seqCanvas
-                    .getFeatureRenderer()
-                    .getFeatureStyle(featureType);
+                    .getFeatureRenderer().getFeatureStyle(featureType);
             Setting setting = new Setting();
             setting.setType(featureType);
             if (!fcol.isSimpleColour())
@@ -1345,8 +1364,8 @@ public class Jalview2XML
               setting.setAutoScale(fcol.isAutoScaled());
               setting.setThreshold(fcol.getThreshold());
               // -1 = No threshold, 0 = Below, 1 = Above
-              setting.setThreshstate(fcol.isAboveThreshold() ? 1
-                      : (fcol.isBelowThreshold() ? 0 : -1));
+              setting.setThreshstate(fcol.isAboveThreshold() ? 1 : (fcol
+                      .isBelowThreshold() ? 0 : -1));
             }
             else
             {
@@ -1368,8 +1387,7 @@ public class Jalview2XML
 
         // is groups actually supposed to be a map here ?
         Iterator<String> en = ap.getSeqPanel().seqCanvas
-                .getFeatureRenderer()
-                .getFeatureGroups().iterator();
+                .getFeatureRenderer().getFeatureGroups().iterator();
         Vector<String> groupsAdded = new Vector<String>();
         while (en.hasNext())
         {
@@ -2527,6 +2545,8 @@ public class Jalview2XML
           SplitFrame sf = createSplitFrame(dnaFrame, af);
           addedToSplitFrames.add(dnaFrame);
           addedToSplitFrames.add(af);
+          dnaFrame.setMenusForViewport();
+          af.setMenusForViewport();
           if (af.viewport.isGatherViewsHere())
           {
             gatherTo.add(sf);
@@ -2548,6 +2568,7 @@ public class Jalview2XML
         Viewport view = candidate.getKey();
         Desktop.addInternalFrame(af, view.getTitle(), view.getWidth(),
                 view.getHeight());
+        af.setMenusForViewport();
         System.err.println("Failed to restore view " + view.getTitle()
                 + " to split frame");
       }
@@ -2651,14 +2672,16 @@ public class Jalview2XML
    * @param pdbId
    * @return
    */
-  String loadPDBFile(jarInputStreamProvider jprovider, String pdbId)
+  String loadPDBFile(jarInputStreamProvider jprovider, String pdbId,
+          String origFile)
   {
     if (alreadyLoadedPDB.containsKey(pdbId))
     {
       return alreadyLoadedPDB.get(pdbId).toString();
     }
 
-    String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb");
+    String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb",
+            origFile);
     if (tempFile != null)
     {
       alreadyLoadedPDB.put(pdbId, tempFile);
@@ -2675,14 +2698,26 @@ public class Jalview2XML
    * @param prefix
    *          a prefix for the temporary file name, must be at least three
    *          characters long
+   * @param origFile
+   *          null or original file - so new file can be given the same suffix
+   *          as the old one
    * @return
    */
   protected String copyJarEntry(jarInputStreamProvider jprovider,
-          String jarEntryName, String prefix)
+          String jarEntryName, String prefix, String origFile)
   {
     BufferedReader in = null;
     PrintWriter out = null;
-
+    String suffix = ".tmp";
+    if (origFile == null)
+    {
+      origFile = jarEntryName;
+    }
+    int sfpos = origFile.lastIndexOf(".");
+    if (sfpos > -1 && sfpos < (origFile.length() - 3))
+    {
+      suffix = "." + origFile.substring(sfpos + 1);
+    }
     try
     {
       JarInputStream jin = jprovider.getJarInputStream();
@@ -2700,7 +2735,7 @@ public class Jalview2XML
       if (entry != null)
       {
         in = new BufferedReader(new InputStreamReader(jin, UTF_8));
-        File outFile = File.createTempFile(prefix, ".tmp");
+        File outFile = File.createTempFile(prefix, suffix);
         outFile.deleteOnExit();
         out = new PrintWriter(new FileOutputStream(outFile));
         String data;
@@ -2789,7 +2824,6 @@ public class Jalview2XML
 
     List<SequenceI> hiddenSeqs = null;
 
-
     List<SequenceI> tmpseqs = new ArrayList<SequenceI>();
 
     boolean multipleView = false;
@@ -2806,19 +2840,35 @@ public class Jalview2XML
         if (!incompleteSeqs.containsKey(seqId))
         {
           // may not need this check, but keep it for at least 2.9,1 release
-          if (tmpSeq.getStart()!=jseqs[i].getStart() || tmpSeq.getEnd()!=jseqs[i].getEnd())
-          { 
+          if (tmpSeq.getStart() != jseqs[i].getStart()
+                  || tmpSeq.getEnd() != jseqs[i].getEnd())
+          {
             System.err
                     .println("Warning JAL-2154 regression: updating start/end for sequence "
-                    + tmpSeq.toString());
+                            + tmpSeq.toString() + " to " + jseqs[i]);
           }
-        } else {
+        }
+        else
+        {
           incompleteSeqs.remove(seqId);
         }
+        if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId))
+        {
+          // most likely we are reading a dataset XML document so
+          // update from vamsasSeq section of XML for this sequence
+          tmpSeq.setName(vamsasSeq[vi].getName());
+          tmpSeq.setDescription(vamsasSeq[vi].getDescription());
+          tmpSeq.setSequence(vamsasSeq[vi].getSequence());
+          vi++;
+        }
+        else
+        {
+          // reading multiple views, so vamsasSeq set is a subset of JSeq
+          multipleView = true;
+        }
         tmpSeq.setStart(jseqs[i].getStart());
         tmpSeq.setEnd(jseqs[i].getEnd());
         tmpseqs.add(tmpSeq);
-        multipleView = true;
       }
       else
       {
@@ -2907,6 +2957,12 @@ public class Jalview2XML
     {
       // load sequence features, database references and any associated PDB
       // structures for the alignment
+      //
+      // prior to 2.10, this part would only be executed the first time a
+      // sequence was encountered, but not afterwards.
+      // now, for 2.10 projects, this is also done if the xml doc includes
+      // dataset sequences not actually present in any particular view.
+      //
       for (int i = 0; i < vamsasSeq.length; i++)
       {
         if (jseqs[i].getFeaturesCount() > 0)
@@ -2933,13 +2989,17 @@ public class Jalview2XML
               }
 
             }
-
-            al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf);
+            // adds feature to datasequence's feature set (since Jalview 2.10)
+            al.getSequenceAt(i).addSequenceFeature(sf);
           }
         }
         if (vamsasSeq[i].getDBRefCount() > 0)
         {
-          addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]);
+          // adds dbrefs to datasequence's set (since Jalview 2.10)
+          addDBRefs(
+                  al.getSequenceAt(i).getDatasetSequence() == null ? al.getSequenceAt(i)
+                          : al.getSequenceAt(i).getDatasetSequence(),
+                  vamsasSeq[i]);
         }
         if (jseqs[i].getPdbidsCount() > 0)
         {
@@ -2950,29 +3010,49 @@ public class Jalview2XML
             entry.setId(ids[p].getId());
             if (ids[p].getType() != null)
             {
-              if (ids[p].getType().equalsIgnoreCase("PDB"))
+              if (PDBEntry.Type.getType(ids[p].getType()) != null)
               {
-                entry.setType(PDBEntry.Type.PDB);
+                entry.setType(PDBEntry.Type.getType(ids[p].getType()));
               }
               else
               {
                 entry.setType(PDBEntry.Type.FILE);
               }
             }
-            if (ids[p].getFile() != null)
+            // jprovider is null when executing 'New View'
+            if (ids[p].getFile() != null && jprovider != null)
             {
               if (!pdbloaded.containsKey(ids[p].getFile()))
               {
-                entry.setFile(loadPDBFile(jprovider, ids[p].getId()));
+                entry.setFile(loadPDBFile(jprovider, ids[p].getId(),
+                        ids[p].getFile()));
               }
               else
               {
                 entry.setFile(pdbloaded.get(ids[p].getId()).toString());
               }
             }
+            if (ids[p].getPdbentryItem() != null)
+            {
+              for (PdbentryItem item : ids[p].getPdbentryItem())
+              {
+                for (Property pr : item.getProperty())
+                {
+                  entry.setProperty(pr.getName(), pr.getValue());
+                }
+              }
+            }
             StructureSelectionManager.getStructureSelectionManager(
                     Desktop.instance).registerPDBEntry(entry);
-            al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
+            // adds PDBEntry to datasequence's set (since Jalview 2.10)
+            if (al.getSequenceAt(i).getDatasetSequence() != null)
+            {
+              al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
+            }
+            else
+            {
+              al.getSequenceAt(i).addPDBId(entry);
+            }
           }
         }
       }
@@ -3001,16 +3081,16 @@ public class Jalview2XML
             if (maps[m].getMapping() != null)
             {
               mapping = addMapping(maps[m].getMapping());
-            }
-            if (dnaseq != null && mapping.getTo() != null)
-            {
-              cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
-            }
-            else
-            {
-              // defer to later
-              frefedSequence.add(newAlcodMapRef(maps[m].getDnasq(), cf,
-                      mapping));
+              if (dnaseq != null && mapping.getTo() != null)
+              {
+                cf.addMap(dnaseq, mapping.getTo(), mapping.getMap());
+              }
+              else
+              {
+                // defer to later
+                frefedSequence.add(newAlcodMapRef(maps[m].getDnasq(), cf,
+                        mapping));
+              }
             }
           }
           al.addCodonFrame(cf);
@@ -3323,9 +3403,8 @@ public class Jalview2XML
         }
         if (jGroup.getConsThreshold() != 0)
         {
-          jalview.analysis.Conservation c = new jalview.analysis.Conservation(
-                  "All", ResidueProperties.propHash, 3,
-                  sg.getSequences(null), 0, sg.getWidth() - 1);
+          Conservation c = new Conservation("All", sg.getSequences(null),
+                  0, sg.getWidth() - 1);
           c.calculate();
           c.verdict(false, 25);
           sg.cs.setConservation(c);
@@ -3514,7 +3593,7 @@ public class Jalview2XML
           String rnaTitle = ss.getTitle();
           String sessionState = ss.getViewerState();
           String tempStateFile = copyJarEntry(jprovider, sessionState,
-                  "varna");
+                  "varna", null);
           RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped);
           appVarna.addModelSession(rna, rnaTitle, tempStateFile);
         }
@@ -3689,7 +3768,8 @@ public class Jalview2XML
             // Originally : ids[p].getFile()
             // : TODO: verify external PDB file recovery still works in normal
             // jalview project load
-            jpdb.setFile(loadPDBFile(jprovider, ids[p].getId()));
+            jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(),
+                    ids[p].getFile()));
             jpdb.setId(ids[p].getId());
 
             int x = structureState.getXpos();
@@ -3700,7 +3780,8 @@ public class Jalview2XML
             // Probably don't need to do this anymore...
             // Desktop.desktop.getComponentAt(x, y);
             // TODO: NOW: check that this recovers the PDB file correctly.
-            String pdbFile = loadPDBFile(jprovider, ids[p].getId());
+            String pdbFile = loadPDBFile(jprovider, ids[p].getId(),
+                    ids[p].getFile());
             jalview.datamodel.SequenceI seq = seqRefIds.get(jseqs[i]
                     .getId() + "");
             if (sviewid == null)
@@ -3860,7 +3941,7 @@ public class Jalview2XML
      */
     String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
     chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
-            "chimera");
+            "chimera", null);
 
     Set<Entry<File, StructureData>> fileData = data.getFileData()
             .entrySet();
@@ -3941,6 +4022,11 @@ public class Jalview2XML
         // filename
         // translation differently.
         StructureData filedat = oldFiles.get(new File(oldfilenam));
+        if (filedat == null)
+        {
+          String reformatedOldFilename = oldfilenam.replaceAll("/", "\\\\");
+          filedat = oldFiles.get(new File(reformatedOldFilename));
+        }
         newFileLoc.append(Platform.escapeString(filedat.getFilePath()));
         pdbfilenames.add(filedat.getFilePath());
         pdbids.add(filedat.getPdbId());
@@ -4899,7 +4985,7 @@ public class Jalview2XML
     for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++)
     {
       Sequence vamsasSeq = vamsasSet.getSequence(i);
-      ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed);
+      ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i);
     }
     // create a new dataset
     if (ds == null)
@@ -4926,18 +5012,29 @@ public class Jalview2XML
    *          dataset alignment
    * @param dseqs
    *          vector to add new dataset sequence to
+   * @param ignoreUnrefed
+   *          - when true, don't create new sequences from vamsasSeq if it's id
+   *          doesn't already have an asssociated Jalview sequence.
+   * @param vseqpos
+   *          - used to reorder the sequence in the alignment according to the
+   *          vamsasSeq array ordering, to preserve ordering of dataset
    */
   private void ensureJalviewDatasetSequence(Sequence vamsasSeq,
-          AlignmentI ds, Vector dseqs, boolean ignoreUnrefed)
+          AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos)
   {
     // JBP TODO: Check this is called for AlCodonFrames to support recovery of
     // xRef Codon Maps
     SequenceI sq = seqRefIds.get(vamsasSeq.getId());
+    boolean reorder = false;
     SequenceI dsq = null;
     if (sq != null && sq.getDatasetSequence() != null)
     {
       dsq = sq.getDatasetSequence();
     }
+    else
+    {
+      reorder = true;
+    }
     if (sq == null && ignoreUnrefed)
     {
       return;
@@ -5033,6 +5130,35 @@ public class Jalview2XML
         // + (post ? "appended" : ""));
       }
     }
+    else
+    {
+      // sequence refs are identical. We may need to update the existing dataset
+      // alignment with this one, though.
+      if (ds != null && dseqs == null)
+      {
+        int opos = ds.findIndex(dsq);
+        SequenceI tseq = null;
+        if (opos != -1 && vseqpos != opos)
+        {
+          // remove from old position
+          ds.deleteSequence(dsq);
+        }
+        if (vseqpos < ds.getHeight())
+        {
+          if (vseqpos != opos)
+          {
+            // save sequence at destination position
+            tseq = ds.getSequenceAt(vseqpos);
+            ds.replaceSequenceAt(vseqpos, dsq);
+            ds.addSequence(tseq);
+          }
+        }
+        else
+        {
+          ds.addSequence(dsq);
+        }
+      }
+    }
   }
 
   /*
index 4a582de..5cd3bb2 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.analysis.Conservation;
 import jalview.binding.Annotation;
 import jalview.binding.AnnotationElement;
 import jalview.binding.Features;
@@ -38,7 +39,6 @@ import jalview.datamodel.PDBEntry;
 import jalview.io.FileFormat;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.util.jarInputStreamProvider;
@@ -360,9 +360,8 @@ public class Jalview2XML_V1
 
         if (groups[i].getConsThreshold() != 0)
         {
-          jalview.analysis.Conservation c = new jalview.analysis.Conservation(
-                  "All", ResidueProperties.propHash, 3,
-                  sg.getSequences(null), 0, sg.getWidth() - 1);
+          Conservation c = new Conservation("All", sg.getSequences(null),
+                  0, sg.getWidth() - 1);
           c.calculate();
           c.verdict(false, 25);
           sg.cs.setConservation(c);
index 76d2703..a399db3 100644 (file)
@@ -33,12 +33,12 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
 
   private FeatureRenderer fr = null;
 
+
   public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame,
           StructureSelectionManager ssm, PDBEntry[] pdbentry,
-          SequenceI[][] sequenceIs, String[][] chains,
-          DataSourceType protocol)
+          SequenceI[][] sequenceIs, DataSourceType protocol)
   {
-    super(ssm, pdbentry, sequenceIs, chains, protocol);
+    super(ssm, pdbentry, sequenceIs, protocol);
     cvf = chimeraViewFrame;
   }
 
@@ -140,4 +140,6 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding
     thread.start();
 
   }
+
+
 }
index 3a4dfab..8742253 100644 (file)
@@ -59,6 +59,7 @@ public abstract class JalviewDialog extends JPanel
       new Thread(new Runnable()
       {
 
+        @Override
         public void run()
         {
           frame.setVisible(true);
@@ -95,6 +96,7 @@ public abstract class JalviewDialog extends JPanel
     ok.setText(MessageManager.getString("action.ok"));
     ok.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         okPressed();
@@ -105,6 +107,7 @@ public abstract class JalviewDialog extends JPanel
     cancel.setText(MessageManager.getString("action.cancel"));
     cancel.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         cancelPressed();
index 7f1b305..e584eb7 100644 (file)
@@ -210,7 +210,7 @@ public class OptsAndParamsPage
     @Override
     public void mouseClicked(MouseEvent e)
     {
-      if (e.isPopupTrigger())
+      if (e.isPopupTrigger()) // for Windows
       {
         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
       }
@@ -233,15 +233,15 @@ public class OptsAndParamsPage
     @Override
     public void mousePressed(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
+      if (e.isPopupTrigger()) // Mac
+      {
+        showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
+      }
     }
 
     @Override
     public void mouseReleased(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
     }
 
     public void resetToDefault(boolean setDefaultParams)
@@ -537,7 +537,7 @@ public class OptsAndParamsPage
     @Override
     public void mouseClicked(MouseEvent e)
     {
-      if (e.isPopupTrigger())
+      if (e.isPopupTrigger()) // for Windows
       {
         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
       }
@@ -560,8 +560,10 @@ public class OptsAndParamsPage
     @Override
     public void mousePressed(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
+      if (e.isPopupTrigger()) // for Mac
+      {
+        showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
+      }
     }
 
     @Override
@@ -577,8 +579,8 @@ public class OptsAndParamsPage
       if (!adjusting)
       {
         valueField.setText(""
-                + ((integ) ? ("" + slider.getValue())
-                        : ("" + slider.getValue() / 1000f)));
+                + ((integ) ? ("" + slider.getValue()) : ("" + slider
+                        .getValue() / 1000f)));
         checkIfModified();
       }
 
index d09c756..1c48690 100755 (executable)
@@ -480,6 +480,7 @@ public class OverviewPanel extends JPanel implements Runnable
   }
 
   private BufferedImage lastMiniMe = null;
+
   /**
    * DOCUMENT ME!
    * 
index 9f65708..6f4f3b9 100644 (file)
@@ -51,13 +51,11 @@ import jalview.schemes.HydrophobicColourScheme;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.PIDColourScheme;
 import jalview.schemes.PurinePyrimidineColourScheme;
-import jalview.schemes.ResidueProperties;
 import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.schemes.UserColourScheme;
 import jalview.schemes.ZappoColourScheme;
-import jalview.util.DBRefUtils;
 import jalview.util.GroupUrlLink;
 import jalview.util.GroupUrlLink.UrlStringTooLongException;
 import jalview.util.MessageManager;
@@ -66,8 +64,8 @@ import jalview.util.UrlLink;
 import java.awt.Color;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Hashtable;
 import java.util.LinkedHashMap;
@@ -619,7 +617,8 @@ public class PopupMenu extends JPopupMenu
   void addFeatureLinks(final SequenceI seq, List<String> links)
   {
     JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
-    List<String> linkset = new ArrayList<String>();
+    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+
     for (String link : links)
     {
       UrlLink urlLink = null;
@@ -631,97 +630,28 @@ public class PopupMenu extends JPopupMenu
         Cache.log.error("Exception for URLLink '" + link + "'", foo);
         continue;
       }
-      ;
+
       if (!urlLink.isValid())
       {
         Cache.log.error(urlLink.getInvalidMessage());
         continue;
       }
-      final String label = urlLink.getLabel();
-      if (seq != null && urlLink.isDynamic())
-      {
 
-        // collect matching db-refs
-        DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
-                new String[] { urlLink.getTarget() });
-        // collect id string too
-        String id = seq.getName();
-        String descr = seq.getDescription();
-        if (descr != null && descr.length() < 1)
-        {
-          descr = null;
-        }
+      urlLink.createLinksFromSeq(seq, linkset);
+    }
 
-        if (dbr != null)
-        {
-          for (int r = 0; r < dbr.length; r++)
-          {
-            if (id != null && dbr[r].getAccessionId().equals(id))
-            {
-              // suppress duplicate link creation for the bare sequence ID
-              // string with this link
-              id = null;
-            }
-            // create Bare ID link for this URL
-            String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
-            if (urls != null)
-            {
-              for (int u = 0; u < urls.length; u += 2)
-              {
-                if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-                {
-                  linkset.add(urls[u] + "|" + urls[u + 1]);
-                  addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
-                }
-              }
-            }
-          }
-        }
-        if (id != null)
-        {
-          // create Bare ID link for this URL
-          String[] urls = urlLink.makeUrls(id, true);
-          if (urls != null)
-          {
-            for (int u = 0; u < urls.length; u += 2)
-            {
-              if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-              {
-                linkset.add(urls[u] + "|" + urls[u + 1]);
-                addshowLink(linkMenu, label, urls[u + 1]);
-              }
-            }
-          }
-        }
-        // Create urls from description but only for URL links which are regex
-        // links
-        if (descr != null && urlLink.getRegexReplace() != null)
-        {
-          // create link for this URL from description where regex matches
-          String[] urls = urlLink.makeUrls(descr, true);
-          if (urls != null)
-          {
-            for (int u = 0; u < urls.length; u += 2)
-            {
-              if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-              {
-                linkset.add(urls[u] + "|" + urls[u + 1]);
-                addshowLink(linkMenu, label, urls[u + 1]);
-              }
-            }
-          }
-        }
-      }
-      else
-      {
-        if (!linkset.contains(label + "|" + urlLink.getUrl_prefix()))
-        {
-          linkset.add(label + "|" + urlLink.getUrl_prefix());
-          // Add a non-dynamic link
-          addshowLink(linkMenu, label, urlLink.getUrl_prefix());
-        }
-      }
+    addshowLinks(linkMenu, linkset.values());
+
+    // disable link menu if there are no valid entries
+    if (linkMenu.getItemCount() > 0)
+    {
+      linkMenu.setEnabled(true);
     }
+    else
+    {
+      linkMenu.setEnabled(false);
+    }
+
     if (sequence != null)
     {
       sequenceMenu.add(linkMenu);
@@ -730,8 +660,11 @@ public class PopupMenu extends JPopupMenu
     {
       add(linkMenu);
     }
+
   }
 
+
+
   /**
    * Add annotation types to 'Show annotations' and/or 'Hide annotations' menus.
    * "All" is added first, followed by a separator. Then add any annotation
@@ -930,8 +863,7 @@ public class PopupMenu extends JPopupMenu
         urlLink = new GroupUrlLink(link);
       } catch (Exception foo)
       {
-        Cache.log.error("Exception for GroupURLLink '" + link
-                + "'", foo);
+        Cache.log.error("Exception for GroupURLLink '" + link + "'", foo);
         continue;
       }
       ;
@@ -1007,6 +939,15 @@ public class PopupMenu extends JPopupMenu
     }
   }
 
+  private void addshowLinks(JMenu linkMenu, Collection<List<String>> linkset)
+  {
+    for (List<String> linkstrset : linkset)
+    {
+      // split linkstr into label and url
+      addshowLink(linkMenu, linkstrset.get(1), linkstrset.get(3));
+    }
+  }
+
   /**
    * add a show URL menu item to the given linkMenu
    * 
@@ -1737,7 +1678,7 @@ public class PopupMenu extends JPopupMenu
   public void createSequenceDetailsReport(SequenceI[] sequences)
   {
     CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
-    StringBuffer contents = new StringBuffer();
+    StringBuilder contents = new StringBuilder(128);
     for (SequenceI seq : sequences)
     {
       contents.append("<p><h2>"
@@ -1752,7 +1693,6 @@ public class PopupMenu extends JPopupMenu
                       seq,
                       true,
                       true,
-                      false,
                       (ap.getSeqPanel().seqCanvas.fr != null) ? ap
                               .getSeqPanel().seqCanvas.fr.getMinMax()
                               : null);
@@ -2040,9 +1980,8 @@ public class PopupMenu extends JPopupMenu
     if (conservationMenuItem.isSelected())
     {
       // JBPNote: Conservation name shouldn't be i18n translated
-      Conservation c = new Conservation("Group",
-              ResidueProperties.propHash, 3, sg.getSequences(ap.av
-                      .getHiddenRepSequences()), sg.getStartRes(),
+      Conservation c = new Conservation("Group", sg.getSequences(ap.av
+              .getHiddenRepSequences()), sg.getStartRes(),
               sg.getEndRes() + 1);
 
       c.calculate();
index 4f4dcd0..c45feb9 100755 (executable)
  */
 package jalview.gui;
 
+import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.EMBLEBI_STRING;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SRS_STRING;
+
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.bin.Cache;
 import jalview.gui.Help.HelpId;
@@ -111,10 +116,7 @@ public class Preferences extends GPreferences
   public static List<String> groupURLLinks;
   static
   {
-    String string = Cache
-            .getDefault(
-                    "SEQUENCE_LINKS",
-                    "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$");
+    String string = Cache.getDefault("SEQUENCE_LINKS", EMBLEBI_STRING);
     sequenceURLLinks = new Vector<String>();
 
     try
@@ -125,7 +127,11 @@ public class Preferences extends GPreferences
         String name = st.nextToken();
         String url = st.nextToken();
         // check for '|' within a regex
-        int rxstart = url.indexOf("$SEQUENCE_ID$");
+        int rxstart = url.indexOf("$" + DB_ACCESSION + "$");
+        if (rxstart == -1)
+        {
+          rxstart = url.indexOf("$" + SEQUENCE_ID + "$");
+        }
         while (rxstart == -1 && url.indexOf("/=$") == -1)
         {
           url = url + "|" + st.nextToken();
@@ -138,14 +144,10 @@ public class Preferences extends GPreferences
     }
     {
       // upgrade old SRS link
-      int srsPos = sequenceURLLinks
-              .indexOf("SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry");
+      int srsPos = sequenceURLLinks.indexOf(SRS_STRING);
       if (srsPos > -1)
       {
-        sequenceURLLinks
-                .setElementAt(
-                        "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$",
-                        srsPos);
+        sequenceURLLinks.setElementAt(EMBLEBI_STRING, srsPos);
       }
     }
 
@@ -537,8 +539,8 @@ public class Preferences extends GPreferences
     /*
      * Save Output settings
      */
-      Cache.applicationProperties.setProperty("EPS_RENDERING",
-              ((OptionsParam) epsRendering.getSelectedItem()).getCode());
+    Cache.applicationProperties.setProperty("EPS_RENDERING",
+            ((OptionsParam) epsRendering.getSelectedItem()).getCode());
 
     /*
      * Save Connections settings
@@ -566,6 +568,7 @@ public class Preferences extends GPreferences
     else
     {
       Cache.applicationProperties.remove("SEQUENCE_LINKS");
+      sequenceURLLinks.clear();
     }
 
     Cache.applicationProperties.setProperty("USE_PROXY",
@@ -1053,7 +1056,8 @@ public class Preferences extends GPreferences
     }
 
     @Override
-    public int hashCode(){
+    public int hashCode()
+    {
       return name.hashCode() + code.hashCode();
     }
   }
index 316b6be..0aa2459 100755 (executable)
@@ -43,6 +43,7 @@ import java.util.List;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 
 /**
@@ -120,10 +121,19 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     min = res;
     max = res;
 
-    if (evt.isPopupTrigger())
+    if (evt.isPopupTrigger()) // Mac: mousePressed
     {
       rightMouseButtonPressed(evt, res);
     }
+    else if (SwingUtilities.isRightMouseButton(evt) && !Platform.isAMac())
+    {
+      /*
+       * defer right-mouse click handling to mouse up on Windows
+       * (where isPopupTrigger() will answer true)
+       * but accept Cmd-click on Mac which passes isRightMouseButton
+       */
+      return;
+    }
     else
     {
       leftMouseButtonPressed(evt, res);
@@ -222,6 +232,11 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
    */
   protected void leftMouseButtonPressed(MouseEvent evt, final int res)
   {
+    /*
+     * Ctrl-click/Cmd-click adds to the selection
+     * Shift-click extends the selection
+     */
+    // TODO Problem: right-click on Windows not reported until mouseReleased?!?
     if (!Platform.isControlDown(evt) && !evt.isShiftDown())
     {
       av.getColumnSelection().clear();
@@ -281,8 +296,14 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     if (!stretchingGroup)
     {
-      ap.paintAlignment(false);
-
+      if (evt.isPopupTrigger()) // Windows: mouseReleased
+      {
+        rightMouseButtonPressed(evt, res);
+      }
+      else
+      {
+        ap.paintAlignment(false);
+      }
       return;
     }
 
index 760ece0..d015292 100755 (executable)
@@ -21,7 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.ScaleRenderer;
@@ -62,8 +62,6 @@ public class SeqCanvas extends JComponent
 
   AlignViewport av;
 
-  SearchResults searchResults = null;
-
   boolean fastPaint = false;
 
   int LABEL_WEST;
@@ -740,10 +738,10 @@ public class SeqCanvas extends JComponent
 
       // / Highlight search Results once all sequences have been drawn
       // ////////////////////////////////////////////////////////
-      if (searchResults != null)
+      if (av.hasSearchResults())
       {
-        int[] visibleResults = searchResults.getResults(nextSeq, startRes,
-                endRes);
+        int[] visibleResults = av.getSearchResults().getResults(nextSeq,
+                startRes, endRes);
         if (visibleResults != null)
         {
           for (int r = 0; r < visibleResults.length; r += 2)
@@ -965,11 +963,11 @@ public class SeqCanvas extends JComponent
    * @param results
    *          DOCUMENT ME!
    */
-  public void highlightSearchResults(SearchResults results)
+  public void highlightSearchResults(SearchResultsI results)
   {
     img = null;
 
-    searchResults = results;
+    av.setSearchResults(results);
 
     repaint();
   }
index f476d41..36fb052 100644 (file)
@@ -27,8 +27,9 @@ import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
-import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -43,6 +44,7 @@ import jalview.structure.VamsasSource;
 import jalview.util.Comparison;
 import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.BorderLayout;
@@ -123,7 +125,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   private final SequenceAnnotationReport seqARep;
 
-  StringBuffer tooltipText = new StringBuffer();
+  StringBuilder tooltipText = new StringBuilder();
 
   String tmpString;
 
@@ -131,7 +133,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   StructureSelectionManager ssm;
 
-  SearchResults lastSearchResults;
+  SearchResultsI lastSearchResults;
 
   /**
    * Creates a new SeqPanel object.
@@ -582,6 +584,13 @@ public class SeqPanel extends JPanel implements MouseListener,
     mouseDragging = false;
     mouseWheelPressed = false;
 
+    if (evt.isPopupTrigger()) // Windows: mouseReleased
+    {
+      showPopupMenu(evt);
+      evt.consume();
+      return;
+    }
+
     if (!editingSeqs)
     {
       doMouseReleasedDefineMode(evt);
@@ -608,13 +617,14 @@ public class SeqPanel extends JPanel implements MouseListener,
       return;
     }
 
-    if (evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())
+    boolean isControlDown = Platform.isControlDown(evt);
+    if (evt.isShiftDown() || isControlDown)
     {
-      if (evt.isAltDown() || evt.isControlDown())
+      editingSeqs = true;
+      if (isControlDown)
       {
         groupEditing = true;
       }
-      editingSeqs = true;
     }
     else
     {
@@ -667,7 +677,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    * the start of the highlighted region.
    */
   @Override
-  public void highlightSequence(SearchResults results)
+  public void highlightSequence(SearchResultsI results)
   {
     if (results == null || results.equals(lastSearchResults))
     {
@@ -776,7 +786,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       seqARep.appendFeatures(tooltipText, rpos, features,
               this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
     }
-    if (tooltipText.length() == 6) // <html></html>
+    if (tooltipText.length() == 6) // <html>
     {
       setToolTipText(null);
       lastTooltip = null;
@@ -836,7 +846,8 @@ public class SeqPanel extends JPanel implements MouseListener,
    * set if av.getSelectionGroup() refers to a group that is defined on the
    * alignment view, rather than a transient selection
    */
-  private boolean editingDefinedGroup = false;  // TODO: refactor to avcontroller or viewModel
+  // private boolean editingDefinedGroup = false; // TODO: refactor to
+  // avcontroller or viewModel
 
   /**
    * Set status message in alignment panel
@@ -900,7 +911,7 @@ public class SeqPanel extends JPanel implements MouseListener,
    * 
    * @param results
    */
-  private void setStatusMessage(SearchResults results)
+  private void setStatusMessage(SearchResultsI results)
   {
     AlignmentI al = this.av.getAlignment();
     int sequenceIndex = al.findIndex(results);
@@ -909,7 +920,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       return;
     }
     SequenceI ds = al.getSequenceAt(sequenceIndex).getDatasetSequence();
-    for (Match m : results.getResults())
+    for (SearchResultMatchI m : results.getResults())
     {
       SequenceI seq = m.getSequence();
       if (seq.getDatasetSequence() != null)
@@ -1491,7 +1502,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
       if (features != null && features.size() > 0)
       {
-        SearchResults highlight = new SearchResults();
+        SearchResultsI highlight = new SearchResults();
         highlight.addResult(sequence, features.get(0).getBegin(), features
                 .get(0).getEnd());
         seqCanvas.highlightSearchResults(highlight);
@@ -1546,9 +1557,10 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   public void doMousePressedDefineMode(MouseEvent evt)
   {
-    int res = findRes(evt);
-    int seq = findSeq(evt);
+    final int res = findRes(evt);
+    final int seq = findSeq(evt);
     oldSeq = seq;
+    needOverviewUpdate = false;
 
     startWrapBlock = wrappedBlock;
 
@@ -1583,12 +1595,10 @@ public class SeqPanel extends JPanel implements MouseListener,
               && (res < stretchGroup.getEndRes()))
       {
         av.setSelectionGroup(stretchGroup);
-        editingDefinedGroup = true;
       }
       else
       {
         stretchGroup = null;
-        editingDefinedGroup = false;
       }
     }
     else if (!stretchGroup.getSequences(null).contains(sequence)
@@ -1607,35 +1617,27 @@ public class SeqPanel extends JPanel implements MouseListener,
                   && (allGroups[i].getEndRes() >= res))
           {
             stretchGroup = allGroups[i];
-            editingDefinedGroup = true;
             break;
           }
         }
       }
 
       av.setSelectionGroup(stretchGroup);
-
     }
 
-    if (evt.isPopupTrigger())
+    if (evt.isPopupTrigger()) // Mac: mousePressed
     {
-      List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
-              .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      sequence.findPosition(res));
-      List<String> links = new ArrayList<String>();
-      for (SequenceFeature sf : allFeatures)
-      {
-        if (sf.links != null)
-        {
-          for (String link : sf.links)
-          {
-            links.add(link);
-          }
-        }
-      }
+      showPopupMenu(evt);
+      return;
+    }
 
-      PopupMenu pop = new PopupMenu(ap, null, links);
-      pop.show(this, evt.getX(), evt.getY());
+    /*
+     * defer right-mouse click handling to mouseReleased on Windows
+     * (where isPopupTrigger() will answer true)
+     * NB isRightMouseButton is also true for Cmd-click on Mac
+     */
+    if (SwingUtilities.isRightMouseButton(evt) && !Platform.isAMac())
+    {
       return;
     }
 
@@ -1657,7 +1659,6 @@ public class SeqPanel extends JPanel implements MouseListener,
       sg.setEndRes(res);
       sg.addSequence(sequence, false);
       av.setSelectionGroup(sg);
-      editingDefinedGroup = false;
       stretchGroup = sg;
 
       if (av.getConservationSelected())
@@ -1689,6 +1690,37 @@ public class SeqPanel extends JPanel implements MouseListener,
   }
 
   /**
+   * Build and show a pop-up menu at the right-click mouse position
+   * 
+   * @param evt
+   * @param res
+   * @param sequence
+   */
+  void showPopupMenu(MouseEvent evt)
+  {
+    final int res = findRes(evt);
+    final int seq = findSeq(evt);
+    SequenceI sequence = av.getAlignment().getSequenceAt(seq);
+    List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
+            .findFeaturesAtRes(sequence.getDatasetSequence(),
+                    sequence.findPosition(res));
+    List<String> links = new ArrayList<String>();
+    for (SequenceFeature sf : allFeatures)
+    {
+      if (sf.links != null)
+      {
+        for (String link : sf.links)
+        {
+          links.add(link);
+        }
+      }
+    }
+
+    PopupMenu pop = new PopupMenu(ap, null, links);
+    pop.show(this, evt.getX(), evt.getY());
+  }
+
+  /**
    * DOCUMENT ME!
    * 
    * @param evt
@@ -1703,7 +1735,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     // always do this - annotation has own state
     // but defer colourscheme update until hidden sequences are passed in
     boolean vischange = stretchGroup.recalcConservation(true);
-    needOverviewUpdate |= vischange && editingDefinedGroup;
+    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
     if (stretchGroup.cs != null)
     {
       stretchGroup.cs.alignmentChanged(stretchGroup,
@@ -1722,8 +1754,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     PaintRefresher.Refresh(this, av.getSequenceSetId());
     ap.paintAlignment(needOverviewUpdate);
-    needOverviewUpdate =false;
-    editingDefinedGroup = false;
+    needOverviewUpdate = false;
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
@@ -1777,7 +1808,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       if (res > (stretchGroup.getStartRes() - 1))
       {
         stretchGroup.setEndRes(res);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
     else if (changeStartRes)
@@ -1785,7 +1816,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       if (res < (stretchGroup.getEndRes() + 1))
       {
         stretchGroup.setStartRes(res);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1819,7 +1850,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       if (stretchGroup.getSequences(null).contains(nextSeq))
       {
         stretchGroup.deleteSequence(seq, false);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
       else
       {
@@ -1829,7 +1860,7 @@ public class SeqPanel extends JPanel implements MouseListener,
         }
 
         stretchGroup.addSequence(nextSeq, false);
-        needOverviewUpdate |= editingDefinedGroup;
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1983,8 +2014,8 @@ public class SeqPanel extends JPanel implements MouseListener,
     {
       if (av.getAlignment() == null)
       {
-        Cache.log.warn("alignviewport av SeqSetId="
-                + av.getSequenceSetId() + " ViewId=" + av.getViewId()
+        Cache.log.warn("alignviewport av SeqSetId=" + av.getSequenceSetId()
+                + " ViewId=" + av.getViewId()
                 + " 's alignment is NULL! returning immediately.");
         return;
       }
index fca130b..5b65041 100755 (executable)
@@ -44,6 +44,7 @@ import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
@@ -116,8 +117,6 @@ public class SequenceFetcher extends JPanel implements Runnable
 
   private static Thread initingThread = null;
 
-  int debounceTrap = 0;
-
   public JTextArea getTextArea()
   {
     return textArea;
@@ -169,9 +168,8 @@ public class SequenceFetcher extends JPanel implements Runnable
     if (sfetch == null
             || dasRegistry != Cache.getDasSourceRegistry()
             || lastDasSourceRegistry != (Cache.getDasSourceRegistry()
-                    .getDasRegistryURL() + Cache
-                    .getDasSourceRegistry().getLocalSourceString())
-                    .hashCode())
+                    .getDasRegistryURL() + Cache.getDasSourceRegistry()
+                    .getLocalSourceString()).hashCode())
     {
       _initingFetcher = true;
       initingThread = Thread.currentThread();
@@ -203,8 +201,19 @@ public class SequenceFetcher extends JPanel implements Runnable
 
   private IProgressIndicator progressIndicator;
 
+  private volatile boolean _isConstructing = false;
+
+  private List<AlignFrame> newAlframes = null;
+
   public SequenceFetcher(IProgressIndicator guiIndic)
   {
+    this(guiIndic, null, null);
+  }
+
+  public SequenceFetcher(IProgressIndicator guiIndic,
+          final String selectedDb, final String queryString)
+  {
+    this._isConstructing = true;
     this.progressIndicator = guiIndic;
     final SequenceFetcher us = this;
     // launch initialiser thread
@@ -216,7 +225,8 @@ public class SequenceFetcher extends JPanel implements Runnable
       {
         if (getSequenceFetcherSingleton(progressIndicator) != null)
         {
-          us.initGui(progressIndicator);
+          us.initGui(progressIndicator, selectedDb, queryString);
+          us._isConstructing = false;
         }
         else
         {
@@ -243,6 +253,32 @@ public class SequenceFetcher extends JPanel implements Runnable
     sf.start();
   }
 
+  /**
+   * blocking call which creates a new sequence fetcher panel, configures it and
+   * presses the OK button with the given database and query.
+   * 
+   * @param database
+   * @param query
+   */
+  public static List<AlignFrame> fetchAndShow(String database, String query)
+  {
+    final SequenceFetcher sf = new SequenceFetcher(Desktop.instance,
+            database, query);
+    while (sf._isConstructing)
+    {
+      try
+      {
+        Thread.sleep(50);
+      } catch (Exception q)
+      {
+        return Collections.emptyList();
+      }
+    }
+    sf.newAlframes = new ArrayList<AlignFrame>();
+    sf.run();
+    return sf.newAlframes;
+  }
+
   private class DatabaseAuthority extends DefaultMutableTreeNode
   {
 
@@ -254,11 +290,57 @@ public class SequenceFetcher extends JPanel implements Runnable
   };
 
   /**
+   * initialise the database and query for this fetcher panel
+   * 
+   * @param selectedDb
+   *          - string that should correspond to a sequence fetcher
+   * @param queryString
+   *          - string that will be entered in the query dialog
+   * @return true if UI was configured with valid database and query string
+   */
+  protected boolean setInitialQuery(String selectedDb, String queryString)
+  {
+    if (selectedDb == null || selectedDb.trim().length() == 0)
+    {
+      return false;
+    }
+    try
+    {
+      List<DbSourceProxy> sp = sfetch.getSourceProxy(selectedDb);
+      for (DbSourceProxy sourcep : sp)
+      {
+        if (sourcep.getTier() == 0)
+        {
+          database.selection = Arrays
+                  .asList(new DbSourceProxy[] { sourcep });
+          break;
+        }
+      }
+      if (database.selection == null || database.selection.size() == 0)
+      {
+        System.err.println("Ignoring fetch parameter db='" + selectedDb
+                + "'");
+        return false;
+      }
+      textArea.setText(queryString);
+    } catch (Exception q)
+    {
+      System.err.println("Ignoring fetch parameter db='" + selectedDb
+              + "' and query='" + queryString + "'");
+      return false;
+    }
+    return true;
+  }
+
+  /**
    * called by thread spawned by constructor
    * 
    * @param guiWindow
+   * @param queryString
+   * @param selectedDb
    */
-  private void initGui(IProgressIndicator guiWindow)
+  private void initGui(IProgressIndicator guiWindow, String selectedDb,
+          String queryString)
   {
     this.guiWindow = guiWindow;
     if (guiWindow instanceof AlignFrame)
@@ -269,6 +351,16 @@ public class SequenceFetcher extends JPanel implements Runnable
     try
     {
       jbInit();
+      /*
+       * configure the UI with any query parameters we were called with
+       */
+      if (!setInitialQuery(selectedDb, queryString))
+      {
+        /*
+         * none provided, so show the database chooser
+         */
+        database.waitForInput();
+      }
     } catch (Exception ex)
     {
       ex.printStackTrace();
@@ -365,7 +457,6 @@ public class SequenceFetcher extends JPanel implements Runnable
     jPanel1.add(example);
     jPanel1.add(clear);
     jPanel1.add(close);
-    jPanel3.add(jPanel2, java.awt.BorderLayout.CENTER);
     jPanel2.setLayout(borderLayout3);
     databaseButt = /*database.getDatabaseSelectorButton();
                    final JButton viewdbs =*/new JButton(
@@ -386,7 +477,6 @@ public class SequenceFetcher extends JPanel implements Runnable
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        debounceTrap++;
         String currentSelection = database.getSelectedItem();
         if (currentSelection == null)
         {
@@ -395,13 +485,11 @@ public class SequenceFetcher extends JPanel implements Runnable
 
         showPanel();
 
-        if (currentSelection.equalsIgnoreCase("pdb")
-                && (database.action == KeyEvent.VK_ENTER || ((debounceTrap % 2) == 0)))
+        if ("pdb".equalsIgnoreCase(currentSelection))
         {
           pdbSourceAction();
         }
-        else if (currentSelection.equalsIgnoreCase("uniprot")
-                && (database.action == KeyEvent.VK_ENTER || ((debounceTrap % 2) == 0)))
+        else if ("uniprot".equalsIgnoreCase(currentSelection))
         {
           uniprotSourceAction();
         }
@@ -426,11 +514,6 @@ public class SequenceFetcher extends JPanel implements Runnable
     this.add(jPanel3, java.awt.BorderLayout.CENTER);
     this.add(jPanel2, java.awt.BorderLayout.NORTH);
     jScrollPane1.getViewport().add(textArea);
-
-    /*
-     * open the database tree
-     */
-    database.waitForInput();
   }
 
   private void pdbSourceAction()
@@ -446,6 +529,7 @@ public class SequenceFetcher extends JPanel implements Runnable
     new UniprotFTSPanel(this);
     frame.dispose();
   }
+
   private void otherSourceAction()
   {
     try
@@ -835,8 +919,8 @@ public class SequenceFetcher extends JPanel implements Runnable
     } catch (Exception e)
     {
       Cache.log.info(
-              "Error retrieving " + accession
-              + " from " + proxy.getDbName(), e);
+              "Error retrieving " + accession + " from "
+                      + proxy.getDbName(), e);
     }
     return success;
   }
@@ -943,7 +1027,10 @@ public class SequenceFetcher extends JPanel implements Runnable
         {
           af.hideFeatureColumns(SequenceOntologyI.EXON, false);
         }
-
+        if (newAlframes != null)
+        {
+          newAlframes.add(af);
+        }
         Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH,
                 AlignFrame.DEFAULT_HEIGHT);
 
@@ -952,8 +1039,7 @@ public class SequenceFetcher extends JPanel implements Runnable
 
         try
         {
-          af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN",
-                  false));
+          af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false));
         } catch (Exception ex)
         {
         }
index c3fec4f..a381e8b 100755 (executable)
@@ -219,8 +219,9 @@ public class SliderPanel extends GSliderPanel
       pid.cs = cs;
     }
 
-    PIDSlider.setTitle(MessageManager
-            .formatMessage("label.percentage_identity_threshold",
+    PIDSlider
+            .setTitle(MessageManager.formatMessage(
+                    "label.percentage_identity_threshold",
                     new String[] { source }));
 
     if (ap.av.getAlignment().getGroups() != null)
index 1bc85d2..6c849c3 100644 (file)
@@ -70,7 +70,9 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
   private static final int WINDOWS_INSETS_HEIGHT = 50; // tbc
 
   private static final int MAC_INSETS_HEIGHT = 50;
+
   private static final int DESKTOP_DECORATORS_HEIGHT = 65;
+
   private static final long serialVersionUID = 1L;
 
   public SplitFrame(GAlignFrame top, GAlignFrame bottom)
@@ -723,6 +725,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     return Arrays.asList(new AlignFrame[] { (AlignFrame) getTopFrame(),
         (AlignFrame) getBottomFrame() });
   }
+
   /**
    * Replace Cmd-F Find action with our version. This is necessary because the
    * 'default' Finder searches in the first AlignFrame it finds. We need it to
index 3581cf9..c6ba8e9 100644 (file)
@@ -34,6 +34,7 @@ import jalview.fts.core.FTSRestResponse;
 import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.io.DataSourceType;
 import jalview.jbgui.GStructureChooser;
+import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.ws.DBRefFetcher;
@@ -65,7 +66,7 @@ import javax.swing.table.AbstractTableModel;
 public class StructureChooser extends GStructureChooser implements
         IProgressIndicator
 {
-  private boolean structuresDiscovered = false;
+  private static int MAX_QLENGTH = 7820;
 
   private SequenceI selectedSequence;
 
@@ -83,6 +84,8 @@ public class StructureChooser extends GStructureChooser implements
 
   private boolean isValidPBDEntry;
 
+  private boolean cachedPDBExists;
+
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap)
   {
@@ -103,6 +106,8 @@ public class StructureChooser extends GStructureChooser implements
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
     }
 
+    // ensure a filter option is in force for search
+    populateFilterComboBox(true, cachedPDBExists);
     Thread discoverPDBStructuresThread = new Thread(new Runnable()
     {
       @Override
@@ -117,7 +122,8 @@ public class StructureChooser extends GStructureChooser implements
                 .getString("status.searching_for_pdb_structures"),
                 startTime);
         fetchStructuresMetaData();
-        populateFilterComboBox();
+        // revise filter options if no results were found
+        populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
         updateProgressIndicator(null, startTime);
         mainFrame.setVisible(true);
         updateCurrentView();
@@ -161,6 +167,10 @@ public class StructureChooser extends GStructureChooser implements
       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);
@@ -190,8 +200,7 @@ public class StructureChooser extends GStructureChooser implements
     {
       getResultTable().setModel(
               FTSRestResponse.getTableModel(lastPdbRequest,
-              discoveredStructuresSet));
-      structuresDiscovered = true;
+                      discoveredStructuresSet));
       noOfStructuresFound = discoveredStructuresSet.size();
       mainFrame.setTitle(MessageManager.formatMessage(
               "label.structure_chooser_no_of_structures",
@@ -233,7 +242,7 @@ public class StructureChooser extends GStructureChooser implements
         }
       }
     }
-
+    cachedPDBExists = !entries.isEmpty();
     PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
     tbl_local_pdb.setModel(tableModelx);
   }
@@ -253,17 +262,16 @@ public class StructureChooser extends GStructureChooser implements
     StringBuilder queryBuilder = new StringBuilder();
     Set<String> seqRefs = new LinkedHashSet<String>();
 
-    if (seq.getAllPDBEntries() != null)
+    if (seq.getAllPDBEntries() != null
+            && queryBuilder.length() < MAX_QLENGTH)
     {
       for (PDBEntry entry : seq.getAllPDBEntries())
       {
         if (isValidSeqName(entry.getId()))
         {
           queryBuilder.append("pdb_id:")
-                  .append(entry.getId().toLowerCase())
-                  .append(" OR ");
+                  .append(entry.getId().toLowerCase()).append(" OR ");
           isPDBRefsFound = true;
-          // seqRefs.add(entry.getId());
         }
       }
     }
@@ -272,13 +280,13 @@ public class StructureChooser extends GStructureChooser implements
     {
       for (DBRefEntry dbRef : seq.getDBRefs())
       {
-        if (isValidSeqName(getDBRefId(dbRef)))
+        if (isValidSeqName(getDBRefId(dbRef))
+                && queryBuilder.length() < MAX_QLENGTH)
         {
           if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
           {
             queryBuilder.append("uniprot_accession:")
-                    .append(getDBRefId(dbRef))
-                    .append(" OR ");
+                    .append(getDBRefId(dbRef)).append(" OR ");
             queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
                     .append(" OR ");
             isUniProtRefsFound = true;
@@ -287,8 +295,7 @@ public class StructureChooser extends GStructureChooser implements
           {
 
             queryBuilder.append("pdb_id:")
-                    .append(getDBRefId(dbRef).toLowerCase())
-                    .append(" OR ");
+                    .append(getDBRefId(dbRef).toLowerCase()).append(" OR ");
             isPDBRefsFound = true;
           }
           else
@@ -343,7 +350,6 @@ public class StructureChooser extends GStructureChooser implements
             .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
   }
 
-
   /**
    * Ensures sequence ref names are not less than 3 characters and does not
    * contain a database name
@@ -454,8 +460,8 @@ public class StructureChooser extends GStructureChooser implements
           reorderedStructuresSet.addAll(filteredResponse);
           reorderedStructuresSet.addAll(discoveredStructuresSet);
           getResultTable().setModel(
-                  FTSRestResponse.getTableModel(
-                  lastPdbRequest, reorderedStructuresSet));
+                  FTSRestResponse.getTableModel(lastPdbRequest,
+                          reorderedStructuresSet));
 
           FTSRestResponse.configureTableColumn(getResultTable(),
                   wantedFields, tempUserPrefs);
@@ -524,10 +530,16 @@ public class StructureChooser extends GStructureChooser implements
    * Populates the filter combo-box options dynamically depending on discovered
    * structures
    */
-  @Override
-  protected void populateFilterComboBox()
+  protected void populateFilterComboBox(boolean haveData,
+          boolean cachedPDBExists)
   {
-    if (isStructuresDiscovered())
+    /*
+     * temporarily suspend the change listener behaviour
+     */
+    cmb_filterOption.removeItemListener(this);
+
+    cmb_filterOption.removeAllItems();
+    if (haveData)
     {
       cmb_filterOption.addItem(new FilterOption("Best Quality",
               "overall_quality", VIEWS_FILTER));
@@ -544,14 +556,21 @@ public class StructureChooser extends GStructureChooser implements
             VIEWS_ENTER_ID));
     cmb_filterOption.addItem(new FilterOption("From File", "-",
             VIEWS_FROM_FILE));
-    cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-",
-            VIEWS_LOCAL_PDB));
+    FilterOption cachedOption = new FilterOption("Cached PDB Entries", "-",
+            VIEWS_LOCAL_PDB);
+    cmb_filterOption.addItem(cachedOption);
+
+    if (/*!haveData &&*/cachedPDBExists)
+    {
+      cmb_filterOption.setSelectedItem(cachedOption);
+    }
+
+    cmb_filterOption.addItemListener(this);
   }
 
   /**
    * Updates the displayed view based on the selected filter option
    */
-  @Override
   protected void updateCurrentView()
   {
     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
@@ -717,6 +736,7 @@ public class StructureChooser extends GStructureChooser implements
   {
     final long progressSessionId = System.currentTimeMillis();
     final StructureSelectionManager ssm = ap.getStructureSelectionManager();
+    final int preferredHeight = pnl_filter.getHeight();
     ssm.setProgressIndicator(this);
     ssm.setProgressSessionId(progressSessionId);
     new Thread(new Runnable()
@@ -724,84 +744,82 @@ public class StructureChooser extends GStructureChooser implements
       @Override
       public void run()
       {
-    FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
-            .getSelectedItem());
-    String currentView = selectedFilterOpt.getView();
-    if (currentView == VIEWS_FILTER)
-    {
+        FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+                .getSelectedItem());
+        String currentView = selectedFilterOpt.getView();
+        if (currentView == VIEWS_FILTER)
+        {
           int pdbIdColIndex = getResultTable().getColumn("PDB Id")
                   .getModelIndex();
           int refSeqColIndex = getResultTable().getColumn("Ref Sequence")
-              .getModelIndex();
+                  .getModelIndex();
           int[] selectedRows = getResultTable().getSelectedRows();
-      PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
-      int count = 0;
-      ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
-      for (int row : selectedRows)
-      {
+          PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
+          int count = 0;
+          List<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+          for (int row : selectedRows)
+          {
             String pdbIdStr = getResultTable().getValueAt(row,
-                    pdbIdColIndex)
-                .toString();
+                    pdbIdColIndex).toString();
             SequenceI selectedSeq = (SequenceI) getResultTable()
-                    .getValueAt(row,
-                refSeqColIndex);
-        selectedSeqsToView.add(selectedSeq);
+                    .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.PDB);
-          selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
-        }
-        pdbEntriesToView[count++] = pdbEntry;
-      }
-      SequenceI[] selectedSeqs = selectedSeqsToView
-              .toArray(new SequenceI[selectedSeqsToView.size()]);
+            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()]);
           launchStructureViewer(ssm, pdbEntriesToView, ap, selectedSeqs);
-    }
-    else if (currentView == VIEWS_LOCAL_PDB)
-    {
-      int[] selectedRows = tbl_local_pdb.getSelectedRows();
-      PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
-      int count = 0;
+        }
+        else if (currentView == VIEWS_LOCAL_PDB)
+        {
+          int[] selectedRows = tbl_local_pdb.getSelectedRows();
+          PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
+          int count = 0;
           int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
                   .getModelIndex();
-      int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
-              .getModelIndex();
-      ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
-      for (int row : selectedRows)
-      {
-        PDBEntry pdbEntry = (PDBEntry) tbl_local_pdb.getValueAt(row,
-                pdbIdColIndex);
-        pdbEntriesToView[count++] = pdbEntry;
-        SequenceI selectedSeq = (SequenceI) tbl_local_pdb.getValueAt(row,
-                refSeqColIndex);
-        selectedSeqsToView.add(selectedSeq);
-      }
-      SequenceI[] selectedSeqs = selectedSeqsToView
-              .toArray(new SequenceI[selectedSeqsToView.size()]);
+          int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
+                  .getModelIndex();
+          List<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+          for (int row : selectedRows)
+          {
+            PDBEntry pdbEntry = (PDBEntry) tbl_local_pdb.getValueAt(row,
+                    pdbIdColIndex);
+            pdbEntriesToView[count++] = pdbEntry;
+            SequenceI selectedSeq = (SequenceI) tbl_local_pdb.getValueAt(
+                    row, refSeqColIndex);
+            selectedSeqsToView.add(selectedSeq);
+          }
+          SequenceI[] selectedSeqs = selectedSeqsToView
+                  .toArray(new SequenceI[selectedSeqsToView.size()]);
           launchStructureViewer(ssm, pdbEntriesToView, ap, selectedSeqs);
-    }
-    else if (currentView == VIEWS_ENTER_ID)
-    {
-      SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
-              .getCmb_assSeq().getSelectedItem()).getSequence();
-      if (userSelectedSeq != null)
-      {
-        selectedSequence = userSelectedSeq;
-      }
+        }
+        else if (currentView == VIEWS_ENTER_ID)
+        {
+          SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
+                  .getCmb_assSeq().getSelectedItem()).getSequence();
+          if (userSelectedSeq != null)
+          {
+            selectedSequence = userSelectedSeq;
+          }
 
-      String pdbIdStr = txt_search.getText();
-      PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
-      if (pdbEntry == null)
-      {
-        pdbEntry = new PDBEntry();
+          String pdbIdStr = txt_search.getText();
+          PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
+          if (pdbEntry == null)
+          {
+            pdbEntry = new PDBEntry();
             if (pdbIdStr.split(":").length > 1)
             {
               pdbEntry.setId(pdbIdStr.split(":")[0]);
@@ -811,11 +829,11 @@ public class StructureChooser extends GStructureChooser implements
             {
               pdbEntry.setId(pdbIdStr);
             }
-        pdbEntry.setType(PDBEntry.Type.PDB);
-        selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
-      }
+            pdbEntry.setType(PDBEntry.Type.PDB);
+            selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
+          }
 
-      PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
+          PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
           launchStructureViewer(ssm, pdbEntriesToView, ap,
                   new SequenceI[] { selectedSequence });
     }
@@ -834,8 +852,8 @@ public class StructureChooser extends GStructureChooser implements
 
           launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
                   new SequenceI[] { selectedSequence });
-    }
-        closeAction();
+        }
+        closeAction(preferredHeight);
       }
     }).start();
   }
@@ -865,14 +883,33 @@ public class StructureChooser extends GStructureChooser implements
 
     if (SiftsSettings.isMapWithSifts())
     {
-      ArrayList<SequenceI> seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
+      List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
+      int p = 0;
+      // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
+      // real PDB ID. For moment, we can also safely do this if there is already
+      // a known mapping between the PDBEntry and the sequence.
       for (SequenceI seq : sequences)
       {
-        if (seq.getSourceDBRef() == null && seq.getDBRefs() == null)
+        PDBEntry pdbe = pdbEntriesToView[p++];
+        if (pdbe != null && pdbe.getFile() != null)
         {
-            seqsWithoutSourceDBRef.add(seq);
-            continue;
+          StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
+          if (smm != null && smm.length > 0)
+          {
+            for (StructureMapping sm : smm)
+            {
+              if (sm.getSequence() == seq)
+              {
+                continue;
+              }
+            }
           }
+        }
+        if (seq.getPrimaryDBRefs().size() == 0)
+        {
+          seqsWithoutSourceDBRef.add(seq);
+          continue;
+        }
       }
       if (!seqsWithoutSourceDBRef.isEmpty())
       {
@@ -887,7 +924,8 @@ public class StructureChooser extends GStructureChooser implements
         {
           seqWithoutSrcDBRef[x++] = fSeq;
         }
-        new DBRefFetcher(seqWithoutSrcDBRef).fetchDBRefs(true);
+        DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
+        dbRefFetcher.fetchDBRefs(true);
       }
     }
     if (pdbEntriesToView.length > 1)
@@ -944,12 +982,8 @@ public class StructureChooser extends GStructureChooser implements
 
   public boolean isStructuresDiscovered()
   {
-    return structuresDiscovered;
-  }
-
-  public void setStructuresDiscovered(boolean structuresDiscovered)
-  {
-    this.structuresDiscovered = structuresDiscovered;
+    return discoveredStructuresSet != null
+            && !discoveredStructuresSet.isEmpty();
   }
 
   public Collection<FTSData> getDiscoveredStructuresSet()
@@ -978,8 +1012,7 @@ public class StructureChooser extends GStructureChooser implements
           pdbRequest.setResponseSize(1);
           pdbRequest.setFieldToSearchBy("(pdb_id:");
           pdbRequest.setWantedFields(wantedFields);
-          pdbRequest
-.setSearchTerm(searchTerm + ")");
+          pdbRequest.setSearchTerm(searchTerm + ")");
           pdbRequest.setAssociatedSequence(selectedSequence);
           pdbRestCleint = PDBFTSRestClient.getInstance();
           wantedFields.add(pdbRestCleint.getPrimaryKeyColumn());
index 21b2984..189d490 100644 (file)
@@ -136,14 +136,16 @@ public class StructureViewer
   protected JalviewStructureDisplayI viewStructures(ViewerType viewerType,
           PDBEntry[] pdbs, SequenceI[][] seqsForPdbs, AlignmentPanel ap)
   {
+    PDBEntry[] pdbsForFile = getUniquePdbFiles(pdbs);
     JalviewStructureDisplayI sview = null;
     if (viewerType.equals(ViewerType.JMOL))
     {
-      sview = new AppJmol(ap, pdbs, ap.av.collateForPDB(pdbs));
+      sview = new AppJmol(ap, pdbsForFile, ap.av.collateForPDB(pdbsForFile));
     }
     else if (viewerType.equals(ViewerType.CHIMERA))
     {
-      sview = new ChimeraViewFrame(pdbs, ap.av.collateForPDB(pdbs), ap);
+      sview = new ChimeraViewFrame(pdbsForFile,
+              ap.av.collateForPDB(pdbsForFile), ap);
     }
     else
     {
@@ -153,6 +155,36 @@ public class StructureViewer
     return sview;
   }
 
+  /**
+   * Convert the array of PDBEntry into an array with no filename repeated
+   * 
+   * @param pdbs
+   * @return
+   */
+  static PDBEntry[] getUniquePdbFiles(PDBEntry[] pdbs)
+  {
+    if (pdbs == null)
+    {
+      return null;
+    }
+    List<PDBEntry> uniques = new ArrayList<PDBEntry>();
+    List<String> filesSeen = new ArrayList<String>();
+    for (PDBEntry entry : pdbs)
+    {
+      String file = entry.getFile();
+      if (file == null)
+      {
+        uniques.add(entry);
+      }
+      else if (!filesSeen.contains(file))
+      {
+        uniques.add(entry);
+        filesSeen.add(file);
+      }
+    }
+    return uniques.toArray(new PDBEntry[uniques.size()]);
+  }
+
   protected JalviewStructureDisplayI viewStructures(ViewerType viewerType,
           PDBEntry pdb, SequenceI[] seqsForPdb, AlignmentPanel ap)
   {
index e295dfb..800d525 100644 (file)
@@ -30,10 +30,15 @@ import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 
 import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Vector;
 
+import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 
@@ -76,6 +81,8 @@ public abstract class StructureViewerBase extends GStructureViewer
 
   protected Thread worker = null;
 
+  protected boolean allChainsSelected = false;
+
   /**
    * 
    * @param ap2
@@ -494,4 +501,55 @@ public abstract class StructureViewerBase extends GStructureViewer
     }
     return finished;
   }
+
+  void setChainMenuItems(List<String> chainNames)
+  {
+    chainMenu.removeAll();
+    if (chainNames == null || chainNames.isEmpty())
+    {
+      return;
+    }
+    JMenuItem menuItem = new JMenuItem(
+            MessageManager.getString("label.all"));
+    menuItem.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent evt)
+      {
+        allChainsSelected = true;
+        for (int i = 0; i < chainMenu.getItemCount(); i++)
+        {
+          if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
+          {
+            ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
+          }
+        }
+        showSelectedChains();
+        allChainsSelected = false;
+      }
+    });
+
+    chainMenu.add(menuItem);
+
+    for (String chain : chainNames)
+    {
+      menuItem = new JCheckBoxMenuItem(chain, true);
+      menuItem.addItemListener(new ItemListener()
+      {
+        @Override
+        public void itemStateChanged(ItemEvent evt)
+        {
+          if (!allChainsSelected)
+          {
+            showSelectedChains();
+          }
+        }
+      });
+
+      chainMenu.add(menuItem);
+    }
+  }
+
+  abstract void showSelectedChains();
+
 }
index f21c5e7..84fd82f 100755 (executable)
@@ -29,7 +29,6 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequenceNode;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 import jalview.structure.SelectionSource;
 import jalview.util.Format;
@@ -59,6 +58,7 @@ import java.util.Vector;
 import javax.swing.JColorChooser;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 
 /**
@@ -174,13 +174,13 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     tree.findHeight(tree.getTopNode());
 
     // Now have to calculate longest name based on the leaves
-    Vector leaves = tree.findLeaves(tree.getTopNode(), new Vector());
+    Vector<SequenceNode> leaves = tree.findLeaves(tree.getTopNode());
     boolean has_placeholders = false;
     longestName = "";
 
     for (int i = 0; i < leaves.size(); i++)
     {
-      SequenceNode lf = (SequenceNode) leaves.elementAt(i);
+      SequenceNode lf = leaves.elementAt(i);
 
       if (lf.isPlaceholder())
       {
@@ -747,21 +747,27 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   }
 
   /**
-   * DOCUMENT ME!
+   * Empty method to satisfy the MouseListener interface
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseReleased(MouseEvent e)
   {
+    /*
+     * isPopupTrigger is set on mouseReleased on Windows
+     */
+    if (e.isPopupTrigger())
+    {
+      chooseSubtreeColour();
+      e.consume(); // prevent mouseClicked happening
+    }
   }
 
   /**
-   * DOCUMENT ME!
+   * Empty method to satisfy the MouseListener interface
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseEntered(MouseEvent e)
@@ -769,10 +775,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   }
 
   /**
-   * DOCUMENT ME!
+   * Empty method to satisfy the MouseListener interface
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseExited(MouseEvent e)
@@ -780,47 +785,56 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   }
 
   /**
-   * DOCUMENT ME!
+   * Handles a mouse click on a tree node (clicks elsewhere are handled in
+   * mousePressed). Click selects the sub-tree, double-click swaps leaf nodes
+   * order, right-click opens a dialogue to choose colour for the sub-tree.
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseClicked(MouseEvent evt)
   {
-    if (highlightNode != null)
+    if (highlightNode == null)
     {
-      if (evt.isPopupTrigger())
-      {
-        Color col = JColorChooser.showDialog(this,
-                MessageManager.getString("label.select_subtree_colour"),
-                highlightNode.color);
-        if (col != null)
-        {
-          setColor(highlightNode, col);
-        }
-      }
-      else if (evt.getClickCount() > 1)
+      return;
+    }
+
+    if (evt.getClickCount() > 1)
+    {
+      tree.swapNodes(highlightNode);
+      tree.reCount(tree.getTopNode());
+      tree.findHeight(tree.getTopNode());
+    }
+    else
+    {
+      Vector<SequenceNode> leaves = tree.findLeaves(highlightNode);
+
+      for (int i = 0; i < leaves.size(); i++)
       {
-        tree.swapNodes(highlightNode);
-        tree.reCount(tree.getTopNode());
-        tree.findHeight(tree.getTopNode());
+        SequenceI seq = (SequenceI) leaves.elementAt(i).element();
+        treeSelectionChanged(seq);
       }
-      else
-      {
-        Vector leaves = new Vector();
-        tree.findLeaves(highlightNode, leaves);
+      av.sendSelection();
+    }
 
-        for (int i = 0; i < leaves.size(); i++)
-        {
-          SequenceI seq = (SequenceI) ((SequenceNode) leaves.elementAt(i))
-                  .element();
-          treeSelectionChanged(seq);
-        }
-        av.sendSelection();
-      }
+    PaintRefresher.Refresh(tp, av.getSequenceSetId());
+    repaint();
+  }
 
-      PaintRefresher.Refresh(tp, av.getSequenceSetId());
+  /**
+   * Offer the user the option to choose a colour for the highlighted node and
+   * its children; this colour is also applied to the corresponding sequence ids
+   * in the alignment
+   */
+  void chooseSubtreeColour()
+  {
+    Color col = JColorChooser.showDialog(this,
+            MessageManager.getString("label.select_subtree_colour"),
+            highlightNode.color);
+    if (col != null)
+    {
+      setColor(highlightNode, col);
+      PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
       repaint();
     }
   }
@@ -857,16 +871,42 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
   }
 
   /**
-   * DOCUMENT ME!
+   * Handles a mouse press on a sequence name or the tree background canvas
+   * (click on a node is handled in mouseClicked). The action is to create
+   * groups by partitioning the tree at the mouse position. Colours for the
+   * groups (and sequence names) are generated randomly.
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mousePressed(MouseEvent e)
   {
     av.setCurrentTree(tree);
 
+    /*
+     * isPopupTrigger is set for mousePressed (Mac)
+     * or mouseReleased (Windows)
+     */
+    if (e.isPopupTrigger())
+    {
+      if (highlightNode != null)
+      {
+        chooseSubtreeColour();
+      }
+      return;
+    }
+
+    /*
+     * defer right-click handling on Windows to
+     * mouseClicked; note isRightMouseButton
+     * also matches Cmd-click on Mac which should do
+     * nothing here
+     */
+    if (SwingUtilities.isRightMouseButton(e))
+    {
+      return;
+    }
+
     int x = e.getX();
     int y = e.getY();
 
@@ -925,17 +965,16 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     {
       Color col = new Color((int) (Math.random() * 255),
               (int) (Math.random() * 255), (int) (Math.random() * 255));
-      setColor((SequenceNode) tree.getGroups().elementAt(i), col.brighter());
+      setColor(tree.getGroups().elementAt(i), col.brighter());
 
-      Vector l = tree.findLeaves(
-              (SequenceNode) tree.getGroups().elementAt(i), new Vector());
+      Vector<SequenceNode> l = tree.findLeaves(tree.getGroups()
+              .elementAt(i));
 
-      Vector sequences = new Vector();
+      Vector<SequenceI> sequences = new Vector<SequenceI>();
 
       for (int j = 0; j < l.size(); j++)
       {
-        SequenceI s1 = (SequenceI) ((SequenceNode) l.elementAt(j))
-                .element();
+        SequenceI s1 = (SequenceI) l.elementAt(j).element();
 
         if (!sequences.contains(s1))
         {
@@ -978,10 +1017,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
         if (aps[a].av.getGlobalColourScheme() != null
                 && aps[a].av.getGlobalColourScheme().conservationApplied())
         {
-          Conservation c = new Conservation("Group",
-                  ResidueProperties.propHash, 3, sg.getSequences(null),
+          Conservation c = new Conservation("Group", sg.getSequences(null),
                   sg.getStartRes(), sg.getEndRes());
-
           c.calculate();
           c.verdict(false, aps[a].av.getConsPercGaps());
           sg.cs.setConservation(c);
@@ -993,17 +1030,14 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
                 .getCodingComplement();
         if (codingComplement != null)
         {
-          if (codingComplement != null)
+          SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg, av,
+                  codingComplement);
+          if (mappedGroup.getSequences().size() > 0)
           {
-            SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
-                    av, codingComplement);
-            if (mappedGroup.getSequences().size() > 0)
+            codingComplement.getAlignment().addGroup(mappedGroup);
+            for (SequenceI seq : mappedGroup.getSequences())
             {
-              codingComplement.getAlignment().addGroup(mappedGroup);
-              for (SequenceI seq : mappedGroup.getSequences())
-              {
-                codingComplement.setSequenceColour(seq, col.brighter());
-              }
+              codingComplement.setSequenceColour(seq, col.brighter());
             }
           }
         }
@@ -1022,11 +1056,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       {
         ((AlignViewport) codingComplement).getAlignPanel()
                 .updateAnnotation();
-
       }
-
     }
-
   }
 
   /**
index 7588e07..afb6df4 100644 (file)
@@ -321,6 +321,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
     Thread udthread = new Thread(new Runnable()
     {
 
+      @Override
       public void run()
       {
         Cache.log.info("Jalview updating to the Vamsas Session.");
@@ -639,6 +640,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
     final VamsasApplication client = this;
     vclient.addDocumentUpdateHandler(new PropertyChangeListener()
     {
+      @Override
       public void propertyChange(PropertyChangeEvent evt)
       {
         Cache.log.debug("Dealing with document update event.");
@@ -656,6 +658,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
             uk.ac.vamsas.client.Events.DOCUMENT_REQUESTTOCLOSE,
             new PropertyChangeListener()
             {
+              @Override
               public void propertyChange(PropertyChangeEvent evt)
               {
                 if (client.promptUser)
@@ -774,6 +777,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
         {
           String last = null;
 
+          @Override
           public void handleMessage(Message message)
           {
             if (vobj2jv == null)
@@ -998,6 +1002,7 @@ public class VamsasApplication implements SelectionSource, VamsasSource
         selecter = new SelectionListener()
         {
 
+          @Override
           public void selection(SequenceGroup seqsel,
                   ColumnSelection colsel, SelectionSource source)
           {
@@ -1065,11 +1070,10 @@ public class VamsasApplication implements SelectionSource, VamsasSource
                   {
                     // gather selected columns outwith the sequence positions
                     // too
-                    for (Object obj : colsel.getSelected())
+                    for (Integer ival : colsel.getSelected())
                     {
-                      int ival = ((Integer) obj).intValue();
                       Pos p = new Pos();
-                      p.setI(ival + 1);
+                      p.setI(ival.intValue() + 1);
                       range.addPos(p);
                     }
                   }
index 6e121b3..82e71b5 100755 (executable)
@@ -32,7 +32,6 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 
 import java.io.BufferedReader;
@@ -1638,8 +1637,7 @@ public class AnnotationFile
         else if (key.equalsIgnoreCase("consThreshold"))
         {
           sg.cs.setConservationInc(Integer.parseInt(value));
-          Conservation c = new Conservation("Group",
-                  ResidueProperties.propHash, 3, sg.getSequences(null),
+          Conservation c = new Conservation("Group", sg.getSequences(null),
                   sg.getStartRes(), sg.getEndRes() + 1);
 
           c.calculate();
index 4ffb86d..74fd422 100755 (executable)
@@ -205,9 +205,7 @@ public class AppletFormatAdapter
         {
           StructureImportSettings.addSettings(annotFromStructure,
                   localSecondaryStruct, serviceSecondaryStruct);
-          alignFile = new JmolParser(annotFromStructure,
-                  localSecondaryStruct, serviceSecondaryStruct, inFile,
-                  sourceType);
+          alignFile = new JmolParser(inFile,                  sourceType);
         }
         else
         {
@@ -307,8 +305,7 @@ public class AppletFormatAdapter
         {
           StructureImportSettings.addSettings(annotFromStructure,
                   localSecondaryStruct, serviceSecondaryStruct);
-          alignFile = new JmolParser(annotFromStructure,
-                  localSecondaryStruct, serviceSecondaryStruct, source);
+          alignFile = new JmolParser(source);
         }
         else
         {
index 80df097..fd9c584 100644 (file)
  */
 package jalview.io;
 
-import jalview.api.AlignExportSettingI;
-import jalview.api.AlignmentViewPanel;
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentExportData;
 import jalview.exceptions.NoFileSelectedException;
-import jalview.gui.AlignFrame;
-import jalview.gui.IProgressIndicator;
+import jalview.gui.AlignmentPanel;
 import jalview.gui.OOMWarning;
 import jalview.json.binding.biojs.BioJSReleasePojo;
 import jalview.json.binding.biojs.BioJSRepositoryPojo;
-import jalview.util.ImageMaker;
 import jalview.util.MessageManager;
 
 import java.io.BufferedInputStream;
@@ -45,15 +39,8 @@ import java.net.URL;
 import java.util.Objects;
 import java.util.TreeMap;
 
-public class BioJsHTMLOutput
+public class BioJsHTMLOutput extends HTMLOutput
 {
-  private AlignmentViewPanel ap;
-
-  private long pSessionId;
-
-  private IProgressIndicator pIndicator;
-
-  private boolean headless;
 
   private static File currentBJSTemplateFile;
 
@@ -70,182 +57,41 @@ public class BioJsHTMLOutput
                   "biojs_template_git_repo",
                   "https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json");
 
-  public BioJsHTMLOutput(AlignmentViewPanel ap,
-          IProgressIndicator pIndicator)
+  public BioJsHTMLOutput(AlignmentPanel ap)
   {
-    if (ap != null)
-    {
-      this.ap = ap;
-      this.pSessionId = System.currentTimeMillis();
-      this.pIndicator = pIndicator;
-      this.headless = (System.getProperty("java.awt.headless") != null && System
-              .getProperty("java.awt.headless").equals("true"));
-    }
+    super(ap);
   }
 
-  public void exportJalviewAlignmentAsBioJsHtmlFile()
+  @Override
+  public void exportHTML(String outputFile)
   {
-    String outputFile = null;
+    exportStarted();
     try
     {
-      outputFile = getOutputFile();
-      AlignExportSettingI exportSettings = new AlignExportSettingI()
+      if (outputFile == null)
       {
-        @Override
-        public boolean isExportHiddenSequences()
-        {
-          return true;
-        }
-
-        @Override
-        public boolean isExportHiddenColumns()
-        {
-          return true;
-        }
-
-        @Override
-        public boolean isExportAnnotations()
-        {
-          return true;
-        }
-
-        @Override
-        public boolean isExportFeatures()
-        {
-          return true;
-        }
-
-        @Override
-        public boolean isExportGroups()
-        {
-          return true;
-        }
-
-        @Override
-        public boolean isCancelled()
-        {
-          return false;
-        }
-
-      };
-      AlignmentExportData exportData = AlignFrame
-              .getAlignmentForExport(FileFormat.Json,
-                      ap.getAlignViewport(), exportSettings);
-      String bioJSON = new FormatAdapter(ap, exportData.getSettings())
-              .formatSequences(FileFormat.Json, exportData
-                      .getAlignment(), exportData.getOmitHidden(),
-                      exportData.getStartEndPostions(), ap
-                              .getAlignViewport().getColumnSelection());
-
-      String bioJSTemplateString = getBioJsTemplateAsString();
-      String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
-              .replaceAll("#sequenceData#", bioJSON).toString();
-
-      PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
-              outputFile));
-      out.print(generatedBioJsWithJalviewAlignmentAsJson);
-      out.flush();
-      out.close();
-      jalview.util.BrowserLauncher.openURL("file:///" + outputFile);
-      if (pIndicator != null && !headless)
-      {
-        pIndicator.setProgressBar(MessageManager.formatMessage(
-                "status.export_complete", "BioJS"), pSessionId);
+        outputFile = getOutputFile();
       }
-    } catch (NoFileSelectedException ex)
+      generatedFile = new File(outputFile);
+    } catch (NoFileSelectedException e)
     {
-      // do noting if no file was selected
-    } catch (OutOfMemoryError err)
-    {
-      System.out.println("########################\n" + "OUT OF MEMORY "
-              + outputFile + "\n" + "########################");
-      new OOMWarning("Creating Image for " + outputFile, err);
+      setProgressMessage(MessageManager.formatMessage(
+              "status.cancelled_image_export_operation", "BioJS MSA"));
+      return;
     } catch (Exception e)
     {
-      pIndicator.setProgressBar(MessageManager.formatMessage(
-              "info.error_creating_file", "HTML"), pSessionId);
+      setProgressMessage(MessageManager.formatMessage(
+              "info.error_creating_file", "BioJS MSA"));
       e.printStackTrace();
+      return;
     }
-  }
-
-  public String getOutputFile() throws NoFileSelectedException
-  {
-    String selectedFile = null;
-    if (pIndicator != null && !headless)
-    {
-      pIndicator.setProgressBar(MessageManager.formatMessage(
-              "status.waiting_for_user_to_select_output_file", "HTML"),
-              pSessionId);
-    }
-
-    JalviewFileChooser jvFileChooser = new JalviewFileChooser(
-            Cache.getProperty("LAST_DIRECTORY"), ImageMaker.HTML_EXTENSION,
-            ImageMaker.HTML_EXTENSION, ImageMaker.HTML_EXTENSION);
-    jvFileChooser.setFileView(new JalviewFileView());
+    new Thread(this).start();
 
-    jvFileChooser.setDialogTitle(MessageManager
-            .getString("label.save_as_biojs_html"));
-    jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
-
-    int fileChooserOpt = jvFileChooser.showSaveDialog(null);
-    if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
-    {
-      Cache.setProperty("LAST_DIRECTORY", jvFileChooser
-              .getSelectedFile().getParent());
-      selectedFile = jvFileChooser.getSelectedFile().getPath();
-    }
-    else
-    {
-      pIndicator.setProgressBar(MessageManager.formatMessage(
-              "status.cancelled_image_export_operation", "BioJS"),
-              pSessionId);
-      throw new NoFileSelectedException("No file was selected.");
-    }
-    return selectedFile;
   }
 
-  public static String getBioJsTemplateAsString() throws IOException
-  {
-    InputStreamReader isReader = null;
-    BufferedReader buffReader = null;
-    StringBuilder sb = new StringBuilder();
-    Objects.requireNonNull(getCurrentBJSTemplateFile(),
-            "BioJsTemplate File not initialized!");
-    @SuppressWarnings("deprecation")
-    URL url = getCurrentBJSTemplateFile().toURL();
-    if (url != null)
-    {
-      try
-      {
-        isReader = new InputStreamReader(url.openStream());
-        buffReader = new BufferedReader(isReader);
-        String line;
-        String lineSeparator = System.getProperty("line.separator");
-        while ((line = buffReader.readLine()) != null)
-        {
-          sb.append(line).append(lineSeparator);
-        }
 
-      } catch (Exception ex)
-      {
-        ex.printStackTrace();
-      } finally
-      {
-        if (isReader != null)
-        {
-          isReader.close();
-        }
 
-        if (buffReader != null)
-        {
-          buffReader.close();
-        }
-      }
-    }
-    return sb.toString();
-  }
-
-  public static void refreshBioJSVersionsInfo(String dirName)
+  public static void refreshVersionInfo(String dirName)
           throws URISyntaxException
   {
     File directory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
@@ -293,7 +139,7 @@ public class BioJsHTMLOutput
             BioJSRepositoryPojo release = new BioJSRepositoryPojo(
                     gitRepoPkgJson);
             syncUpdates(BJS_TEMPLATES_LOCAL_DIRECTORY, release);
-            refreshBioJSVersionsInfo(BJS_TEMPLATES_LOCAL_DIRECTORY);
+            refreshVersionInfo(BJS_TEMPLATES_LOCAL_DIRECTORY);
           }
         } catch (URISyntaxException e)
         {
@@ -414,4 +260,56 @@ public class BioJsHTMLOutput
     BioJsHTMLOutput.bioJsMSAVersions = bioJsMSAVersions;
   }
 
+  @Override
+  public boolean isEmbedData()
+  {
+    return true;
+  }
+
+  @Override
+  public boolean isLaunchInBrowserAfterExport()
+  {
+    return true;
+  }
+
+  @Override
+  public File getExportedFile()
+  {
+    return generatedFile;
+  }
+
+  @Override
+  public void run()
+  {
+    try
+    {
+      String bioJSON = getBioJSONData();
+      String bioJSTemplateString = HTMLOutput
+              .readFileAsString(getCurrentBJSTemplateFile());
+      String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
+              .replaceAll("#sequenceData#", bioJSON).toString();
+
+      PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
+              generatedFile));
+      out.print(generatedBioJsWithJalviewAlignmentAsJson);
+      out.flush();
+      out.close();
+      setProgressMessage(MessageManager.formatMessage(
+              "status.export_complete", "BioJS"));
+      exportCompleted();
+
+    } catch (OutOfMemoryError err)
+    {
+      System.out.println("########################\n" + "OUT OF MEMORY "
+              + generatedFile + "\n" + "########################");
+      new OOMWarning("Creating Image for " + generatedFile, err);
+    } catch (Exception e)
+    {
+      setProgressMessage(MessageManager.formatMessage(
+              "info.error_creating_file", "HTML"));
+      e.printStackTrace();
+    }
+
+  }
+
 }
index 9c8cdf6..da925e4 100755 (executable)
@@ -180,8 +180,7 @@ public class FastaFile extends AlignFile
     addProperties(al);
     for (int i = 0; i < annotations.size(); i++)
     {
-      AlignmentAnnotation aa = annotations
-              .elementAt(i);
+      AlignmentAnnotation aa = annotations.elementAt(i);
       aa.setPadGaps(true, al.getGapCharacter());
       al.addAnnotation(aa);
     }
index 07a3b25..6af0cdf 100755 (executable)
@@ -140,8 +140,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return true if features were added
    */
   public boolean parse(AlignmentI align,
-          Map<String, FeatureColourI> colours,
-          boolean removeHTML)
+          Map<String, FeatureColourI> colours, boolean removeHTML)
   {
     return parse(align, colours, removeHTML, false);
   }
@@ -178,8 +177,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return true if features were added
    */
   public boolean parse(AlignmentI align,
-          Map<String, FeatureColourI> colours,
-          boolean removeHTML, boolean relaxedIdmatching)
+          Map<String, FeatureColourI> colours, boolean removeHTML,
+          boolean relaxedIdmatching)
   {
     Map<String, String> gffProps = new HashMap<String, String>();
     /*
@@ -589,7 +588,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
         {
           for (SequenceFeature sequenceFeature : features)
           {
-            isnonpos = sequenceFeature.begin == 0 && sequenceFeature.end == 0;
+            isnonpos = sequenceFeature.begin == 0
+                    && sequenceFeature.end == 0;
             if ((!nonpos && isnonpos)
                     || (!isnonpos && visOnly && !visible
                             .containsKey(sequenceFeature.type)))
index d0ce86e..d52045c 100644 (file)
@@ -364,12 +364,7 @@ public enum FileFormat implements FileFormatI
               .getDefaultStructureFileFormat() != PDBEntry.Type.PDB;
       if (isParseWithJMOL)
       {
-        return new JmolParser(
-                StructureImportSettings.isVisibleChainAnnotation(),
-                StructureImportSettings.isProcessSecondaryStructure(),
-                StructureImportSettings.isExternalSecondaryStructure(),
-                inFile,
-                sourceType);
+        return new JmolParser(inFile, sourceType);
       }
       else
       {
@@ -391,11 +386,7 @@ public enum FileFormat implements FileFormatI
               .getDefaultStructureFileFormat() != PDBEntry.Type.PDB;
       if (isParseWithJMOL)
       {
-        return new JmolParser(
-                StructureImportSettings.isVisibleChainAnnotation(),
-                StructureImportSettings.isProcessSecondaryStructure(),
-                StructureImportSettings.isExternalSecondaryStructure(),
-                source);
+        return new JmolParser(source);
       }
       else
       {
@@ -421,22 +412,14 @@ public enum FileFormat implements FileFormatI
     public AlignmentFileI getAlignmentFile(String inFile,
             DataSourceType sourceType) throws IOException
     {
-      return new JmolParser(
-              StructureImportSettings.isVisibleChainAnnotation(),
-              StructureImportSettings.isProcessSecondaryStructure(),
-              StructureImportSettings.isExternalSecondaryStructure(),
-              inFile, sourceType);
+      return new JmolParser(inFile, sourceType);
     }
 
     @Override
     public AlignmentFileI getAlignmentFile(FileParse source)
             throws IOException
     {
-      return new JmolParser(
-              StructureImportSettings.isVisibleChainAnnotation(),
-              StructureImportSettings.isProcessSecondaryStructure(),
-              StructureImportSettings.isExternalSecondaryStructure(),
-              source);
+      return new JmolParser(source);
     }
 
     @Override
index 2e4a781..381a40b 100755 (executable)
-/*
- * 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 jalview.bin.Cache;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignViewport;
+import jalview.api.AlignExportSettingI;
+import jalview.datamodel.AlignmentExportData;
+import jalview.exceptions.NoFileSelectedException;
 import jalview.gui.AlignmentPanel;
-import jalview.gui.FeatureRenderer;
-import jalview.gui.SequenceRenderer;
-import jalview.util.BrowserLauncher;
-import jalview.util.ImageMaker;
+import jalview.gui.IProgressIndicator;
 import jalview.util.MessageManager;
 
-import java.awt.Color;
-import java.awt.Font;
-import java.io.FileWriter;
-import java.io.PrintWriter;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Objects;
 
-public class HTMLOutput
+public abstract class HTMLOutput implements Runnable
 {
-  AlignViewport av;
+  protected AlignmentPanel ap;
 
-  SequenceRenderer sr;
+  protected long pSessionId;
 
-  jalview.renderer.seqfeatures.FeatureRenderer fr;
+  protected IProgressIndicator pIndicator;
 
-  Color color;
+  protected File generatedFile;
 
-  public HTMLOutput(AlignmentPanel ap, SequenceRenderer sr,
-          FeatureRenderer fr1)
+  public HTMLOutput(AlignmentPanel ap)
   {
-    this.av = ap.av;
-    this.sr = sr;
-
-    fr = new FeatureRenderer(ap);
-    fr.transferSettings(fr1);
-
-    JalviewFileChooser chooser = new JalviewFileChooser(
-            Cache.getProperty("LAST_DIRECTORY"), ImageMaker.HTML_EXTENSION,
-            "HTML files", "HTML files");
-
-    chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(MessageManager.getString("label.save_as_html"));
-    chooser.setToolTipText(MessageManager.getString("action.save"));
-
-    int value = chooser.showSaveDialog(null);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+    if (ap != null)
     {
-      String choice = chooser.getSelectedFile().getPath();
-      Cache.setProperty("LAST_DIRECTORY", chooser
-              .getSelectedFile().getParent());
-
-      try
-      {
-        PrintWriter out = new PrintWriter(new FileWriter(choice));
-        out.println("<HTML>");
-        out.println("<style type=\"text/css\">");
-        out.println("<!--");
-        out.print("td {font-family: \"" + av.getFont().getFamily()
-                + "\", \"" + av.getFont().getName() + "\", mono; "
-                + "font-size: " + av.getFont().getSize() + "px; ");
-
-        if (av.getFont().getStyle() == Font.BOLD)
-        {
-          out.print("font-weight: BOLD; ");
-        }
-
-        if (av.getFont().getStyle() == Font.ITALIC)
-        {
-          out.print("font-style: italic; ");
-        }
-
-        out.println("text-align: center; }");
-
-        out.println("-->");
-        out.println("</style>");
-        out.println("<BODY>");
-
-        if (av.getWrapAlignment())
-        {
-          drawWrappedAlignment(out);
-        }
-        else
-        {
-          drawUnwrappedAlignment(out);
-        }
-
-        out.println("\n</body>\n</html>");
-        out.close();
-        BrowserLauncher.openURL("file:///" + choice);
-      } catch (Exception ex)
-      {
-        ex.printStackTrace();
-      }
+      this.ap = ap;
+      this.pIndicator = ap.alignFrame;
     }
   }
 
-  void drawUnwrappedAlignment(PrintWriter out)
+  public String getBioJSONData()
   {
-    out.println("<table border=\"1\"><tr><td>\n");
-    out.println("<table border=\"0\"  cellpadding=\"0\" cellspacing=\"0\">\n");
-
-    // ////////////
-    SequenceI seq;
-    AlignmentI alignment = av.getAlignment();
-
-    // draws the top row, the measure rule
-    out.println("<tr><td colspan=\"6\"></td>");
-
-    int i = 0;
+    return getBioJSONData(null);
+  }
 
-    for (i = 10; i < (alignment.getWidth() - 10); i += 10)
+  public String getBioJSONData(AlignExportSettingI exportSettings)
+  {
+    if (!isEmbedData())
     {
-      out.println("<td colspan=\"9\">" + i + "<br>|</td><td></td>");
+      return null;
     }
-
-    out.println("<td colspan=\"3\"></td><td colspan=\"3\">" + i
-            + "<br>|</td>");
-    out.println("</tr>");
-
-    for (i = 0; i < alignment.getHeight(); i++)
+    if (exportSettings == null)
     {
-      seq = alignment.getSequenceAt(i);
-
-      String id = seq.getDisplayId(av.getShowJVSuffix());
-
-      out.println("<tr><td nowrap>" + id + "&nbsp;&nbsp;</td>");
-
-      for (int res = 0; res < seq.getLength(); res++)
+      exportSettings = new AlignExportSettingI()
       {
-        if (!jalview.util.Comparison.isGap(seq.getCharAt(res)))
+        @Override
+        public boolean isExportHiddenSequences()
         {
-          color = sr.getResidueBoxColour(seq, res);
+          return true;
+        }
 
-          color = fr.findFeatureColour(color, seq, res);
+        @Override
+        public boolean isExportHiddenColumns()
+        {
+          return true;
         }
-        else
+
+        @Override
+        public boolean isExportAnnotations()
         {
-          color = Color.white;
+          return true;
         }
 
-        if (color.getRGB() < -1)
+        @Override
+        public boolean isExportFeatures()
         {
-          out.println("<td bgcolor=\"#"
-                  + jalview.util.Format.getHexString(color) + "\">"
-                  + seq.getCharAt(res) + "</td>");
+          return true;
         }
-        else
+
+        @Override
+        public boolean isExportGroups()
         {
-          out.println("<td>" + seq.getCharAt(res) + "</td>");
+          return true;
         }
-      }
 
-      out.println("</tr>");
+        @Override
+        public boolean isCancelled()
+        {
+          return false;
+        }
+      };
     }
-
-    // ////////////
-    out.println("</table>");
-    out.println("</td></tr></table>");
+    AlignmentExportData exportData = jalview.gui.AlignFrame
+            .getAlignmentForExport(FileFormat.Json,
+                    ap.getAlignViewport(), exportSettings);
+    String bioJSON = new FormatAdapter(ap, exportData.getSettings())
+            .formatSequences(FileFormat.Json, exportData.getAlignment(),
+                    exportData.getOmitHidden(), exportData
+                            .getStartEndPostions(), ap.getAlignViewport()
+                            .getColumnSelection());
+    return bioJSON;
   }
 
-  void drawWrappedAlignment(PrintWriter out)
+  /**
+   * Read a template file content as string
+   * 
+   * @param file
+   *          - the file to be read
+   * @return File content as String
+   * @throws IOException
+   */
+  public static String readFileAsString(File file) throws IOException
   {
-    // //////////////////////////////////
-    // / How many sequences and residues can we fit on a printable page?
-    AlignmentI al = av.getAlignment();
-    SequenceI seq;
-    String r;
-    String g;
-    String b;
-
-    out.println("<table border=\"1\"><tr><td>\n");
-    out.println("<table border=\"0\"  cellpadding=\"0\" cellspacing=\"0\">\n");
-
-    for (int startRes = 0; startRes < al.getWidth(); startRes += av
-            .getWrappedWidth())
+    InputStreamReader isReader = null;
+    BufferedReader buffReader = null;
+    StringBuilder sb = new StringBuilder();
+    Objects.requireNonNull(file, "File must not be null!");
+    @SuppressWarnings("deprecation")
+    URL url = file.toURL();
+    if (url != null)
     {
-      int endRes = startRes + av.getWrappedWidth();
-
-      if (endRes > al.getWidth())
-      {
-        endRes = al.getWidth();
-      }
-
-      if (av.getScaleAboveWrapped())
+      try
       {
-        out.println("<tr>");
-
-        if (av.getScaleLeftWrapped())
+        isReader = new InputStreamReader(url.openStream());
+        buffReader = new BufferedReader(isReader);
+        String line;
+        String lineSeparator = System.getProperty("line.separator");
+        while ((line = buffReader.readLine()) != null)
         {
-          out.println("<td colspan=\"7\">&nbsp;</td>");
+          sb.append(line).append(lineSeparator);
         }
-        else
-        {
-          out.println("<td colspan=\"6\">&nbsp;</td>");
-        }
-
-        for (int i = startRes + 10; i < endRes; i += 10)
-        {
-          out.println("<td colspan=\"9\">" + i + "<br>|</td><td></td>");
-        }
-
-        out.println("</tr>");
-      }
-
-      int startPos, endPos;
-      for (int s = 0; s < al.getHeight(); s++)
+  
+      } catch (Exception ex)
       {
-        out.println("<tr>");
-        seq = al.getSequenceAt(s);
-
-        startPos = seq.findPosition(startRes);
-        endPos = seq.findPosition(endRes) - 1;
-
-        String id = seq.getDisplayId(av.getShowJVSuffix());
-
-        out.println("<td nowrap>" + id + "&nbsp;&nbsp;</td>");
-
-        if (av.getScaleLeftWrapped())
-        {
-          if (startPos > seq.getEnd() || endPos == 0)
-          {
-            out.println("<td nowrap>&nbsp;</td>");
-          }
-          else
-          {
-            out.println("<td nowrap>" + startPos + "&nbsp;&nbsp;</td>");
-          }
-        }
-
-        for (int res = startRes; res < endRes; res++)
-        {
-          if (!jalview.util.Comparison.isGap(seq.getCharAt(res)))
-          {
-            color = sr.getResidueBoxColour(seq, res);
-
-            color = fr.findFeatureColour(color, seq, res);
-          }
-          else
-          {
-            color = Color.white;
-          }
-
-          if (color.getRGB() < -1)
-          {
-            out.println("<td bgcolor=\"#"
-                    + jalview.util.Format.getHexString(color) + "\">"
-                    + seq.getCharAt(res) + "</td>");
-          }
-          else
-          {
-            out.println("<td>" + seq.getCharAt(res) + "</td>");
-          }
-
-        }
-
-        if (av.getScaleRightWrapped()
-                && endRes < startRes + av.getWrappedWidth())
+        ex.printStackTrace();
+      } finally
+      {
+        if (isReader != null)
         {
-          out.println("<td colspan=\""
-                  + (startRes + av.getWrappedWidth() - endRes) + "\">"
-                  + "&nbsp;&nbsp;</td>");
+          isReader.close();
         }
-
-        if (av.getScaleRightWrapped() && startPos < endPos)
+  
+        if (buffReader != null)
         {
-          out.println("<td nowrap>&nbsp;" + endPos + "&nbsp;&nbsp;</td>");
+          buffReader.close();
         }
-
-        out.println("</tr>");
-      }
-
-      if (endRes < al.getWidth())
-      {
-        out.println("<tr><td height=\"5\"></td></tr>");
       }
     }
-
-    out.println("</table>");
-    out.println("</table>");
+    return sb.toString();
   }
 
   public static String getImageMapHTML()
@@ -388,4 +231,122 @@ public class HTMLOutput
                     + "initToolTips(); //--></script>\n");
 
   }
-}
+
+  public String getOutputFile() throws NoFileSelectedException
+  {
+    String selectedFile = null;
+    if (pIndicator != null && !isHeadless())
+    {
+      pIndicator.setProgressBar(MessageManager.formatMessage(
+              "status.waiting_for_user_to_select_output_file", "HTML"),
+              pSessionId);
+    }
+
+    JalviewFileChooser jvFileChooser = new JalviewFileChooser(
+            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
+            new String[] { "html" }, new String[] { "HTML files" },
+            "HTML files");
+    jvFileChooser.setFileView(new JalviewFileView());
+
+    jvFileChooser.setDialogTitle(MessageManager
+            .getString("label.save_as_html"));
+    jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
+
+    int fileChooserOpt = jvFileChooser.showSaveDialog(null);
+    if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
+    {
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser
+              .getSelectedFile().getParent());
+      selectedFile = jvFileChooser.getSelectedFile().getPath();
+    }
+    else
+    {
+      throw new NoFileSelectedException("No file was selected.");
+    }
+    return selectedFile;
+  }
+
+  protected void setProgressMessage(String message)
+  {
+    if (pIndicator != null && !isHeadless())
+    {
+      pIndicator.setProgressBar(message, pSessionId);
+    }
+    else
+    {
+      System.out.println(message);
+    }
+  }
+
+  /**
+   * Answers true if HTML export is invoke in headless mode or false otherwise
+   * 
+   * @return
+   */
+  protected boolean isHeadless()
+  {
+    return System.getProperty("java.awt.headless") != null
+            && System.getProperty("java.awt.headless").equals("true");
+  }
+
+  /**
+   * This method provides implementation of consistent behaviour which should
+   * occur before a HTML file export. It MUST be called at the start of the
+   * exportHTML() method implementation.
+   */
+  protected void exportStarted()
+  {
+    pSessionId = System.currentTimeMillis();
+  }
+
+  /**
+   * This method provides implementation of consistent behaviour which should
+   * occur after a HTML file export. It MUST be called at the end of the
+   * exportHTML() method implementation.
+   */
+  protected void exportCompleted()
+  {
+    if (isLaunchInBrowserAfterExport() && !isHeadless())
+    {
+      try
+      {
+        jalview.util.BrowserLauncher
+                .openURL("file:///" + getExportedFile());
+      } catch (IOException e)
+      {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * if this answers true then BioJSON data will be embedded to the exported
+   * HTML file otherwise it won't be embedded.
+   * 
+   * @return
+   */
+  public abstract boolean isEmbedData();
+
+  /**
+   * if this answers true then the generated HTML file is opened for viewing in
+   * a browser after its generation otherwise it won't be opened in a browser
+   * 
+   * @return
+   */
+  public abstract boolean isLaunchInBrowserAfterExport();
+
+  /**
+   * handle to the generated HTML file
+   * 
+   * @return
+   */
+  public abstract File getExportedFile();
+
+  /**
+   * This is the main method to handle the HTML generation.
+   * 
+   * @param outputFile
+   *          the file path of the generated HTML
+   */
+  public abstract void exportHTML(String outputFile);
+}
\ No newline at end of file
index 0acddfd..1ec3a4e 100644 (file)
  */
 package jalview.io;
 
-import jalview.api.AlignExportSettingI;
-import jalview.api.FeatureRenderer;
-import jalview.bin.Cache;
-import jalview.datamodel.AlignmentExportData;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignViewport;
+import jalview.exceptions.NoFileSelectedException;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.HTMLOptions;
-import jalview.gui.IProgressIndicator;
 import jalview.gui.OOMWarning;
 import jalview.math.AlignmentDimension;
-import jalview.util.ImageMaker;
 import jalview.util.MessageManager;
 
-import java.awt.Color;
-import java.awt.FontMetrics;
 import java.awt.Graphics;
-import java.awt.print.Printable;
 import java.awt.print.PrinterException;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
 
 import org.jfree.graphics2d.svg.SVGGraphics2D;
 import org.jfree.graphics2d.svg.SVGHints;
 
-public class HtmlSvgOutput
+public class HtmlSvgOutput extends HTMLOutput
 {
-  AlignViewport av;
 
-  FeatureRenderer fr;
 
-  AlignmentPanel ap;
-
-  private IProgressIndicator pIndicator;
-
-  private long pSessionId;
-
-  private boolean headless;
-
-
-  public HtmlSvgOutput(File file, AlignmentPanel ap)
+  public HtmlSvgOutput(AlignmentPanel ap)
   {
-    this.av = ap.av;
-    this.ap = ap;
-    fr = ap.cloneFeatureRenderer();
-    generateHtmlSvgOutput(file);
+    super(ap);
   }
 
-  public void generateHtmlSvgOutput(File file)
+  @Override
+  public void exportHTML(String outputFile)
   {
-    pIndicator = ap.alignFrame;
-    pSessionId = System.currentTimeMillis();
+    exportStarted();
     try
     {
-      headless = (System.getProperty("java.awt.headless") != null && System
-              .getProperty("java.awt.headless").equals("true"));
-      if (file == null)
+      if (outputFile == null)
       {
-        setProgressMessage(MessageManager.formatMessage(
-                "status.waiting_for_user_to_select_output_file", "HTML"));
-        JalviewFileChooser chooser = getHTMLChooser();
-        chooser.setFileView(new jalview.io.JalviewFileView());
-        chooser.setDialogTitle(ap.alignFrame.getTitle());
-        chooser.setToolTipText(MessageManager.getString("action.save"));
-        int value = chooser.showSaveDialog(ap.alignFrame);
-
-        if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
-        {
-          jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
-                  .getSelectedFile().getParent());
-          file = chooser.getSelectedFile();
-          ap.alignFrame.repaint();
-        }
-        else
-        {
-          setProgressMessage(MessageManager.formatMessage(
-                  "status.cancelled_image_export_operation", "HTML"));
-          return;
-        }
+        outputFile = getOutputFile();
       }
+      generatedFile = new File(outputFile);
+    } catch (NoFileSelectedException e)
+    {
+      setProgressMessage(MessageManager.formatMessage(
+              "status.cancelled_image_export_operation", "HTML"));
+      return;
     } catch (Exception e)
     {
-      pIndicator.setProgressBar(MessageManager.formatMessage(
-              "info.error_creating_file", "HTML"), pSessionId);
+      setProgressMessage(MessageManager.formatMessage(
+              "info.error_creating_file", "HTML"));
       e.printStackTrace();
       return;
     }
-    final File fileX = file;
-    new Thread()
-    {
-      @Override
-      public void run()
-      {
-        try
-        {
-          setProgressMessage(null);
-          setProgressMessage(MessageManager.formatMessage(
-                  "status.exporting_alignment_as_x_file", "HTML"));
-          AlignmentDimension aDimension = ap.getAlignmentDimension();
-          SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(),
-                  aDimension.getHeight());
-          SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(),
-                  aDimension.getHeight());
-
-          String renderStyle = jalview.bin.Cache.getDefault(
-                  "HTML_RENDERING", "Prompt each time");
-
-          // If we need to prompt, and if the GUI is visible then
-          // Prompt for rendering style
-          if (renderStyle.equalsIgnoreCase("Prompt each time")
-                  && !(System.getProperty("java.awt.headless") != null && System
-                          .getProperty("java.awt.headless").equals("true")))
-          {
-            HTMLOptions svgOption = new HTMLOptions();
-            renderStyle = svgOption.getValue();
-
-            if (renderStyle == null || svgOption.cancelled)
-            {
-              setProgressMessage(MessageManager.formatMessage(
-                      "status.cancelled_image_export_operation", "HTML"));
-              return;
-            }
-          }
-
-          if (renderStyle.equalsIgnoreCase("Lineart"))
-          {
-            g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
-                    SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
-            g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
-                    SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
-          }
-          printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
-                  g1, g2);
-
-          String titleSvgData = g1.getSVGDocument();
-          String alignSvgData = g2.getSVGDocument();
-          String jsonData = null;
-          boolean isEmbbedBioJSON = Boolean.valueOf(jalview.bin.Cache
-                  .getDefault("EXPORT_EMBBED_BIOJSON", "true"));
-          if (isEmbbedBioJSON)
-          {
-            AlignExportSettingI exportSettings = new AlignExportSettingI()
-            {
-              @Override
-              public boolean isExportHiddenSequences()
-              {
-                return true;
-              }
-
-              @Override
-              public boolean isExportHiddenColumns()
-              {
-                return true;
-              }
-
-              @Override
-              public boolean isExportAnnotations()
-              {
-                return true;
-              }
-
-              @Override
-              public boolean isExportFeatures()
-              {
-                return true;
-              }
-
-              @Override
-              public boolean isExportGroups()
-              {
-                return true;
-              }
-
-              @Override
-              public boolean isCancelled()
-              {
-                return false;
-              }
-
-            };
-            AlignmentExportData exportData = jalview.gui.AlignFrame
-                    .getAlignmentForExport(FileFormat.Json, av,
-                            exportSettings);
-            jsonData = new FormatAdapter(ap, exportData.getSettings())
-                    .formatSequences(FileFormat.Json,
-                            exportData.getAlignment(),
-                            exportData.getOmitHidden(),
-                            exportData.getStartEndPostions(),
-                            av.getColumnSelection());
-          }
-          String htmlData = getHtml(titleSvgData, alignSvgData, jsonData);
-          FileOutputStream out = new FileOutputStream(fileX);
-          out.write(htmlData.getBytes());
-          out.flush();
-          out.close();
-          if (!(System.getProperty("java.awt.headless") != null && System
-                  .getProperty("java.awt.headless").equals("true")))
-          {
-            jalview.util.BrowserLauncher.openURL("file:///" + fileX);
-          }
-        } catch (OutOfMemoryError err)
-        {
-          System.out.println("########################\n"
-                  + "OUT OF MEMORY " + fileX + "\n"
-                  + "########################");
-          new OOMWarning("Creating Image for " + fileX, err);
-        } catch (Exception e)
-        {
-          e.printStackTrace();
-          pIndicator.setProgressBar(MessageManager.formatMessage(
-                  "info.error_creating_file", "HTML"), pSessionId);
-        }
-        setProgressMessage(MessageManager.formatMessage(
-                "status.export_complete", "HTML"));
-      }
-    }.start();
-
+    new Thread(this).start();
   }
 
-  private void setProgressMessage(String message)
-  {
-    if (pIndicator != null && !headless)
-    {
-      pIndicator.setProgressBar(message, pSessionId);
-    }
-    else
-    {
-      System.out.println(message);
-    }
-  }
 
   static JalviewFileChooser getHTMLChooser()
   {
-    return new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"),
-            ImageMaker.HTML_EXTENSION, ImageMaker.HTML_EXTENSION,
-            ImageMaker.HTML_EXTENSION);
+    return new jalview.io.JalviewFileChooser(
+            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
+            new String[] { "html" },
+            new String[] { "Hypertext Markup Language" },
+            "Hypertext Markup Language");
   }
 
-  public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg)
+  public int printUnwrapped(int pwidth, int pheight, int pi,
+          Graphics idGraphics, Graphics alignmentGraphics)
           throws PrinterException
   {
-    int idWidth = ap.getVisibleIdWidth(false);
-    FontMetrics fm = ap.getFontMetrics(av.getFont());
-    int scaleHeight = av.getCharHeight() + fm.getDescent();
-
-    pg[0].setColor(Color.white);
-    pg[0].fillRect(0, 0, pwidth, pheight);
-    pg[0].setFont(av.getFont());
-
-    // //////////////////////////////////
-    // / How many sequences and residues can we fit on a printable page?
-    int totalRes = (pwidth - idWidth) / av.getCharWidth();
-    int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1;
-    int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1;
-
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int startRes;
-
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int endRes;
-
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int startSeq;
-
-    // ///////////////////////////
-    // / Only print these sequences and residues on this page
-    int endSeq;
-    startRes = (pi % pagesWide) * totalRes;
-    endRes = (startRes + totalRes) - 1;
-
-    if (endRes > (av.getAlignment().getWidth() - 1))
-    {
-      endRes = av.getAlignment().getWidth() - 1;
-    }
-    startSeq = (pi / pagesWide) * totalSeq;
-    endSeq = startSeq + totalSeq;
-    if (endSeq > av.getAlignment().getHeight())
-    {
-      endSeq = av.getAlignment().getHeight();
-    }
-    int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1)
-            * pheight;
-    if (av.isShowAnnotation())
-    {
-      pagesHigh += ap.getAnnotationPanel().adjustPanelHeight() + 3;
-    }
-    pagesHigh /= pheight;
-    if (pi >= (pagesWide * pagesHigh))
-    {
-      return Printable.NO_SUCH_PAGE;
-    }
-
-    // draw Scale
-    pg[1].translate(0, 0);
-    ap.getScalePanel().drawScale(pg[1], startRes, endRes, pwidth - idWidth,
-            scaleHeight);
-    pg[1].translate(-idWidth, scaleHeight);
-
-    // //////////////
-    // Draw the ids
-    Color currentColor = null;
-    Color currentTextColor = null;
-    pg[0].translate(0, scaleHeight);
-    pg[0].setFont(ap.getIdPanel().getIdCanvas().getIdfont());
-    SequenceI seq;
-    for (int i = startSeq; i < endSeq; i++)
-    {
-      seq = av.getAlignment().getSequenceAt(i);
-      if ((av.getSelectionGroup() != null)
-              && av.getSelectionGroup().getSequences(null).contains(seq))
-      {
-        currentColor = Color.gray;
-        currentTextColor = Color.black;
-      }
-      else
-      {
-        currentColor = av.getSequenceColour(seq);
-        currentTextColor = Color.black;
-      }
-      pg[0].setColor(currentColor);
-      pg[0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
-              av.getCharHeight());
-      pg[0].setColor(currentTextColor);
-      int xPos = 0;
-      if (av.isRightAlignIds())
-      {
-        fm = pg[0].getFontMetrics();
-        xPos = idWidth
-                - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix()))
-                - 4;
-      }
-      pg[0].drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos,
-              (((i - startSeq) * av.getCharHeight()) + av.getCharHeight())
-                      - (av.getCharHeight() / 5));
-    }
-    pg[0].setFont(av.getFont());
-    pg[0].translate(idWidth, 0);
-
-    // draw main sequence panel
-    pg[1].translate(idWidth, 0);
-    ap.getSeqPanel().seqCanvas.drawPanel(pg[1], startRes, endRes, startSeq,
-            endSeq, 0);
-    if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight()))
-    {
-      // draw annotation label - need to offset for current scroll position
-      int offset = -ap.getAlabels().getScrollOffset();
-      pg[0].translate(0, offset);
-      pg[0].translate(-idWidth - 3,
-              (endSeq - startSeq) * av.getCharHeight() + 3);
-      ap.getAlabels().drawComponent(pg[0], idWidth);
-      pg[0].translate(idWidth + 3, 0);
-      pg[0].translate(0, -offset);
-
-      // draw annotation - need to offset for current scroll position
-      pg[1].translate(0, offset);
-      pg[1].translate(-idWidth - 3,
-              (endSeq - startSeq) * av.getCharHeight() + 3);
-      pg[1].translate(idWidth + 3, 0);
-      ap.getAnnotationPanel().renderer.drawComponent(
-              ap.getAnnotationPanel(), av, pg[1], -1, startRes, endRes + 1);
-      pg[1].translate(0, -offset);
-    }
+    return ap.printUnwrapped(pwidth, pheight, pi, idGraphics,
+            alignmentGraphics);
+  }
 
-    return Printable.PAGE_EXISTS;
+  public int printWrapped(int pwidth, int pheight, int pi, Graphics... pg)
+          throws PrinterException
+  {
+    return ap.printWrappedAlignment(pwidth, pheight, pi, pg[0]);
   }
 
   private String getHtml(String titleSvg, String alignmentSvg,
-          String jsonData)
+          String jsonData, boolean wrapped)
   {
     StringBuilder htmlSvg = new StringBuilder();
     htmlSvg.append("<html>\n");
@@ -430,8 +136,9 @@ public class HtmlSvgOutput
               + ".facebox_hide { z-index:-100; }\n"
               + ".facebox_overlayBG { background-color: #000;  z-index: 99;  }");
     }
-
     htmlSvg.append("</style>");
+    if (!wrapped)
+    {
     htmlSvg.append("<div class=\"main-container\" \n>");
     htmlSvg.append("<div class=\"titlex\">\n");
     htmlSvg.append("<div class=\"sub-category-container\"> \n");
@@ -452,9 +159,16 @@ public class HtmlSvgOutput
             + "subCatContainer.scrollTop($(this).scrollTop());\n});\n");
 
     htmlSvg.append("</script>\n");
+    }
+    else
+    {
+      htmlSvg.append("<div>\n")
+              .append(alignmentSvg).append("</div>");
+      htmlSvg.append("<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js\"></script>\n"
+              + "<script language=\"JavaScript\" type=\"text/javascript\"  src=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js\"></script>\n");
+    }
 
     // javascript for launching file in Jalview
-
     htmlSvg.append("<script language=\"JavaScript\">\n");
     htmlSvg.append("function openJalviewUsingCurrentUrl(){\n");
     htmlSvg.append("    var json = JSON.parse(document.getElementById(\"seqData\").innerHTML);\n");
@@ -479,269 +193,115 @@ public class HtmlSvgOutput
     htmlSvg.append("    document.body.removeChild(myForm);\n");
     htmlSvg.append("}\n");
 
-    // jquery facebox for displaying raw BioJSON data");
     if (jsonData != null)
     {
-      htmlSvg.append("/* Facebox (for jQuery)\n");
-      htmlSvg.append("* version: 1.3\n");
-      htmlSvg.append(" * @requires jQuery v1.2 or later\n");
-      htmlSvg.append(" * @homepage https://github.com/defunkt/facebox\n");
-      htmlSvg.append(" * Licensed under the MIT:\n");
-      htmlSvg.append(" *   http://www.opensource.org/licenses/mit-license.php\n");
-      htmlSvg.append(" * Copyright Forever Chris Wanstrath, Kyle Neath\n");
-      htmlSvg.append(" * Usage:\n");
-      htmlSvg.append(" *  jQuery(document).ready(function() {\n");
-      htmlSvg.append(" *    jQuery('a[rel*=facebox]').facebox()\n");
-      htmlSvg.append(" *  })\n");
-      htmlSvg.append(" *  <a href=\"#terms\" rel=\"facebox\">Terms</a>\n");
-      htmlSvg.append(" *    Loads the #terms div in the box\n");
-      htmlSvg.append(" *  <a href=\"terms.html\" rel=\"facebox\">Terms</a>\n");
-      htmlSvg.append(" *    Loads the terms.html page in the box\n");
-      htmlSvg.append(" *  <a href=\"terms.png\" rel=\"facebox\">Terms</a>\n");
-      htmlSvg.append(" *    Loads the terms.png image in the box\n");
-      htmlSvg.append(" *  You can also use it programmatically:\n");
-      htmlSvg.append(" *    jQuery.facebox('some html')\n");
-      htmlSvg.append(" *    jQuery.facebox('some html', 'my-groovy-style')\n");
-      htmlSvg.append(" *  The above will open a facebox with \"some html\" as the content.\n");
-      htmlSvg.append(" *    jQuery.facebox(function($) {\n");
-      htmlSvg.append(" *      $.get('blah.html', function(data) { $.facebox(data) })\n");
-      htmlSvg.append(" *    })\n");
-      htmlSvg.append(" *  The above will show a loading screen before the passed function is called,\n");
-      htmlSvg.append(" *  allowing for a better ajaxy experience.\n");
-      htmlSvg.append(" *  The facebox function can also display an ajax page, an image, or the contents of a div:\n");
-      htmlSvg.append(" *    jQuery.facebox({ ajax: 'remote.html' })\n");
-      htmlSvg.append(" *    jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')\n");
-      htmlSvg.append(" *    jQuery.facebox({ image: 'stairs.jpg' })\n");
-      htmlSvg.append(" *    jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')\n");
-      htmlSvg.append(" *    jQuery.facebox({ div: '#box' })\n");
-      htmlSvg.append(" *    jQuery.facebox({ div: '#box' }, 'my-groovy-style')\n");
-      htmlSvg.append(" *    Want to close the facebox?  Trigger the 'close.facebox' document event:\n");
-      htmlSvg.append(" *    jQuery(document).trigger('close.facebox')\n");
-      htmlSvg.append(" *  Facebox also has a bunch of other hooks:\n");
-      htmlSvg.append(" *    loading.facebox\n");
-      htmlSvg.append(" *    beforeReveal.facebox\n");
-      htmlSvg.append(" *    reveal.facebox (aliased as 'afterReveal.facebox')\n");
-      htmlSvg.append(" *    init.facebox\n");
-      htmlSvg.append(" *    afterClose.facebox\n");
-      htmlSvg.append(" *  Simply bind a function to any of these hooks:\n");
-      htmlSvg.append(" *   $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })\n");
-      htmlSvg.append(" *\n");
-      htmlSvg.append(" */\n");
-      htmlSvg.append("(function($) {\n");
-      htmlSvg.append("  $.facebox = function(data, klass) {\n");
-      htmlSvg.append("    $.facebox.loading()\n");
-      htmlSvg.append("    if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)\n");
-      htmlSvg.append("    else if (data.image) fillFaceboxFromImage(data.image, klass)\n");
-      htmlSvg.append("    else if (data.div) fillFaceboxFromHref(data.div, klass)\n");
-      htmlSvg.append("    else if ($.isFunction(data)) data.call($)\n");
-      htmlSvg.append("    else $.facebox.reveal(data, klass)\n");
-      htmlSvg.append("  }\n");
-
-      htmlSvg.append("  $.extend($.facebox, {\n");
-      htmlSvg.append("    settings: {\n");
-      htmlSvg.append("      opacity      : 0.2,\n");
-      htmlSvg.append("      overlay      : true,\n");
-      htmlSvg.append("      loadingImage : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/loading.gif',\n");
-      htmlSvg.append("      closeImage   : 'https://raw.githubusercontent.com/jalview/biojson/gh-pages/images/cancel.png',\n");
-      htmlSvg.append("      imageTypes   : [ 'png', 'jpg', 'jpeg', 'gif' ],\n");
-      htmlSvg.append("      faceboxHtml  : '<div  id=\"facebox\" style=\"display:none; width: 95%; height: 85%; overflow: auto;\"> ");
-      htmlSvg.append("      <div class=\"popup\"> ");
-      htmlSvg.append("        <div class=\"content\"> ");
-      htmlSvg.append("        </div> ");
-      htmlSvg.append("        <a href=\"#\" class=\"close\"></a> ");
-      htmlSvg.append("      </div> ");
-      htmlSvg.append("    </div>'\n");
-      htmlSvg.append("    },      \n");
-      htmlSvg.append("    loading: function() {\n");
-      htmlSvg.append("      init()\n");
-      htmlSvg.append("      if ($('#facebox .loading').length == 1) return true\n");
-      htmlSvg.append("      showOverlay()      \n");
-      htmlSvg.append("      $('#facebox .content').empty().\n");
-      htmlSvg.append("        append('<div class=\"loading\"><img src=\"'+$.facebox.settings.loadingImage+'\"/></div>')\n");
-      htmlSvg.append("      $('#facebox').show().css({\n");
-      htmlSvg.append("        top:    getPageScroll()[1] + (getPageHeight() / 10),\n");
-      htmlSvg.append("        left:    $(window).width() / 2 - ($('#facebox .popup').outerWidth() / 2)\n");
-      htmlSvg.append("      })      \n");
-      htmlSvg.append("      $(document).bind('keydown.facebox', function(e) {\n");
-      htmlSvg.append("       if (e.keyCode == 27) $.facebox.close()\n");
-      htmlSvg.append("        return true\n");
-      htmlSvg.append("      })\n");
-      htmlSvg.append("      $(document).trigger('loading.facebox')\n");
-      htmlSvg.append("    },\n");
-      htmlSvg.append("    reveal: function(data, klass) {\n");
-      htmlSvg.append("      $(document).trigger('beforeReveal.facebox')\n");
-      htmlSvg.append("      if (klass) $('#facebox .content').addClass(klass)\n");
-      htmlSvg.append("      $('#facebox .content').empty().append('<pre><code>'+JSON.stringify(JSON.parse(data),null,4)+'</pre></code>')\n");
-      htmlSvg.append("      $('#facebox .popup').children().fadeIn('normal')\n");
-      htmlSvg.append("      $('#facebox').css('left', $(window).width() / 2 - ($('#facebox .popup').outerWidth() / 2))\n");
-      htmlSvg.append("      $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')\n");
-      htmlSvg.append("    },      \n");
-      htmlSvg.append("    close: function() {\n");
-      htmlSvg.append("      $(document).trigger('close.facebox')\n");
-      htmlSvg.append("      return false\n");
-      htmlSvg.append("    }\n");
-      htmlSvg.append("  })\n");
-      htmlSvg.append("  $.fn.facebox = function(settings) {\n");
-      htmlSvg.append("    if ($(this).length == 0) return    \n");
-      htmlSvg.append("    init(settings)      \n");
-      htmlSvg.append("    function clickHandler() {\n");
-      htmlSvg.append("      $.facebox.loading(true)      \n");
-      htmlSvg.append("      // support for rel=\"facebox.inline_popup\" syntax, to add a class\n");
-      htmlSvg.append("      // also supports deprecated \"facebox[.inline_popup]\" syntax\n");
-      htmlSvg.append("      var klass = this.rel.match(/facebox\\[?\\.(\\w+)\\]?/)\n");
-      htmlSvg.append("      if (klass) klass = klass[1]\n");
-      htmlSvg.append("      fillFaceboxFromHref(this.href, klass)\n");
-      htmlSvg.append("      return false\n");
-      htmlSvg.append("    }      \n");
-      htmlSvg.append("    return this.bind('click.facebox', clickHandler)\n");
-      htmlSvg.append("  }\n");
-      htmlSvg.append("  // called one time to setup facebox on this page\n");
-      htmlSvg.append("  function init(settings) {\n");
-      htmlSvg.append("    if ($.facebox.settings.inited) return true\n");
-      htmlSvg.append("    else $.facebox.settings.inited = true\n");
-      htmlSvg.append("    $(document).trigger('init.facebox')\n");
-      htmlSvg.append("    makeCompatible()\n");
-      htmlSvg.append("    var imageTypes = $.facebox.settings.imageTypes.join('|')\n");
-      htmlSvg.append("    $.facebox.settings.imageTypesRegexp = new RegExp('\\\\.(' + imageTypes + ')(\\\\?.*)?$', 'i')\n");
-
-      htmlSvg.append("    if (settings) $.extend($.facebox.settings, settings)\n");
-      htmlSvg.append("    $('body').append($.facebox.settings.faceboxHtml)\n");
-
-      htmlSvg.append("    var preload = [ new Image(), new Image() ]\n");
-      htmlSvg.append("    preload[0].src = $.facebox.settings.closeImage\n");
-      htmlSvg.append("    preload[1].src = $.facebox.settings.loadingImage\n");
-
-      htmlSvg.append("    $('#facebox').find('.b:first, .bl').each(function() {\n");
-      htmlSvg.append("      preload.push(new Image())\n");
-      htmlSvg.append("      preload.slice(-1).src = $(this).css('background-image').replace(/url\\((.+)\\)/, '$1')\n");
-      htmlSvg.append("    })\n");
-
-      htmlSvg.append("    $('#facebox .close')\n");
-      htmlSvg.append("      .click($.facebox.close)\n");
-      htmlSvg.append("      .append('<img src=\"'\n");
-      htmlSvg.append("              + $.facebox.settings.closeImage\n");
-      htmlSvg.append("              + '\" class=\"close_image\" title=\"close\">')\n");
-      htmlSvg.append("  }\n");
-
-      htmlSvg.append("  // getPageScroll() by quirksmode.com\n");
-      htmlSvg.append("  function getPageScroll() {\n");
-      htmlSvg.append("    var xScroll, yScroll;\n");
-      htmlSvg.append("    if (self.pageYOffset) {\n");
-      htmlSvg.append("      yScroll = self.pageYOffset;\n");
-      htmlSvg.append("      xScroll = self.pageXOffset;\n");
-      htmlSvg.append("    } else if (document.documentElement && document.documentElement.scrollTop) {     // Explorer 6 Strict\n");
-      htmlSvg.append("      yScroll = document.documentElement.scrollTop;\n");
-      htmlSvg.append("      xScroll = document.documentElement.scrollLeft;\n");
-      htmlSvg.append("    } else if (document.body) {// all other Explorers\n");
-      htmlSvg.append("      yScroll = document.body.scrollTop;\n");
-      htmlSvg.append("      xScroll = document.body.scrollLeft;\n");
-      htmlSvg.append("    }\n");
-      htmlSvg.append("    return new Array(xScroll,yScroll)\n");
-      htmlSvg.append("  }\n");
-
-      // Adapted from getPageSize() by quirksmode.com");
-      htmlSvg.append("  function getPageHeight() {\n");
-      htmlSvg.append("    var windowHeight\n");
-      htmlSvg.append("    if (self.innerHeight) {    // all except Explorer\n");
-      htmlSvg.append("      windowHeight = self.innerHeight;\n");
-      htmlSvg.append("    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode\n");
-      htmlSvg.append("      windowHeight = document.documentElement.clientHeight;\n");
-      htmlSvg.append("    } else if (document.body) { // other Explorers\n");
-      htmlSvg.append("      windowHeight = document.body.clientHeight;\n");
-      htmlSvg.append("    }\n");
-      htmlSvg.append("    return windowHeight\n");
-      htmlSvg.append("  }\n");
-
-      htmlSvg.append("  // Backwards compatibility\n");
-      htmlSvg.append("  function makeCompatible() {\n");
-      htmlSvg.append("    var $s = $.facebox.settings      \n");
-      htmlSvg.append("    $s.loadingImage = $s.loading_image || $s.loadingImage\n");
-      htmlSvg.append("    $s.closeImage = $s.close_image || $s.closeImage\n");
-      htmlSvg.append("    $s.imageTypes = $s.image_types || $s.imageTypes\n");
-      htmlSvg.append("    $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml\n");
-      htmlSvg.append("  }\n");
-
-      htmlSvg.append("  // Figures out what you want to display and displays it\n");
-      htmlSvg.append("  // formats are:\n");
-      htmlSvg.append("  //     div: #id\n");
-      htmlSvg.append("  //   image: blah.extension\n");
-      htmlSvg.append("  //    ajax: anything else\n");
-      htmlSvg.append("  function fillFaceboxFromHref(href, klass) {\n");
-      htmlSvg.append("    // div\n");
-      htmlSvg.append("    if (href.match(/#/)) {\n");
-      htmlSvg.append("      var url    = window.location.href.split('#')[0]\n");
-      htmlSvg.append("      var target = href.replace(url,'')\n");
-      htmlSvg.append("      if (target == '#') return\n");
-      htmlSvg.append("      $.facebox.reveal($(target).html(), klass)\n");
-
-      htmlSvg.append("    // image\n");
-      htmlSvg.append("    } else if (href.match($.facebox.settings.imageTypesRegexp)) {\n");
-      htmlSvg.append("      fillFaceboxFromImage(href, klass)\n");
-      htmlSvg.append("    // ajax\n");
-      htmlSvg.append("    } else {\n");
-      htmlSvg.append("      fillFaceboxFromAjax(href, klass)\n");
-      htmlSvg.append("    }\n");
-      htmlSvg.append("  }\n");
-
-      htmlSvg.append("  function fillFaceboxFromImage(href, klass) {\n");
-      htmlSvg.append("    var image = new Image()\n");
-      htmlSvg.append("    image.onload = function() {\n");
-      htmlSvg.append("      $.facebox.reveal('<div class=\"image\"><img src=\"' + image.src + '\" /></div>', klass)\n");
-      htmlSvg.append("    }\n");
-      htmlSvg.append("    image.src = href\n");
-      htmlSvg.append("   }\n");
-
-      htmlSvg.append("  function fillFaceboxFromAjax(href, klass) {\n");
-      htmlSvg.append("    $.facebox.jqxhr = $.get(href, function(data) { $.facebox.reveal(data, klass) })\n");
-      htmlSvg.append("  }\n");
+      // JQuery FaceBox for displaying raw BioJSON data");
+      File faceBoxJsFile = new File("examples/javascript/facebox-1.3.js");
+      try
+      {
+        htmlSvg.append(HTMLOutput.readFileAsString(faceBoxJsFile));
+      } catch (IOException e)
+      {
+        e.printStackTrace();
+      }
+    }
 
-      htmlSvg.append("  function skipOverlay() {\n");
-      htmlSvg.append("    return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null\n");
-      htmlSvg.append("  }\n");
+    htmlSvg.append("</script>\n");
+    htmlSvg.append("</html>");
+    return htmlSvg.toString();
+  }
 
-      htmlSvg.append("  function showOverlay() {\n");
-      htmlSvg.append("    if (skipOverlay()) return\n");
+  @Override
+  public boolean isEmbedData()
+  {
+    return Boolean.valueOf(jalview.bin.Cache.getDefault(
+            "EXPORT_EMBBED_BIOJSON", "true"));
+  }
 
-      htmlSvg.append("    if ($('#facebox_overlay').length == 0)\n");
-      htmlSvg.append("      $(\"body\").append('<div id=\"facebox_overlay\" class=\"facebox_hide\"></div>')\n");
+  @Override
+  public boolean isLaunchInBrowserAfterExport()
+  {
+    return true;
+  }
 
-      htmlSvg.append("    $('#facebox_overlay').hide().addClass(\"facebox_overlayBG\")\n");
-      htmlSvg.append("      .css('opacity', $.facebox.settings.opacity)\n");
-      htmlSvg.append("      .click(function() { $(document).trigger('close.facebox') })\n");
-      htmlSvg.append("       .fadeIn(200)\n");
-      htmlSvg.append("    return false\n");
-      htmlSvg.append("  }\n");
+  @Override
+  public File getExportedFile()
+  {
+    return generatedFile;
+  }
 
-      htmlSvg.append("  function hideOverlay() {\n");
-      htmlSvg.append("    if (skipOverlay()) return      \n");
-      htmlSvg.append("    $('#facebox_overlay').fadeOut(200, function(){\n");
-      htmlSvg.append("      $(\"#facebox_overlay\").removeClass(\"facebox_overlayBG\")\n");
-      htmlSvg.append("      $(\"#facebox_overlay\").addClass(\"facebox_hide\")\n");
-      htmlSvg.append("      $(\"#facebox_overlay\").remove()\n");
-      htmlSvg.append("    })      \n");
-      htmlSvg.append("    return false\n");
-      htmlSvg.append("  }\n");
+  @Override
+  public void run()
+  {
+    try
+    {
+      setProgressMessage(null);
+      setProgressMessage(MessageManager.formatMessage(
+              "status.exporting_alignment_as_x_file", "HTML"));
+      AlignmentDimension aDimension = ap.getAlignmentDimension();
+      SVGGraphics2D idPanelGraphics = new SVGGraphics2D(
+              aDimension.getWidth(), aDimension.getHeight());
+      SVGGraphics2D alignPanelGraphics = new SVGGraphics2D(
+              aDimension.getWidth(), aDimension.getHeight());
+
+      String renderStyle = jalview.bin.Cache.getDefault("HTML_RENDERING",
+              "Prompt each time");
+
+      // If we need to prompt, and if the GUI is visible then
+      // Prompt for rendering style
+      if (renderStyle.equalsIgnoreCase("Prompt each time") && !isHeadless())
+      {
+        HTMLOptions svgOption = new HTMLOptions();
+        renderStyle = svgOption.getValue();
 
-      htmlSvg.append("  $(document).bind('close.facebox', function() {\n");
-      htmlSvg.append("    if ($.facebox.jqxhr) {\n");
-      htmlSvg.append("      $.facebox.jqxhr.abort()\n");
-      htmlSvg.append("      $.facebox.jqxhr = null\n");
-      htmlSvg.append("    }\n");
-      htmlSvg.append("    $(document).unbind('keydown.facebox')\n");
-      htmlSvg.append("    $('#facebox').fadeOut(function() {\n");
-      htmlSvg.append("      $('#facebox .content').removeClass().addClass('content')\n");
-      htmlSvg.append("      $('#facebox .loading').remove()\n");
-      htmlSvg.append("      $(document).trigger('afterClose.facebox')\n");
-      htmlSvg.append("    })\n");
-      htmlSvg.append("    hideOverlay()\n");
-      htmlSvg.append("  })\n");
+        if (renderStyle == null || svgOption.cancelled)
+        {
+          setProgressMessage(MessageManager.formatMessage(
+                  "status.cancelled_image_export_operation", "HTML"));
+          return;
+        }
+      }
 
-      htmlSvg.append("})(jQuery);\n");
+      if (renderStyle.equalsIgnoreCase("Lineart"))
+      {
+        idPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
+                SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
+        alignPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
+                SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
+      }
+      if (ap.av.getWrapAlignment())
+      {
+        printWrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
+                alignPanelGraphics);
+      }
+      else
+      {
+        printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
+                idPanelGraphics, alignPanelGraphics);
+      }
 
+      String idPanelSvgData = idPanelGraphics.getSVGDocument();
+      String alignPanelSvgData = alignPanelGraphics.getSVGDocument();
+      String jsonData = getBioJSONData();
+      String htmlData = getHtml(idPanelSvgData, alignPanelSvgData,
+              jsonData, ap.av.getWrapAlignment());
+      FileOutputStream out = new FileOutputStream(generatedFile);
+      out.write(htmlData.getBytes());
+      out.flush();
+      out.close();
+      setProgressMessage(MessageManager.formatMessage(
+              "status.export_complete", "HTML"));
+      exportCompleted();
+    } catch (OutOfMemoryError err)
+    {
+      System.out.println("########################\n" + "OUT OF MEMORY "
+              + generatedFile + "\n" + "########################");
+      new OOMWarning("Creating Image for " + generatedFile, err);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      setProgressMessage(MessageManager.formatMessage(
+              "info.error_creating_file", "HTML"));
     }
-
-    htmlSvg.append("</script>\n");
-    htmlSvg.append("</html>");
-    return htmlSvg.toString();
   }
 }
index f8d8415..72a1155 100755 (executable)
@@ -259,7 +259,7 @@ public class IdentifyFile
         }
         int lessThan = data.indexOf("<");
         if ((lessThan > -1)) // possible Markup Language data i.e HTML,
-                                      // RNAML, XML
+                             // RNAML, XML
         {
           String upper = data.toUpperCase();
           if (upper.substring(lessThan).startsWith("<HTML"))
@@ -370,8 +370,9 @@ public class IdentifyFile
   }
 
   /**
-   * Returns true if the data has at least 6 tab-delimited fields _and_ 
-   * fields 4 and 5 are integer (start/end) 
+   * Returns true if the data has at least 6 tab-delimited fields _and_ fields 4
+   * and 5 are integer (start/end)
+   * 
    * @param data
    * @return
    */
@@ -382,14 +383,17 @@ public class IdentifyFile
       return false;
     }
     String[] columns = data.split("\t");
-    if (columns.length < 6) {
+    if (columns.length < 6)
+    {
       return false;
     }
     for (int col = 3; col < 5; col++)
     {
-      try {
+      try
+      {
         Integer.parseInt(columns[col]);
-      } catch (NumberFormatException e) {
+      } catch (NumberFormatException e)
+      {
         return false;
       }
     }
index 4cef26d..c42771d 100755 (executable)
@@ -53,6 +53,7 @@ public class JalviewFileView extends FileView
     alignSuffix.put("sto", "Stockholm File");
   }
 
+  @Override
   public String getTypeDescription(File f)
   {
     String extension = getExtension(f);
@@ -69,6 +70,7 @@ public class JalviewFileView extends FileView
     return type;
   }
 
+  @Override
   public Icon getIcon(File f)
   {
     String extension = getExtension(f);
index d5593e3..3feae5d 100755 (executable)
@@ -192,13 +192,13 @@ public class JnetAnnotationMaker
           if (id.equals("JNETCONF"))
           {
             annot = new AlignmentAnnotation(preds[i].getName(),
-                    "JNet Output", annotations, 0f, 10f,
+                    "JPred Output", annotations, 0f, 10f,
                     AlignmentAnnotation.BAR_GRAPH);
           }
           else
           {
             annot = new AlignmentAnnotation(preds[i].getName(),
-                    "JNet Output", annotations);
+                    "JPred Output", annotations);
           }
 
           if (seqRef != null)
index aa8e406..f379724 100755 (executable)
@@ -240,8 +240,7 @@ public class MSFfile extends AlignFile
        * modify to MSF format: uses '.' for internal gaps, 
        * and '~' for leading or trailing gaps
        */
-      String seqString = sqs[i].getSequenceAsString()
-              .replace('-', '.');
+      String seqString = sqs[i].getSequenceAsString().replace('-', '.');
 
       StringBuilder sb = new StringBuilder(seqString);
 
index ecce1a3..746c4a7 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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 jalview.api.FeatureColourI;
@@ -8,10 +28,10 @@ import java.awt.Color;
 
 public class PDBFeatureSettings extends FeatureSettingsAdapter
 {
+  // TODO find one central place to define feature names
+  private static final String FEATURE_INSERTION = "INSERTION";
 
-  public static final String FEATURE_INSERTION = "INSERTION";
-
-  public static final String FEATURE_RES_NUM = "RESNUM";
+  private static final String FEATURE_RES_NUM = "RESNUM";
 
   @Override
   public boolean isFeatureDisplayed(String type)
@@ -63,4 +83,3 @@ public class PDBFeatureSettings extends FeatureSettingsAdapter
     return 0;
   }
 }
-
index 05adb0e..bc22fae 100755 (executable)
@@ -125,8 +125,7 @@ public class PfamFile extends AlignFile
     {
       if (seqhash.get(headers.get(i)) != null)
       {
-        if (maxLength < seqhash.get(headers.get(i)).toString()
-                .length())
+        if (maxLength < seqhash.get(headers.get(i)).toString().length())
         {
           maxLength = seqhash.get(headers.get(i)).toString().length();
         }
index 2d76d6b..6c8f40f 100644 (file)
 package jalview.io;
 
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.gff.GffConstants;
-import jalview.util.DBRefUtils;
+import jalview.util.MessageManager;
 import jalview.util.UrlLink;
 
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -38,8 +42,69 @@ import java.util.Map;
  */
 public class SequenceAnnotationReport
 {
+  private static final String COMMA = ",";
+
+  private static final String ELLIPSIS = "...";
+
+  private static final int MAX_REFS_PER_SOURCE = 4;
+
+  private static final int MAX_SOURCES = 40;
+
+  private static final String[][] PRIMARY_SOURCES = new String[][] {
+      DBRefSource.CODINGDBS, DBRefSource.DNACODINGDBS,
+      DBRefSource.PROTEINDBS };
+
   final String linkImageURL;
 
+  /*
+   * Comparator to order DBRefEntry by Source + accession id (case-insensitive)
+   */
+  private static Comparator<DBRefEntry> comparator = new Comparator<DBRefEntry>()
+  {
+
+    @Override
+    public int compare(DBRefEntry ref1, DBRefEntry ref2)
+    {
+      String s1 = ref1.getSource();
+      String s2 = ref2.getSource();
+      boolean s1Primary = isPrimarySource(s1);
+      boolean s2Primary = isPrimarySource(s2);
+      if (s1Primary && !s2Primary)
+      {
+        return -1;
+      }
+      if (!s1Primary && s2Primary)
+      {
+        return 1;
+      }
+      int comp = s1 == null ? -1 : (s2 == null ? 1 : s1
+              .compareToIgnoreCase(s2));
+      if (comp == 0)
+      {
+        String a1 = ref1.getAccessionId();
+        String a2 = ref2.getAccessionId();
+        comp = a1 == null ? -1 : (a2 == null ? 1 : a1
+                .compareToIgnoreCase(a2));
+      }
+      return comp;
+    }
+
+    private boolean isPrimarySource(String source)
+    {
+      for (String[] primary : PRIMARY_SOURCES)
+      {
+        for (String s : primary)
+        {
+          if (source.equals(s))
+          {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+  };
+
   public SequenceAnnotationReport(String linkImageURL)
   {
     this.linkImageURL = linkImageURL;
@@ -48,37 +113,35 @@ public class SequenceAnnotationReport
   /**
    * Append text for the list of features to the tooltip
    * 
-   * @param tooltipText2
+   * @param sb
    * @param rpos
    * @param features
    * @param minmax
    */
-  public void appendFeatures(final StringBuffer tooltipText2, int rpos,
+  public void appendFeatures(final StringBuilder sb, int rpos,
           List<SequenceFeature> features, Map<String, float[][]> minmax)
   {
     if (features != null)
     {
       for (SequenceFeature feature : features)
       {
-        appendFeature(tooltipText2, rpos, minmax, feature);
+        appendFeature(sb, rpos, minmax, feature);
       }
     }
   }
 
   /**
-   * Appends text for one sequence feature to the string buffer
+   * Appends the feature at rpos to the given buffer
    * 
    * @param sb
    * @param rpos
    * @param minmax
-   *          {{min, max}, {min, max}} positional and non-positional feature
-   *          scores for this type
    * @param feature
    */
-  void appendFeature(final StringBuffer sb, int rpos,
+  void appendFeature(final StringBuilder sb, int rpos,
           Map<String, float[][]> minmax, SequenceFeature feature)
   {
-    if ("disulfide bond".equals(feature.getType()))
+    if (feature.isContactFeature())
     {
       if (feature.getBegin() == rpos || feature.getEnd() == rpos)
       {
@@ -86,7 +149,8 @@ public class SequenceAnnotationReport
         {
           sb.append("<br>");
         }
-        sb.append("disulfide bond ").append(feature.getBegin()).append(":")
+        sb.append(feature.getType()).append(" ").append(feature.getBegin())
+                .append(":")
                 .append(feature.getEnd());
       }
     }
@@ -108,7 +172,7 @@ public class SequenceAnnotationReport
         }
         if (feature.begin != feature.end)
         {
-          sb.append(" " + feature.end);
+          sb.append(" ").append(feature.end);
         }
 
         if (feature.getDescription() != null
@@ -116,13 +180,12 @@ public class SequenceAnnotationReport
         {
           String tmpString = feature.getDescription();
           String tmp2up = tmpString.toUpperCase();
-          final int startTag = tmp2up.indexOf("<HTML>");
+          int startTag = tmp2up.indexOf("<HTML>");
           if (startTag > -1)
           {
             tmpString = tmpString.substring(startTag + 6);
             tmp2up = tmp2up.substring(startTag + 6);
           }
-          // TODO strips off </body> but not <body> - is that intended?
           int endTag = tmp2up.indexOf("</BODY>");
           if (endTag > -1)
           {
@@ -141,14 +204,15 @@ public class SequenceAnnotationReport
           }
           else
           {
-            if (tmpString.indexOf("<") > -1
-                    || tmpString.indexOf(">") > -1)
+            if (tmpString.indexOf("<") > -1 || tmpString.indexOf(">") > -1)
             {
               // The description does not specify html is to
               // be used, so we must remove < > symbols
               tmpString = tmpString.replaceAll("<", "&lt;");
               tmpString = tmpString.replaceAll(">", "&gt;");
-              sb.append("; ").append(tmpString);
+
+              sb.append("; ");
+              sb.append(tmpString);
             }
             else
             {
@@ -156,19 +220,14 @@ public class SequenceAnnotationReport
             }
           }
         }
-
-        /*
-         * score should be shown if there is one, and min != max
-         * for this feature type (e.g. not all 0)
-         */
+        // check score should be shown
         if (!Float.isNaN(feature.getScore()))
         {
           float[][] rng = (minmax == null) ? null : minmax.get(feature
                   .getType());
           if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
           {
-            sb.append(" Score=").append(
-                    String.valueOf(feature.getScore()));
+            sb.append(" Score=").append(String.valueOf(feature.getScore()));
           }
         }
         String status = (String) feature.getValue("status");
@@ -184,7 +243,6 @@ public class SequenceAnnotationReport
         }
       }
     }
-    appendLinks(sb, feature);
   }
 
   /**
@@ -208,16 +266,17 @@ public class SequenceAnnotationReport
         {
           try
           {
-            for (String[] urllink : createLinksFrom(null, urlstring))
+            for (List<String> urllink : createLinksFrom(null, urlstring))
             {
               sb.append("<br/> <a href=\""
-                      + urllink[3]
+                      + urllink.get(3)
                       + "\" target=\""
-                      + urllink[0]
+                      + urllink.get(0)
                       + "\">"
-                      + (urllink[0].toLowerCase().equals(
-                              urllink[1].toLowerCase()) ? urllink[0]
-                              : (urllink[0] + ":" + urllink[1]))
+                      + (urllink.get(0).toLowerCase()
+                              .equals(urllink.get(1).toLowerCase()) ? urllink
+                              .get(0) : (urllink.get(0) + ":" + urllink
+                              .get(1)))
                       + "</a></br>");
             }
           } catch (Exception x)
@@ -236,149 +295,60 @@ public class SequenceAnnotationReport
    * 
    * @param seq
    * @param link
-   * @return String[][] { String[] { link target, link label, dynamic component
-   *         inserted (if any), url }}
+   * @return Collection< List<String> > { List<String> { link target, link
+   *         label, dynamic component inserted (if any), url }}
    */
-  String[][] createLinksFrom(SequenceI seq, String link)
+  Collection<List<String>> createLinksFrom(SequenceI seq, String link)
   {
-    List<String[]> urlSets = new ArrayList<String[]>();
-    List<String> uniques = new ArrayList<String>();
+    Map<String, List<String>> urlSets = new LinkedHashMap<String, List<String>>();
     UrlLink urlLink = new UrlLink(link);
     if (!urlLink.isValid())
     {
       System.err.println(urlLink.getInvalidMessage());
       return null;
     }
-    if (seq != null && urlLink.isDynamic())
-    {
-      urlSets.addAll(createDynamicLinks(seq, urlLink, uniques));
-    }
-    else
-    {
-      String target = urlLink.getTarget();
-      String label = urlLink.getLabel();
-      String unq = label + "|" + urlLink.getUrl_prefix();
-      if (!uniques.contains(unq))
-      {
-        uniques.add(unq);
-        urlSets.add(new String[] { target, label, null,
-            urlLink.getUrl_prefix() });
-      }
-    }
 
-    return urlSets.toArray(new String[][] {});
-  }
+    urlLink.createLinksFromSeq(seq, urlSets);
 
-  /**
-   * Formats and returns a list of dynamic href links
-   * 
-   * @param seq
-   * @param urlLink
-   * @param uniques
-   */
-  List<String[]> createDynamicLinks(SequenceI seq, UrlLink urlLink,
-          List<String> uniques)
-  {
-    List<String[]> result = new ArrayList<String[]>();
-    final String target = urlLink.getTarget();
-    final String label = urlLink.getLabel();
-
-    // collect matching db-refs
-    DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
-            new String[] { target });
-    // collect id string too
-    String id = seq.getName();
-    String descr = seq.getDescription();
-    if (descr != null && descr.length() < 1)
-    {
-      descr = null;
-    }
-    if (dbr != null)
-    {
-      for (int r = 0; r < dbr.length; r++)
-      {
-        if (id != null && dbr[r].getAccessionId().equals(id))
-        {
-          // suppress duplicate link creation for the bare sequence ID
-          // string with this link
-          id = null;
-        }
-        // create Bare ID link for this URL
-        String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
-        if (urls != null)
-        {
-          for (int u = 0; u < urls.length; u += 2)
-          {
-            String unq = urls[u] + "|" + urls[u + 1];
-            if (!uniques.contains(unq))
-            {
-              result.add(new String[] { target, label, urls[u],
-                  urls[u + 1] });
-              uniques.add(unq);
-            }
-          }
-        }
-      }
-    }
-    if (id != null)
-    {
-      // create Bare ID link for this URL
-      String[] urls = urlLink.makeUrls(id, true);
-      if (urls != null)
-      {
-        for (int u = 0; u < urls.length; u += 2)
-        {
-          String unq = urls[u] + "|" + urls[u + 1];
-          if (!uniques.contains(unq))
-          {
-            result.add(new String[] { target, label, urls[u],
-                urls[u + 1] });
-            uniques.add(unq);
-          }
-        }
-      }
-    }
-    if (descr != null && urlLink.getRegexReplace() != null)
-    {
-      // create link for this URL from description only if regex matches
-      String[] urls = urlLink.makeUrls(descr, true);
-      if (urls != null)
-      {
-        for (int u = 0; u < urls.length; u += 2)
-        {
-          String unq = urls[u] + "|" + urls[u + 1];
-          if (!uniques.contains(unq))
-          {
-            result.add(new String[] { target, label, urls[u],
-                urls[u + 1] });
-            uniques.add(unq);
-          }
-        }
-      }
-    }
-    return result;
+    return urlSets.values();
   }
 
-  public void createSequenceAnnotationReport(final StringBuffer tip,
+  public void createSequenceAnnotationReport(final StringBuilder tip,
           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
           Map<String, float[][]> minmax)
   {
     createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
-            true, minmax);
+            minmax, false);
   }
 
-  public void createSequenceAnnotationReport(final StringBuffer tip,
+  /**
+   * Builds an html formatted report of sequence details and appends it to the
+   * provided buffer.
+   * 
+   * @param sb
+   *          buffer to append report to
+   * @param sequence
+   *          the sequence the report is for
+   * @param showDbRefs
+   *          whether to include database references for the sequence
+   * @param showNpFeats
+   *          whether to include non-positional sequence features
+   * @param minmax
+   * @param summary
+   * @return
+   */
+  int createSequenceAnnotationReport(final StringBuilder sb,
           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
-          boolean tableWrap, Map<String, float[][]> minmax)
+          Map<String, float[][]> minmax, boolean summary)
   {
     String tmp;
-    tip.append("<i>");
+    sb.append("<i>");
 
     int maxWidth = 0;
     if (sequence.getDescription() != null)
     {
       tmp = sequence.getDescription();
-      tip.append("<br>" + tmp);
+      sb.append("<br>").append(tmp);
       maxWidth = Math.max(maxWidth, tmp.length());
     }
     SequenceI ds = sequence;
@@ -389,16 +359,81 @@ public class SequenceAnnotationReport
     DBRefEntry[] dbrefs = ds.getDBRefs();
     if (showDbRefs && dbrefs != null)
     {
-      for (int i = 0; i < dbrefs.length; i++)
+      // note this sorts the refs held on the sequence!
+      Arrays.sort(dbrefs, comparator);
+      boolean ellipsis = false;
+      String source = null;
+      String lastSource = null;
+      int countForSource = 0;
+      int sourceCount = 0;
+      boolean moreSources = false;
+      int lineLength = 0;
+
+      for (DBRefEntry ref : dbrefs)
+      {
+        source = ref.getSource();
+        if (source == null)
+        {
+          // shouldn't happen
+          continue;
+        }
+        boolean sourceChanged = !source.equals(lastSource);
+        if (sourceChanged)
+        {
+          lineLength = 0;
+          countForSource = 0;
+          sourceCount++;
+        }
+        if (sourceCount > MAX_SOURCES && summary)
+        {
+          ellipsis = true;
+          moreSources = true;
+          break;
+        }
+        lastSource = source;
+        countForSource++;
+        if (countForSource == 1 || !summary)
+        {
+          sb.append("<br>");
+        }
+        if (countForSource <= MAX_REFS_PER_SOURCE || !summary)
+        {
+          String accessionId = ref.getAccessionId();
+          lineLength += accessionId.length() + 1;
+          if (countForSource > 1 && summary)
+          {
+            sb.append(", ").append(accessionId);
+            lineLength++;
+          }
+          else
+          {
+            sb.append(source).append(" ").append(accessionId);
+            lineLength += source.length();
+          }
+          maxWidth = Math.max(maxWidth, lineLength);
+        }
+        if (countForSource == MAX_REFS_PER_SOURCE && summary)
+        {
+          sb.append(COMMA).append(ELLIPSIS);
+          ellipsis = true;
+        }
+      }
+      if (moreSources)
+      {
+        sb.append("<br>").append(ELLIPSIS).append(COMMA).append(source)
+                .append(COMMA).append(ELLIPSIS);
+      }
+      if (ellipsis)
       {
-        tip.append("<br>");
-        tmp = dbrefs[i].getSource() + " " + dbrefs[i].getAccessionId();
-        tip.append(tmp);
-        maxWidth = Math.max(maxWidth, tmp.length());
+        sb.append("<br>(");
+        sb.append(MessageManager.getString("label.output_seq_details"));
+        sb.append(")");
       }
     }
 
-    // ADD NON POSITIONAL SEQUENCE INFO
+    /*
+     * add non-positional features if wanted
+     */
     SequenceFeature[] features = sequence.getSequenceFeatures();
     if (showNpFeats && features != null)
     {
@@ -406,21 +441,29 @@ public class SequenceAnnotationReport
       {
         if (features[i].begin == 0 && features[i].end == 0)
         {
-          int sz = -tip.length();
-          List<SequenceFeature> tfeat = new ArrayList<SequenceFeature>();
-          tfeat.add(features[i]);
-          appendFeatures(tip, 0, tfeat, minmax);
-          sz += tip.length();
+          int sz = -sb.length();
+          appendFeature(sb, 0, minmax, features[i]);
+          sz += sb.length();
           maxWidth = Math.max(maxWidth, sz);
         }
       }
     }
+    sb.append("</i>");
+    return maxWidth;
+  }
+
+  public void createTooltipAnnotationReport(final StringBuilder tip,
+          SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
+          Map<String, float[][]> minmax)
+  {
+    int maxWidth = createSequenceAnnotationReport(tip, sequence,
+            showDbRefs, showNpFeats, minmax, true);
 
-    if (tableWrap && maxWidth > 60)
+    if (maxWidth > 60)
     {
-      tip.insert(0, "<table width=350 border=0><tr><td><i>");
-      tip.append("</i></td></tr></table>");
+      // ? not sure this serves any useful purpose
+      // tip.insert(0, "<table width=350 border=0><tr><td>");
+      // tip.append("</td></tr></table>");
     }
-
   }
 }
index 3fd0505..2061f29 100644 (file)
@@ -830,8 +830,7 @@ public class StockholmFile extends AlignFile
         {
           if (DETECT_BRACKETS.search(pos))
           {
-            ann.secondaryStructure = Rna.getRNASecStrucState(
-                    pos).charAt(0);
+            ann.secondaryStructure = Rna.getRNASecStrucState(pos).charAt(0);
           }
           else
           {
index 152a2c0..d39ab38 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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 jalview.analysis.AlignSeq;
@@ -15,7 +35,6 @@ import jalview.structure.StructureImportSettings;
 import java.awt.Color;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Vector;
 
@@ -26,6 +45,11 @@ public abstract class StructureFile extends AlignFile
 
   private String id;
 
+  public enum StructureFileType
+  {
+    PDB, MMCIF, MMTF
+  };
+
   private PDBEntry.Type dbRefType;
 
   /**
@@ -48,6 +72,8 @@ public abstract class StructureFile extends AlignFile
 
   private Vector<PDBChain> chains;
 
+  private boolean pdbIdAvailable;
+
   public StructureFile(String inFile, DataSourceType sourceType)
           throws IOException
   {
@@ -93,18 +119,16 @@ public abstract class StructureFile extends AlignFile
   {
   }
 
-  @SuppressWarnings("rawtypes")
   protected SequenceI postProcessChain(PDBChain chain)
   {
     SequenceI pdbSequence = chain.sequence;
     pdbSequence.setName(getId() + "|" + pdbSequence.getName());
     PDBEntry entry = new PDBEntry();
     entry.setId(getId());
-    entry.setType(this.dbRefType);
-    entry.setProperty(new Hashtable());
+    entry.setType(getStructureFileType());
     if (chain.id != null)
     {
-      entry.setChainCode(String.valueOf(chain.id));
+      entry.setChainCode(chain.id);
     }
     if (inFile != null)
     {
@@ -118,7 +142,9 @@ public abstract class StructureFile extends AlignFile
     DBRefEntry sourceDBRef = new DBRefEntry();
     sourceDBRef.setAccessionId(getId());
     sourceDBRef.setSource(DBRefSource.PDB);
-    pdbSequence.setSourceDBRef(sourceDBRef);
+    // TODO: specify version for 'PDB' database ref if it is read from a file.
+    // TODO: decide if jalview.io should be creating primary refs!
+    sourceDBRef.setVersion("");
     pdbSequence.addPDBId(entry);
     pdbSequence.addDBRef(sourceDBRef);
     SequenceI chainseq = pdbSequence;
@@ -136,6 +162,26 @@ public abstract class StructureFile extends AlignFile
     return chainseq;
   }
 
+  /**
+   * filetype of structure file - default is PDB
+   */
+  String structureFileType = PDBEntry.Type.PDB.toString();
+
+  protected void setStructureFileType(String structureFileType)
+  {
+    this.structureFileType = structureFileType;
+  }
+
+  /**
+   * filetype of last file processed
+   * 
+   * @return
+   */
+  public String getStructureFileType()
+  {
+    return structureFileType;
+  }
+
   @SuppressWarnings({ "unchecked", "rawtypes" })
   protected void processPdbFileWithAnnotate3d(List<SequenceI> rna)
           throws Exception
@@ -264,11 +310,8 @@ public abstract class StructureFile extends AlignFile
       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
       if (cl != null)
       {
-        final Constructor constructor = cl.getConstructor(new Class[] {
-            boolean.class, boolean.class, boolean.class, FileParse.class });
-        final Object[] args = new Object[] { visibleChainAnnotation,
-            predictSecondaryStructure, externalSecondaryStructure,
-            new FileParse(getDataName(), dataSourceType) };
+        final Constructor constructor = cl.getConstructor(new Class[] {FileParse.class });
+        final Object[] args = new Object[] { new FileParse(getDataName(), dataSourceType) };
 
         StructureImportSettings.setShowSeqFeatures(false);
         StructureImportSettings.setVisibleChainAnnotation(false);
@@ -408,7 +451,7 @@ public abstract class StructureFile extends AlignFile
 
   public void setDbRefType(String dbRefType)
   {
-    this.dbRefType = Type.valueOf(dbRefType);
+    this.dbRefType = Type.getType(dbRefType);
   }
 
   public void setDbRefType(Type dbRefType)
@@ -430,4 +473,35 @@ public abstract class StructureFile extends AlignFile
   {
     return new PDBFeatureSettings();
   }
+
+  /**
+   * Answers true if the structure file has a PDBId
+   * 
+   * @return
+   */
+  public boolean isPPDBIdAvailable()
+  {
+    return pdbIdAvailable;
+  }
+
+  public void setPDBIdAvailable(boolean pdbIdAvailable)
+  {
+    this.pdbIdAvailable = pdbIdAvailable;
+  }
+
+  public static boolean isStructureFile(String fileType)
+  {
+    if (fileType == null)
+    {
+      return false;
+    }
+    for (StructureFileType sfType : StructureFileType.values())
+    {
+      if (sfType.name().equalsIgnoreCase(fileType))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
 }
index f7805fd..eb74eea 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import jalview.datamodel.AlignedCodonFrame;
@@ -64,8 +84,8 @@ public class ExonerateHelper extends Gff2Helper
 
     try
     {
-      processGffSimilarity(set, seq, gffColumns,
-              align, newseqs, relaxedIdMatching);
+      processGffSimilarity(set, seq, gffColumns, align, newseqs,
+              relaxedIdMatching);
     } catch (IOException ivfe)
     {
       System.err.println(ivfe);
@@ -98,8 +118,7 @@ public class ExonerateHelper extends Gff2Helper
    *          if true allow fuzzy search for a matching target sequence
    * @throws IOException
    */
-  protected void processGffSimilarity(
-          Map<String, List<String>> set,
+  protected void processGffSimilarity(Map<String, List<String>> set,
           SequenceI seq, String[] gff, AlignmentI align,
           List<SequenceI> newseqs, boolean relaxedIdMatching)
           throws IOException
@@ -228,15 +247,17 @@ public class ExonerateHelper extends Gff2Helper
     int alignFromStart;
     int alignToStart;
     int alignCount;
-    try {
+    try
+    {
       alignFromStart = Integer.parseInt(tokens[0]);
       alignToStart = Integer.parseInt(tokens[1]);
       alignCount = Integer.parseInt(tokens[2]);
-    } catch (NumberFormatException nfe) {
+    } catch (NumberFormatException nfe)
+    {
       System.err.println(nfe.toString());
       return null;
     }
-    
+
     int fromStart;
     int fromEnd;
     int toStart;
@@ -290,10 +311,8 @@ public class ExonerateHelper extends Gff2Helper
     {
       result = MappingType.PeptideToNucleotide;
     }
-    else if (model.contains(CODING2CODING)
-            || model.contains(CODING2GENOME)
-            || model.contains(CDNA2GENOME)
-            || model.contains(GENOME2GENOME))
+    else if (model.contains(CODING2CODING) || model.contains(CODING2GENOME)
+            || model.contains(CDNA2GENOME) || model.contains(GENOME2GENOME))
     {
       result = MappingType.NucleotideToNucleotide;
     }
@@ -323,10 +342,8 @@ public class ExonerateHelper extends Gff2Helper
     {
       String mdl = model.toLowerCase();
       if (mdl.contains(PROTEIN2DNA) || mdl.contains(PROTEIN2GENOME)
-              || mdl.contains(CODING2CODING)
-              || mdl.contains(CODING2GENOME)
-              || mdl.contains(CDNA2GENOME)
-              || mdl.contains(GENOME2GENOME))
+              || mdl.contains(CODING2CODING) || mdl.contains(CODING2GENOME)
+              || mdl.contains(CDNA2GENOME) || mdl.contains(GENOME2GENOME))
       {
         return true;
       }
index 31303b1..19045d5 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import jalview.datamodel.AlignmentI;
index 031900d..82e5313 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import jalview.datamodel.AlignedCodonFrame;
@@ -77,8 +97,8 @@ public class Gff3Helper extends GffHelperBase
       }
       else if (so.isA(soTerm, SequenceOntologyI.NUCLEOTIDE_MATCH))
       {
-        sf = processNucleotideMatch(attributes, seq, gff, align,
-                newseqs, relaxedIdMatching);
+        sf = processNucleotideMatch(attributes, seq, gff, align, newseqs,
+                relaxedIdMatching);
       }
       else
       {
@@ -92,7 +112,7 @@ public class Gff3Helper extends GffHelperBase
        */
       sf = buildSequenceFeature(gff, null);
     }
-  
+
     return sf;
   }
 
@@ -119,8 +139,7 @@ public class Gff3Helper extends GffHelperBase
   protected SequenceFeature processNucleotideMatch(
           Map<String, List<String>> attributes, SequenceI seq,
           String[] gffColumns, AlignmentI align, List<SequenceI> newseqs,
-          boolean relaxedIdMatching)
-          throws IOException
+          boolean relaxedIdMatching) throws IOException
   {
     String strand = gffColumns[STRAND_COL];
 
@@ -166,8 +185,8 @@ public class Gff3Helper extends GffHelperBase
        * (new or existing) virtual sequence in the newseqs list 
        */
       String targetId = findTargetId(tokens[0], attributes);
-      SequenceI mappedSequence1 = findSequence(targetId, align,
-      newseqs, relaxedIdMatching);
+      SequenceI mappedSequence1 = findSequence(targetId, align, newseqs,
+              relaxedIdMatching);
       SequenceI mappedSequence = mappedSequence1;
       if (mappedSequence == null)
       {
@@ -195,8 +214,7 @@ public class Gff3Helper extends GffHelperBase
         int fromStart = Integer.parseInt(gffColumns[START_COL]);
         int fromEnd = Integer.parseInt(gffColumns[END_COL]);
         MapList mapping = constructMappingFromAlign(fromStart, fromEnd,
-                toStart, toEnd,
-                MappingType.NucleotideToNucleotide);
+                toStart, toEnd, MappingType.NucleotideToNucleotide);
 
         if (mapping != null)
         {
@@ -280,8 +298,8 @@ public class Gff3Helper extends GffHelperBase
       for (String target : targets)
       {
 
-        SequenceI mappedSequence1 = findSequence(findTargetId(target, set), align,
-        newseqs, relaxedIdMatching);
+        SequenceI mappedSequence1 = findSequence(findTargetId(target, set),
+                align, newseqs, relaxedIdMatching);
         SequenceI mappedSequence = mappedSequence1;
         if (mappedSequence == null)
         {
@@ -379,8 +397,8 @@ public class Gff3Helper extends GffHelperBase
       /*
        * Ensembl returns dna variants as 'alleles'
        */
-      desc = StringUtils.listToDelimitedString(
-              attributes.get("alleles"), ",");
+      desc = StringUtils.listToDelimitedString(attributes.get("alleles"),
+              ",");
     }
 
     /*
index 545c6e3..571f0ea 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 /**
index feeec1d..48c33e5 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import jalview.analysis.SequenceIdMatcher;
@@ -392,7 +412,8 @@ public abstract class GffHelperBase implements GffHelperI
    * @param toSeq
    * @return
    */
-  protected AlignedCodonFrame getMapping(AlignmentI align, SequenceI fromSeq, SequenceI toSeq)
+  protected AlignedCodonFrame getMapping(AlignmentI align,
+          SequenceI fromSeq, SequenceI toSeq)
   {
     AlignedCodonFrame acf = align.getMapping(fromSeq, toSeq);
     if (acf == null)
index 8bd5115..c03082a 100644 (file)
@@ -1,6 +1,25 @@
+/*
+ * 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.gff;
 
-
 /**
  * A factory to serve instances of GFF helper classes
  */
index 3d9dc6f..7fbcf5c 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import jalview.datamodel.AlignmentI;
@@ -35,9 +55,8 @@ public interface GffHelperI
    * @throws IOException
    */
   SequenceFeature processGff(SequenceI seq, String[] gffColumns,
-          AlignmentI align,
-          List<SequenceI> newseqs, boolean relaxedIdMatching)
-          throws IOException;
+          AlignmentI align, List<SequenceI> newseqs,
+          boolean relaxedIdMatching) throws IOException;
 
   // java 8 will allow static methods in interfaces:
   // static boolean recognises(String [] columns);
index 68d5d4f..e1334e1 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import jalview.datamodel.AlignmentI;
index 3eaa5d1..90cae7a 100644 (file)
@@ -1,5 +1,33 @@
+/*
+ * 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.gff;
 
+/**
+ * A factory class that returns a model of the Sequence Ontology. By default a
+ * hard-coded subset is used (for the applet, or testing), or setInstance() can
+ * be used to set full Ontology data.
+ * 
+ * @author gmcarstairs
+ *
+ */
 public class SequenceOntologyFactory
 {
   private static SequenceOntologyI instance;
@@ -8,7 +36,6 @@ public class SequenceOntologyFactory
   {
     if (instance == null)
     {
-      // instance = new SequenceOntology();
       instance = new SequenceOntologyLite();
     }
     return instance;
index c7a5baa..c0570e0 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import java.util.List;
index b3f8161..f989f7b 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import java.util.ArrayList;
@@ -51,6 +71,7 @@ public class SequenceOntologyLite implements SequenceOntologyI
     { "miRNA", "transcript" },
     { "lincRNA", "transcript" },
     { "rRNA", "transcript" },
+    { "mRNA", "transcript" },
     // there are many more sub-types of ncRNA...
     
     /*
@@ -111,7 +132,8 @@ public class SequenceOntologyLite implements SequenceOntologyI
   private void loadStaticData()
   {
     parents = new HashMap<String, List<String>>();
-    for (String [] pair : TERMS) {
+    for (String[] pair : TERMS)
+    {
       List<String> p = parents.get(pair[0]);
       if (p == null)
       {
@@ -180,9 +202,11 @@ public class SequenceOntologyLite implements SequenceOntologyI
     {
       if (!termsNotFound.contains(term))
       {
-        System.out.println("SO term " + term
-                + " not known - may be invalid, or model if needed in "
-                + getClass().getName());
+        // suppress logging here as it reports Uniprot sequence features
+        // (which do not use SO terms) when auto-configuring feature colours
+        // System.out.println("SO term " + term
+        // + " not known - add to model if needed in "
+        // + getClass().getName());
         termsNotFound.add(term);
       }
     }
index 63263d2..c1ca1b7 100644 (file)
@@ -211,8 +211,7 @@ public class JalviewDataset
    * @param parentAlignment
    */
   public JalviewDataset(AlignmentI aldataset,
-          Map<String, FeatureColourI> fc,
-          Hashtable seqDets)
+          Map<String, FeatureColourI> fc, Hashtable seqDets)
   {
     // TODO not used - remove?
     this(aldataset, fc, seqDets, null);
@@ -234,8 +233,8 @@ public class JalviewDataset
    *          with.
    */
   public JalviewDataset(AlignmentI aldataset,
-          Map<String, FeatureColourI> fc,
-          Hashtable seqDets, AlignmentI parentAlignment)
+          Map<String, FeatureColourI> fc, Hashtable seqDets,
+          AlignmentI parentAlignment)
   {
     this();
     parentDataset = aldataset;
index 2879889..ff7a764 100644 (file)
@@ -152,7 +152,8 @@ public class DatastoreRegistry
     return dsregitem;
   }
 
-  protected void finalize()
+  @Override
+  protected void finalize() throws Throwable
   {
     if (dsObjReg != null)
     {
@@ -171,5 +172,6 @@ public class DatastoreRegistry
     {
       dsItemReg.clear();
     }
+    super.finalize();
   }
 }
index 0bf4096..a3781a7 100644 (file)
@@ -291,8 +291,10 @@ public class Tree extends DatastoreItem
       }
     }
     if (alsq.size() < sequences.length)
+    {
       Cache.log
               .warn("Not recovered all alignment sequences for given set of input sequence CIGARS");
+    }
     return alsq;
   }
 
@@ -306,15 +308,18 @@ public class Tree extends DatastoreItem
   public void UpdateSequenceTreeMap(TreePanel tp)
   {
     if (tp == null || tree == null)
+    {
       return;
-    Vector leaves = new Vector();
+    }
+
     if (tp.getTree() == null)
     {
       Cache.log.warn("Not updating SequenceTreeMap for "
               + tree.getVorbaId());
       return;
     }
-    tp.getTree().findLeaves(tp.getTree().getTopNode(), leaves);
+    Vector<SequenceNode> leaves = tp.getTree().findLeaves(
+            tp.getTree().getTopNode());
     Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
     // particular tree
     int sz = tn.length;
@@ -371,8 +376,7 @@ public class Tree extends DatastoreItem
    */
   public Treenode[] makeTreeNodes(NJTree ntree, Newick newick)
   {
-    Vector leaves = new Vector();
-    ntree.findLeaves(ntree.getTopNode(), leaves);
+    Vector<SequenceNode> leaves = ntree.findLeaves(ntree.getTopNode());
     Vector tnv = new Vector();
     Enumeration l = leaves.elements();
     Hashtable nodespecs = new Hashtable();
@@ -473,7 +477,9 @@ public class Tree extends DatastoreItem
         --occurence;
       }
       else
+      {
         bn = null;
+      }
     }
     return bn;
   }
index 4d7c0d4..6daf275 100644 (file)
@@ -39,7 +39,8 @@ public class JSFunctionExec implements Runnable
     jvlite.setExecutor(this);
   }
 
-  public void finalize()
+  @Override
+  protected void finalize() throws Throwable
   {
     jvlite = null;
     executor = null;
@@ -48,6 +49,7 @@ public class JSFunctionExec implements Runnable
       jsExecQueue.clear();
     }
     jsExecQueue = null;
+    super.finalize();
   }
 
   private Vector jsExecQueue;
@@ -82,6 +84,7 @@ public class JSFunctionExec implements Runnable
     executor = null;
   }
 
+  @Override
   public void run()
   {
     while (jsExecQueue != null)
@@ -164,6 +167,7 @@ public class JSFunctionExec implements Runnable
     final Exception[] jsex = new Exception[1];
     Runnable exec = new Runnable()
     {
+      @Override
       public void run()
       {
         try
@@ -196,7 +200,7 @@ public class JSFunctionExec implements Runnable
             if (jex instanceof netscape.javascript.JSException
                     && jvlite.jsfallbackEnabled)
             {
-              jsex[0] = (netscape.javascript.JSException) jex;
+              jsex[0] = jex;
               if (jvlite.debug)
               {
                 System.err.println("Falling back to javascript: url call");
index 35c7860..4f833bc 100644 (file)
@@ -298,7 +298,7 @@ public class MouseOverStructureListener extends JSFunctionExec implements
     return _listenerfn;
   }
 
-  public void finalise()
+  public void finalize() throws Throwable
   {
     jvlite = null;
     super.finalize();
index 44c4192..cbeb93c 100755 (executable)
@@ -292,34 +292,50 @@ public class GAlignFrame extends JInternalFrame
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isPopupTrigger())
+            if (evt.isPopupTrigger()) // Mac
             {
-              radioItem.removeActionListener(radioItem.getActionListeners()[0]);
-
-              int option = JOptionPane.showInternalConfirmDialog(
-                      jalview.gui.Desktop.desktop,
-                      MessageManager
-                              .getString("label.remove_from_default_list"),
-                      MessageManager
-                              .getString("label.remove_user_defined_colour"),
-                      JOptionPane.YES_NO_OPTION);
-              if (option == JOptionPane.YES_OPTION)
-              {
-                jalview.gui.UserDefinedColours
-                        .removeColourFromDefaults(radioItem.getText());
-                colourMenu.remove(radioItem);
-              }
-              else
+              offerRemoval(radioItem);
+            }
+          }
+
+          @Override
+          public void mouseReleased(MouseEvent evt)
+          {
+            if (evt.isPopupTrigger()) // Windows
+            {
+              offerRemoval(radioItem);
+            }
+          }
+
+          /**
+           * @param radioItem
+           */
+          void offerRemoval(final JRadioButtonMenuItem radioItem)
+          {
+            radioItem.removeActionListener(radioItem.getActionListeners()[0]);
+
+            int option = JOptionPane.showInternalConfirmDialog(
+                    jalview.gui.Desktop.desktop, MessageManager
+                            .getString("label.remove_from_default_list"),
+                    MessageManager
+                            .getString("label.remove_user_defined_colour"),
+                    JOptionPane.YES_NO_OPTION);
+            if (option == JOptionPane.YES_OPTION)
+            {
+              jalview.gui.UserDefinedColours
+                      .removeColourFromDefaults(radioItem.getText());
+              colourMenu.remove(radioItem);
+            }
+            else
+            {
+              radioItem.addActionListener(new ActionListener()
               {
-                radioItem.addActionListener(new ActionListener()
+                @Override
+                public void actionPerformed(ActionEvent evt)
                 {
-                  @Override
-                  public void actionPerformed(ActionEvent evt)
-                  {
-                    userDefinedColour_actionPerformed(evt);
-                  }
-                });
-              }
+                  userDefinedColour_actionPerformed(evt);
+                }
+              });
             }
           }
         });
@@ -1725,7 +1741,8 @@ public class GAlignFrame extends JInternalFrame
     showProducts.setText(MessageManager.getString("label.get_cross_refs"));
 
     runGroovy.setText(MessageManager.getString("label.run_groovy"));
-    runGroovy.setToolTipText(MessageManager.getString("label.run_groovy_tip"));
+    runGroovy.setToolTipText(MessageManager
+            .getString("label.run_groovy_tip"));
     runGroovy.addActionListener(new ActionListener()
     {
       @Override
@@ -2030,7 +2047,19 @@ public class GAlignFrame extends JInternalFrame
       @Override
       public void mousePressed(MouseEvent e)
       {
-        tabbedPane_mousePressed(e);
+        if (e.isPopupTrigger()) // Mac
+        {
+          tabbedPane_mousePressed(e);
+        }
+      }
+
+      @Override
+      public void mouseReleased(MouseEvent e)
+      {
+        if (e.isPopupTrigger()) // Windows
+        {
+          tabbedPane_mousePressed(e);
+        }
       }
     });
     tabbedPane.addFocusListener(new FocusAdapter()
@@ -2152,6 +2181,19 @@ public class GAlignFrame extends JInternalFrame
         alignmentProperties();
       }
     });
+    JMenuItem selectHighlighted = new JMenuItem(
+            MessageManager.getString("action.select_highlighted_columns"));
+    selectHighlighted.setToolTipText(MessageManager
+            .getString("tooltip.select_highlighted_columns"));
+    al = new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent actionEvent)
+      {
+        selectHighlightedColumns_actionPerformed(actionEvent);
+      }
+    };
+    selectHighlighted.addActionListener(al);
     JMenu tooltipSettingsMenu = new JMenu(
             MessageManager.getString("label.sequence_id_tooltip"));
     JMenu autoAnnMenu = new JMenu(
@@ -2353,12 +2395,20 @@ public class GAlignFrame extends JInternalFrame
     selectMenu.add(grpsFromSelection);
     selectMenu.add(deleteGroups);
     selectMenu.add(annotationColumn);
+    selectMenu.add(selectHighlighted);
     // TODO - determine if the listenToViewSelections button is needed : see bug
     // JAL-574
     // selectMenu.addSeparator();
     // selectMenu.add(listenToViewSelections);
   }
 
+  protected void selectHighlightedColumns_actionPerformed(
+          ActionEvent actionEvent)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
   /**
    * Generate the reverse sequence (or reverse complement if the flag is true)
    * and add it to the alignment
@@ -2377,6 +2427,7 @@ public class GAlignFrame extends JInternalFrame
   {
 
   }
+
   /**
    * Adds the given action listener and key accelerator to the given menu item.
    * Also saves in a lookup table to support lookup of action by key stroke.
index a9e3112..157dddd 100644 (file)
@@ -106,6 +106,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame
     ok.setText(MessageManager.getString("label.new_window"));
     ok.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         ok_actionPerformed(e);
@@ -114,6 +115,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame
     cancel.setText(MessageManager.getString("action.close"));
     cancel.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         cancel_actionPerformed(e);
@@ -123,6 +125,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame
     close.setText(MessageManager.getString("action.close"));
     close.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         cancel_actionPerformed(e);
@@ -137,6 +140,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame
                     .getMenuShortcutKeyMask(), false));
     selectAll.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         selectAll_actionPerformed(e);
@@ -149,6 +153,7 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame
                     .getMenuShortcutKeyMask(), false));
     save.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         save_actionPerformed(e);
@@ -163,15 +168,23 @@ public class GCutAndPasteHtmlTransfer extends JInternalFrame
     textarea.setFont(new java.awt.Font("Monospaced", Font.PLAIN, 12));
     textarea.addMouseListener(new java.awt.event.MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         textarea_mousePressed(e);
       }
+
+      @Override
+      public void mouseReleased(MouseEvent e)
+      {
+        textarea_mousePressed(e);
+      }
     });
     editMenu.setText(MessageManager.getString("action.edit"));
     copyItem.setText(MessageManager.getString("action.copy"));
     copyItem.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         copyItem_actionPerformed(e);
index acf1581..21705f0 100755 (executable)
@@ -103,6 +103,7 @@ public class GCutAndPasteTransfer extends JInternalFrame
     ok.setText(MessageManager.getString("label.new_window"));
     ok.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         ok_actionPerformed(e);
@@ -111,6 +112,7 @@ public class GCutAndPasteTransfer extends JInternalFrame
     cancel.setText(MessageManager.getString("action.close"));
     cancel.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         cancel_actionPerformed(e);
@@ -124,6 +126,7 @@ public class GCutAndPasteTransfer extends JInternalFrame
                     .getMenuShortcutKeyMask(), false));
     selectAll.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         selectAll_actionPerformed(e);
@@ -136,6 +139,7 @@ public class GCutAndPasteTransfer extends JInternalFrame
                     .getMenuShortcutKeyMask(), false));
     save.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         save_actionPerformed(e);
@@ -152,15 +156,23 @@ public class GCutAndPasteTransfer extends JInternalFrame
     textarea.setFont(new java.awt.Font("Monospaced", Font.PLAIN, 12));
     textarea.addMouseListener(new java.awt.event.MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
-        textarea_mousePressed(e);
+        textarea_mousePressed(e); // on Mac
+      }
+
+      @Override
+      public void mouseReleased(MouseEvent e)
+      {
+        textarea_mousePressed(e); // on Windows
       }
     });
     editMenu.setText(MessageManager.getString("action.edit"));
     pasteMenu.setText(MessageManager.getString("action.paste"));
     pasteMenu.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         pasteMenu_actionPerformed(e);
@@ -169,6 +181,7 @@ public class GCutAndPasteTransfer extends JInternalFrame
     copyItem.setText(MessageManager.getString("action.copy"));
     copyItem.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         copyItem_actionPerformed(e);
index 46580a2..2689946 100755 (executable)
@@ -60,16 +60,18 @@ public class GSequenceLink extends Panel
     nameTB.setBounds(new Rectangle(77, 10, 310, 23));
     nameTB.addKeyListener(new KeyAdapter()
     {
+      @Override
       public void keyTyped(KeyEvent e)
       {
         nameTB_keyTyped(e);
       }
     });
     urlTB.setFont(JvSwingUtils.getLabelFont());
-    urlTB.setText("http://www.");
+    urlTB.setText("http://");
     urlTB.setBounds(new Rectangle(78, 40, 309, 23));
     urlTB.addKeyListener(new KeyAdapter()
     {
+      @Override
       public void keyTyped(KeyEvent e)
       {
         urlTB_keyTyped(e);
@@ -88,7 +90,20 @@ public class GSequenceLink extends Panel
     jLabel3.setBounds(new Rectangle(21, 72, 351, 15));
     jLabel4.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
     jLabel4.setText(MessageManager.getString("label.use_sequence_id_2"));
-    jLabel4.setBounds(new Rectangle(21, 93, 351, 15));
+    jLabel4.setBounds(new Rectangle(21, 88, 351, 15));
+    jLabel5.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
+    jLabel5.setText(MessageManager.getString("label.use_sequence_id_3"));
+    jLabel5.setBounds(new Rectangle(21, 106, 351, 15));
+
+    String lastLabel = MessageManager.getString("label.use_sequence_id_4");
+    if (lastLabel.length() > 0)
+    {
+      // e.g. Spanish version has longer text
+      jLabel6.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
+      jLabel6.setText(lastLabel);
+      jLabel6.setBounds(new Rectangle(21, 122, 351, 15));
+    }
+
     jPanel1.setBorder(BorderFactory.createEtchedBorder());
     jPanel1.setLayout(null);
     jPanel1.add(jLabel1);
@@ -97,11 +112,21 @@ public class GSequenceLink extends Panel
     jPanel1.add(jLabel2);
     jPanel1.add(jLabel3);
     jPanel1.add(jLabel4);
+    jPanel1.add(jLabel5);
+
+    int height = 130;
+    if (lastLabel.length() > 0)
+    {
+      jPanel1.add(jLabel6);
+      height = 146;
+    }
+
     this.add(jPanel1, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
             GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
-                    5, 4, 6, 5), 390, 130));
+                    5, 4, 6, 5), 390, height));
   }
 
+  @Override
   public void setName(String name)
   {
     nameTB.setText(name);
@@ -112,6 +137,7 @@ public class GSequenceLink extends Panel
     urlTB.setText(url);
   }
 
+  @Override
   public String getName()
   {
     return nameTB.getText();
@@ -149,6 +175,10 @@ public class GSequenceLink extends Panel
 
   JLabel jLabel4 = new JLabel();
 
+  JLabel jLabel5 = new JLabel();
+
+  JLabel jLabel6 = new JLabel();
+
   JPanel jPanel1 = new JPanel();
 
   GridBagLayout gridBagLayout1 = new GridBagLayout();
index 1348e59..3a064d2 100644 (file)
@@ -166,7 +166,7 @@ public abstract class GStructureChooser extends JPanel implements
 
   protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
 
-  private JTabbedPane pnl_filter = new JTabbedPane();
+  protected JTabbedPane pnl_filter = new JTabbedPane();
 
   protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
           PreferenceSource.STRUCTURE_CHOOSER,
@@ -414,7 +414,7 @@ public abstract class GStructureChooser extends JPanel implements
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        closeAction();
+        closeAction(pnl_filter.getHeight());
       }
     });
     btn_cancel.addKeyListener(new KeyAdapter()
@@ -424,7 +424,7 @@ public abstract class GStructureChooser extends JPanel implements
       {
         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
         {
-          closeAction();
+          closeAction(pnl_filter.getHeight());
         }
       }
     });
@@ -577,7 +577,7 @@ public abstract class GStructureChooser extends JPanel implements
               @Override
               public void internalFrameClosing(InternalFrameEvent e)
               {
-                closeAction();
+                closeAction(pnl_filter.getHeight());
               }
             });
     mainFrame.setVisible(true);
@@ -592,7 +592,7 @@ public abstract class GStructureChooser extends JPanel implements
     Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
   }
 
-  protected void closeAction()
+  protected void closeAction(int preferredHeight)
   {
     // System.out.println(">>>>>>>>>> closing internal frame!!!");
     // System.out.println("width : " + mainFrame.getWidth());
@@ -600,21 +600,21 @@ public abstract class GStructureChooser extends JPanel implements
     // System.out.println("x : " + mainFrame.getX());
     // System.out.println("y : " + mainFrame.getY());
     tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
-    tempUserPrefs.put("structureChooser.height", pnl_filter.getHeight());
+    tempUserPrefs.put("structureChooser.height", preferredHeight);
     tempUserPrefs.put("structureChooser.x", mainFrame.getX());
     tempUserPrefs.put("structureChooser.y", mainFrame.getY());
     mainFrame.dispose();
   }
+
   public boolean wantedFieldsUpdated()
   {
     if (previousWantedFields == null)
     {
       return true;
     }
-    
+
     FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
-            .getStructureSummaryFields()
-            .toArray(new FTSDataColumnI[0]);
+            .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
     return Arrays.equals(currentWantedFields, previousWantedFields) ? false
             : true;
 
@@ -794,6 +794,7 @@ public abstract class GStructureChooser extends JPanel implements
   {
     return tbl_summary;
   }
+
   public JComboBox<FilterOption> getCmbFilterOption()
   {
     return cmb_filterOption;
@@ -801,10 +802,6 @@ public abstract class GStructureChooser extends JPanel implements
 
   protected abstract void stateChanged(ItemEvent e);
 
-  protected abstract void updateCurrentView();
-
-  protected abstract void populateFilterComboBox();
-
   protected abstract void ok_ActionPerformed();
 
   protected abstract void pdbFromFile_actionPerformed();
index 82f6ffb..a0e530c 100644 (file)
@@ -28,8 +28,10 @@ import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ProfilesI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
+import jalview.util.Platform;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
@@ -57,6 +59,70 @@ public class AnnotationRenderer
    */
   private final boolean debugRedraw;
 
+  private int charWidth, endRes, charHeight;
+
+  private boolean validCharWidth, hasHiddenColumns;
+
+  private FontMetrics fm;
+
+  private final boolean MAC = Platform.isAMac();
+
+  boolean av_renderHistogram = true, av_renderProfile = true,
+          av_normaliseProfile = false;
+
+  ColourSchemeI profcolour = null;
+
+  private ColumnSelection columnSelection;
+
+  private ProfilesI hconsensus;
+
+  private Hashtable[] complementConsensus;
+
+  private Hashtable[] hStrucConsensus;
+
+  private boolean av_ignoreGapsConsensus;
+
+  /**
+   * attributes set from AwtRenderPanelI
+   */
+  /**
+   * old image used when data is currently being calculated and cannot be
+   * rendered
+   */
+  private Image fadedImage;
+
+  /**
+   * panel being rendered into
+   */
+  private ImageObserver annotationPanel;
+
+  /**
+   * width of image to render in panel
+   */
+  private int imgWidth;
+
+  /**
+   * offset to beginning of visible area
+   */
+  private int sOffset;
+
+  /**
+   * offset to end of visible area
+   */
+  private int visHeight;
+
+  /**
+   * indicate if the renderer should only render the visible portion of the
+   * annotation given the current view settings
+   */
+  private boolean useClip = true;
+
+  /**
+   * master flag indicating if renderer should ever try to clip. not enabled for
+   * jalview 2.8.1
+   */
+  private boolean canClip = false;
+
   public AnnotationRenderer()
   {
     this(false);
@@ -74,9 +140,21 @@ public class AnnotationRenderer
     this.debugRedraw = debugRedraw;
   }
 
-  void drawStemAnnot(Graphics g, Annotation[] row_annotations,
-          int lastSSX, int x, int y, int iconOffset, int startRes,
-          int column, boolean validRes, boolean validEnd)
+  /**
+   * Remove any references and resources when this object is no longer required
+   */
+  public void dispose()
+  {
+    hconsensus = null;
+    complementConsensus = null;
+    hStrucConsensus = null;
+    fadedImage = null;
+    annotationPanel = null;
+  }
+
+  void drawStemAnnot(Graphics g, Annotation[] row_annotations, int lastSSX,
+          int x, int y, int iconOffset, int startRes, int column,
+          boolean validRes, boolean validEnd)
   {
     g.setColor(STEM_COLOUR);
     int sCol = (lastSSX / charWidth) + startRes;
@@ -134,70 +212,6 @@ public class AnnotationRenderer
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7);
   }
 
-  private int charWidth, endRes, charHeight;
-
-  private boolean validCharWidth, hasHiddenColumns;
-
-  private FontMetrics fm;
-
-  private final boolean MAC = jalview.util.Platform.isAMac();
-
-  boolean av_renderHistogram = true, av_renderProfile = true,
-          av_normaliseProfile = false;
-
-  ColourSchemeI profcolour = null;
-
-  private ColumnSelection columnSelection;
-
-  private Hashtable[] hconsensus;
-
-  private Hashtable[] complementConsensus;
-
-  private Hashtable[] hStrucConsensus;
-
-  private boolean av_ignoreGapsConsensus;
-
-  /**
-   * attributes set from AwtRenderPanelI
-   */
-  /**
-   * old image used when data is currently being calculated and cannot be
-   * rendered
-   */
-  private Image fadedImage;
-
-  /**
-   * panel being rendered into
-   */
-  private ImageObserver annotationPanel;
-
-  /**
-   * width of image to render in panel
-   */
-  private int imgWidth;
-
-  /**
-   * offset to beginning of visible area
-   */
-  private int sOffset;
-
-  /**
-   * offset to end of visible area
-   */
-  private int visHeight;
-
-  /**
-   * indicate if the renderer should only render the visible portion of the
-   * annotation given the current view settings
-   */
-  private boolean useClip = true;
-
-  /**
-   * master flag indicating if renderer should ever try to clip. not enabled for
-   * jalview 2.8.1
-   */
-  private boolean canClip = false;
-
   void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
           Annotation[] row_annotations, int lastSSX, int x, int y,
           int iconOffset, int startRes, int column, boolean validRes,
@@ -338,7 +352,7 @@ public class AnnotationRenderer
       {
         // TODO? group consensus for cDNA complement
         return AAFrequency.extractProfile(
-                aa.groupRef.consensusData[column],
+                aa.groupRef.consensusData.get(column),
                 aa.groupRef.getIgnoreGapsConsensus());
       }
       // TODO extend annotation row to enable dynamic and static profile data to
@@ -352,7 +366,8 @@ public class AnnotationRenderer
         }
         else
         {
-          return AAFrequency.extractProfile(hconsensus[column],
+          return AAFrequency.extractProfile(
+hconsensus.get(column),
                   av_ignoreGapsConsensus);
         }
       }
@@ -1072,8 +1087,8 @@ public class AnnotationRenderer
 
   private Color sdNOTCANONICAL_COLOUR;
 
-  void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX,
-          int x, int y, int iconOffset, int startRes, int column,
+  void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x,
+          int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
   {
     g.setColor(GLYPHLINE_COLOR);
@@ -1104,8 +1119,8 @@ public class AnnotationRenderer
 
   }
 
-  void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX,
-          int x, int y, int iconOffset, int startRes, int column,
+  void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX, int x,
+          int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
   {
     g.setColor(HELIX_COLOUR);
index 6940f22..82536d4 100644 (file)
@@ -62,8 +62,8 @@ public class ScaleRenderer
    *         marker position in alignment column coords, a String to be rendered
    *         at the position (or null)
    */
-  public List<ScaleMark> calculateMarks(AlignViewportI av,
-          int startx, int endx)
+  public List<ScaleMark> calculateMarks(AlignViewportI av, int startx,
+          int endx)
   {
     int scalestartx = (startx / 10) * 10;
 
index b007365..9e0089f 100644 (file)
@@ -188,15 +188,20 @@ public class FeatureRenderer extends FeatureRendererModel
   }
 
   /**
-   * This is used by the Molecule Viewer and Overview to get the accurate colour
-   * of the rendered sequence
+   * This is used by Structure Viewers and the Overview Window to get the
+   * feature colour of the rendered sequence, returned as an RGB value
+   * 
+   * @param defaultColour
+   * @param seq
+   * @param column
+   * @return
    */
-  public synchronized int findFeatureColour(int initialCol,
+  public synchronized int findFeatureColour(int defaultColour,
           final SequenceI seq, int column)
   {
     if (!av.isShowSequenceFeatures())
     {
-      return initialCol;
+      return defaultColour;
     }
 
     SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
@@ -223,7 +228,7 @@ public class FeatureRenderer extends FeatureRendererModel
 
     if (lastSequenceFeatures == null || sfSize == 0)
     {
-      return initialCol;
+      return defaultColour;
     }
 
     if (jalview.util.Comparison.isGap(lastSeq.getCharAt(column)))
@@ -244,7 +249,7 @@ public class FeatureRenderer extends FeatureRendererModel
 
     if (offscreenImage != null)
     {
-      offscreenImage.setRGB(0, 0, initialCol);
+      offscreenImage.setRGB(0, 0, defaultColour);
       drawSequence(offscreenImage.getGraphics(), lastSeq, column, column, 0);
 
       return offscreenImage.getRGB(0, 0);
@@ -255,7 +260,7 @@ public class FeatureRenderer extends FeatureRendererModel
 
       if (currentColour == null)
       {
-        return initialCol;
+        return defaultColour;
       }
       else
       {
@@ -275,6 +280,19 @@ public class FeatureRenderer extends FeatureRendererModel
 
   int epos;
 
+  /**
+   * Draws the sequence on the graphics context, or just determines the colour
+   * that would be drawn (if flag offscreenrender is true).
+   * 
+   * @param g
+   * @param seq
+   * @param start
+   *          start column (or sequence position in offscreenrender mode)
+   * @param end
+   *          end column (not used in offscreenrender mode)
+   * @param y1
+   *          vertical offset at which to draw on the graphics
+   */
   public synchronized void drawSequence(Graphics g, final SequenceI seq,
           int start, int end, int y1)
   {
@@ -312,12 +330,10 @@ public class FeatureRenderer extends FeatureRendererModel
     }
 
     sfSize = lastSequenceFeatures.length;
-    String type;
     for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
     {
-      type = renderOrder[renderIndex];
-
-      if (type == null || !showFeatureOfType(type))
+      String type = renderOrder[renderIndex];
+      if (!showFeatureOfType(type))
       {
         continue;
       }
@@ -332,16 +348,16 @@ public class FeatureRenderer extends FeatureRendererModel
           continue;
         }
 
-        if (featureGroups != null
-                && sequenceFeature.featureGroup != null
-                && sequenceFeature.featureGroup.length() != 0
-                && featureGroups.containsKey(sequenceFeature.featureGroup)
-                && !featureGroups.get(sequenceFeature.featureGroup)
-                        .booleanValue())
+        if (featureGroupNotShown(sequenceFeature))
         {
           continue;
         }
 
+        /*
+         * check feature overlaps the visible part of the alignment, 
+         * unless doing offscreenRender (to the Overview window or a 
+         * structure viewer) which is not limited 
+         */
         if (!offscreenRender
                 && (sequenceFeature.getBegin() > epos || sequenceFeature
                         .getEnd() < spos))
@@ -349,35 +365,43 @@ public class FeatureRenderer extends FeatureRendererModel
           continue;
         }
 
+        Color featureColour = getColour(sequenceFeature);
+        boolean isContactFeature = sequenceFeature.isContactFeature();
+
         if (offscreenRender && offscreenImage == null)
         {
-          if (sequenceFeature.begin <= start
-                  && sequenceFeature.end >= start)
+          /*
+           * offscreen mode with no image (image is only needed if transparency 
+           * is applied to feature colours) - just check feature is rendered at 
+           * the requested position (start == sequence position in this mode)
+           */
+          boolean featureIsAtPosition = sequenceFeature.begin <= start
+                  && sequenceFeature.end >= start;
+          if (isContactFeature)
+          {
+            featureIsAtPosition = sequenceFeature.begin == start
+                    || sequenceFeature.end == start;
+          }
+          if (featureIsAtPosition)
           {
             // this is passed out to the overview and other sequence renderers
             // (e.g. molecule viewer) to get displayed colour for rendered
             // sequence
-            currentColour = new Integer(getColour(sequenceFeature).getRGB());
+            currentColour = new Integer(featureColour.getRGB());
             // used to be retreived from av.featuresDisplayed
             // currentColour = av.featuresDisplayed
             // .get(sequenceFeatures[sfindex].type);
 
           }
         }
-        else if (sequenceFeature.type.equals("disulfide bond"))
+        else if (isContactFeature)
         {
           renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
-                  seq.findIndex(sequenceFeature.begin) - 1,
-                  getColour(sequenceFeature)
-                  // new Color(((Integer) av.featuresDisplayed
-                  // .get(sequenceFeatures[sfindex].type)).intValue())
-                  , start, end, y1);
+                  seq.findIndex(sequenceFeature.begin) - 1, featureColour,
+                  start, end, y1);
           renderFeature(g, seq, seq.findIndex(sequenceFeature.end) - 1,
-                  seq.findIndex(sequenceFeature.end) - 1,
-                  getColour(sequenceFeature)
-                  // new Color(((Integer) av.featuresDisplayed
-                  // .get(sequenceFeatures[sfindex].type)).intValue())
-                  , start, end, y1);
+                  seq.findIndex(sequenceFeature.end) - 1, featureColour,
+                  start, end, y1);
 
         }
         else if (showFeature(sequenceFeature))
@@ -388,19 +412,17 @@ public class FeatureRenderer extends FeatureRendererModel
             renderScoreFeature(g, seq,
                     seq.findIndex(sequenceFeature.begin) - 1,
                     seq.findIndex(sequenceFeature.end) - 1,
-                    getColour(sequenceFeature), start, end, y1,
+                    featureColour, start, end, y1,
                     normaliseScore(sequenceFeature));
           }
           else
           {
             renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1,
                     seq.findIndex(sequenceFeature.end) - 1,
-                    getColour(sequenceFeature), start, end, y1);
+                    featureColour, start, end, y1);
           }
         }
-
       }
-
     }
 
     if (transparency != 1.0f && g != null)
@@ -412,6 +434,24 @@ public class FeatureRenderer extends FeatureRendererModel
   }
 
   /**
+   * Answers true if the feature belongs to a feature group which is not
+   * currently displayed, else false
+   * 
+   * @param sequenceFeature
+   * @return
+   */
+  protected boolean featureGroupNotShown(
+          final SequenceFeature sequenceFeature)
+  {
+    return featureGroups != null
+            && sequenceFeature.featureGroup != null
+            && sequenceFeature.featureGroup.length() != 0
+            && featureGroups.containsKey(sequenceFeature.featureGroup)
+            && !featureGroups.get(sequenceFeature.featureGroup)
+                    .booleanValue();
+  }
+
+  /**
    * Called when alignment in associated view has new/modified features to
    * discover and display.
    * 
index 9d09259..c47f171 100755 (executable)
  */
 package jalview.schemes;
 
-import jalview.analysis.AAFrequency;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 
 import java.awt.Color;
 import java.util.Map;
 
 public class Blosum62ColourScheme extends ResidueColourScheme
 {
+  private static final Color LIGHT_BLUE = new Color(204, 204, 255);
+  private static final Color DARK_BLUE = new Color(154, 154, 255);
+
   public Blosum62ColourScheme()
   {
     super();
@@ -44,7 +47,7 @@ public class Blosum62ColourScheme extends ResidueColourScheme
       res -= ('a' - 'A');
     }
 
-    if (consensus == null || j >= consensus.length || consensus[j] == null
+    if (consensus == null || consensus.get(j) == null
             || (threshold != 0 && !aboveThreshold(res, j)))
     {
       return Color.white;
@@ -52,14 +55,16 @@ public class Blosum62ColourScheme extends ResidueColourScheme
 
     Color currentColour;
 
-    if (!jalview.util.Comparison.isGap(res))
+    if (!Comparison.isGap(res))
     {
-      String max = (String) consensus[j].get(AAFrequency.MAXRESIDUE);
+      /*
+       * test if this is the consensus (or joint consensus) residue
+       */
+      String max = consensus.get(j).getModalResidue();
 
       if (max.indexOf(res) > -1)
       {
-        // TODO use a constant here?
-        currentColour = new Color(154, 154, 255);
+        currentColour = DARK_BLUE;
       }
       else
       {
@@ -74,8 +79,7 @@ public class Blosum62ColourScheme extends ResidueColourScheme
 
         if (c > 0)
         {
-          // TODO use a constant here?
-          currentColour = new Color(204, 204, 255);
+          currentColour = LIGHT_BLUE;
         }
         else
         {
index effdf59..da99a4a 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.schemes;
 
 import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
 
@@ -52,7 +53,7 @@ public interface ColourSchemeI
   /**
    * assign the given consensus profile for the colourscheme
    */
-  public void setConsensus(java.util.Hashtable[] h);
+  public void setConsensus(ProfilesI hconsensus);
 
   /**
    * assign the given conservation to the colourscheme
index bdc70c9..23087a8 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.schemes;
 
 import jalview.api.FeatureColourI;
@@ -336,9 +356,10 @@ public class FeatureColour implements FeatureColourI
     setAutoScaled(fc.isAutoScaled());
     setColourByLabel(fc.isColourByLabel());
   }
-  
+
   /**
    * Copy constructor with new min/max ranges
+   * 
    * @param fc
    * @param min
    * @param max
@@ -406,6 +427,7 @@ public class FeatureColour implements FeatureColourI
       setGraduatedColour(false);
     }
   }
+
   @Override
   public boolean isBelowThreshold()
   {
@@ -543,7 +565,8 @@ public class FeatureColour implements FeatureColourI
     {
       scl = 1f;
     }
-    return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen, minBlue + scl * deltaBlue);
+    return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen,
+            minBlue + scl * deltaBlue);
   }
 
   /**
index 699d954..b15e4cf 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.schemes;
 
 import jalview.api.FeatureColourI;
index eac467a..35be31b 100644 (file)
@@ -21,8 +21,7 @@
 package jalview.schemes;
 
 import jalview.analysis.Conservation;
-
-import java.util.Hashtable;
+import jalview.datamodel.ProfilesI;
 
 /**
  * Colourscheme that takes its colours from some other colourscheme
@@ -41,7 +40,7 @@ public class FollowerColourScheme extends ResidueColourScheme
   }
 
   @Override
-  public void setConsensus(Hashtable[] consensus)
+  public void setConsensus(ProfilesI consensus)
   {
     if (colourScheme != null)
     {
index 9dd763d..0ad5b5c 100755 (executable)
  */
 package jalview.schemes;
 
-import jalview.analysis.AAFrequency;
+import jalview.datamodel.ProfileI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 
 import java.awt.Color;
 
@@ -48,7 +49,7 @@ public class PIDColourScheme extends ResidueColourScheme
       c -= ('a' - 'A');
     }
 
-    if (consensus == null || j >= consensus.length || consensus[j] == null)
+    if (consensus == null || consensus.get(j) == null)
     {
       return Color.white;
     }
@@ -62,25 +63,24 @@ public class PIDColourScheme extends ResidueColourScheme
 
     double sc = 0;
 
-    if (consensus.length <= j)
-    {
-      return Color.white;
-    }
 
-    if ((Integer
-            .parseInt(consensus[j].get(AAFrequency.MAXCOUNT).toString()) != -1)
-            && consensus[j].contains(String.valueOf(c)))
+    /*
+     * test whether this is the consensus (or joint consensus) residue
+     */
+    ProfileI profile = consensus.get(j);
+    boolean matchesConsensus = profile.getModalResidue().contains(
+            String.valueOf(c));
+    if (matchesConsensus)
     {
-      sc = ((Float) consensus[j].get(ignoreGaps)).floatValue();
+      sc = profile.getPercentageIdentity(ignoreGaps);
 
-      if (!jalview.util.Comparison.isGap(c))
+      if (!Comparison.isGap(c))
       {
         for (int i = 0; i < thresholds.length; i++)
         {
           if (sc > thresholds[i])
           {
             currentColour = pidColours[i];
-
             break;
           }
         }
index bca98cf..f6b7c5e 100755 (executable)
  */
 package jalview.schemes;
 
-import jalview.analysis.AAFrequency;
 import jalview.analysis.Conservation;
 import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ProfileI;
+import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
-import java.util.Hashtable;
 import java.util.Map;
 
 /**
@@ -48,17 +50,21 @@ public class ResidueColourScheme implements ColourSchemeI
   int threshold = 0;
 
   /* Set when threshold colouring to either pid_gaps or pid_nogaps */
-  protected String ignoreGaps = AAFrequency.PID_GAPS;
+  protected boolean ignoreGaps = false;
 
-  /** Consenus as a hashtable array */
-  Hashtable[] consensus;
+  /*
+   * Consensus data indexed by column
+   */
+  ProfilesI consensus;
 
-  /** Conservation string as a char array */
+  /*
+   * Conservation string as a char array 
+   */
   char[] conservation;
 
-  int conservationLength = 0;
-
-  /** DOCUMENT ME!! */
+  /*
+   * The conservation slider percentage setting 
+   */
   int inc = 30;
 
   /**
@@ -100,6 +106,7 @@ public class ResidueColourScheme implements ColourSchemeI
   /**
    * Find a colour without an index in a sequence
    */
+  @Override
   public Color findColour(char c)
   {
     return colors == null ? Color.white : colors[symbolIndex[c]];
@@ -133,58 +140,63 @@ public class ResidueColourScheme implements ColourSchemeI
    * 
    * @return Returns the percentage threshold
    */
+  @Override
   public int getThreshold()
   {
     return threshold;
   }
 
   /**
-   * DOCUMENT ME!
+   * Sets the percentage consensus threshold value, and whether gaps are ignored
+   * in percentage identity calculation
    * 
-   * @param ct
-   *          DOCUMENT ME!
+   * @param consensusThreshold
+   * @param ignoreGaps
    */
-  public void setThreshold(int ct, boolean ignoreGaps)
+  @Override
+  public void setThreshold(int consensusThreshold, boolean ignoreGaps)
   {
-    threshold = ct;
-    if (ignoreGaps)
-    {
-      this.ignoreGaps = AAFrequency.PID_NOGAPS;
-    }
-    else
-    {
-      this.ignoreGaps = AAFrequency.PID_GAPS;
-    }
+    threshold = consensusThreshold;
+    this.ignoreGaps = ignoreGaps;
   }
 
   /**
-   * DOCUMENT ME!
+   * Answers true if there is a consensus profile for the specified column, and
+   * the given residue matches the consensus (or joint consensus) residue for
+   * the column, and the percentage identity for the profile is equal to or
+   * greater than the current threshold; else answers false. The percentage
+   * calculation depends on whether or not we are ignoring gapped sequences.
    * 
-   * @param s
-   *          DOCUMENT ME!
-   * @param j
-   *          DOCUMENT ME!
+   * @param residue
+   * @param column
+   *          (index into consensus profiles)
    * 
-   * @return DOCUMENT ME!
+   * @return
+   * @see #setThreshold(int, boolean)
    */
-  public boolean aboveThreshold(char c, int j)
+  public boolean aboveThreshold(char residue, int column)
   {
-    if ('a' <= c && c <= 'z')
+    if ('a' <= residue && residue <= 'z')
     {
       // TO UPPERCASE !!!
       // Faster than toUpperCase
-      c -= ('a' - 'A');
+      residue -= ('a' - 'A');
     }
 
-    if (consensus == null || consensus.length < j || consensus[j] == null)
+    if (consensus == null)
     {
       return false;
     }
 
-    if ((((Integer) consensus[j].get(AAFrequency.MAXCOUNT)).intValue() != -1)
-            && consensus[j].contains(String.valueOf(c)))
+    ProfileI profile = consensus.get(column);
+
+    /*
+     * test whether this is the consensus (or joint consensus) residue
+     */
+    if (profile != null
+            && profile.getModalResidue().contains(String.valueOf(residue)))
     {
-      if (((Float) consensus[j].get(ignoreGaps)).floatValue() >= threshold)
+      if (profile.getPercentageIdentity(ignoreGaps) >= threshold)
       {
         return true;
       }
@@ -193,6 +205,7 @@ public class ResidueColourScheme implements ColourSchemeI
     return false;
   }
 
+  @Override
   public boolean conservationApplied()
   {
     return conservationColouring;
@@ -204,11 +217,13 @@ public class ResidueColourScheme implements ColourSchemeI
     conservationColouring = conservationApplied;
   }
 
+  @Override
   public void setConservationInc(int i)
   {
     inc = i;
   }
 
+  @Override
   public int getConservationInc()
   {
     return inc;
@@ -220,7 +235,8 @@ public class ResidueColourScheme implements ColourSchemeI
    * @param consensus
    *          DOCUMENT ME!
    */
-  public void setConsensus(Hashtable[] consensus)
+  @Override
+  public void setConsensus(ProfilesI consensus)
   {
     if (consensus == null)
     {
@@ -230,6 +246,7 @@ public class ResidueColourScheme implements ColourSchemeI
     this.consensus = consensus;
   }
 
+  @Override
   public void setConservation(Conservation cons)
   {
     if (cons == null)
@@ -240,73 +257,70 @@ public class ResidueColourScheme implements ColourSchemeI
     else
     {
       conservationColouring = true;
-      int i, iSize = cons.getConsSequence().getLength();
+      int iSize = cons.getConsSequence().getLength();
       conservation = new char[iSize];
-      for (i = 0; i < iSize; i++)
+      for (int i = 0; i < iSize; i++)
       {
         conservation[i] = cons.getConsSequence().getCharAt(i);
       }
-      conservationLength = conservation.length;
     }
 
   }
 
   /**
-   * DOCUMENT ME!
+   * Applies a combination of column conservation score, and conservation
+   * percentage slider, to 'bleach' out the residue colours towards white.
+   * <p>
+   * If a column is fully conserved (identical residues, conservation score 11,
+   * shown as *), or all 10 physico-chemical properties are conserved
+   * (conservation score 10, shown as +), then the colour is left unchanged.
+   * <p>
+   * Otherwise a 'bleaching' factor is computed and applied to the colour. This
+   * is designed to fade colours for scores of 0-9 completely to white at slider
+   * positions ranging from 18% - 100% respectively.
    * 
-   * @param s
-   *          DOCUMENT ME!
-   * @param i
-   *          DOCUMENT ME!
+   * @param currentColour
+   * @param column
    * 
-   * @return DOCUMENT ME!
+   * @return bleached (or unmodified) colour
    */
-
-  Color applyConservation(Color currentColour, int i)
+  Color applyConservation(Color currentColour, int column)
   {
+    if (conservation == null || conservation.length <= column)
+    {
+      return currentColour;
+    }
+    char conservationScore = conservation[column];
+
+    /*
+     * if residues are fully conserved (* or 11), or all properties
+     * are conserved (+ or 10), leave colour unchanged
+     */
+    if (conservationScore == '*' || conservationScore == '+'
+            || conservationScore == (char) 10
+            || conservationScore == (char) 11)
+    {
+      return currentColour;
+    }
 
-    if ((conservationLength > i) && (conservation[i] != '*')
-            && (conservation[i] != '+'))
+    if (Comparison.isGap(conservationScore))
     {
-      if (jalview.util.Comparison.isGap(conservation[i]))
-      {
-        currentColour = Color.white;
-      }
-      else
-      {
-        float t = 11 - (conservation[i] - '0');
-        if (t == 0)
-        {
-          return Color.white;
-        }
-
-        int red = currentColour.getRed();
-        int green = currentColour.getGreen();
-        int blue = currentColour.getBlue();
-
-        int dr = 255 - red;
-        int dg = 255 - green;
-        int db = 255 - blue;
-
-        dr *= t / 10f;
-        dg *= t / 10f;
-        db *= t / 10f;
-
-        red += (inc / 20f) * dr;
-        green += (inc / 20f) * dg;
-        blue += (inc / 20f) * db;
-
-        if (red > 255 || green > 255 || blue > 255)
-        {
-          currentColour = Color.white;
-        }
-        else
-        {
-          currentColour = new Color(red, green, blue);
-        }
-      }
+      return Color.white;
     }
-    return currentColour;
+
+    /*
+     * convert score 0-9 to a bleaching factor 1.1 - 0.2
+     */
+    float bleachFactor = (11 - (conservationScore - '0')) / 10f;
+
+    /*
+     * scale this up by 0-5 (percentage slider / 20)
+     * as a result, scores of:         0  1  2  3  4  5  6  7  8  9
+     * fade to white at slider value: 18 20 22 25 29 33 40 50 67 100%
+     */
+    bleachFactor *= (inc / 20f);
+
+    return ColorUtils.bleachColour(currentColour, bleachFactor);
   }
 
   @Override
index d0d26b0..4d46279 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.api.analysis.ScoreModelI;
 
 import java.awt.Color;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -221,38 +222,42 @@ public class ResidueProperties
     purinepyrimidineIndex['n'] = 2;
   }
 
+  private static final Integer ONE = Integer.valueOf(1);
+
+  private static final Integer ZERO = Integer.valueOf(0);
+
   static
   {
-    aa3Hash.put("ALA", new Integer(0));
-    aa3Hash.put("ARG", new Integer(1));
-    aa3Hash.put("ASN", new Integer(2));
-    aa3Hash.put("ASP", new Integer(3)); // D
-    aa3Hash.put("CYS", new Integer(4));
-    aa3Hash.put("GLN", new Integer(5)); // Q
-    aa3Hash.put("GLU", new Integer(6)); // E
-    aa3Hash.put("GLY", new Integer(7));
-    aa3Hash.put("HIS", new Integer(8));
-    aa3Hash.put("ILE", new Integer(9));
-    aa3Hash.put("LEU", new Integer(10));
-    aa3Hash.put("LYS", new Integer(11));
-    aa3Hash.put("MET", new Integer(12));
-    aa3Hash.put("PHE", new Integer(13));
-    aa3Hash.put("PRO", new Integer(14));
-    aa3Hash.put("SER", new Integer(15));
-    aa3Hash.put("THR", new Integer(16));
-    aa3Hash.put("TRP", new Integer(17));
-    aa3Hash.put("TYR", new Integer(18));
-    aa3Hash.put("VAL", new Integer(19));
+    aa3Hash.put("ALA", ZERO);
+    aa3Hash.put("ARG", ONE);
+    aa3Hash.put("ASN", Integer.valueOf(2));
+    aa3Hash.put("ASP", Integer.valueOf(3)); // D
+    aa3Hash.put("CYS", Integer.valueOf(4));
+    aa3Hash.put("GLN", Integer.valueOf(5)); // Q
+    aa3Hash.put("GLU", Integer.valueOf(6)); // E
+    aa3Hash.put("GLY", Integer.valueOf(7));
+    aa3Hash.put("HIS", Integer.valueOf(8));
+    aa3Hash.put("ILE", Integer.valueOf(9));
+    aa3Hash.put("LEU", Integer.valueOf(10));
+    aa3Hash.put("LYS", Integer.valueOf(11));
+    aa3Hash.put("MET", Integer.valueOf(12));
+    aa3Hash.put("PHE", Integer.valueOf(13));
+    aa3Hash.put("PRO", Integer.valueOf(14));
+    aa3Hash.put("SER", Integer.valueOf(15));
+    aa3Hash.put("THR", Integer.valueOf(16));
+    aa3Hash.put("TRP", Integer.valueOf(17));
+    aa3Hash.put("TYR", Integer.valueOf(18));
+    aa3Hash.put("VAL", Integer.valueOf(19));
     // IUB Nomenclature for ambiguous peptides
-    aa3Hash.put("ASX", new Integer(20)); // "B";
-    aa3Hash.put("GLX", new Integer(21)); // Z
-    aa3Hash.put("XAA", new Integer(22)); // X unknown
-    aa3Hash.put("-", new Integer(23));
-    aa3Hash.put("*", new Integer(23));
-    aa3Hash.put(".", new Integer(23));
-    aa3Hash.put(" ", new Integer(23));
-    aa3Hash.put("Gap", new Integer(23));
-    aa3Hash.put("UR3", new Integer(24));
+    aa3Hash.put("ASX", Integer.valueOf(20)); // "B";
+    aa3Hash.put("GLX", Integer.valueOf(21)); // Z
+    aa3Hash.put("XAA", Integer.valueOf(22)); // X unknown
+    aa3Hash.put("-", Integer.valueOf(23));
+    aa3Hash.put("*", Integer.valueOf(23));
+    aa3Hash.put(".", Integer.valueOf(23));
+    aa3Hash.put(" ", Integer.valueOf(23));
+    aa3Hash.put("Gap", Integer.valueOf(23));
+    aa3Hash.put("UR3", Integer.valueOf(24));
   }
 
   static
@@ -305,24 +310,24 @@ public class ResidueProperties
 
   public static final Color midBlue = new Color(100, 100, 255);
 
-  public static final Vector scaleColours = new Vector();
-
-  static
-  {
-    scaleColours.addElement(new Color(114, 0, 147));
-    scaleColours.addElement(new Color(156, 0, 98));
-    scaleColours.addElement(new Color(190, 0, 0));
-    scaleColours.addElement(Color.red);
-    scaleColours.addElement(new Color(255, 125, 0));
-    scaleColours.addElement(Color.orange);
-    scaleColours.addElement(new Color(255, 194, 85));
-    scaleColours.addElement(Color.yellow);
-    scaleColours.addElement(new Color(255, 255, 181));
-    scaleColours.addElement(Color.white);
-  }
-
-  public static final Color[] taylor = { new Color(204, 255, 0), // A
-                                                                 // Greenish-yellowy-yellow
+  // not currently in use
+  // public static final Vector<Color> scaleColours = new Vector<Color>();
+  // static
+  // {
+  // scaleColours.addElement(new Color(114, 0, 147));
+  // scaleColours.addElement(new Color(156, 0, 98));
+  // scaleColours.addElement(new Color(190, 0, 0));
+  // scaleColours.addElement(Color.red);
+  // scaleColours.addElement(new Color(255, 125, 0));
+  // scaleColours.addElement(Color.orange);
+  // scaleColours.addElement(new Color(255, 194, 85));
+  // scaleColours.addElement(Color.yellow);
+  // scaleColours.addElement(new Color(255, 255, 181));
+  // scaleColours.addElement(Color.white);
+  // }
+
+  public static final Color[] taylor = { new Color(204, 255, 0),
+      // A Greenish-yellowy-yellow
       new Color(0, 0, 255), // R Blueish-bluey-blue
       new Color(204, 0, 255), // N Blueish-reddy-blue
       new Color(255, 0, 0), // D Reddish-reddy-red
@@ -572,21 +577,21 @@ public class ResidueProperties
       { -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
           -8, -8, -8, -8, -8, -8, 1 }, };
 
-  public static final Hashtable ssHash = new Hashtable(); // stores the number
-  // value of the aa
-
-  static
-  {
-    ssHash.put("H", Color.magenta);
-    ssHash.put("E", Color.yellow);
-    ssHash.put("-", Color.white);
-    ssHash.put(".", Color.white);
-    ssHash.put("S", Color.cyan);
-    ssHash.put("T", Color.blue);
-    ssHash.put("G", Color.pink);
-    ssHash.put("I", Color.pink);
-    ssHash.put("B", Color.yellow);
-  }
+  // not currently used
+  // public static final Map<String, Color> ssHash = new Hashtable<String,
+  // Color>();
+  // static
+  // {
+  // ssHash.put("H", Color.magenta);
+  // ssHash.put("E", Color.yellow);
+  // ssHash.put("-", Color.white);
+  // ssHash.put(".", Color.white);
+  // ssHash.put("S", Color.cyan);
+  // ssHash.put("T", Color.blue);
+  // ssHash.put("G", Color.pink);
+  // ssHash.put("I", Color.pink);
+  // ssHash.put("B", Color.yellow);
+  // }
 
   /*
    * new Color(60, 136, 238), // U Color.white, // I Color.white, // X
@@ -618,7 +623,6 @@ public class ResidueProperties
     scoreMatrices.put("BLOSUM62", new ScoreMatrix("BLOSUM62", BLOSUM62, 0));
     scoreMatrices.put("PAM250", new ScoreMatrix("PAM250", PAM250, 0));
     scoreMatrices.put("DNA", new ScoreMatrix("DNA", DNA, 1));
-
   }
 
   public static final Color[] pidColours = { midBlue,
@@ -628,77 +632,10 @@ public class ResidueProperties
 
   public static final float[] pidThresholds = { 80, 60, 40, };
 
-  public static Map<String, List<String>> codonHash = new HashMap<String, List<String>>();
-
-  private static List<String> Lys = new ArrayList<String>();
-
-  private static List<String> Asn = new ArrayList<String>();
-
-  private static List<String> Gln = new ArrayList<String>();
-
-  private static List<String> His = new ArrayList<String>();
-
-  private static List<String> Glu = new ArrayList<String>();
-
-  private static List<String> Asp = new ArrayList<String>();
-
-  private static List<String> Tyr = new ArrayList<String>();
-
-  private static List<String> Thr = new ArrayList<String>();
-
-  private static List<String> Pro = new ArrayList<String>();
-
-  private static List<String> Ala = new ArrayList<String>();
-
-  private static List<String> Ser = new ArrayList<String>();
-
-  private static List<String> Arg = new ArrayList<String>();
-
-  private static List<String> Gly = new ArrayList<String>();
-
-  private static List<String> Trp = new ArrayList<String>();
-
-  private static List<String> Cys = new ArrayList<String>();
-
-  private static List<String> Ile = new ArrayList<String>();
-
-  private static List<String> Met = new ArrayList<String>();
-
-  private static List<String> Leu = new ArrayList<String>();
-
-  private static List<String> Val = new ArrayList<String>();
-
-  private static List<String> Phe = new ArrayList<String>();
-
-  public static List<String> STOP = new ArrayList<String>();
+  public static List<String> STOP = Arrays.asList("TGA", "TAA", "TAG");
 
   public static String START = "ATG";
 
-  static
-  {
-    codonHash.put("K", Lys);
-    codonHash.put("N", Asn);
-    codonHash.put("Q", Gln);
-    codonHash.put("H", His);
-    codonHash.put("E", Glu);
-    codonHash.put("D", Asp);
-    codonHash.put("Y", Tyr);
-    codonHash.put("T", Thr);
-    codonHash.put("P", Pro);
-    codonHash.put("A", Ala);
-    codonHash.put("S", Ser);
-    codonHash.put("R", Arg);
-    codonHash.put("G", Gly);
-    codonHash.put("W", Trp);
-    codonHash.put("C", Cys);
-    codonHash.put("I", Ile);
-    codonHash.put("M", Met);
-    codonHash.put("L", Leu);
-    codonHash.put("V", Val);
-    codonHash.put("F", Phe);
-    codonHash.put("STOP", STOP);
-  }
-
   /**
    * Nucleotide Ambiguity Codes
    */
@@ -885,7 +822,6 @@ public class ResidueProperties
         // make all codons for this combination
         char allres[][] = new char[tpos.length][];
         String _acodon = "";
-        char _anuc;
         for (ipos = 0; ipos < tpos.length; ipos++)
         {
           if (acodon[ipos].length == 0 || tpos[ipos] < 0)
@@ -951,379 +887,294 @@ public class ResidueProperties
         }
       }
     }
-
-  }
-
-  static
-  {
-    Lys.add("AAA");
-    Lys.add("AAG");
-    Asn.add("AAC");
-    Asn.add("AAT");
-
-    Gln.add("CAA");
-    Gln.add("CAG");
-    His.add("CAC");
-    His.add("CAT");
-
-    Glu.add("GAA");
-    Glu.add("GAG");
-    Asp.add("GAC");
-    Asp.add("GAT");
-
-    Tyr.add("TAC");
-    Tyr.add("TAT");
-
-    Thr.add("ACA");
-    Thr.add("ACG");
-    Thr.add("ACC");
-    Thr.add("ACT");
-
-    Pro.add("CCA");
-    Pro.add("CCG");
-    Pro.add("CCC");
-    Pro.add("CCT");
-
-    Ala.add("GCA");
-    Ala.add("GCG");
-    Ala.add("GCC");
-    Ala.add("GCT");
-
-    Ser.add("TCA");
-    Ser.add("TCG");
-    Ser.add("TCC");
-    Ser.add("TCT");
-    Ser.add("AGC");
-    Ser.add("AGT");
-
-    Arg.add("AGA");
-    Arg.add("AGG");
-    Arg.add("CGA");
-    Arg.add("CGG");
-    Arg.add("CGC");
-    Arg.add("CGT");
-
-    Gly.add("GGA");
-    Gly.add("GGG");
-    Gly.add("GGC");
-    Gly.add("GGT");
-
-    STOP.add("TGA");
-    STOP.add("TAA");
-    STOP.add("TAG");
-
-    Trp.add("TGG");
-
-    Cys.add("TGC");
-    Cys.add("TGT");
-
-    Ile.add("ATA");
-    Ile.add("ATC");
-    Ile.add("ATT");
-
-    Met.add("ATG");
-
-    Leu.add("CTA");
-    Leu.add("CTG");
-    Leu.add("CTC");
-    Leu.add("CTT");
-    Leu.add("TTA");
-    Leu.add("TTG");
-
-    Val.add("GTA");
-    Val.add("GTG");
-    Val.add("GTC");
-    Val.add("GTT");
-
-    Phe.add("TTC");
-    Phe.add("TTT");
   }
 
   // Stores residue codes/names and colours and other things
-  public static Hashtable propHash = new Hashtable();
+  public static Map<String, Map<String, Integer>> propHash = new Hashtable<String, Map<String, Integer>>();
 
-  public static Hashtable hydrophobic = new Hashtable();
+  public static Map<String, Integer> hydrophobic = new Hashtable<String, Integer>();
 
-  public static Hashtable polar = new Hashtable();
+  public static Map<String, Integer> polar = new Hashtable<String, Integer>();
 
-  public static Hashtable small = new Hashtable();
+  public static Map<String, Integer> small = new Hashtable<String, Integer>();
 
-  public static Hashtable positive = new Hashtable();
+  public static Map<String, Integer> positive = new Hashtable<String, Integer>();
 
-  public static Hashtable negative = new Hashtable();
+  public static Map<String, Integer> negative = new Hashtable<String, Integer>();
 
-  public static Hashtable charged = new Hashtable();
+  public static Map<String, Integer> charged = new Hashtable<String, Integer>();
 
-  public static Hashtable aromatic = new Hashtable();
+  public static Map<String, Integer> aromatic = new Hashtable<String, Integer>();
 
-  public static Hashtable aliphatic = new Hashtable();
+  public static Map<String, Integer> aliphatic = new Hashtable<String, Integer>();
 
-  public static Hashtable tiny = new Hashtable();
+  public static Map<String, Integer> tiny = new Hashtable<String, Integer>();
 
-  public static Hashtable proline = new Hashtable();
+  public static Map<String, Integer> proline = new Hashtable<String, Integer>();
 
   static
   {
-    hydrophobic.put("I", new Integer(1));
-    hydrophobic.put("L", new Integer(1));
-    hydrophobic.put("V", new Integer(1));
-    hydrophobic.put("C", new Integer(1));
-    hydrophobic.put("A", new Integer(1));
-    hydrophobic.put("G", new Integer(1));
-    hydrophobic.put("M", new Integer(1));
-    hydrophobic.put("F", new Integer(1));
-    hydrophobic.put("Y", new Integer(1));
-    hydrophobic.put("W", new Integer(1));
-    hydrophobic.put("H", new Integer(1));
-    hydrophobic.put("K", new Integer(1));
-    hydrophobic.put("X", new Integer(1));
-    hydrophobic.put("-", new Integer(1));
-    hydrophobic.put("*", new Integer(1));
-    hydrophobic.put("R", new Integer(0));
-    hydrophobic.put("E", new Integer(0));
-    hydrophobic.put("Q", new Integer(0));
-    hydrophobic.put("D", new Integer(0));
-    hydrophobic.put("N", new Integer(0));
-    hydrophobic.put("S", new Integer(0));
-    hydrophobic.put("T", new Integer(0));
-    hydrophobic.put("P", new Integer(0));
+    hydrophobic.put("I", ONE);
+    hydrophobic.put("L", ONE);
+    hydrophobic.put("V", ONE);
+    hydrophobic.put("C", ONE);
+    hydrophobic.put("A", ONE);
+    hydrophobic.put("G", ONE);
+    hydrophobic.put("M", ONE);
+    hydrophobic.put("F", ONE);
+    hydrophobic.put("Y", ONE);
+    hydrophobic.put("W", ONE);
+    hydrophobic.put("H", ONE);
+    hydrophobic.put("K", ONE);
+    hydrophobic.put("X", ONE);
+    hydrophobic.put("-", ONE);
+    hydrophobic.put("*", ONE);
+    hydrophobic.put("R", ZERO);
+    hydrophobic.put("E", ZERO);
+    hydrophobic.put("Q", ZERO);
+    hydrophobic.put("D", ZERO);
+    hydrophobic.put("N", ZERO);
+    hydrophobic.put("S", ZERO);
+    hydrophobic.put("T", ONE);
+    hydrophobic.put("P", ZERO);
   }
 
   static
   {
-    polar.put("Y", new Integer(1));
-    polar.put("W", new Integer(1));
-    polar.put("H", new Integer(1));
-    polar.put("K", new Integer(1));
-    polar.put("R", new Integer(1));
-    polar.put("E", new Integer(1));
-    polar.put("Q", new Integer(1));
-    polar.put("D", new Integer(1));
-    polar.put("N", new Integer(1));
-    polar.put("S", new Integer(1));
-    polar.put("T", new Integer(1));
-    polar.put("X", new Integer(1));
-    polar.put("-", new Integer(1));
-    polar.put("*", new Integer(1));
-    polar.put("I", new Integer(0));
-    polar.put("L", new Integer(0));
-    polar.put("V", new Integer(0));
-    polar.put("C", new Integer(0));
-    polar.put("A", new Integer(0));
-    polar.put("G", new Integer(0));
-    polar.put("M", new Integer(0));
-    polar.put("F", new Integer(0));
-    polar.put("P", new Integer(0));
+    polar.put("Y", ONE);
+    polar.put("W", ONE);
+    polar.put("H", ONE);
+    polar.put("K", ONE);
+    polar.put("R", ONE);
+    polar.put("E", ONE);
+    polar.put("Q", ONE);
+    polar.put("D", ONE);
+    polar.put("N", ONE);
+    polar.put("S", ONE);
+    polar.put("T", ONE);
+    polar.put("X", ONE);
+    polar.put("-", ONE);
+    polar.put("*", ONE);
+    polar.put("I", ZERO);
+    polar.put("L", ZERO);
+    polar.put("V", ZERO);
+    polar.put("C", ZERO);
+    polar.put("A", ZERO);
+    polar.put("G", ZERO);
+    polar.put("M", ZERO);
+    polar.put("F", ZERO);
+    polar.put("P", ZERO);
   }
 
   static
   {
-    small.put("I", new Integer(0));
-    small.put("L", new Integer(0));
-    small.put("V", new Integer(1));
-    small.put("C", new Integer(1));
-    small.put("A", new Integer(1));
-    small.put("G", new Integer(1));
-    small.put("M", new Integer(0));
-    small.put("F", new Integer(0));
-    small.put("Y", new Integer(0));
-    small.put("W", new Integer(0));
-    small.put("H", new Integer(0));
-    small.put("K", new Integer(0));
-    small.put("R", new Integer(0));
-    small.put("E", new Integer(0));
-    small.put("Q", new Integer(0));
-    small.put("D", new Integer(1));
-    small.put("N", new Integer(1));
-    small.put("S", new Integer(1));
-    small.put("T", new Integer(1));
-    small.put("P", new Integer(1));
-    small.put("-", new Integer(1));
-    small.put("*", new Integer(1));
+    small.put("I", ZERO);
+    small.put("L", ZERO);
+    small.put("V", ONE);
+    small.put("C", ONE);
+    small.put("A", ONE);
+    small.put("G", ONE);
+    small.put("M", ZERO);
+    small.put("F", ZERO);
+    small.put("Y", ZERO);
+    small.put("W", ZERO);
+    small.put("H", ZERO);
+    small.put("K", ZERO);
+    small.put("R", ZERO);
+    small.put("E", ZERO);
+    small.put("Q", ZERO);
+    small.put("D", ONE);
+    small.put("N", ONE);
+    small.put("S", ONE);
+    small.put("T", ONE);
+    small.put("P", ONE);
+    small.put("-", ONE);
+    small.put("*", ONE);
   }
 
   static
   {
-    positive.put("I", new Integer(0));
-    positive.put("L", new Integer(0));
-    positive.put("V", new Integer(0));
-    positive.put("C", new Integer(0));
-    positive.put("A", new Integer(0));
-    positive.put("G", new Integer(0));
-    positive.put("M", new Integer(0));
-    positive.put("F", new Integer(0));
-    positive.put("Y", new Integer(0));
-    positive.put("W", new Integer(0));
-    positive.put("H", new Integer(1));
-    positive.put("K", new Integer(1));
-    positive.put("R", new Integer(1));
-    positive.put("E", new Integer(0));
-    positive.put("Q", new Integer(0));
-    positive.put("D", new Integer(0));
-    positive.put("N", new Integer(0));
-    positive.put("S", new Integer(0));
-    positive.put("T", new Integer(0));
-    positive.put("P", new Integer(0));
-    positive.put("-", new Integer(1));
-    positive.put("*", new Integer(1));
+    positive.put("I", ZERO);
+    positive.put("L", ZERO);
+    positive.put("V", ZERO);
+    positive.put("C", ZERO);
+    positive.put("A", ZERO);
+    positive.put("G", ZERO);
+    positive.put("M", ZERO);
+    positive.put("F", ZERO);
+    positive.put("Y", ZERO);
+    positive.put("W", ZERO);
+    positive.put("H", ONE);
+    positive.put("K", ONE);
+    positive.put("R", ONE);
+    positive.put("E", ZERO);
+    positive.put("Q", ZERO);
+    positive.put("D", ZERO);
+    positive.put("N", ZERO);
+    positive.put("S", ZERO);
+    positive.put("T", ZERO);
+    positive.put("P", ZERO);
+    positive.put("-", ONE);
+    positive.put("*", ONE);
   }
 
   static
   {
-    negative.put("I", new Integer(0));
-    negative.put("L", new Integer(0));
-    negative.put("V", new Integer(0));
-    negative.put("C", new Integer(0));
-    negative.put("A", new Integer(0));
-    negative.put("G", new Integer(0));
-    negative.put("M", new Integer(0));
-    negative.put("F", new Integer(0));
-    negative.put("Y", new Integer(0));
-    negative.put("W", new Integer(0));
-    negative.put("H", new Integer(0));
-    negative.put("K", new Integer(0));
-    negative.put("R", new Integer(0));
-    negative.put("E", new Integer(1));
-    negative.put("Q", new Integer(0));
-    negative.put("D", new Integer(1));
-    negative.put("N", new Integer(0));
-    negative.put("S", new Integer(0));
-    negative.put("T", new Integer(0));
-    negative.put("P", new Integer(0));
-    negative.put("-", new Integer(1));
-    negative.put("*", new Integer(1));
+    negative.put("I", ZERO);
+    negative.put("L", ZERO);
+    negative.put("V", ZERO);
+    negative.put("C", ZERO);
+    negative.put("A", ZERO);
+    negative.put("G", ZERO);
+    negative.put("M", ZERO);
+    negative.put("F", ZERO);
+    negative.put("Y", ZERO);
+    negative.put("W", ZERO);
+    negative.put("H", ZERO);
+    negative.put("K", ZERO);
+    negative.put("R", ZERO);
+    negative.put("E", ONE);
+    negative.put("Q", ZERO);
+    negative.put("D", ONE);
+    negative.put("N", ZERO);
+    negative.put("S", ZERO);
+    negative.put("T", ZERO);
+    negative.put("P", ZERO);
+    negative.put("-", ONE);
+    negative.put("*", ONE);
   }
 
   static
   {
-    charged.put("I", new Integer(0));
-    charged.put("L", new Integer(0));
-    charged.put("V", new Integer(0));
-    charged.put("C", new Integer(0));
-    charged.put("A", new Integer(0));
-    charged.put("G", new Integer(0));
-    charged.put("M", new Integer(0));
-    charged.put("F", new Integer(0));
-    charged.put("Y", new Integer(0));
-    charged.put("W", new Integer(0));
-    charged.put("H", new Integer(1));
-    charged.put("K", new Integer(1));
-    charged.put("R", new Integer(1));
-    charged.put("E", new Integer(1));
-    charged.put("Q", new Integer(0));
-    charged.put("D", new Integer(1));
-    charged.put("N", new Integer(0)); // Asparagine is polar but not charged.
-                                      // Alternative would be charged and
-                                      // negative (in basic form)?
-    charged.put("S", new Integer(0));
-    charged.put("T", new Integer(0));
-    charged.put("P", new Integer(0));
-    charged.put("-", new Integer(1));
-    charged.put("*", new Integer(1));
+    charged.put("I", ZERO);
+    charged.put("L", ZERO);
+    charged.put("V", ZERO);
+    charged.put("C", ZERO);
+    charged.put("A", ZERO);
+    charged.put("G", ZERO);
+    charged.put("M", ZERO);
+    charged.put("F", ZERO);
+    charged.put("Y", ZERO);
+    charged.put("W", ZERO);
+    charged.put("H", ONE);
+    charged.put("K", ONE);
+    charged.put("R", ONE);
+    charged.put("E", ONE);
+    charged.put("Q", ZERO);
+    charged.put("D", ONE);
+    charged.put("N", ZERO); // Asparagine is polar but not
+                                          // charged.
+    // Alternative would be charged and
+    // negative (in basic form)?
+    charged.put("S", ZERO);
+    charged.put("T", ZERO);
+    charged.put("P", ZERO);
+    charged.put("-", ONE);
+    charged.put("*", ONE);
   }
 
   static
   {
-    aromatic.put("I", new Integer(0));
-    aromatic.put("L", new Integer(0));
-    aromatic.put("V", new Integer(0));
-    aromatic.put("C", new Integer(0));
-    aromatic.put("A", new Integer(0));
-    aromatic.put("G", new Integer(0));
-    aromatic.put("M", new Integer(0));
-    aromatic.put("F", new Integer(1));
-    aromatic.put("Y", new Integer(1));
-    aromatic.put("W", new Integer(1));
-    aromatic.put("H", new Integer(1));
-    aromatic.put("K", new Integer(0));
-    aromatic.put("R", new Integer(0));
-    aromatic.put("E", new Integer(0));
-    aromatic.put("Q", new Integer(0));
-    aromatic.put("D", new Integer(0));
-    aromatic.put("N", new Integer(0));
-    aromatic.put("S", new Integer(0));
-    aromatic.put("T", new Integer(0));
-    aromatic.put("P", new Integer(0));
-    aromatic.put("-", new Integer(1));
-    aromatic.put("*", new Integer(1));
+    aromatic.put("I", ZERO);
+    aromatic.put("L", ZERO);
+    aromatic.put("V", ZERO);
+    aromatic.put("C", ZERO);
+    aromatic.put("A", ZERO);
+    aromatic.put("G", ZERO);
+    aromatic.put("M", ZERO);
+    aromatic.put("F", ONE);
+    aromatic.put("Y", ONE);
+    aromatic.put("W", ONE);
+    aromatic.put("H", ONE);
+    aromatic.put("K", ZERO);
+    aromatic.put("R", ZERO);
+    aromatic.put("E", ZERO);
+    aromatic.put("Q", ZERO);
+    aromatic.put("D", ZERO);
+    aromatic.put("N", ZERO);
+    aromatic.put("S", ZERO);
+    aromatic.put("T", ZERO);
+    aromatic.put("P", ZERO);
+    aromatic.put("-", ONE);
+    aromatic.put("*", ONE);
   }
 
   static
   {
-    aliphatic.put("I", new Integer(1));
-    aliphatic.put("L", new Integer(1));
-    aliphatic.put("V", new Integer(1));
-    aliphatic.put("C", new Integer(0));
-    aliphatic.put("A", new Integer(0));
-    aliphatic.put("G", new Integer(0));
-    aliphatic.put("M", new Integer(0));
-    aliphatic.put("F", new Integer(0));
-    aliphatic.put("Y", new Integer(0));
-    aliphatic.put("W", new Integer(0));
-    aliphatic.put("H", new Integer(0));
-    aliphatic.put("K", new Integer(0));
-    aliphatic.put("R", new Integer(0));
-    aliphatic.put("E", new Integer(0));
-    aliphatic.put("Q", new Integer(0));
-    aliphatic.put("D", new Integer(0));
-    aliphatic.put("N", new Integer(0));
-    aliphatic.put("S", new Integer(0));
-    aliphatic.put("T", new Integer(0));
-    aliphatic.put("P", new Integer(0));
-    aliphatic.put("-", new Integer(1));
-    aliphatic.put("*", new Integer(1));
+    aliphatic.put("I", ONE);
+    aliphatic.put("L", ONE);
+    aliphatic.put("V", ONE);
+    aliphatic.put("C", ZERO);
+    aliphatic.put("A", ZERO);
+    aliphatic.put("G", ZERO);
+    aliphatic.put("M", ZERO);
+    aliphatic.put("F", ZERO);
+    aliphatic.put("Y", ZERO);
+    aliphatic.put("W", ZERO);
+    aliphatic.put("H", ZERO);
+    aliphatic.put("K", ZERO);
+    aliphatic.put("R", ZERO);
+    aliphatic.put("E", ZERO);
+    aliphatic.put("Q", ZERO);
+    aliphatic.put("D", ZERO);
+    aliphatic.put("N", ZERO);
+    aliphatic.put("S", ZERO);
+    aliphatic.put("T", ZERO);
+    aliphatic.put("P", ZERO);
+    aliphatic.put("-", ONE);
+    aliphatic.put("*", ONE);
   }
 
   static
   {
-    tiny.put("I", new Integer(0));
-    tiny.put("L", new Integer(0));
-    tiny.put("V", new Integer(0));
-    tiny.put("C", new Integer(0));
-    tiny.put("A", new Integer(1));
-    tiny.put("G", new Integer(1));
-    tiny.put("M", new Integer(0));
-    tiny.put("F", new Integer(0));
-    tiny.put("Y", new Integer(0));
-    tiny.put("W", new Integer(0));
-    tiny.put("H", new Integer(0));
-    tiny.put("K", new Integer(0));
-    tiny.put("R", new Integer(0));
-    tiny.put("E", new Integer(0));
-    tiny.put("Q", new Integer(0));
-    tiny.put("D", new Integer(0));
-    tiny.put("N", new Integer(0));
-    tiny.put("S", new Integer(1));
-    tiny.put("T", new Integer(0));
-    tiny.put("P", new Integer(0));
-    tiny.put("-", new Integer(1));
-    tiny.put("*", new Integer(1));
+    tiny.put("I", ZERO);
+    tiny.put("L", ZERO);
+    tiny.put("V", ZERO);
+    tiny.put("C", ZERO);
+    tiny.put("A", ONE);
+    tiny.put("G", ONE);
+    tiny.put("M", ZERO);
+    tiny.put("F", ZERO);
+    tiny.put("Y", ZERO);
+    tiny.put("W", ZERO);
+    tiny.put("H", ZERO);
+    tiny.put("K", ZERO);
+    tiny.put("R", ZERO);
+    tiny.put("E", ZERO);
+    tiny.put("Q", ZERO);
+    tiny.put("D", ZERO);
+    tiny.put("N", ZERO);
+    tiny.put("S", ONE);
+    tiny.put("T", ZERO);
+    tiny.put("P", ZERO);
+    tiny.put("-", ONE);
+    tiny.put("*", ONE);
   }
 
   static
   {
-    proline.put("I", new Integer(0));
-    proline.put("L", new Integer(0));
-    proline.put("V", new Integer(0));
-    proline.put("C", new Integer(0));
-    proline.put("A", new Integer(0));
-    proline.put("G", new Integer(0));
-    proline.put("M", new Integer(0));
-    proline.put("F", new Integer(0));
-    proline.put("Y", new Integer(0));
-    proline.put("W", new Integer(0));
-    proline.put("H", new Integer(0));
-    proline.put("K", new Integer(0));
-    proline.put("R", new Integer(0));
-    proline.put("E", new Integer(0));
-    proline.put("Q", new Integer(0));
-    proline.put("D", new Integer(0));
-    proline.put("N", new Integer(0));
-    proline.put("S", new Integer(0));
-    proline.put("T", new Integer(0));
-    proline.put("P", new Integer(1));
-    proline.put("-", new Integer(1));
-    proline.put("*", new Integer(1));
+    proline.put("I", ZERO);
+    proline.put("L", ZERO);
+    proline.put("V", ZERO);
+    proline.put("C", ZERO);
+    proline.put("A", ZERO);
+    proline.put("G", ZERO);
+    proline.put("M", ZERO);
+    proline.put("F", ZERO);
+    proline.put("Y", ZERO);
+    proline.put("W", ZERO);
+    proline.put("H", ZERO);
+    proline.put("K", ZERO);
+    proline.put("R", ZERO);
+    proline.put("E", ZERO);
+    proline.put("Q", ZERO);
+    proline.put("D", ZERO);
+    proline.put("N", ZERO);
+    proline.put("S", ZERO);
+    proline.put("T", ZERO);
+    proline.put("P", ONE);
+    proline.put("-", ONE);
+    proline.put("*", ONE);
   }
 
   static
@@ -1368,11 +1219,9 @@ public class ResidueProperties
         propMatrixF[i][j] = 0;
         propMatrixPos[i][j] = 0;
         propMatrixEpos[i][j] = 0;
-        for (Enumeration<String> en = propHash.keys(); en.hasMoreElements();)
+        for (String ph : propHash.keySet())
         {
-          String ph = en.nextElement();
-          Map<String, Integer> pph = (Map<String, Integer>) propHash
-                  .get(ph);
+          Map<String, Integer> pph = propHash.get(ph);
           if (pph.get(ic) != null && pph.get(jc) != null)
           {
             int icp = pph.get(ic).intValue(), jcp = pph.get(jc).intValue();
@@ -1470,22 +1319,8 @@ public class ResidueProperties
     return pog;
   }
 
-  public static Vector getCodons(String res)
-  {
-    if (codonHash.containsKey(res))
-    {
-      return (Vector) codonHash.get(res);
-    }
-
-    return null;
-  }
-
   public static String codonTranslate(String lccodon)
   {
-    if (false)
-    {
-      return _codonTranslate(lccodon);
-    }
     String cdn = codonHash2.get(lccodon.toUpperCase());
     if ("*".equals(cdn))
     {
@@ -1494,25 +1329,6 @@ public class ResidueProperties
     return cdn;
   }
 
-  public static String _codonTranslate(String lccodon)
-  {
-    String codon = lccodon.toUpperCase();
-    // all base ambiguity codes yield an 'X' amino acid residue
-    if (codon.indexOf('X') > -1 || codon.indexOf('N') > -1)
-    {
-      return "X";
-    }
-    for (String key : codonHash.keySet())
-    {
-      if (codonHash.get(key).contains(codon))
-      {
-        return key;
-      }
-    }
-
-    return null;
-  }
-
   public static int[][] getDefaultPeptideMatrix()
   {
     return ResidueProperties.getBLOSUM62();
@@ -1560,10 +1376,10 @@ public class ResidueProperties
     return pog;
   }
 
-  public static Hashtable toDssp3State;
+  public static Hashtable<String, String> toDssp3State;
   static
   {
-    toDssp3State = new Hashtable();
+    toDssp3State = new Hashtable<String, String>();
     toDssp3State.put("H", "H");
     toDssp3State.put("E", "E");
     toDssp3State.put("C", " ");
@@ -1593,7 +1409,7 @@ public class ResidueProperties
       String ssc = ssstring.substring(i, i + 1);
       if (toDssp3State.containsKey(ssc))
       {
-        ss.append((String) toDssp3State.get(ssc));
+        ss.append(toDssp3State.get(ssc));
       }
       else
       {
@@ -2921,51 +2737,47 @@ public class ResidueProperties
 
   }
 
-  public static String getCanonicalAminoAcid(String aa)
+  public static String getCanonicalAminoAcid(String aA)
   {
-    String canonical = modifications.get(aa);
-    return canonical == null ? aa : canonical;
+    String canonical = modifications.get(aA);
+    return canonical == null ? aA : canonical;
   }
 
   // main method generates perl representation of residue property hash
   // / cut here
   public static void main(String[] args)
   {
-    Hashtable aa = new Hashtable();
+    Hashtable<String, Vector<String>> aaProps = new Hashtable<String, Vector<String>>();
     System.out.println("my %aa = {");
     // invert property hashes
-    Enumeration prop = propHash.keys();
-    while (prop.hasMoreElements())
+    for (String pname : propHash.keySet())
     {
-      String pname = (String) prop.nextElement();
-      Hashtable phash = (Hashtable) propHash.get(pname);
-      Enumeration res = phash.keys();
-      while (res.hasMoreElements())
+      Map<String, Integer> phash = propHash.get(pname);
+      for (String rname : phash.keySet())
       {
-        String rname = (String) res.nextElement();
-        Vector aprops = (Vector) aa.get(rname);
+        Vector<String> aprops = aaProps.get(rname);
         if (aprops == null)
         {
-          aprops = new Vector();
-          aa.put(rname, aprops);
+          aprops = new Vector<String>();
+          aaProps.put(rname, aprops);
         }
-        Integer hasprop = (Integer) phash.get(rname);
+        Integer hasprop = phash.get(rname);
         if (hasprop.intValue() == 1)
         {
           aprops.addElement(pname);
         }
       }
     }
-    Enumeration res = aa.keys();
+    Enumeration<String> res = aaProps.keys();
     while (res.hasMoreElements())
     {
-      String rname = (String) res.nextElement();
+      String rname = res.nextElement();
 
       System.out.print("'" + rname + "' => [");
-      Enumeration props = ((Vector) aa.get(rname)).elements();
+      Enumeration<String> props = aaProps.get(rname).elements();
       while (props.hasMoreElements())
       {
-        System.out.print("'" + (String) props.nextElement() + "'");
+        System.out.print("'" + props.nextElement() + "'");
         if (props.hasMoreElements())
         {
           System.out.println(", ");
@@ -2981,15 +2793,15 @@ public class ResidueProperties
   /**
    * Returns a list of residue characters for the specified inputs
    * 
-   * @param nucleotide
+   * @param forNucleotide
    * @param includeAmbiguous
    * @return
    */
-  public static List<String> getResidues(boolean nucleotide,
+  public static List<String> getResidues(boolean forNucleotide,
           boolean includeAmbiguous)
   {
     List<String> result = new ArrayList<String>();
-    if (nucleotide)
+    if (forNucleotide)
     {
       for (String nuc : nucleotideName.keySet())
       {
index 62f3a2e..2be51c2 100644 (file)
@@ -86,6 +86,10 @@ public class TCoffeeColourScheme extends ResidueColourScheme
     seqMap = new IdentityHashMap<SequenceI, Color[]>();
     AnnotatedCollectionI alcontext = alignment instanceof AlignmentI ? alignment
             : alignment.getContext();
+    if (alcontext == null)
+    {
+      return;
+    }
     int w = 0;
     for (AlignmentAnnotation al : alcontext
             .findAnnotation(TCoffeeScoreFile.TCOFFEE_SCORE))
index 771b8a0..81ff739 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.structure;
 
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 
 public interface SequenceListener
@@ -27,7 +28,7 @@ public interface SequenceListener
   // TODO remove this? never called on SequenceListener type
   public void mouseOverSequence(SequenceI sequence, int index, int pos);
 
-  public void highlightSequence(jalview.datamodel.SearchResults results);
+  public void highlightSequence(SearchResultsI results);
 
   // TODO remove this? never called
   public void updateColours(SequenceI sequence, int index);
index f5963de..9662fee 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.structure;
 
 import jalview.datamodel.PDBEntry;
@@ -37,7 +57,6 @@ public class StructureImportSettings
     JMOL_PARSER, JALVIEW_PARSER
   }
 
-
   /**
    * Determines the default file format for structure files to be downloaded
    * from the PDB sequence fetcher. Possible options include: PDB|mmCIF
@@ -49,6 +68,7 @@ public class StructureImportSettings
    * are : JMolParser|JalveiwParser
    */
   private static StructureParser defaultPDBFileParser = StructureParser.JMOL_PARSER;
+
   public static void addSettings(boolean addAlignmentAnnotations,
           boolean processSecStr, boolean externalSecStr)
   {
index 1738f99..65fd5e7 100644 (file)
@@ -31,6 +31,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceI;
 import jalview.ext.jmol.JmolParser;
 import jalview.gui.IProgressIndicator;
@@ -317,17 +318,16 @@ public class StructureSelectionManager
    *          (may be nill, individual elements may be nill)
    * @param pdbFile
    *          - structure data resource
-   * @param paste
+   * @param protocol
    *          - how to resolve data from resource
    * @return null or the structure data parsed as a pdb file
    */
   synchronized public StructureFile setMapping(SequenceI[] sequence,
-          String[] targetChains, String pdbFile, DataSourceType paste)
+          String[] targetChains, String pdbFile, DataSourceType protocol)
   {
-    return setMapping(true, sequence, targetChains, pdbFile, paste);
+    return setMapping(true, sequence, targetChains, pdbFile, protocol);
   }
 
-
   /**
    * create sequence structure mappings between each sequence and the given
    * pdbFile (retrieved via the given protocol).
@@ -348,8 +348,7 @@ public class StructureSelectionManager
    */
   synchronized public StructureFile setMapping(boolean forStructureView,
           SequenceI[] sequenceArray, String[] targetChainIds,
-          String pdbFile,
- DataSourceType sourceType)
+          String pdbFile, DataSourceType sourceType)
   {
     /*
      * There will be better ways of doing this in the future, for now we'll use
@@ -385,27 +384,16 @@ public class StructureSelectionManager
     boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
     try
     {
-
-      boolean isParseWithJMOL = StructureImportSettings
-              .getDefaultPDBFileParser().equalsIgnoreCase(
-                      StructureImportSettings.StructureParser.JMOL_PARSER
-                              .toString());
-      if (isParseWithJMOL || (pdbFile != null && isCIFFile(pdbFile)))
-      {
-        pdb = new JmolParser(addTempFacAnnot, parseSecStr,
-                secStructServices, pdbFile, sourceType);
-      }
-      else
-      {
-        pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
-                pdbFile, sourceType);
-      }
+      pdb = new JmolParser(pdbFile, sourceType);
 
       if (pdb.getId() != null && pdb.getId().trim().length() > 0
-              && sourceType == DataSourceType.FILE)
+              && DataSourceType.FILE == sourceType)
       {
         registerPDBFile(pdb.getId().trim(), pdbFile);
       }
+      // if PDBId is unavailable then skip SIFTS mapping execution path
+      isMapUsingSIFTs = isMapUsingSIFTs && pdb.isPPDBIdAvailable();
+
     } catch (Exception ex)
     {
       ex.printStackTrace();
@@ -429,6 +417,12 @@ public class StructureSelectionManager
     {
       boolean infChain = true;
       final SequenceI seq = sequenceArray[s];
+      SequenceI ds = seq;
+      while (ds.getDatasetSequence() != null)
+      {
+        ds = ds.getDatasetSequence();
+      }
+
       if (targetChainIds != null && targetChainIds[s] != null)
       {
         infChain = false;
@@ -502,8 +496,8 @@ public class StructureSelectionManager
         pdbFile = "INLINE" + pdb.getId();
       }
 
-      ArrayList<StructureMapping> seqToStrucMapping = new ArrayList<StructureMapping>();
-      if (isMapUsingSIFTs)
+      List<StructureMapping> seqToStrucMapping = new ArrayList<StructureMapping>();
+      if (isMapUsingSIFTs && seq.isProtein())
       {
         setProgressBar(null);
         setProgressBar(MessageManager
@@ -519,8 +513,11 @@ public class StructureSelectionManager
                     pdb, maxChain, sqmpping, maxAlignseq);
             seqToStrucMapping.add(siftsMapping);
             maxChain.makeExactMapping(maxAlignseq, seq);
-            maxChain.transferRESNUMFeatures(seq, null);
+            maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
+                                                       // "IEA:SIFTS" ?
             maxChain.transferResidueAnnotation(siftsMapping, sqmpping);
+            ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
+
           } catch (SiftsException e)
           {
             // fall back to NW alignment
@@ -528,18 +525,22 @@ public class StructureSelectionManager
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     targetChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
+            maxChain.makeExactMapping(maxAlignseq, seq);
+            maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
+                                                        // "IEA:Jalview" ?
+            maxChain.transferResidueAnnotation(nwMapping, sqmpping);
+            ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
           }
         }
         else
         {
-          ArrayList<StructureMapping> foundSiftsMappings = new ArrayList<StructureMapping>();
+          List<StructureMapping> foundSiftsMappings = new ArrayList<StructureMapping>();
           for (PDBChain chain : pdb.getChains())
           {
             try
             {
               StructureMapping siftsMapping = getStructureMapping(seq,
-                      pdbFile,
-                      chain.id, pdb, chain, sqmpping, maxAlignseq);
+                      pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq);
               foundSiftsMappings.add(siftsMapping);
             } catch (SiftsException e)
             {
@@ -550,15 +551,21 @@ public class StructureSelectionManager
           {
             seqToStrucMapping.addAll(foundSiftsMappings);
             maxChain.makeExactMapping(maxAlignseq, seq);
-            maxChain.transferRESNUMFeatures(seq, null);
+            maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this
+                                                       // "IEA:SIFTS" ?
             maxChain.transferResidueAnnotation(foundSiftsMappings.get(0),
                     sqmpping);
+            ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0));
           }
           else
           {
             StructureMapping nwMapping = getNWMappings(seq, pdbFile,
                     maxChainId, maxChain, pdb, maxAlignseq);
             seqToStrucMapping.add(nwMapping);
+            maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this
+                                                        // "IEA:Jalview" ?
+            maxChain.transferResidueAnnotation(nwMapping, sqmpping);
+            ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
           }
         }
       }
@@ -567,8 +574,11 @@ public class StructureSelectionManager
         setProgressBar(null);
         setProgressBar(MessageManager
                 .getString("status.obtaining_mapping_with_nw_alignment"));
-        seqToStrucMapping.add(getNWMappings(seq, pdbFile, maxChainId,
-                maxChain, pdb, maxAlignseq));
+        StructureMapping nwMapping = getNWMappings(seq, pdbFile,
+                maxChainId, maxChain, pdb, maxAlignseq);
+        seqToStrucMapping.add(nwMapping);
+        ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
+
       }
 
       if (forStructureView)
@@ -586,29 +596,42 @@ public class StructureSelectionManager
     return "cif".equalsIgnoreCase(fileExt);
   }
 
+  /**
+   * retrieve a mapping for seq from SIFTs using associated DBRefEntry for
+   * uniprot or PDB
+   * 
+   * @param seq
+   * @param pdbFile
+   * @param targetChainId
+   * @param pdb
+   * @param maxChain
+   * @param sqmpping
+   * @param maxAlignseq
+   * @return
+   * @throws SiftsException
+   */
   private StructureMapping getStructureMapping(SequenceI seq,
           String pdbFile, String targetChainId, StructureFile pdb,
           PDBChain maxChain, jalview.datamodel.Mapping sqmpping,
           AlignSeq maxAlignseq) throws SiftsException
   {
-      StructureMapping curChainMapping = siftsClient
-              .getSiftsStructureMapping(seq, pdbFile, targetChainId);
-      try
-      {
+    StructureMapping curChainMapping = siftsClient
+            .getSiftsStructureMapping(seq, pdbFile, targetChainId);
+    try
+    {
       PDBChain chain = pdb.findChain(targetChainId);
       if (chain != null)
       {
         chain.transferResidueAnnotation(curChainMapping, sqmpping);
       }
-      } catch (Exception e)
-      {
-        e.printStackTrace();
-      }
-      return curChainMapping;
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    return curChainMapping;
   }
 
-  private StructureMapping getNWMappings(SequenceI seq,
-          String pdbFile,
+  private StructureMapping getNWMappings(SequenceI seq, String pdbFile,
           String maxChainId, PDBChain maxChain, StructureFile pdb,
           AlignSeq maxAlignseq)
   {
@@ -783,7 +806,7 @@ public class StructureSelectionManager
       return;
     }
 
-    SearchResults results = new SearchResults();
+    SearchResultsI results = new SearchResults();
     for (AtomSpec atom : atoms)
     {
       SequenceI lastseq = null;
@@ -833,7 +856,7 @@ public class StructureSelectionManager
   {
     boolean hasSequenceListeners = handlingVamsasMo
             || !seqmappings.isEmpty();
-    SearchResults results = null;
+    SearchResultsI results = null;
     if (seqPos == -1)
     {
       seqPos = seq.findPosition(indexpos);
index 70fe609..6846de0 100644 (file)
@@ -52,6 +52,10 @@ public abstract class AAStructureBindingModel extends
 
   private StructureSelectionManager ssm;
 
+  /*
+   * distinct PDB entries (pdb files) associated
+   * with sequences
+   */
   private PDBEntry[] pdbEntry;
 
   /*
@@ -76,6 +80,11 @@ public abstract class AAStructureBindingModel extends
   private boolean finishedInit = false;
 
   /**
+   * current set of model filenames loaded in the Jmol instance
+   */
+  protected String[] modelFileNames = null;
+
+  /**
    * Data bean class to simplify parameterisation in superposeStructures
    */
   protected class SuperposeData
@@ -124,22 +133,17 @@ public abstract class AAStructureBindingModel extends
    * @param pdbentry
    * @param sequenceIs
    * @param chains
-   * @param protocol2
+   * @param protocol
    */
   public AAStructureBindingModel(StructureSelectionManager ssm,
-          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
-          DataSourceType protocol2)
+          PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
+          DataSourceType protocol)
   {
     this.ssm = ssm;
     this.sequence = sequenceIs;
     this.nucleotide = Comparison.isNucleotide(sequenceIs);
-    this.chains = chains;
     this.pdbEntry = pdbentry;
-    this.protocol = protocol2;
-    if (chains == null)
-    {
-      this.chains = new String[pdbentry.length][];
-    }
+    this.protocol = protocol;
   }
 
   public StructureSelectionManager getSsm()
@@ -240,24 +244,21 @@ public abstract class AAStructureBindingModel extends
     // TODO: give a more informative title when multiple structures are
     // displayed.
     StringBuilder title = new StringBuilder(64);
-    final PDBEntry pdbEntry = getPdbEntry(0);
+    final PDBEntry pdbe = getPdbEntry(0);
     title.append(viewerName + " view for " + getSequence()[0][0].getName()
-            + ":" + pdbEntry.getId());
+            + ":" + pdbe.getId());
 
     if (verbose)
     {
-      if (pdbEntry.getProperty() != null)
+      String method = (String) pdbe.getProperty("method");
+      if (method != null)
       {
-        if (pdbEntry.getProperty().get("method") != null)
-        {
-          title.append(" Method: ");
-          title.append(pdbEntry.getProperty().get("method"));
-        }
-        if (pdbEntry.getProperty().get("chains") != null)
-        {
-          title.append(" Chain:");
-          title.append(pdbEntry.getProperty().get("chains"));
-        }
+        title.append(" Method: ").append(method);
+      }
+      String chain = (String) pdbe.getProperty("chains");
+      if (chain != null)
+      {
+        title.append(" Chain:").append(chain);
       }
     }
     return title.toString();
@@ -522,6 +523,10 @@ public abstract class AAStructureBindingModel extends
   {
     int refStructure = -1;
     String[] files = getPdbFile();
+    if (files == null)
+    {
+      return -1;
+    }
     for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
     {
       StructureMapping[] mappings = getSsm().getMapping(files[pdbfnum]);
@@ -566,7 +571,11 @@ public abstract class AAStructureBindingModel extends
             }
             structures[pdbfnum].pdbId = mapping.getPdbId();
             structures[pdbfnum].isRna = theSequence.getRNA() != null;
-            // move on to next pdb file
+
+            /*
+             * move on to next pdb file (ignore sequences for other chains
+             * for the same structure)
+             */
             s = seqCountForPdbFile;
             break;
           }
@@ -661,4 +670,12 @@ public abstract class AAStructureBindingModel extends
   {
     this.finishedInit = fi;
   }
+
+  /**
+   * Returns a list of chains mapped in this viewer.
+   * 
+   * @return
+   */
+  public abstract List<String> getChainNames();
+
 }
index 92085c3..c05dac5 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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;
 
 public class ArrayUtils
diff --git a/src/jalview/util/CaseInsensitiveString.java b/src/jalview/util/CaseInsensitiveString.java
new file mode 100644 (file)
index 0000000..b66e80d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+/**
+ * A class to wrap a case insensitive string. For use in collections where we
+ * want to preserve case, but do not want to duplicate upper and lower case
+ * variants
+ */
+public final class CaseInsensitiveString
+{
+  String value;
+
+  public CaseInsensitiveString(String s)
+  {
+    this.value = s;
+  }
+
+  @Override
+  public String toString()
+  {
+    return value;
+  }
+
+  /**
+   * Answers true if the object compared to is a CaseInsensitiveString wrapping
+   * the same string value (ignoring case), or if both wrap a null value, else
+   * false
+   */
+  @Override
+  public boolean equals(Object o)
+  {
+    if (o == null)
+    {
+      return false;
+    }
+    if (!(o instanceof CaseInsensitiveString))
+    {
+      return false;
+    }
+    CaseInsensitiveString obj = (CaseInsensitiveString) o;
+    if (value == null)
+    {
+      return obj.value == null;
+    }
+    return value.equalsIgnoreCase(obj.value);
+  }
+
+  /**
+   * hashCode overriden to guarantee that 'equal' objects have the same hash
+   * code
+   */
+  @Override
+  public int hashCode()
+  {
+    return value == null ? super.hashCode() : value.toUpperCase()
+            .hashCode();
+  }
+}
index 31d1ded..525bfdb 100644 (file)
@@ -142,4 +142,53 @@ public class ColorUtils
             * (maxColour.getBlue() - minColour.getBlue());
     return new Color(r / 255, g / 255, b / 255);
   }
+
+  /**
+   * 'Fades' the given colour towards white by the specified proportion. A
+   * factor of 1 or more results in White, a factor of 0 leaves the colour
+   * unchanged, and a factor between 0 and 1 results in a proportionate change
+   * of RGB values towards (255, 255, 255).
+   * <p>
+   * A negative bleachFactor can be specified to darken the colour towards Black
+   * (0, 0, 0).
+   * 
+   * @param colour
+   * @param bleachFactor
+   * @return
+   */
+  public static Color bleachColour(Color colour, float bleachFactor)
+  {
+    if (bleachFactor >= 1f)
+    {
+      return Color.WHITE;
+    }
+    if (bleachFactor <= -1f)
+    {
+      return Color.BLACK;
+    }
+    if (bleachFactor == 0f)
+    {
+      return colour;
+    }
+
+    int red = colour.getRed();
+    int green = colour.getGreen();
+    int blue = colour.getBlue();
+
+    if (bleachFactor > 0)
+    {
+      red += (255 - red) * bleachFactor;
+      green += (255 - green) * bleachFactor;
+      blue += (255 - blue) * bleachFactor;
+      return new Color(red, green, blue);
+    }
+    else
+    {
+      float factor = 1 + bleachFactor;
+      red *= factor;
+      green *= factor;
+      blue *= factor;
+      return new Color(red, green, blue);
+    }
+  }
 }
index 0beb45b..1326647 100644 (file)
@@ -415,4 +415,29 @@ public class Comparison
             .size()]);
     return isNucleotide(oneDArray);
   }
+
+  /**
+   * Compares two residues either case sensitively or case insensitively
+   * depending on the caseSensitive flag
+   * 
+   * @param c1
+   *          first char
+   * @param c2
+   *          second char to compare with
+   * @param caseSensitive
+   *          if true comparison will be case sensitive otherwise its not
+   * @return
+   */
+  public static boolean isSameResidue(char c1, char c2,
+          boolean caseSensitive)
+  {
+    if (caseSensitive)
+    {
+      return (c1 == c2);
+    }
+    else
+    {
+      return Character.toUpperCase(c1) == Character.toUpperCase(c2);
+    }
+  }
 }
index d5d0cf5..04cb75e 100755 (executable)
@@ -26,11 +26,12 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import com.stevesoft.pat.Regex;
 
@@ -59,6 +60,18 @@ public class DBRefUtils
 
     canonicalSourceNameLookup.put("pdb", DBRefSource.PDB);
     canonicalSourceNameLookup.put("ensembl", DBRefSource.ENSEMBL);
+    // Ensembl Gn and Tr are for Ensembl genomic and transcript IDs as served
+    // from ENA.
+    canonicalSourceNameLookup.put("ensembl-tr", DBRefSource.ENSEMBL);
+    canonicalSourceNameLookup.put("ensembl-gn", DBRefSource.ENSEMBL);
+
+    // Make sure we have lowercase entries for all canonical string lookups
+    Set<String> keys = canonicalSourceNameLookup.keySet();
+    for (String k : keys)
+    {
+      canonicalSourceNameLookup.put(k.toLowerCase(),
+              canonicalSourceNameLookup.get(k));
+    }
 
     dasCoordinateSystemsLookup.put("pdbresnum", DBRefSource.PDB);
     dasCoordinateSystemsLookup.put("uniprot", DBRefSource.UNIPROT);
@@ -87,14 +100,14 @@ public class DBRefUtils
     HashSet<String> srcs = new HashSet<String>();
     for (String src : sources)
     {
-      srcs.add(src);
+      srcs.add(src.toUpperCase());
     }
 
     List<DBRefEntry> res = new ArrayList<DBRefEntry>();
     for (DBRefEntry dbr : dbrefs)
     {
       String source = getCanonicalName(dbr.getSource());
-      if (srcs.contains(source))
+      if (srcs.contains(source.toUpperCase()))
       {
         res.add(dbr);
       }
@@ -235,7 +248,8 @@ public class DBRefUtils
     public boolean matches(DBRefEntry refa, DBRefEntry refb)
     {
       if (refa.getSource() == null
-              || refb.getSource().equals(refa.getSource()))
+              || DBRefUtils.getCanonicalName(refb.getSource()).equals(
+                      DBRefUtils.getCanonicalName(refa.getSource())))
       {
         if (refa.getVersion() == null
                 || refb.getVersion().equals(refa.getVersion()))
@@ -266,7 +280,7 @@ public class DBRefUtils
     @Override
     public boolean matches(DBRefEntry refa, DBRefEntry refb)
     {
-      if (nullOrEqual(refa.getSource(), refb.getSource())
+      if (nullOrEqualSource(refa.getSource(), refb.getSource())
               && nullOrEqual(refa.getVersion(), refb.getVersion())
               && nullOrEqual(refa.getAccessionId(), refb.getAccessionId())
               && nullOrEqual(refa.getMap(), refb.getMap()))
@@ -287,8 +301,10 @@ public class DBRefUtils
     @Override
     public boolean matches(DBRefEntry refa, DBRefEntry refb)
     {
-      if (refa.getSource() != null && refb.getSource() != null
-              && refb.getSource().equals(refa.getSource()))
+      if (refa.getSource() != null
+              && refb.getSource() != null
+              && DBRefUtils.getCanonicalName(refb.getSource()).equals(
+                      DBRefUtils.getCanonicalName(refa.getSource())))
       {
         // We dont care about version
         if (refa.getAccessionId() != null && refb.getAccessionId() != null
@@ -318,8 +334,10 @@ public class DBRefUtils
     @Override
     public boolean matches(DBRefEntry refa, DBRefEntry refb)
     {
-      if (refa.getSource() != null && refb.getSource() != null
-              && refb.getSource().equals(refa.getSource()))
+      if (refa.getSource() != null
+              && refb.getSource() != null
+              && DBRefUtils.getCanonicalName(refb.getSource()).equals(
+                      DBRefUtils.getCanonicalName(refa.getSource())))
       {
         // We dont care about version
         if (refa.getAccessionId() != null && refb.getAccessionId() != null
@@ -354,8 +372,10 @@ public class DBRefUtils
     @Override
     public boolean matches(DBRefEntry refa, DBRefEntry refb)
     {
-      if (refa.getSource() != null && refb.getSource() != null
-              && refb.getSource().equals(refa.getSource()))
+      if (refa.getSource() != null
+              && refb.getSource() != null
+              && DBRefUtils.getCanonicalName(refb.getSource()).equals(
+                      DBRefUtils.getCanonicalName(refa.getSource())))
       {
         // We dont care about version
         // if ((refa.getVersion()==null || refb.getVersion()==null)
@@ -393,8 +413,10 @@ public class DBRefUtils
     @Override
     public boolean matches(DBRefEntry refa, DBRefEntry refb)
     {
-      if (refa.getSource() != null && refb.getSource() != null
-              && refb.getSource().equals(refa.getSource()))
+      if (refa.getSource() != null
+              && refb.getSource() != null
+              && DBRefUtils.getCanonicalName(refb.getSource()).equals(
+                      DBRefUtils.getCanonicalName(refa.getSource())))
       {
         // We dont care about version
 
@@ -485,9 +507,7 @@ public class DBRefUtils
           PDBEntry pdbr = new PDBEntry();
           pdbr.setId(pdbid);
           pdbr.setType(PDBEntry.Type.PDB);
-          pdbr.setProperty(new Hashtable());
           pdbr.setChainCode(chaincode);
-          // pdbr.getProperty().put("CHAIN", chaincode);
           seq.addPDBId(pdbr);
         }
         else
@@ -521,7 +541,28 @@ public class DBRefUtils
     {
       return true;
     }
-    return (o1 == null ? o2.equals(o1) : o1.equals(o2));
+    return o1.equals(o2);
+  }
+
+  /**
+   * canonicalise source string before comparing. null is always wildcard
+   * 
+   * @param o1
+   *          - null or source string to compare
+   * @param o2
+   *          - null or source string to compare
+   * @return true if either o1 or o2 are null, or o1 equals o2 under
+   *         DBRefUtils.getCanonicalName
+   *         (o1).equals(DBRefUtils.getCanonicalName(o2))
+   */
+  public static boolean nullOrEqualSource(String o1, String o2)
+  {
+    if (o1 == null || o2 == null)
+    {
+      return true;
+    }
+    return DBRefUtils.getCanonicalName(o1).equals(
+            DBRefUtils.getCanonicalName(o2));
   }
 
   /**
@@ -569,4 +610,127 @@ public class DBRefUtils
     return matches;
   }
 
+  /**
+   * promote direct database references to primary for nucleotide or protein
+   * sequences if they have an appropriate primary ref
+   * <table>
+   * <tr>
+   * <th>Seq Type</th>
+   * <th>Primary DB</th>
+   * <th>Direct which will be promoted</th>
+   * </tr>
+   * <tr align=center>
+   * <td>peptides</td>
+   * <td>Ensembl</td>
+   * <td>Uniprot</td>
+   * </tr>
+   * <tr align=center>
+   * <td>peptides</td>
+   * <td>Ensembl</td>
+   * <td>Uniprot</td>
+   * </tr>
+   * <tr align=center>
+   * <td>dna</td>
+   * <td>Ensembl</td>
+   * <td>ENA</td>
+   * </tr>
+   * </table>
+   * 
+   * @param sequence
+   */
+  public static void ensurePrimaries(SequenceI sequence)
+  {
+    List<DBRefEntry> pr = sequence.getPrimaryDBRefs();
+    if (pr.size() == 0)
+    {
+      // nothing to do
+      return;
+    }
+    List<DBRefEntry> selfs = new ArrayList<DBRefEntry>();
+    {
+      DBRefEntry[] selfArray = selectDbRefs(!sequence.isProtein(),
+              sequence.getDBRefs());
+      if (selfArray == null || selfArray.length == 0)
+      {
+        // nothing to do
+        return;
+      }
+      selfs.addAll(Arrays.asList(selfArray));
+    }
+
+    // filter non-primary refs
+    for (DBRefEntry p : pr)
+    {
+      while (selfs.contains(p))
+      {
+        selfs.remove(p);
+      }
+    }
+    List<DBRefEntry> toPromote = new ArrayList<DBRefEntry>();
+
+    for (DBRefEntry p : pr)
+    {
+      List<String> promType = new ArrayList<String>();
+      if (sequence.isProtein())
+      {
+        switch (getCanonicalName(p.getSource()))
+        {
+        case DBRefSource.UNIPROT:
+          // case DBRefSource.UNIPROTKB:
+          // case DBRefSource.UP_NAME:
+          // search for and promote ensembl
+          promType.add(DBRefSource.ENSEMBL);
+          break;
+        case DBRefSource.ENSEMBL:
+          // search for and promote Uniprot
+          promType.add(DBRefSource.UNIPROT);
+          break;
+        }
+      }
+      else
+      {
+        // TODO: promote transcript refs
+      }
+
+      // collate candidates and promote them
+      DBRefEntry[] candidates = selectRefs(
+              selfs.toArray(new DBRefEntry[0]),
+              promType.toArray(new String[0]));
+      if (candidates != null)
+      {
+        for (DBRefEntry cand : candidates)
+        {
+          if (cand.hasMap())
+          {
+            if (cand.getMap().getTo() != null
+                    && cand.getMap().getTo() != sequence)
+            {
+              // can't promote refs with mappings to other sequences
+              continue;
+            }
+            if (cand.getMap().getMap().getFromLowest() != sequence
+                    .getStart()
+                    && cand.getMap().getMap().getFromHighest() != sequence
+                            .getEnd())
+            {
+              // can't promote refs with mappings from a region of this sequence
+              // - eg CDS
+              continue;
+            }
+          }
+          // and promote
+          cand.setVersion(p.getVersion() + " (promoted)");
+          selfs.remove(cand);
+          toPromote.add(cand);
+          if (!cand.isPrimaryCandidate())
+          {
+            System.out.println("Warning: Couldn't promote dbref "
+                    + cand.toString() + " for sequence "
+                    + sequence.toString());
+          }
+        }
+      }
+    }
+  }
+
 }
index 9582e2e..284ec10 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.text.ParseException;
index d14e4ad..389afcd 100755 (executable)
@@ -26,6 +26,8 @@
  */
 package jalview.util;
 
+import java.util.Arrays;
+
 /**
  * DOCUMENT ME!
  * 
@@ -664,30 +666,22 @@ public class Format
   }
 
   /**
-   * DOCUMENT ME!
+   * Returns a string consisting of n repeats of character c
    * 
    * @param c
-   *          DOCUMENT ME!
    * @param n
-   *          DOCUMENT ME!
    * 
-   * @return DOCUMENT ME!
+   * @return
    */
-  private static String repeat(char c, int n)
+  static String repeat(char c, int n)
   {
     if (n <= 0)
     {
       return "";
     }
-
-    StringBuffer s = new StringBuffer(n);
-
-    for (int i = 0; i < n; i++)
-    {
-      s.append(c);
-    }
-
-    return s.toString();
+    char[] chars = new char[n];
+    Arrays.fill(chars, c);
+    return new String(chars);
   }
 
   /**
@@ -947,4 +941,49 @@ public class Format
   {
     return formatString;
   }
+
+  /**
+   * Bespoke method to format percentage float value to the specified number of
+   * decimal places. Avoids use of general-purpose format parsers as a
+   * processing hotspot.
+   * 
+   * @param sb
+   * @param value
+   * @param dp
+   */
+  public static void appendPercentage(StringBuilder sb, float value, int dp)
+  {
+    /*
+     * rounding first
+     */
+    double d = value;
+    long factor = 1L;
+    for (int i = 0; i < dp; i++)
+    {
+      factor *= 10;
+    }
+    d *= factor;
+    d += 0.5;
+
+    /*
+     * integer part
+     */
+    value = (float) (d / factor);
+    sb.append((long) value);
+
+    /*
+     * decimal places
+     */
+    if (dp > 0)
+    {
+      sb.append(".");
+      while (dp > 0)
+      {
+        value = value - (int) value;
+        value *= 10;
+        sb.append((int) value);
+        dp--;
+      }
+    }
+  }
 }
index 991a20a..a5a9460 100644 (file)
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*
  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
@@ -17,7 +17,7 @@
  * 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.IOException;
index d8b6a7b..71e2c7e 100755 (executable)
@@ -79,9 +79,9 @@ public class ImageMaker
 
   public enum TYPE
   {
-    EPS("EPS", MessageManager.getString("label.eps_file"), getEPSChooser()), PNG(
-            "PNG", MessageManager.getString("label.png_image"),
-            getPNGChooser()), SVG("SVG", "SVG", getSVGChooser());
+    EPS("EPS", MessageManager.getString("label.eps_file"), getEPSChooser()),
+    PNG("PNG", MessageManager.getString("label.png_image"), getPNGChooser()),
+    SVG("SVG", "SVG", getSVGChooser());
 
     private JalviewFileChooser chooser;
 
diff --git a/src/jalview/util/LinkedIdentityHashSet.java b/src/jalview/util/LinkedIdentityHashSet.java
new file mode 100644 (file)
index 0000000..bce540f
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.util.AbstractSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+
+/**
+ * Order preserving Set based on System.identityHashCode() for an object, which
+ * also supports Object->index lookup.
+ * 
+ * @author Jim Procter (2016) based on Evgeniy Dorofeev's response: via
+ *         https://stackoverflow.com/questions/17276658/linkedidentityhashset
+ * 
+ */
+public class LinkedIdentityHashSet<E> extends AbstractSet<E>
+{
+  LinkedHashMap<IdentityWrapper, IdentityWrapper> set = new LinkedHashMap<IdentityWrapper, IdentityWrapper>();
+
+  static class IdentityWrapper
+  {
+    Object obj;
+
+    public int p;
+
+    IdentityWrapper(Object obj, int p)
+    {
+      this.obj = obj;
+      this.p = p;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+      return this.obj == obj;
+    }
+
+    @Override
+    public int hashCode()
+    {
+      return System.identityHashCode(obj);
+    }
+  }
+
+  @Override
+  public boolean add(E e)
+  {
+    IdentityWrapper el = (new IdentityWrapper(e, set.size()));
+    // Map.putIfAbsent() from Java 8
+    // return set.putIfAbsent(el, el) == null;
+    return putIfAbsent(el, el) == null;
+  }
+
+  /**
+   * If the specified key is not already associated with a value (or is mapped
+   * to null) associates it with the given value and returns null, else returns
+   * the current value.
+   * 
+   * Method added for Java 7 (can remove for Java 8)
+   * 
+   * @param key
+   * @param value
+   * @return
+   * @see https
+   *      ://docs.oracle.com/javase/8/docs/api/java/util/Map.html#putIfAbsent
+   *      -K-V-
+   */
+  private IdentityWrapper putIfAbsent(IdentityWrapper key,
+          IdentityWrapper value)
+  {
+    IdentityWrapper v = set.get(key);
+    if (v == null)
+    {
+      v = set.put(key, value);
+    }
+    return v;
+  }
+
+  @Override
+  public Iterator<E> iterator()
+  {
+    return new Iterator<E>()
+    {
+      final Iterator<IdentityWrapper> se = set.keySet().iterator();
+
+      @Override
+      public boolean hasNext()
+      {
+        return se.hasNext();
+      }
+
+      @SuppressWarnings("unchecked")
+      @Override
+      public E next()
+      {
+        return (E) se.next().obj;
+      }
+
+      @Override
+      public void remove()
+      {
+        // Java 8 default behaviour
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+  @Override
+  public int size()
+  {
+    return set.size();
+  }
+
+  /**
+   * Lookup the index for e in the set
+   * 
+   * @param e
+   * @return position of e in the set when it was added.
+   */
+  public int indexOf(E e)
+  {
+    return set.get(e).p;
+  }
+}
index cae968e..58abdc3 100644 (file)
@@ -342,7 +342,8 @@ public class MapList
    */
   public static List<int[]> coalesceRanges(final List<int[]> ranges)
   {
-    if (ranges == null || ranges.size() < 2) {
+    if (ranges == null || ranges.size() < 2)
+    {
       return ranges;
     }
 
@@ -353,7 +354,7 @@ public class MapList
     lastRange = new int[] { lastRange[0], lastRange[1] };
     merged.add(lastRange);
     boolean first = true;
-    
+
     for (final int[] range : ranges)
     {
       if (first)
@@ -387,7 +388,8 @@ public class MapList
        * if next range is in the same direction as last and contiguous,
        * just update the end position of the last range
        */
-      boolean sameDirection = range[1] == range[0] || direction == lastDirection;
+      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]);
@@ -404,7 +406,7 @@ public class MapList
         lastDirection = (range[1] == range[0]) ? lastDirection : direction;
       }
     }
-    
+
     return changed ? merged : ranges;
   }
 
@@ -1103,4 +1105,14 @@ public class MapList
     return forwardStrand;
   }
 
+  /**
+   * 
+   * @return true if from, or to is a three to 1 mapping
+   */
+  public boolean isTripletMap()
+  {
+    return (toRatio == 3 && fromRatio == 1)
+            || (fromRatio == 3 && toRatio == 1);
+  }
+
 }
index 515ff51..f35339c 100644 (file)
@@ -31,8 +31,9 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
-import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -194,7 +195,7 @@ public final class MappingUtils
       /*
        * Determine all mappings from this position to mapped sequences.
        */
-      SearchResults sr = buildSearchResults(seq, seqpos, mappings);
+      SearchResultsI sr = buildSearchResults(seq, seqpos, mappings);
 
       if (!sr.isEmpty())
       {
@@ -266,10 +267,10 @@ public final class MappingUtils
    * @param seqmappings
    * @return
    */
-  public static SearchResults buildSearchResults(SequenceI seq, int index,
+  public static SearchResultsI buildSearchResults(SequenceI seq, int index,
           List<AlignedCodonFrame> seqmappings)
   {
-    SearchResults results = new SearchResults();
+    SearchResultsI results = new SearchResults();
     addSearchResults(results, seq, index, seqmappings);
     return results;
   }
@@ -283,7 +284,7 @@ public final class MappingUtils
    * @param index
    * @param seqmappings
    */
-  public static void addSearchResults(SearchResults results, SequenceI seq,
+  public static void addSearchResults(SearchResultsI results, SequenceI seq,
           int index, List<AlignedCodonFrame> seqmappings)
   {
     if (index >= seq.getStart() && index <= seq.getEnd())
@@ -374,16 +375,17 @@ public final class MappingUtils
               /*
                * Found a sequence mapping. Locate the start/end mapped residues.
                */
-              List<AlignedCodonFrame> mapping = Arrays.asList(new AlignedCodonFrame[] { acf });
-              SearchResults sr = buildSearchResults(selected,
+              List<AlignedCodonFrame> mapping = Arrays
+                      .asList(new AlignedCodonFrame[] { acf });
+              SearchResultsI sr = buildSearchResults(selected,
                       startResiduePos, mapping);
-              for (Match m : sr.getResults())
+              for (SearchResultMatchI m : sr.getResults())
               {
                 mappedStartResidue = m.getStart();
                 mappedEndResidue = m.getEnd();
               }
               sr = buildSearchResults(selected, endResiduePos, mapping);
-              for (Match m : sr.getResults())
+              for (SearchResultMatchI m : sr.getResults())
               {
                 mappedStartResidue = Math.min(mappedStartResidue,
                         m.getStart());
@@ -555,9 +557,9 @@ public final class MappingUtils
    * @param fromGapChar
    */
   protected static void mapHiddenColumns(int[] hidden,
-          List<AlignedCodonFrame> mappings,
-          ColumnSelection mappedColumns, List<SequenceI> fromSequences,
-          List<SequenceI> toSequences, char fromGapChar)
+          List<AlignedCodonFrame> mappings, ColumnSelection mappedColumns,
+          List<SequenceI> fromSequences, List<SequenceI> toSequences,
+          char fromGapChar)
   {
     for (int col = hidden[0]; col <= hidden[1]; col++)
     {
@@ -589,9 +591,9 @@ public final class MappingUtils
    * @param fromGapChar
    */
   protected static void mapColumn(int col,
-          List<AlignedCodonFrame> mappings,
-          ColumnSelection mappedColumns, List<SequenceI> fromSequences,
-          List<SequenceI> toSequences, char fromGapChar)
+          List<AlignedCodonFrame> mappings, ColumnSelection mappedColumns,
+          List<SequenceI> fromSequences, List<SequenceI> toSequences,
+          char fromGapChar)
   {
     int[] mappedTo = findMappedColumns(col, mappings, fromSequences,
             toSequences, fromGapChar);
@@ -646,9 +648,8 @@ public final class MappingUtils
        * Get the residue position and find the mapped position.
        */
       int residuePos = fromSeq.findPosition(col);
-      SearchResults sr = buildSearchResults(fromSeq, residuePos,
-              mappings);
-      for (Match m : sr.getResults())
+      SearchResultsI sr = buildSearchResults(fromSeq, residuePos, mappings);
+      for (SearchResultMatchI m : sr.getResults())
       {
         int mappedStartResidue = m.getStart();
         int mappedEndResidue = m.getEnd();
@@ -757,9 +758,19 @@ public final class MappingUtils
     return findMappingsForSequenceAndOthers(sequence, mappings, null);
   }
 
+  /**
+   * Returns a list of any mappings that are from or to the given (aligned or
+   * dataset) sequence, optionally limited to mappings involving one of a given
+   * list of sequences.
+   * 
+   * @param sequence
+   * @param mappings
+   * @param filterList
+   * @return
+   */
   public static List<AlignedCodonFrame> findMappingsForSequenceAndOthers(
           SequenceI sequence, List<AlignedCodonFrame> mappings,
-          AlignmentI alignment)
+          List<SequenceI> filterList)
   {
     List<AlignedCodonFrame> result = new ArrayList<AlignedCodonFrame>();
     if (sequence == null || mappings == null)
@@ -770,14 +781,14 @@ public final class MappingUtils
     {
       if (mapping.involvesSequence(sequence))
       {
-        if (alignment != null)
+        if (filterList != null)
         {
-          for (SequenceI otherseq : alignment.getSequences())
+          for (SequenceI otherseq : filterList)
           {
+            SequenceI otherDataset = otherseq.getDatasetSequence();
             if (otherseq == sequence
-                    || (otherseq.getDatasetSequence() != null && (otherseq
-                            .getDatasetSequence() == sequence || otherseq
-                            .getDatasetSequence() == sequence
+                    || otherseq == sequence.getDatasetSequence()
+                    || (otherDataset != null && (otherDataset == sequence || otherDataset == sequence
                             .getDatasetSequence())))
             {
               // skip sequences in subset which directly relate to sequence
@@ -883,7 +894,7 @@ public final class MappingUtils
     {
       return ranges;
     }
-  
+
     int[] copy = Arrays.copyOf(ranges, ranges.length);
     int sxpos = -1;
     int cdspos = 0;
@@ -911,7 +922,7 @@ public final class MappingUtils
         break;
       }
     }
-  
+
     if (sxpos > 0)
     {
       /*
index 85a27f6..49dc7ff 100644 (file)
@@ -30,6 +30,10 @@ import java.awt.event.MouseEvent;
  */
 public class Platform
 {
+  private static Boolean isAMac = null;
+
+  private static Boolean isHeadless = null;
+
   /**
    * sorry folks - Macs really are different
    * 
@@ -37,15 +41,21 @@ public class Platform
    */
   public static boolean isAMac()
   {
-    return java.lang.System.getProperty("os.name").indexOf("Mac") > -1;
+    if (isAMac == null)
+    {
+      isAMac = System.getProperty("os.name").indexOf("Mac") > -1;
+    }
+    return isAMac.booleanValue();
 
   }
 
   public static boolean isHeadless()
   {
-    String hdls = java.lang.System.getProperty("java.awt.headless");
-
-    return hdls != null && hdls.equals("true");
+    if (isHeadless == null)
+    {
+      isHeadless = "true".equals(System.getProperty("java.awt.headless"));
+    }
+    return isHeadless;
   }
 
   /**
@@ -79,16 +89,38 @@ public class Platform
   }
 
   /**
-   * Answers true if the mouse event has Meta-down (on Mac) or Ctrl-down (on
-   * other o/s)
+   * Answers true if the mouse event has Meta-down (Command key on Mac) or
+   * Ctrl-down (on other o/s). Note this answers _false_ if the Ctrl key is
+   * pressed instead of the Meta/Cmd key on Mac. To test for Ctrl-click on Mac,
+   * you can use e.isPopupTrigger().
    * 
    * @param e
    * @return
    */
   public static boolean isControlDown(MouseEvent e)
   {
-    if (isAMac())
+    boolean aMac = isAMac();
+    return isControlDown(e, aMac);
+  }
+
+  /**
+   * Overloaded version of method (to allow unit testing)
+   * 
+   * @param e
+   * @param aMac
+   * @return
+   */
+  protected static boolean isControlDown(MouseEvent e, boolean aMac)
+  {
+    if (aMac)
     {
+      /*
+       * answer false for right mouse button
+       */
+      if (e.isPopupTrigger())
+      {
+        return false;
+      }
       return (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() & e
               .getModifiers()) != 0;
       // could we use e.isMetaDown() here?
index c1ef153..62fd56e 100755 (executable)
@@ -670,7 +670,7 @@ public class QuickSort
     final int length = arr.length;
     Integer[] indices = makeIndexArray(length);
     Arrays.sort(indices, new IntComparator(arr, ascending));
-  
+
     /*
      * Copy the array values as per the sorted indices
      */
@@ -681,7 +681,7 @@ public class QuickSort
       sortedInts[i] = arr[indices[i]];
       sortedObjects[i] = s[indices[i]];
     }
-  
+
     /*
      * And copy the sorted values back into the arrays
      */
@@ -707,7 +707,7 @@ public class QuickSort
     final int length = arr.length;
     Integer[] indices = makeIndexArray(length);
     Arrays.sort(indices, new ExternalComparator(arr, ascending));
-  
+
     /*
      * Copy the array values as per the sorted indices
      */
@@ -718,7 +718,7 @@ public class QuickSort
       sortedStrings[i] = arr[indices[i]];
       sortedObjects[i] = s[indices[i]];
     }
-  
+
     /*
      * And copy the sorted values back into the arrays
      */
@@ -743,7 +743,7 @@ public class QuickSort
     final int length = arr.length;
     Integer[] indices = makeIndexArray(length);
     Arrays.sort(indices, new DoubleComparator(arr, ascending));
-  
+
     /*
      * Copy the array values as per the sorted indices
      */
@@ -754,7 +754,7 @@ public class QuickSort
       sortedDoubles[i] = arr[indices[i]];
       sortedObjects[i] = s[indices[i]];
     }
-  
+
     /*
      * And copy the sorted values back into the arrays
      */
diff --git a/src/jalview/util/SparseCount.java b/src/jalview/util/SparseCount.java
new file mode 100644 (file)
index 0000000..7fd9792
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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 jalview.ext.android.SparseIntArray;
+import jalview.ext.android.SparseShortArray;
+
+/**
+ * A class to count occurrences of characters with minimal memory footprint.
+ * Sparse arrays of short values are used to hold the counts, with automatic
+ * promotion to arrays of int if any count exceeds the maximum value for a
+ * short.
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class SparseCount
+{
+  private static final int DEFAULT_PROFILE_SIZE = 2;
+
+  /*
+   * array of keys (chars) and values (counts)
+   * held either as shorts or (if shorts overflow) as ints 
+   */
+  private SparseShortArray shortProfile;
+
+  private SparseIntArray intProfile;
+
+  /*
+   * flag is set true after short overflow occurs
+   */
+  private boolean useInts;
+
+  /**
+   * Constructor which initially creates a new sparse array of short values to
+   * hold counts.
+   * 
+   * @param profileSize
+   */
+  public SparseCount(int profileSize)
+  {
+    this.shortProfile = new SparseShortArray(profileSize);
+  }
+
+  /**
+   * Constructor which allocates an initial count array for only two distinct
+   * values (the array will grow if needed)
+   */
+  public SparseCount()
+  {
+    this(DEFAULT_PROFILE_SIZE);
+  }
+
+  /**
+   * Adds the given value for the given key (or sets the initial value), and
+   * returns the new value
+   * 
+   * @param key
+   * @param value
+   */
+  public int add(int key, int value)
+  {
+    int newValue = 0;
+    if (useInts)
+    {
+      newValue = intProfile.add(key, value);
+    }
+    else
+    {
+      try {
+        newValue = shortProfile.add(key, value);
+      } catch (ArithmeticException e) {
+        handleOverflow();
+        newValue = intProfile.add(key, value);
+      }
+    }
+    return newValue;
+  }
+
+  /**
+   * Switch from counting shorts to counting ints
+   */
+  synchronized void handleOverflow()
+  {
+    int size = shortProfile.size();
+    intProfile = new SparseIntArray(size);
+    for (int i = 0; i < size; i++)
+    {
+      short key = shortProfile.keyAt(i);
+      short value = shortProfile.valueAt(i);
+      intProfile.put(key, value);
+    }
+    shortProfile = null;
+    useInts = true;
+  }
+
+  /**
+   * Returns the size of the profile (number of distinct items counted)
+   * 
+   * @return
+   */
+  public int size()
+  {
+    return useInts ? intProfile.size() : shortProfile.size();
+  }
+
+  /**
+   * Returns the value for the key (zero if no such key)
+   * 
+   * @param key
+   * @return
+   */
+  public int get(int key)
+  {
+    return useInts ? intProfile.get(key) : shortProfile.get(key);
+  }
+
+  /**
+   * Sets the value for the given key
+   * 
+   * @param key
+   * @param value
+   */
+  public void put(int key, int value)
+  {
+    if (useInts)
+    {
+      intProfile.put(key, value);
+    }
+    else
+    {
+      shortProfile.put(key, value);
+    }
+  }
+
+  public int keyAt(int k)
+  {
+    return useInts ? intProfile.keyAt(k) : shortProfile.keyAt(k);
+  }
+
+  public int valueAt(int k)
+  {
+    return useInts ? intProfile.valueAt(k) : shortProfile.valueAt(k);
+  }
+
+  /**
+   * Answers true if this object wraps arrays of int values, false if using
+   * short values
+   * 
+   * @return
+   */
+  boolean isUsingInt()
+  {
+    return useInts;
+  }
+}
index ccc2012..b5ab40d 100644 (file)
@@ -248,7 +248,7 @@ public class StringUtils
     }
     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
diff --git a/src/jalview/util/UrlConstants.java b/src/jalview/util/UrlConstants.java
new file mode 100644 (file)
index 0000000..1910bff
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * A class to hold constants relating to Url links used in Jalview
+ */
+public class UrlConstants
+{
+
+  /*
+   * Sequence ID string
+   */
+  public static final String DB_ACCESSION = "DB_ACCESSION";
+
+  /*
+   * Sequence Name string
+   */
+  public static final String SEQUENCE_ID = "SEQUENCE_ID";
+
+  /*
+   * Default sequence URL link string for EMBL-EBI search
+   */
+  public static final String EMBLEBI_STRING = "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$";
+
+  /*
+   * Default sequence URL link string for SRS 
+   */
+  public static final String SRS_STRING = "SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry";
+
+  /*
+   * not instantiable
+   */
+  private UrlConstants()
+  {
+  }
+}
index 4297090..3ee6432 100644 (file)
  */
 package jalview.util;
 
+import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.SequenceI;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
 import java.util.Vector;
 
 public class UrlLink
@@ -30,17 +39,33 @@ public class UrlLink
    * Jalview 2.4 extension allows regular expressions to be used to parse ID
    * strings and replace the result in the URL. Regex's operate on the whole ID
    * string given to the matchURL method, if no regex is supplied, then only
-   * text following the first pipe symbol will be susbstituted. Usage
+   * text following the first pipe symbol will be substituted. Usage
    * documentation todo.
    */
-  private String url_suffix, url_prefix, target, label, regexReplace;
+
+  // Internal constants
+  private static final String SEP = "|";
+
+  private static final String DELIM = "$";
+
+  private String urlSuffix;
+
+  private String urlPrefix;
+
+  private String target;
+
+  private String label;
+
+  private String regexReplace;
 
   private boolean dynamic = false;
 
+  private boolean usesDBaccession = false;
+
   private String invalidMessage = null;
 
   /**
-   * parse the given linkString of the form '<label>|<url>' into parts url may
+   * parse the given linkString of the form '<label>SEP<url>' into parts url may
    * contain a string $SEQUENCE_ID<=optional regex=>$ where <=optional regex=>
    * must be of the form =/<perl style regex>/=$
    * 
@@ -48,81 +73,37 @@ public class UrlLink
    */
   public UrlLink(String link)
   {
-    int sep = link.indexOf("|"), psqid = link.indexOf("$SEQUENCE_ID");
+    int sep = link.indexOf(SEP);
+    int psqid = link.indexOf(DELIM + DB_ACCESSION);
+    int nsqid = link.indexOf(DELIM + SEQUENCE_ID);
     if (psqid > -1)
     {
       dynamic = true;
-      int p = sep;
-      do
-      {
-        sep = p;
-        p = link.indexOf("|", sep + 1);
-      } while (p > sep && p < psqid);
-      // Assuming that the URL itself does not contain any '|' symbols
-      // sep now contains last pipe symbol position prior to any regex symbols
-      label = link.substring(0, sep);
-      if (label.indexOf("|") > -1)
-      {
-        // | terminated database name / www target at start of Label
-        target = label.substring(0, label.indexOf("|"));
-      }
-      else if (label.indexOf(" ") > 2)
-      {
-        // space separated Label - matches database name
-        target = label.substring(0, label.indexOf(" "));
-      }
-      else
-      {
-        target = label;
-      }
-      // Parse URL : Whole URL string first
-      url_prefix = link.substring(sep + 1, psqid);
-      if (link.indexOf("$SEQUENCE_ID=/") == psqid
-              && (p = link.indexOf("/=$", psqid + 14)) > psqid + 14)
-      {
-        // Extract Regex and suffix
-        url_suffix = link.substring(p + 3);
-        regexReplace = link.substring(psqid + 14, p);
-        try
-        {
-          com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex.perlCode("/"
-                  + regexReplace + "/");
-          if (rg == null)
-          {
-            invalidMessage = "Invalid Regular Expression : '"
-                    + regexReplace + "'\n";
-          }
-        } catch (Exception e)
-        {
-          invalidMessage = "Invalid Regular Expression : '" + regexReplace
-                  + "'\n";
-        }
-      }
-      else
-      {
-        regexReplace = null;
-        // verify format is really correct.
-        if (link.indexOf("$SEQUENCE_ID$") == psqid)
-        {
-          url_suffix = link.substring(psqid + 13);
-          regexReplace = null;
-        }
-        else
-        {
-          invalidMessage = "Warning: invalid regex structure for URL link : "
-                  + link;
-        }
-      }
+      usesDBaccession = true;
+
+      sep = parseTargetAndLabel(sep, psqid, link);
+
+      parseUrl(link, DB_ACCESSION, psqid, sep);
+    }
+    else if (nsqid > -1)
+    {
+      dynamic = true;
+      sep = parseTargetAndLabel(sep, nsqid, link);
+
+      parseUrl(link, SEQUENCE_ID, nsqid, sep);
     }
     else
     {
       target = link.substring(0, sep);
-      label = link.substring(0, sep = link.lastIndexOf("|"));
-      url_prefix = link.substring(sep + 1);
+      sep = link.lastIndexOf(SEP);
+      label = link.substring(0, sep);
+      urlPrefix = link.substring(sep + 1).trim();
       regexReplace = null; // implies we trim any prefix if necessary //
-      // regexReplace=".*\\|?(.*)";
-      url_suffix = null;
+      urlSuffix = null;
     }
+
+    label = label.trim();
+    target = target.trim();
   }
 
   /**
@@ -130,7 +111,7 @@ public class UrlLink
    */
   public String getUrl_suffix()
   {
-    return url_suffix;
+    return urlSuffix;
   }
 
   /**
@@ -138,7 +119,7 @@ public class UrlLink
    */
   public String getUrl_prefix()
   {
-    return url_prefix;
+    return urlPrefix;
   }
 
   /**
@@ -185,6 +166,34 @@ public class UrlLink
   }
 
   /**
+   * 
+   * @return whether link is dynamic
+   */
+  public boolean isDynamic()
+  {
+    return dynamic;
+  }
+
+  /**
+   * 
+   * @return whether link uses DB Accession id
+   */
+  public boolean usesDBAccession()
+  {
+    return usesDBaccession;
+  }
+
+  /**
+   * Set the label
+   * 
+   * @param newlabel
+   */
+  public void setLabel(String newlabel)
+  {
+    this.label = newlabel;
+  }
+
+  /**
    * return one or more URL strings by applying regex to the given idstring
    * 
    * @param idstring
@@ -209,7 +218,7 @@ public class UrlLink
           {
             // take whole regex
             return new String[] { rg.stringMatched(),
-                url_prefix + rg.stringMatched() + url_suffix };
+                urlPrefix + rg.stringMatched() + urlSuffix };
           } /*
              * else if (ns==1) { // take only subgroup match return new String[]
              * { rg.stringMatched(1), url_prefix+rg.stringMatched(1)+url_suffix
@@ -250,7 +259,7 @@ public class UrlLink
                 if (mtch.length() > 0)
                 {
                   subs.addElement(mtch);
-                  subs.addElement(url_prefix + mtch + url_suffix);
+                  subs.addElement(urlPrefix + mtch + urlSuffix);
                 }
                 s = r;
               }
@@ -259,8 +268,8 @@ public class UrlLink
                 if (rg.matchedFrom(s) > -1)
                 {
                   subs.addElement(rg.stringMatched(s));
-                  subs.addElement(url_prefix + rg.stringMatched(s)
-                          + url_suffix);
+                  subs.addElement(urlPrefix + rg.stringMatched(s)
+                          + urlSuffix);
                 }
                 s++;
               }
@@ -281,29 +290,254 @@ public class UrlLink
         }
       }
       /* Otherwise - trim off any 'prefix' - pre 2.4 Jalview behaviour */
-      if (idstring.indexOf("|") > -1)
+      if (idstring.indexOf(SEP) > -1)
       {
-        idstring = idstring.substring(idstring.lastIndexOf("|") + 1);
+        idstring = idstring.substring(idstring.lastIndexOf(SEP) + 1);
       }
 
       // just return simple url substitution.
-      return new String[] { idstring, url_prefix + idstring + url_suffix };
+      return new String[] { idstring, urlPrefix + idstring + urlSuffix };
     }
     else
     {
-      return new String[] { "", url_prefix };
+      return new String[] { "", urlPrefix };
     }
   }
 
+  @Override
   public String toString()
   {
+    String var = (usesDBaccession ? DB_ACCESSION : SEQUENCE_ID);
+
     return label
-            + "|"
-            + url_prefix
-            + (dynamic ? ("$SEQUENCE_ID" + ((regexReplace != null) ? "="
-                    + regexReplace + "=$" : "$")) : "")
-            + ((url_suffix == null) ? "" : url_suffix);
+            + SEP
+            + urlPrefix
+            + (dynamic ? (DELIM + var + ((regexReplace != null) ? "="
+                    + regexReplace + "=" + DELIM : DELIM)) : "")
+            + ((urlSuffix == null) ? "" : urlSuffix);
+  }
+
+  /**
+   * 
+   * @param firstSep
+   *          Location of first occurrence of separator in link string
+   * @param psqid
+   *          Position of sequence id or name in link string
+   * @param link
+   *          Link string containing database name and url
+   * @return Position of last separator symbol prior to any regex symbols
+   */
+  protected int parseTargetAndLabel(int firstSep, int psqid, String link)
+  {
+    int p = firstSep;
+    int sep = firstSep;
+    do
+    {
+      sep = p;
+      p = link.indexOf(SEP, sep + 1);
+    } while (p > sep && p < psqid);
+    // Assuming that the URL itself does not contain any SEP symbols
+    // sep now contains last pipe symbol position prior to any regex symbols
+    label = link.substring(0, sep);
+    if (label.indexOf(SEP) > -1)
+    {
+      // SEP terminated database name / www target at start of Label
+      target = label.substring(0, label.indexOf(SEP));
+    }
+    else if (label.indexOf(" ") > 2)
+    {
+      // space separated Label - matches database name
+      target = label.substring(0, label.indexOf(" "));
+    }
+    else
+    {
+      target = label;
+    }
+    return sep;
+  }
+
+  /**
+   * Parse the URL part of the link string
+   * 
+   * @param link
+   *          Link string containing database name and url
+   * @param varName
+   *          Name of variable in url string (e.g. SEQUENCE_ID, SEQUENCE_NAME)
+   * @param sqidPos
+   *          Position of id or name in link string
+   * @param sep
+   *          Position of separator in link string
+   */
+  protected void parseUrl(String link, String varName, int sqidPos, int sep)
+  {
+    urlPrefix = link.substring(sep + 1, sqidPos).trim();
+
+    // delimiter at start of regex: e.g. $SEQUENCE_ID=/
+    String startDelimiter = DELIM + varName + "=/";
+
+    // delimiter at end of regex: /=$
+    String endDelimiter = "/=" + DELIM;
+
+    int startLength = startDelimiter.length();
+
+    // Parse URL : Whole URL string first
+    int p = link.indexOf(endDelimiter, sqidPos + startLength);
+
+    if (link.indexOf(startDelimiter) == sqidPos
+            && (p > sqidPos + startLength))
+    {
+      // Extract Regex and suffix
+      urlSuffix = link.substring(p + endDelimiter.length());
+      regexReplace = link.substring(sqidPos + startLength, p);
+      try
+      {
+        com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex.perlCode("/"
+                + regexReplace + "/");
+        if (rg == null)
+        {
+          invalidMessage = "Invalid Regular Expression : '" + regexReplace
+                  + "'\n";
+        }
+      } catch (Exception e)
+      {
+        invalidMessage = "Invalid Regular Expression : '" + regexReplace
+                + "'\n";
+      }
+    }
+    else
+    {
+      // no regex
+      regexReplace = null;
+      // verify format is really correct.
+      if (link.indexOf(DELIM + varName + DELIM) == sqidPos)
+      {
+        urlSuffix = link.substring(sqidPos + startLength - 1);
+        regexReplace = null;
+      }
+      else
+      {
+        invalidMessage = "Warning: invalid regex structure for URL link : "
+                + link;
+      }
+    }
+  }
+
+  /**
+   * Create a set of URL links for a sequence
+   * 
+   * @param seq
+   *          The sequence to create links for
+   * @param linkset
+   *          Map of links: key = id + SEP + link, value = [target, label, id,
+   *          link]
+   */
+  public void createLinksFromSeq(final SequenceI seq,
+          Map<String, List<String>> linkset)
+  {
+    if (seq != null && dynamic)
+    {
+      createDynamicLinks(seq, linkset);
+    }
+    else
+    {
+      createStaticLink(linkset);
+    }
+  }
+
+  /**
+   * Create a static URL link
+   * 
+   * @param linkset
+   *          Map of links: key = id + SEP + link, value = [target, label, id,
+   *          link]
+   */
+  protected void createStaticLink(Map<String, List<String>> linkset)
+  {
+    if (!linkset.containsKey(label + SEP + getUrl_prefix()))
+    {
+      // Add a non-dynamic link
+      linkset.put(label + SEP + getUrl_prefix(),
+              Arrays.asList(target, label, null, getUrl_prefix()));
+    }
+  }
+
+  /**
+   * Create dynamic URL links
+   * 
+   * @param seq
+   *          The sequence to create links for
+   * @param linkset
+   *          Map of links: key = id + SEP + link, value = [target, label, id,
+   *          link]
+   */
+  protected void createDynamicLinks(final SequenceI seq,
+          Map<String, List<String>> linkset)
+  {
+    // collect id string too
+    String id = seq.getName();
+    String descr = seq.getDescription();
+    if (descr != null && descr.length() < 1)
+    {
+      descr = null;
+    }
+
+    if (usesDBAccession()) // link is ID
+    {
+      // collect matching db-refs
+      DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
+              new String[] { target });
+
+      // if there are any dbrefs which match up with the link
+      if (dbr != null)
+      {
+        for (int r = 0; r < dbr.length; r++)
+        {
+          // create Bare ID link for this URL
+          createBareURLLink(dbr[r].getAccessionId(), true, linkset);
+        }
+      }
+    }
+    else if (!usesDBAccession() && id != null) // link is name
+    {
+      // create Bare ID link for this URL
+      createBareURLLink(id, false, linkset);
+    }
+
+    // Create urls from description but only for URL links which are regex
+    // links
+    if (descr != null && getRegexReplace() != null)
+    {
+      // create link for this URL from description where regex matches
+      createBareURLLink(descr, false, linkset);
+    }
+  }
 
+  /*
+   * Create a bare URL Link
+   * Returns map where key = id + SEP + link, and value = [target, label, id, link]
+   */
+  protected void createBareURLLink(String id, Boolean combineLabel,
+          Map<String, List<String>> linkset)
+  {
+    String[] urls = makeUrls(id, true);
+    if (urls != null)
+    {
+      for (int u = 0; u < urls.length; u += 2)
+      {
+        if (!linkset.containsKey(urls[u] + SEP + urls[u + 1]))
+        {
+          String thisLabel = label;
+          if (combineLabel)
+          {
+            // incorporate label with idstring
+            thisLabel = label + SEP + urls[u];
+          }
+
+          linkset.put(urls[u] + SEP + urls[u + 1],
+                  Arrays.asList(target, thisLabel, urls[u], urls[u + 1]));
+        }
+      }
+    }
   }
 
   private static void testUrls(UrlLink ul, String idstring, String[] urls)
@@ -341,7 +575,8 @@ public class UrlLink
      * "PF3|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/PFAM:(.+)/=$"
      * , "NOTFER|http://notfer.org/$SEQUENCE_ID=/(?<!\\s)(.+)/=$",
      */
-    "NESTED|http://nested/$SEQUENCE_ID=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
+    "NESTED|http://nested/$" + DB_ACCESSION
+            + "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
     String[] idstrings = new String[] {
     /*
      * //"LGUL_human", //"QWIQW_123123", "uniprot|why_do+_12313_foo",
@@ -382,15 +617,4 @@ public class UrlLink
       }
     }
   }
-
-  public boolean isDynamic()
-  {
-    // TODO Auto-generated method stub
-    return dynamic;
-  }
-
-  public void setLabel(String newlabel)
-  {
-    this.label = newlabel;
-  }
 }
index 19ebf45..fecccb0 100644 (file)
@@ -36,7 +36,8 @@ import jalview.datamodel.Annotation;
 import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenSequences;
-import jalview.datamodel.SearchResults;
+import jalview.datamodel.ProfilesI;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
@@ -44,7 +45,6 @@ import jalview.datamodel.SequenceI;
 import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.PIDColourScheme;
-import jalview.schemes.ResidueProperties;
 import jalview.structure.CommandListener;
 import jalview.structure.StructureSelectionManager;
 import jalview.structure.VamsasSource;
@@ -58,6 +58,7 @@ import jalview.workers.ConsensusThread;
 import jalview.workers.StrucConsensusThread;
 
 import java.awt.Color;
+import java.beans.PropertyChangeSupport;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.BitSet;
@@ -612,7 +613,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     boolean recalc = false;
     if (cs != null)
     {
-      cs.setConservationApplied(recalc = getConservationSelected());
+      recalc = getConservationSelected();
       if (getAbovePIDThreshold() || cs instanceof PIDColourScheme
               || cs instanceof Blosum62ColourScheme)
       {
@@ -629,6 +630,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
         cs.setConsensus(hconsensus);
         cs.setConservation(hconservation);
       }
+      cs.setConservationApplied(getConservationSelected());
       cs.alignmentChanged(alignment, hiddenRepSequences);
     }
     if (getColourAppliesToAllGroups())
@@ -699,7 +701,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   /**
    * results of alignment consensus analysis for visible portion of view
    */
-  protected Hashtable[] hconsensus = null;
+  protected ProfilesI hconsensus = null;
 
   /**
    * results of cDNA complement consensus visible portion of view
@@ -733,7 +735,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public void setSequenceConsensusHash(Hashtable[] hconsensus)
+  public void setSequenceConsensusHash(ProfilesI hconsensus)
   {
     this.hconsensus = hconsensus;
   }
@@ -745,7 +747,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public Hashtable[] getSequenceConsensusHash()
+  public ProfilesI getSequenceConsensusHash()
   {
     return hconsensus;
   }
@@ -807,7 +809,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public void updateConservation(final AlignmentViewPanel ap)
   {
     // see note in mantis : issue number 8585
-    if (alignment.isNucleotide() || conservation == null
+    if (alignment.isNucleotide()
+            || (conservation == null && quality == null)
             || !autoCalculateConsensus)
     {
       return;
@@ -913,6 +916,37 @@ public abstract class AlignmentViewport implements AlignViewportI,
     return false;
   }
 
+  public void setAlignment(AlignmentI align)
+  {
+    this.alignment = align;
+  }
+
+  /**
+   * Clean up references when this viewport is closed
+   */
+  @Override
+  public void dispose()
+  {
+    /*
+     * defensively null out references to large objects in case
+     * this object is not garbage collected (as if!)
+     */
+    consensus = null;
+    complementConsensus = null;
+    strucConsensus = null;
+    conservation = null;
+    quality = null;
+    groupConsensus = null;
+    groupConservation = null;
+    hconsensus = null;
+    hcomplementConsensus = null;
+    // colour scheme may hold reference to consensus
+    globalColourScheme = null;
+    // TODO remove listeners from changeSupport?
+    changeSupport = null;
+    setAlignment(null);
+  }
+
   @Override
   public boolean isClosed()
   {
@@ -1107,6 +1141,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
+  public boolean hasSelectedColumns()
+  {
+    ColumnSelection columnSelection = getColumnSelection();
+    return columnSelection != null && columnSelection.hasSelectedColumns();
+  }
+
+  @Override
   public boolean hasHiddenColumns()
   {
     return colSel != null && colSel.hasHiddenColumns();
@@ -1233,10 +1274,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
     return ignoreGapsInConsensusCalculation;
   }
 
-  // / property change stuff
-
+  // property change stuff
   // JBPNote Prolly only need this in the applet version.
-  private final java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
+  private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
           this);
 
   protected boolean showConservation = true;
@@ -1537,7 +1577,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public boolean isHiddenRepSequence(SequenceI seq)
   {
     return (hiddenRepSequences != null && hiddenRepSequences
-                    .containsKey(seq));
+            .containsKey(seq));
   }
 
   /**
@@ -1828,8 +1868,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
       if (cs.conservationApplied())
       {
         cs.setConservation(Conservation.calculateConservation("All",
-                ResidueProperties.propHash, 3, alignment.getSequences(), 0,
-                alignment.getWidth(), false, getConsPercGaps(), false));
+                alignment.getSequences(), 0, alignment.getWidth(), false,
+                getConsPercGaps(), false));
       }
     }
 
@@ -2678,7 +2718,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
    *          the SearchResults to add to
    * @return the offset (below top of visible region) of the matched sequence
    */
-  protected int findComplementScrollTarget(SearchResults sr)
+  protected int findComplementScrollTarget(SearchResultsI sr)
   {
     final AlignViewportI complement = getCodingComplement();
     if (complement == null || !complement.isFollowHighlight())
@@ -2730,7 +2770,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
       }
       seqMappings = MappingUtils
               .findMappingsForSequenceAndOthers(sequence, mappings,
-                      getCodingComplement().getAlignment());
+                      getCodingComplement().getAlignment().getSequences());
       if (!seqMappings.isEmpty())
       {
         break;
@@ -2760,11 +2800,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
   {
     int sgs, sge;
-    if (sg != null
-            && (sgs = sg.getStartRes()) >= 0
+    if (sg != null && (sgs = sg.getStartRes()) >= 0
             && sg.getStartRes() <= (sge = sg.getEndRes())
-            && (colSel == null || colSel.getSelected() == null || colSel
-                    .getSelected().size() == 0))
+            && !this.hasSelectedColumns())
     {
       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
       {
@@ -2782,5 +2820,56 @@ public abstract class AlignmentViewport implements AlignViewportI,
     }
   }
 
+  /**
+   * hold status of current selection group - defined on alignment or not.
+   */
+  private boolean selectionIsDefinedGroup = false;
+
 
+  @Override
+  public boolean isSelectionDefinedGroup()
+  {
+    if (selectionGroup == null)
+    {
+      return false;
+    }
+    if (isSelectionGroupChanged(true))
+    {
+      selectionIsDefinedGroup = false;
+      List<SequenceGroup> gps = alignment.getGroups();
+      if (gps == null || gps.size() == 0)
+      {
+        selectionIsDefinedGroup = false;
+      }
+      else
+      {
+        selectionIsDefinedGroup = gps.contains(selectionGroup);
+      }
+    }
+    return selectionGroup.getContext() == alignment
+            || selectionIsDefinedGroup;
+  }
+
+  /**
+   * null, or currently highlighted results on this view
+   */
+  private SearchResultsI searchResults = null;
+
+  @Override
+  public boolean hasSearchResults()
+  {
+    return searchResults != null;
+  }
+
+  @Override
+  public void setSearchResults(SearchResultsI results)
+  {
+    searchResults = results;
+  }
+
+  @Override
+  public SearchResultsI getSearchResults()
+  {
+    return searchResults;
+  }
 }
index d813fe2..c1ad465 100644 (file)
@@ -288,8 +288,12 @@ public abstract class FeatureRendererModel implements
           continue;
         }
 
-        if ((features[i].getBegin() <= res)
-                && (features[i].getEnd() >= res))
+        // check if start/end are at res, and if not a contact feature, that res
+        // lies between start and end
+        if ((features[i].getBegin() == res || features[i].getEnd() == res)
+                || (!features[i].isContactFeature()
+                        && (features[i].getBegin() < res) && (features[i]
+                        .getEnd() >= res)))
         {
           tmp.add(features[i]);
         }
@@ -564,15 +568,22 @@ public abstract class FeatureRendererModel implements
     return fc.isColored(sequenceFeature);
   }
 
+  /**
+   * Answers true if the feature type is currently selected to be displayed,
+   * else false
+   * 
+   * @param type
+   * @return
+   */
   protected boolean showFeatureOfType(String type)
   {
-    return av.getFeaturesDisplayed().isVisible(type);
+    return type == null ? false : av.getFeaturesDisplayed().isVisible(type);
   }
 
   @Override
   public void setColour(String featureType, FeatureColourI col)
   {
-     featureColours.put(featureType, col);
+    featureColours.put(featureType, col);
   }
 
   public void setTransparency(float value)
index 771c492..0ad8726 100644 (file)
@@ -95,6 +95,7 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
       ourAnnots.clear();
     }
   }
+
   // TODO: allow GUI to query workers associated with annotation to add items to
   // annotation label panel popup menu
 
@@ -118,8 +119,10 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
     float max = Float.MIN_VALUE;
     float min = Float.MAX_VALUE;
     boolean set = false;
-    for (Annotation a : anns) {
-      if (a != null) {
+    for (Annotation a : anns)
+    {
+      if (a != null)
+      {
         set = true;
         float val = a.value;
         max = Math.max(max, val);
index f804a19..beee1eb 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.workers;
 
 import jalview.api.AlignViewportI;
@@ -32,11 +52,11 @@ public class AlignmentAnnotationFactory
   {
     // TODO need an interface for AlignFrame by which to access
     // its AlignViewportI and AlignmentViewPanel
-    AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame() ;
+    AlignmentViewPanel currentAlignFrame = Jalview.getCurrentAlignFrame().alignPanel;
     if (currentAlignFrame != null)
     {
-      newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
-              .getAlignPanels().get(0), counter);
+      newCalculator(currentAlignFrame.getAlignViewport(),
+              currentAlignFrame, counter);
     }
     else
     {
@@ -69,7 +89,7 @@ public class AlignmentAnnotationFactory
   {
     // TODO need an interface for AlignFrame by which to access
     // its AlignViewportI and AlignmentViewPanel
-    AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame() ;
+    AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame();
     if (currentAlignFrame != null)
     {
       newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
@@ -91,8 +111,7 @@ public class AlignmentAnnotationFactory
    *          provider of AlignmentAnnotation for the alignment
    */
   public static void newCalculator(AlignViewportI viewport,
-          AlignmentViewPanel panel,
-          AnnotationProviderI calculator)
+          AlignmentViewPanel panel, AnnotationProviderI calculator)
   {
     new AnnotationWorker(viewport, panel, calculator);
   }
index bd24461..d11429e 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.workers;
 
 import jalview.api.FeatureRenderer;
index 2f73cb5..dd56aaf 100644 (file)
@@ -168,8 +168,7 @@ class ColumnCounterWorker extends AlignCalcWorker
      */
     AlignmentAnnotation ann = alignViewport.getAlignment()
             .findOrCreateAnnotation(counter.getName(),
-                    counter.getDescription(), false, null,
-                    null);
+                    counter.getDescription(), false, null, null);
     ann.description = counter.getDescription();
     ann.showAllColLabels = true;
     ann.scaleColLabel = true;
index 529df6f..431fbec 100644 (file)
@@ -96,7 +96,6 @@ public class ComplementConsensusThread extends ConsensusThread
    * @param consensusData
    *          the computed consensus data
    */
-  @Override
   protected void deriveConsensus(AlignmentAnnotation consensusAnnotation,
           Hashtable[] consensusData)
   {
@@ -104,4 +103,16 @@ public class ComplementConsensusThread extends ConsensusThread
             alignViewport.isShowSequenceLogo(), getSequences().length);
   }
 
+  @Override
+  public void updateResultAnnotation(boolean immediate)
+  {
+    AlignmentAnnotation consensus = getConsensusAnnotation();
+    Hashtable[] hconsensus = getViewportConsensus();
+    if (immediate || !calcMan.isWorking(this) && consensus != null
+            && hconsensus != null)
+    {
+      deriveConsensus(consensus, hconsensus);
+    }
+  }
+
 }
index 5f0ec84..debe45d 100644 (file)
@@ -26,11 +26,10 @@ import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 
-import java.util.Hashtable;
-
 public class ConsensusThread extends AlignCalcWorker
 {
   public ConsensusThread(AlignViewportI alignViewport,
@@ -125,10 +124,11 @@ public class ConsensusThread extends AlignCalcWorker
    */
   protected void computeConsensus(AlignmentI alignment)
   {
-    Hashtable[] hconsensus = new Hashtable[alignment.getWidth()];
 
     SequenceI[] aseqs = getSequences();
-    AAFrequency.calculate(aseqs, 0, alignment.getWidth(), hconsensus, true);
+    int width = alignment.getWidth();
+    ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0,
+            width, true);
 
     alignViewport.setSequenceConsensusHash(hconsensus);
     setColourSchemeConsensus(hconsensus);
@@ -145,7 +145,7 @@ public class ConsensusThread extends AlignCalcWorker
   /**
    * @param hconsensus
    */
-  protected void setColourSchemeConsensus(Hashtable[] hconsensus)
+  protected void setColourSchemeConsensus(ProfilesI hconsensus)
   {
     ColourSchemeI globalColourScheme = alignViewport
             .getGlobalColourScheme();
@@ -178,7 +178,7 @@ public class ConsensusThread extends AlignCalcWorker
   public void updateResultAnnotation(boolean immediate)
   {
     AlignmentAnnotation consensus = getConsensusAnnotation();
-    Hashtable[] hconsensus = getViewportConsensus();
+    ProfilesI hconsensus = (ProfilesI) getViewportConsensus();
     if (immediate || !calcMan.isWorking(this) && consensus != null
             && hconsensus != null)
     {
@@ -192,15 +192,18 @@ public class ConsensusThread extends AlignCalcWorker
    * 
    * @param consensusAnnotation
    *          the annotation to be populated
-   * @param consensusData
+   * @param hconsensus
    *          the computed consensus data
    */
   protected void deriveConsensus(AlignmentAnnotation consensusAnnotation,
-          Hashtable[] consensusData)
+          ProfilesI hconsensus)
   {
+
     long nseq = getSequences().length;
-    AAFrequency.completeConsensus(consensusAnnotation, consensusData, 0,
-            consensusData.length, alignViewport.isIgnoreGapsConsensus(),
+    AAFrequency.completeConsensus(consensusAnnotation, hconsensus,
+            hconsensus.getStartColumn(),
+            hconsensus.getEndColumn() + 1,
+            alignViewport.isIgnoreGapsConsensus(),
             alignViewport.isShowSequenceLogo(), nseq);
   }
 
@@ -209,8 +212,9 @@ public class ConsensusThread extends AlignCalcWorker
    * 
    * @return
    */
-  protected Hashtable[] getViewportConsensus()
+  protected Object getViewportConsensus()
   {
+    // TODO convert ComplementConsensusThread to use Profile
     return alignViewport.getSequenceConsensusHash();
   }
 }
index 5c303fd..e71c4f5 100644 (file)
@@ -95,7 +95,6 @@ public class ConservationThread extends AlignCalcWorker
       try
       {
         cons = Conservation.calculateConservation("All",
-                jalview.schemes.ResidueProperties.propHash, 3,
                 alignment.getSequences(), 0, alWidth - 1, false,
                 ConsPercGaps, quality != null);
       } catch (IndexOutOfBoundsException x)
index aa4a283..3a080ec 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.workers;
 
 import jalview.datamodel.SequenceFeature;
index 3ba0e34..fd511dc 100644 (file)
@@ -29,15 +29,19 @@ import jalview.datamodel.Mapping;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.CutAndPasteTransfer;
+import jalview.gui.DasSourceBrowser;
 import jalview.gui.Desktop;
 import jalview.gui.FeatureSettings;
 import jalview.gui.IProgressIndicator;
 import jalview.gui.OOMWarning;
+import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
 import jalview.ws.dbsources.das.api.jalviewSourceI;
+import jalview.ws.dbsources.das.datamodel.DasSequenceSource;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.List;
@@ -45,6 +49,7 @@ import java.util.StringTokenizer;
 import java.util.Vector;
 
 import uk.ac.ebi.picr.model.UPEntry;
+import uk.ac.ebi.www.picr.AccessionMappingService.AccessionMapperServiceLocator;
 
 /**
  * Implements a runnable for validating a sequence against external databases
@@ -55,21 +60,19 @@ import uk.ac.ebi.picr.model.UPEntry;
  */
 public class DBRefFetcher implements Runnable
 {
+  private static final String NEWLINE = System.lineSeparator();
+
   public interface FetchFinishedListenerI
   {
     void finished();
   }
 
-  private List<FetchFinishedListenerI> listeners;
-
   SequenceI[] dataset;
 
   IProgressIndicator progressWindow;
 
   CutAndPasteTransfer output = new CutAndPasteTransfer();
 
-  StringBuffer sbuffer = new StringBuffer();
-
   boolean running = false;
 
   /**
@@ -77,17 +80,19 @@ public class DBRefFetcher implements Runnable
    */
   uk.ac.ebi.www.picr.AccessionMappingService.AccessionMapperInterface picrClient = null;
 
-  // /This will be a collection of Vectors of sequenceI refs.
+  // This will be a collection of Vectors of sequenceI refs.
   // The key will be the seq name or accession id of the seq
-  Hashtable seqRefs;
+  Hashtable<String, Vector<SequenceI>> seqRefs;
 
   DbSourceProxy[] dbSources;
 
   SequenceFetcher sfetcher;
 
+  private List<FetchFinishedListenerI> listeners;
+
   private SequenceI[] alseqs;
 
-  /**
+  /*
    * when true - retrieved sequences will be trimmed to cover longest derived
    * alignment sequence
    */
@@ -110,7 +115,8 @@ public class DBRefFetcher implements Runnable
    */
   public DBRefFetcher(SequenceI[] seqs,
           IProgressIndicator progressIndicatorFrame,
-          DbSourceProxy[] sources, FeatureSettings featureSettings, boolean isNucleotide)
+          DbSourceProxy[] sources, FeatureSettings featureSettings,
+          boolean isNucleotide)
   {
     listeners = new ArrayList<FetchFinishedListenerI>();
     this.progressWindow = progressIndicatorFrame;
@@ -137,56 +143,74 @@ public class DBRefFetcher implements Runnable
     trimDsSeqs = Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true);
     if (sources == null)
     {
-      // af.featureSettings_actionPerformed(null);
-      String[] defdb = null, otherdb = sfetcher
-              .getDbInstances(jalview.ws.dbsources.das.datamodel.DasSequenceSource.class);
-      List<DbSourceProxy> selsources = new ArrayList<DbSourceProxy>();
-      Vector<jalviewSourceI> dasselsrc = (featureSettings != null) ? featureSettings
-              .getSelectedSources() : new jalview.gui.DasSourceBrowser()
-              .getSelectedSources();
-      Enumeration<jalviewSourceI> en = dasselsrc.elements();
-      while (en.hasMoreElements())
+      setDatabaseSources(featureSettings, isNucleotide);
+    }
+    else
+    {
+      // we assume the caller knows what they're doing and ensured that all the
+      // db source names are valid
+      dbSources = sources;
+    }
+  }
+
+  /**
+   * Helper method to configure the list of database sources to query
+   * 
+   * @param featureSettings
+   * @param forNucleotide
+   */
+  void setDatabaseSources(FeatureSettings featureSettings,
+          boolean forNucleotide)
+  {
+    // af.featureSettings_actionPerformed(null);
+    String[] defdb = null;
+    List<DbSourceProxy> selsources = new ArrayList<DbSourceProxy>();
+    Vector<jalviewSourceI> dasselsrc = (featureSettings != null) ? featureSettings
+            .getSelectedSources() : new DasSourceBrowser()
+            .getSelectedSources();
+
+    for (jalviewSourceI src : dasselsrc)
+    {
+      List<DbSourceProxy> sp = src.getSequenceSourceProxies();
+      if (sp != null)
       {
-        jalviewSourceI src = en.nextElement();
-        List<DbSourceProxy> sp = src.getSequenceSourceProxies();
-        if (sp != null)
+        selsources.addAll(sp);
+        if (sp.size() > 1)
         {
-          selsources.addAll(sp);
-          if (sp.size() > 1)
-          {
-            Cache.log.debug("Added many Db Sources for :" + src.getTitle());
-          }
+          Cache.log.debug("Added many Db Sources for :" + src.getTitle());
         }
       }
-      // select appropriate databases based on alignFrame context.
-      if (isNucleotide)
-      {
-        defdb = DBRefSource.DNACODINGDBS;
-      }
-      else
-      {
-        defdb = DBRefSource.PROTEINDBS;
-      }
-      List<DbSourceProxy> srces = new ArrayList<DbSourceProxy>();
-      for (String ddb : defdb)
+    }
+    // select appropriate databases based on alignFrame context.
+    if (forNucleotide)
+    {
+      defdb = DBRefSource.DNACODINGDBS;
+    }
+    else
+    {
+      defdb = DBRefSource.PROTEINDBS;
+    }
+    List<DbSourceProxy> srces = new ArrayList<DbSourceProxy>();
+    for (String ddb : defdb)
+    {
+      List<DbSourceProxy> srcesfordb = sfetcher.getSourceProxy(ddb);
+      if (srcesfordb != null)
       {
-        List<DbSourceProxy> srcesfordb = sfetcher.getSourceProxy(ddb);
-        if (srcesfordb != null)
+        for (DbSourceProxy src : srcesfordb)
         {
-          srces.addAll(srcesfordb);
+          if (!srces.contains(src))
+          {
+            srces.addAll(srcesfordb);
+          }
         }
       }
-
-      // append the selected sequence sources to the default dbs
-      srces.addAll(selsources);
-      dbSources = srces.toArray(new DbSourceProxy[0]);
-    }
-    else
-    {
-      // we assume the caller knows what they're doing and ensured that all the
-      // db source names are valid
-      dbSources = sources;
     }
+    // append the PDB data source, since it is 'special', catering for both
+    // nucleotide and protein
+    // srces.addAll(sfetcher.getSourceProxy(DBRefSource.PDB));
+
+    srces.addAll(selsources);
+    dbSources = srces.toArray(new DbSourceProxy[srces.size()]);
   }
 
   /**
@@ -221,7 +245,7 @@ public class DBRefFetcher implements Runnable
     }
     // append additional sources
     DbSourceProxy[] otherdb = sfetcher
-            .getDbSourceProxyInstances(jalview.ws.dbsources.das.datamodel.DasSequenceSource.class);
+            .getDbSourceProxyInstances(DasSequenceSource.class);
     if (otherdb != null && otherdb.length > 0)
     {
       DbSourceProxy[] newsrc = new DbSourceProxy[dbSources.length
@@ -240,6 +264,9 @@ public class DBRefFetcher implements Runnable
    */
   public void fetchDBRefs(boolean waitTillFinished)
   {
+    // TODO can we not simply write
+    // if (waitTillFinished) { run(); } else { new Thread(this).start(); }
+
     Thread thread = new Thread(this);
     thread.start();
     running = true;
@@ -271,10 +298,10 @@ public class DBRefFetcher implements Runnable
   {
     key = key.toUpperCase();
 
-    Vector seqs;
+    Vector<SequenceI> seqs;
     if (seqRefs.containsKey(key))
     {
-      seqs = (Vector) seqRefs.get(key);
+      seqs = seqRefs.get(key);
 
       if (seqs != null && !seqs.contains(seq))
       {
@@ -282,14 +309,14 @@ public class DBRefFetcher implements Runnable
       }
       else if (seqs == null)
       {
-        seqs = new Vector();
+        seqs = new Vector<SequenceI>();
         seqs.addElement(seq);
       }
 
     }
     else
     {
-      seqs = new Vector();
+      seqs = new Vector<SequenceI>();
       seqs.addElement(seq);
     }
 
@@ -314,13 +341,13 @@ public class DBRefFetcher implements Runnable
     {
       progressWindow.setProgressBar(
               MessageManager.getString("status.fetching_db_refs"),
-            startTime);
+              startTime);
     }
     try
     {
       if (Cache.getDefault("DBREFFETCH_USEPICR", false))
       {
-        picrClient = new uk.ac.ebi.www.picr.AccessionMappingService.AccessionMapperServiceLocator()
+        picrClient = new AccessionMapperServiceLocator()
                 .getAccessionMapperPort();
       }
     } catch (Exception e)
@@ -328,149 +355,145 @@ public class DBRefFetcher implements Runnable
       System.err.println("Couldn't locate PICR service instance.\n");
       e.printStackTrace();
     }
+
+    Vector<SequenceI> sdataset = new Vector<SequenceI>(
+            Arrays.asList(dataset));
+    List<String> warningMessages = new ArrayList<String>();
+
     int db = 0;
-    Vector sdataset = new Vector();
-    for (int s = 0; s < dataset.length; s++)
-    {
-      sdataset.addElement(dataset[s]);
-    }
     while (sdataset.size() > 0 && db < dbSources.length)
     {
-      int maxqlen = 1; // default number of queries made to at one time
-      System.err.println("Verifying against " + dbSources[db].getDbName());
-      boolean dn = false;
+      int maxqlen = 1; // default number of queries made at one time
+      System.out.println("Verifying against " + dbSources[db].getDbName());
 
       // iterate through db for each remaining un-verified sequence
       SequenceI[] currSeqs = new SequenceI[sdataset.size()];
       sdataset.copyInto(currSeqs);// seqs that are to be validated against
       // dbSources[db]
-      Vector queries = new Vector(); // generated queries curSeq
-      seqRefs = new Hashtable();
+      Vector<String> queries = new Vector<String>(); // generated queries curSeq
+      seqRefs = new Hashtable<String, Vector<SequenceI>>();
 
       int seqIndex = 0;
 
-      jalview.ws.seqfetcher.DbSourceProxy dbsource = dbSources[db];
+      DbSourceProxy dbsource = dbSources[db];
+      // for moment, we dumbly iterate over all retrieval sources for a
+      // particular database
+      // TODO: introduce multithread multisource queries and logic to remove a
+      // query from other sources if any source for a database returns a
+      // record
+      maxqlen = dbsource.getMaximumQueryCount();
+
+      while (queries.size() > 0 || seqIndex < currSeqs.length)
       {
-        // for moment, we dumbly iterate over all retrieval sources for a
-        // particular database
-        // TODO: introduce multithread multisource queries and logic to remove a
-        // query from other sources if any source for a database returns a
-        // record
-        maxqlen = dbsource.getMaximumQueryCount();
-
-        while (queries.size() > 0 || seqIndex < currSeqs.length)
+        if (queries.size() > 0)
         {
-          if (queries.size() > 0)
-          {
-            // Still queries to make for current seqIndex
-            StringBuffer queryString = new StringBuffer("");
-            int numq = 0, nqSize = (maxqlen > queries.size()) ? queries
-                    .size() : maxqlen;
+          // Still queries to make for current seqIndex
+          StringBuffer queryString = new StringBuffer("");
+          int numq = 0;
+          int nqSize = (maxqlen > queries.size()) ? queries.size()
+                  : maxqlen;
 
-            while (queries.size() > 0 && numq < nqSize)
-            {
-              String query = (String) queries.elementAt(0);
-              if (dbsource.isValidReference(query))
-              {
-                queryString.append((numq == 0) ? "" : dbsource
-                        .getAccessionSeparator());
-                queryString.append(query);
-                numq++;
-              }
-              // remove the extracted query string
-              queries.removeElementAt(0);
-            }
-            // make the queries and process the response
-            AlignmentI retrieved = null;
-            try
-            {
-              if (jalview.bin.Cache.log.isDebugEnabled())
-              {
-                jalview.bin.Cache.log.debug("Querying "
-                        + dbsource.getDbName() + " with : '"
-                        + queryString.toString() + "'");
-              }
-              retrieved = dbsource.getSequenceRecords(queryString
-                      .toString());
-            } catch (Exception ex)
-            {
-              ex.printStackTrace();
-            } catch (OutOfMemoryError err)
+          while (queries.size() > 0 && numq < nqSize)
+          {
+            String query = queries.elementAt(0);
+            if (dbsource.isValidReference(query))
             {
-              new OOMWarning("retrieving database references ("
-                      + queryString.toString() + ")", err);
+              queryString.append((numq == 0) ? "" : dbsource
+                      .getAccessionSeparator());
+              queryString.append(query);
+              numq++;
             }
-            if (retrieved != null)
+            // remove the extracted query string
+            queries.removeElementAt(0);
+          }
+          // make the queries and process the response
+          AlignmentI retrieved = null;
+          try
+          {
+            if (Cache.log.isDebugEnabled())
             {
-              transferReferences(sdataset, dbsource.getDbSource(),
-                      retrieved, trimDsSeqs);
+              Cache.log.debug("Querying " + dbsource.getDbName()
+                      + " with : '" + queryString.toString() + "'");
             }
+            retrieved = dbsource.getSequenceRecords(queryString.toString());
+          } catch (Exception ex)
+          {
+            ex.printStackTrace();
+          } catch (OutOfMemoryError err)
+          {
+            new OOMWarning("retrieving database references ("
+                    + queryString.toString() + ")", err);
           }
-          else
+          if (retrieved != null)
           {
-            // make some more strings for use as queries
-            for (int i = 0; (seqIndex < dataset.length) && (i < 50); seqIndex++, i++)
+            transferReferences(sdataset, dbsource.getDbSource(), retrieved,
+                    trimDsSeqs, warningMessages);
+          }
+        }
+        else
+        {
+          // make some more strings for use as queries
+          for (int i = 0; (seqIndex < dataset.length) && (i < 50); seqIndex++, i++)
+          {
+            SequenceI sequence = dataset[seqIndex];
+            DBRefEntry[] uprefs = DBRefUtils.selectRefs(
+                    sequence.getDBRefs(),
+                    new String[] { dbsource.getDbSource() }); // jalview.datamodel.DBRefSource.UNIPROT
+            // });
+            // check for existing dbrefs to use
+            if (uprefs != null && uprefs.length > 0)
             {
-              SequenceI sequence = dataset[seqIndex];
-              DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(
-                      sequence.getDBRefs(),
-                      new String[] { dbsource.getDbSource() }); // jalview.datamodel.DBRefSource.UNIPROT
-              // });
-              // check for existing dbrefs to use
-              if (uprefs != null && uprefs.length > 0)
+              for (int j = 0; j < uprefs.length; j++)
               {
-                for (int j = 0; j < uprefs.length; j++)
-                {
-                  addSeqId(sequence, uprefs[j].getAccessionId());
-                  queries.addElement(uprefs[j].getAccessionId()
-                          .toUpperCase());
-                }
+                addSeqId(sequence, uprefs[j].getAccessionId());
+                queries.addElement(uprefs[j].getAccessionId().toUpperCase());
               }
-              else
+            }
+            else
+            {
+              // generate queries from sequence ID string
+              StringTokenizer st = new StringTokenizer(sequence.getName(),
+                      "|");
+              while (st.hasMoreTokens())
               {
-                // generate queries from sequence ID string
-                StringTokenizer st = new StringTokenizer(
-                        sequence.getName(), "|");
-                while (st.hasMoreTokens())
+                String token = st.nextToken();
+                UPEntry[] presp = null;
+                if (picrClient != null)
                 {
-                  String token = st.nextToken();
-                  UPEntry[] presp = null;
-                  if (picrClient != null)
+                  // resolve the string against PICR to recover valid IDs
+                  try
                   {
-                    // resolve the string against PICR to recover valid IDs
-                    try
-                    {
-                      presp = picrClient.getUPIForAccession(token, null,
-                              picrClient.getMappedDatabaseNames(), null,
-                              true);
-                    } catch (Exception e)
-                    {
-                      System.err.println("Exception with Picr for '"
-                              + token + "'\n");
-                      e.printStackTrace();
-                    }
-                  }
-                  if (presp != null && presp.length > 0)
+                    presp = picrClient
+                            .getUPIForAccession(token, null,
+                                    picrClient.getMappedDatabaseNames(),
+                                    null, true);
+                  } catch (Exception e)
                   {
-                    for (int id = 0; id < presp.length; id++)
-                    {
-                      // construct sequences from response if sequences are
-                      // present, and do a transferReferences
-                      // otherwise transfer non sequence x-references directly.
-                    }
-                    System.out
-                            .println("Validated ID against PICR... (for what its worth):"
-                                    + token);
-                    addSeqId(sequence, token);
-                    queries.addElement(token.toUpperCase());
+                    System.err.println("Exception with Picr for '" + token
+                            + "'\n");
+                    e.printStackTrace();
                   }
-                  else
+                }
+                if (presp != null && presp.length > 0)
+                {
+                  for (int id = 0; id < presp.length; id++)
                   {
-                    // if ()
-                    // System.out.println("Not querying source with token="+token+"\n");
-                    addSeqId(sequence, token);
-                    queries.addElement(token.toUpperCase());
+                    // construct sequences from response if sequences are
+                    // present, and do a transferReferences
+                    // otherwise transfer non sequence x-references directly.
                   }
+                  System.out
+                          .println("Validated ID against PICR... (for what its worth):"
+                                  + token);
+                  addSeqId(sequence, token);
+                  queries.addElement(token.toUpperCase());
+                }
+                else
+                {
+                  // if ()
+                  // System.out.println("Not querying source with token="+token+"\n");
+                  addSeqId(sequence, token);
+                  queries.addElement(token.toUpperCase());
                 }
               }
             }
@@ -479,15 +502,20 @@ public class DBRefFetcher implements Runnable
       }
       // advance to next database
       db++;
-    } // all databases have been queries.
-    if (sbuffer.length() > 0)
+    } // all databases have been queried
+    if (!warningMessages.isEmpty())
     {
-      output.setText(MessageManager
-              .getString("label.your_sequences_have_been_verified")
-              + sbuffer.toString());
+      StringBuilder sb = new StringBuilder(warningMessages.size() * 30);
+      sb.append(MessageManager
+              .getString("label.your_sequences_have_been_verified"));
+      for (String msg : warningMessages)
+      {
+        sb.append(msg).append(NEWLINE);
+      }
+      output.setText(sb.toString());
+
       Desktop.addInternalFrame(output,
-              MessageManager.getString("label.sequence_names_updated"),
-              600, 300);
+              MessageManager.getString("label.sequences_updated"), 600, 300);
       // The above is the dataset, we must now find out the index
       // of the viewed sequence
 
@@ -508,57 +536,61 @@ public class DBRefFetcher implements Runnable
 
   /**
    * Verify local sequences in seqRefs against the retrieved sequence database
-   * records.
+   * records. Returns true if any sequence was modified as a result (start/end
+   * changed and/or sequence enlarged), else false.
    * 
+   * @param sdataset
+   *          dataset sequences we are retrieving for
+   * @param dbSource
+   *          database source we are retrieving from
+   * @param retrievedAl
+   *          retrieved sequences as alignment
    * @param trimDatasetSeqs
-   * 
+   *          if true, sequences will not be enlarged to match longer retrieved
+   *          sequences, only their start/end adjusted
+   * @param warningMessages
+   *          a list of messages to add to
    */
-  void transferReferences(Vector sdataset, String dbSource,
-          AlignmentI retrievedAl, boolean trimDatasetSeqs) // File
-  // file)
+  boolean transferReferences(Vector<SequenceI> sdataset, String dbSource,
+          AlignmentI retrievedAl, boolean trimDatasetSeqs,
+          List<String> warningMessages)
   {
-    System.out.println("trimming ? " + trimDatasetSeqs);
+    // System.out.println("trimming ? " + trimDatasetSeqs);
     if (retrievedAl == null || retrievedAl.getHeight() == 0)
     {
-      return;
+      return false;
     }
+
+    boolean modified = false;
     SequenceI[] retrieved = recoverDbSequences(retrievedAl
             .getSequencesArray());
     SequenceI sequence = null;
-    boolean transferred = false;
-    StringBuffer messages = new StringBuffer();
-
-    // Vector entries = new Uniprot().getUniprotEntries(file);
 
-    int i, iSize = retrieved.length; // entries == null ? 0 : entries.size();
-    // UniprotEntry entry;
-    for (i = 0; i < iSize; i++)
+    for (SequenceI retrievedSeq : retrieved)
     {
-      SequenceI entry = retrieved[i]; // (UniprotEntry) entries.elementAt(i);
-
       // Work out which sequences this sequence matches,
       // taking into account all accessionIds and names in the file
-      Vector sequenceMatches = new Vector();
+      Vector<SequenceI> sequenceMatches = new Vector<SequenceI>();
       // look for corresponding accession ids
-      DBRefEntry[] entryRefs = jalview.util.DBRefUtils.selectRefs(
-              entry.getDBRefs(), new String[] { dbSource });
+      DBRefEntry[] entryRefs = DBRefUtils.selectRefs(
+              retrievedSeq.getDBRefs(), new String[] { dbSource });
       if (entryRefs == null)
       {
         System.err
                 .println("Dud dbSource string ? no entryrefs selected for "
-                        + dbSource + " on " + entry.getName());
+                        + dbSource + " on " + retrievedSeq.getName());
         continue;
       }
       for (int j = 0; j < entryRefs.length; j++)
       {
-        String accessionId = entryRefs[j].getAccessionId(); // .getAccession().elementAt(j).toString();
+        String accessionId = entryRefs[j].getAccessionId();
         // match up on accessionId
         if (seqRefs.containsKey(accessionId.toUpperCase()))
         {
-          Vector seqs = (Vector) seqRefs.get(accessionId);
+          Vector<SequenceI> seqs = seqRefs.get(accessionId);
           for (int jj = 0; jj < seqs.size(); jj++)
           {
-            sequence = (SequenceI) seqs.elementAt(jj);
+            sequence = seqs.elementAt(jj);
             if (!sequenceMatches.contains(sequence))
             {
               sequenceMatches.addElement(sequence);
@@ -566,17 +598,17 @@ public class DBRefFetcher implements Runnable
           }
         }
       }
-      if (sequenceMatches.size() == 0)
+      if (sequenceMatches.isEmpty())
       {
         // failed to match directly on accessionId==query so just compare all
         // sequences to entry
-        Enumeration e = seqRefs.keys();
+        Enumeration<String> e = seqRefs.keys();
         while (e.hasMoreElements())
         {
-          Vector sqs = (Vector) seqRefs.get(e.nextElement());
+          Vector<SequenceI> sqs = seqRefs.get(e.nextElement());
           if (sqs != null && sqs.size() > 0)
           {
-            Enumeration sqe = sqs.elements();
+            Enumeration<SequenceI> sqe = sqs.elements();
             while (sqe.hasMoreElements())
             {
               sequenceMatches.addElement(sqe.nextElement());
@@ -600,10 +632,11 @@ public class DBRefFetcher implements Runnable
        */
       // sequenceMatches now contains the set of all sequences associated with
       // the returned db record
-      String entrySeq = entry.getSequenceAsString().toUpperCase();
+      final String retrievedSeqString = retrievedSeq.getSequenceAsString();
+      String entrySeq = retrievedSeqString.toUpperCase();
       for (int m = 0; m < sequenceMatches.size(); m++)
       {
-        sequence = (SequenceI) sequenceMatches.elementAt(m);
+        sequence = sequenceMatches.elementAt(m);
         // only update start and end positions and shift features if there are
         // no existing references
         // TODO: test for legacy where uniprot or EMBL refs exist but no
@@ -613,70 +646,77 @@ public class DBRefFetcher implements Runnable
         // TODO:
         // verify sequence against the entry sequence
 
+        Mapping mp;
+        final int sequenceStart = sequence.getStart();
+
+        boolean remoteEnclosesLocal = false;
         String nonGapped = AlignSeq.extractGaps("-. ",
                 sequence.getSequenceAsString()).toUpperCase();
-
         int absStart = entrySeq.indexOf(nonGapped);
-        Mapping mp;
-
-        final int sequenceStart = sequence.getStart();
         if (absStart == -1)
         {
-          // Is local sequence contained in dataset sequence?
+          // couldn't find local sequence in sequence from database, so check if
+          // the database sequence is a subsequence of local sequence
           absStart = nonGapped.indexOf(entrySeq);
           if (absStart == -1)
-          { // verification failed.
-            messages.append(sequence.getName()
-                    + " SEQUENCE NOT %100 MATCH \n");
+          {
+            // verification failed. couldn't find any relationship between
+            // entrySeq and local sequence
+            // messages suppressed as many-to-many matches are confusing
+            // String msg = sequence.getName()
+            // + " Sequence not 100% match with "
+            // + retrievedSeq.getName();
+            // addWarningMessage(warningMessages, msg);
             continue;
           }
-          transferred = true;
-          sbuffer.append(sequence.getName() + " HAS " + absStart
-                  + " PREFIXED RESIDUES COMPARED TO " + dbSource + "\n");
-          //
-          // + " - ANY SEQUENCE FEATURES"
-          // + " HAVE BEEN ADJUSTED ACCORDINGLY \n");
-          // absStart = 0;
-          // create valid mapping between matching region of local sequence and
-          // the mapped sequence
+          /*
+           * retrieved sequence is a proper subsequence of local sequence
+           */
+          String msg = sequence.getName() + " has " + absStart
+                  + " prefixed residues compared to "
+                  + retrievedSeq.getName();
+          addWarningMessage(warningMessages, msg);
+
+          /*
+           * So create a mapping to the external entry from the matching region of 
+           * the local sequence, and leave local start/end untouched. 
+           */
           mp = new Mapping(null, new int[] { sequenceStart + absStart,
               sequenceStart + absStart + entrySeq.length() - 1 }, new int[]
-          { entry.getStart(), entry.getStart() + entrySeq.length() - 1 },
-                  1, 1);
-          updateRefFrame = false; // mapping is based on current start/end so
-          // don't modify start and end
+          { retrievedSeq.getStart(),
+              retrievedSeq.getStart() + entrySeq.length() - 1 }, 1, 1);
+          updateRefFrame = false;
         }
         else
         {
-          transferred = true;
-          // update start and end of local sequence to place it in entry's
-          // reference frame.
-          // apply identity map map from whole of local sequence to matching
-          // region of database
-          // sequence
-          mp = null; // Mapping.getIdentityMap();
-          // new Mapping(null,
-          // new int[] { absStart+sequence.getStart(),
-          // absStart+sequence.getStart()+entrySeq.length()-1},
-          // new int[] { entry.getStart(), entry.getEnd() }, 1, 1);
-          // relocate local features for updated start
+          /*
+           * local sequence is a subsequence of (or matches) retrieved sequence
+           */
+          remoteEnclosesLocal = true;
+          mp = null;
+
           if (updateRefFrame)
           {
-            if (sequence.getSequenceFeatures() != null)
+            SequenceFeature[] sfs = sequence.getSequenceFeatures();
+            if (sfs != null)
             {
-              SequenceFeature[] sf = sequence.getSequenceFeatures();
+              /*
+               * relocate existing sequence features by offset
+               */
               int start = sequenceStart;
               int end = sequence.getEnd();
-              int startShift = 1 - absStart - start; // how much the features
-                                                     // are
-              // to be shifted by
-              for (int sfi = 0; sfi < sf.length; sfi++)
+              int startShift = 1 - absStart - start;
+
+              if (startShift != 0)
               {
-                if (sf[sfi].getBegin() >= start && sf[sfi].getEnd() <= end)
+                for (SequenceFeature sf : sfs)
                 {
-                  // shift feature along by absstart
-                  sf[sfi].setBegin(sf[sfi].getBegin() + startShift);
-                  sf[sfi].setEnd(sf[sfi].getEnd() + startShift);
+                  if (sf.getBegin() >= start && sf.getEnd() <= end)
+                  {
+                    sf.setBegin(sf.getBegin() + startShift);
+                    sf.setEnd(sf.getEnd() + startShift);
+                    modified = true;
+                  }
                 }
               }
             }
@@ -684,16 +724,37 @@ public class DBRefFetcher implements Runnable
         }
 
         System.out.println("Adding dbrefs to " + sequence.getName()
-                + " from " + dbSource + " sequence : " + entry.getName());
-        sequence.transferAnnotation(entry, mp);
-        // unknownSequences.remove(sequence);
-        absStart += entry.getStart();
+                + " from " + dbSource + " sequence : "
+                + retrievedSeq.getName());
+        sequence.transferAnnotation(retrievedSeq, mp);
+
+        absStart += retrievedSeq.getStart();
         int absEnd = absStart + nonGapped.length() - 1;
         if (!trimDatasetSeqs)
         {
-          // insert full length sequence from record
-          sequence.setSequence(entry.getSequenceAsString());
-          sequence.setStart(entry.getStart());
+          /*
+           * update start position and/or expand to longer retrieved sequence
+           */
+          if (!retrievedSeqString.equals(sequence.getSequenceAsString())
+                  && remoteEnclosesLocal)
+          {
+            sequence.setSequence(retrievedSeqString);
+            modified = true;
+            addWarningMessage(warningMessages,
+                    "Sequence for " + sequence.getName()
+                            + " expanded from " + retrievedSeq.getName());
+          }
+          if (sequence.getStart() != retrievedSeq.getStart())
+          {
+            sequence.setStart(retrievedSeq.getStart());
+            modified = true;
+            if (absStart != sequenceStart)
+            {
+              addWarningMessage(warningMessages, "Start/end position for "
+                      + sequence.getName() + " updated from "
+                      + retrievedSeq.getName());
+            }
+          }
         }
         if (updateRefFrame)
         {
@@ -701,8 +762,16 @@ public class DBRefFetcher implements Runnable
           if (trimDatasetSeqs)
           {
             // just fix start/end
-            sequence.setStart(absStart);
-            sequence.setEnd(absEnd);
+            if (sequence.getStart() != absStart
+                    || sequence.getEnd() != absEnd)
+            {
+              sequence.setStart(absStart);
+              sequence.setEnd(absEnd);
+              modified = true;
+              addWarningMessage(warningMessages, "Start/end for "
+                      + sequence.getName() + " updated from "
+                      + retrievedSeq.getName());
+            }
           }
           // search for alignment sequences to update coordinate frame for
           for (int alsq = 0; alsq < alseqs.length; alsq++)
@@ -719,6 +788,7 @@ public class DBRefFetcher implements Runnable
               {
                 alseqs[alsq].setEnd(ngAlsq.length()
                         + alseqs[alsq].getStart() - 1);
+                modified = true;
               }
             }
           }
@@ -735,10 +805,20 @@ public class DBRefFetcher implements Runnable
         // ids, so we can query all enabled DAS servers for them ?
       }
     }
-    if (!transferred)
+    return modified;
+  }
+
+  /**
+   * Adds the message to the list unless it already contains it
+   * 
+   * @param messageList
+   * @param msg
+   */
+  void addWarningMessage(List<String> messageList, String msg)
+  {
+    if (!messageList.contains(msg))
     {
-      // report the ID/sequence mismatches
-      sbuffer.append(messages);
+      messageList.add(msg);
     }
   }
 
@@ -750,12 +830,12 @@ public class DBRefFetcher implements Runnable
    */
   private SequenceI[] recoverDbSequences(SequenceI[] sequencesArray)
   {
-    Vector nseq = new Vector();
+    Vector<SequenceI> nseq = new Vector<SequenceI>();
     for (int i = 0; sequencesArray != null && i < sequencesArray.length; i++)
     {
       nseq.addElement(sequencesArray[i]);
-      DBRefEntry dbr[] = sequencesArray[i].getDBRefs();
-      jalview.datamodel.Mapping map = null;
+      DBRefEntry[] dbr = sequencesArray[i].getDBRefs();
+      Mapping map = null;
       for (int r = 0; (dbr != null) && r < dbr.length; r++)
       {
         if ((map = dbr[r].getMap()) != null)
index 5f9b2d9..7e069e3 100644 (file)
@@ -253,8 +253,7 @@ public class DasSequenceFeatureFetcher
     public void run()
     {
       running = true;
-      boolean isNucleotide = af.getViewport().getAlignment()
-              .isNucleotide();
+      boolean isNucleotide = af.getViewport().getAlignment().isNucleotide();
       new DBRefFetcher(sequences, af, null, af.featureSettings,
               isNucleotide).fetchDBRefs(true);
 
@@ -287,8 +286,7 @@ public class DasSequenceFeatureFetcher
       {
         jalviewSourceI[] sources = sourceRegistry.getSources().toArray(
                 new jalviewSourceI[0]);
-        String active = Cache.getDefault("DAS_ACTIVE_SOURCE",
-                "uniprot");
+        String active = Cache.getDefault("DAS_ACTIVE_SOURCE", "uniprot");
         StringTokenizer st = new StringTokenizer(active, "\t");
         selectedSources = new Vector();
         String token;
@@ -644,8 +642,8 @@ public class DasSequenceFeatureFetcher
     {
       return null;
     }
-    DBRefEntry[] uprefs = DBRefUtils.selectRefs(
-            seq.getDBRefs(), new String[] {
+    DBRefEntry[] uprefs = DBRefUtils.selectRefs(seq.getDBRefs(),
+            new String[] {
             // jalview.datamodel.DBRefSource.PDB,
             DBRefSource.UNIPROT,
             // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord
@@ -666,8 +664,8 @@ public class DasSequenceFeatureFetcher
 
         for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())
         {
-          if (DBRefUtils.isDasCoordinateSystem(
-                  csys.getAuthority(), uprefs[j]))
+          if (DBRefUtils.isDasCoordinateSystem(csys.getAuthority(),
+                  uprefs[j]))
           {
             debug("Launched fetcher for coordinate system "
                     + csys.getAuthority());
index 2b8f364..9cc4960 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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;
 
 import jalview.ws.seqfetcher.ASequenceFetcher;
index 2049766..b139574 100644 (file)
@@ -102,8 +102,13 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
       }
     }
 
+    /*
+     * invalid accession gets a reply with no <entry> elements, text content of
+     * EmbFile reads something like (e.g.) this ungrammatical phrase
+     * Entry: <acc> display type is either not supported or entry is not found.
+     */
     List<SequenceI> peptides = new ArrayList<SequenceI>();
-    if (efile != null)
+    if (efile != null && efile.getEntries() != null)
     {
       for (EmblEntry entry : efile.getEntries())
       {
index 757ab83..0aae38f 100644 (file)
@@ -50,15 +50,17 @@ import com.stevesoft.pat.Regex;
  */
 public class Pdb extends EbiFileRetrievedProxy
 {
+  private static final String SEPARATOR = "|";
+
+  private static final String COLON = ":";
+
+  private static final int PDB_ID_LENGTH = 4;
+
   public Pdb()
   {
     super();
   }
 
-  public static final String FEATURE_INSERTION = "INSERTION";
-
-  public static final String FEATURE_RES_NUM = "RESNUM";
-
   /*
    * (non-Javadoc)
    * 
@@ -67,7 +69,6 @@ public class Pdb extends EbiFileRetrievedProxy
   @Override
   public String getAccessionSeparator()
   {
-    // TODO Auto-generated method stub
     return null;
   }
 
@@ -113,23 +114,28 @@ public class Pdb extends EbiFileRetrievedProxy
   public AlignmentI getSequenceRecords(String queries) throws Exception
   {
     AlignmentI pdbAlignment = null;
-    Vector result = new Vector();
     String chain = null;
     String id = null;
-    if (queries.indexOf(":") > -1)
+    if (queries.indexOf(COLON) > -1)
     {
-      chain = queries.substring(queries.indexOf(":") + 1);
-      id = queries.substring(0, queries.indexOf(":"));
+      chain = queries.substring(queries.indexOf(COLON) + 1);
+      id = queries.substring(0, queries.indexOf(COLON));
     }
     else
     {
       id = queries;
     }
-    if (queries.length() > 4 && chain == null)
+
+    /*
+     * extract chain code if it is appended to the id and we
+     * don't already have one
+     */
+    if (queries.length() > PDB_ID_LENGTH && chain == null)
     {
-      chain = queries.substring(4, 5);
-      id = queries.substring(0, 4);
+      chain = queries.substring(PDB_ID_LENGTH, PDB_ID_LENGTH + 1);
+      id = queries.substring(0, PDB_ID_LENGTH);
     }
+
     if (!isValidReference(id))
     {
       System.err.println("Ignoring invalid pdb query: '" + id + "'");
@@ -168,16 +174,16 @@ public class Pdb extends EbiFileRetrievedProxy
               chid = pid.getChainCode();
 
             }
-            ;
-
           }
           if (chain == null
                   || (chid != null && (chid.equals(chain)
                           || chid.trim().equals(chain.trim()) || (chain
                           .trim().length() == 0 && chid.equals("_")))))
           {
-            pdbcs.setName(jalview.datamodel.DBRefSource.PDB + "|" + id
-                    + "|" + pdbcs.getName());
+            // 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(jalview.datamodel.DBRefSource.PDB + SEPARATOR
+                    + id + SEPARATOR + pdbcs.getName());
             // Might need to add more metadata to the PDBEntry object
             // like below
             /*
@@ -268,7 +274,6 @@ public class Pdb extends EbiFileRetrievedProxy
     return 0;
   }
 
-
   /**
    * Returns a descriptor for suitable feature display settings with
    * <ul>
index 5b8a3ae..941bf1a 100644 (file)
@@ -125,10 +125,9 @@ abstract public class Pfam extends Xfam
             FileFormat.Stockholm);
     for (int s = 0, sNum = rcds.getHeight(); s < sNum; s++)
     {
-      rcds.getSequenceAt(s).addDBRef(
-new DBRefEntry(DBRefSource.PFAM,
-              // getDbSource(),
-                      getDbVersion(), queries.trim().toUpperCase()));
+      rcds.getSequenceAt(s).addDBRef(new DBRefEntry(DBRefSource.PFAM,
+      // getDbSource(),
+              getDbVersion(), queries.trim().toUpperCase()));
       if (!getDbSource().equals(DBRefSource.PFAM))
       { // add the specific ref too
         rcds.getSequenceAt(s).addDBRef(
index 62b9686..3c5373d 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * flyweight class specifying retrieval of Full family alignments from PFAM
  * 
index 053953c..ba9d1e0 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * flyweight class specifying retrieval of Seed alignments from PFAM
  * 
index 3053363..e6fc8ff 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * Flyweight class specifying retrieval of Full family alignments from RFAM
  * 
index 77fb841..580ebe2 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * Flyweight class specifying retrieval of Seed family alignments from RFAM
  * 
@@ -52,6 +51,7 @@ public class RfamSeed extends Rfam
   {
     return "/alignment";
   }
+
   /*
    * (non-Javadoc)
    * 
index 8cc0ce4..b6f53cd 100644 (file)
@@ -193,7 +193,8 @@ public class Uniprot extends DbSourceProxyImpl
    *          UniprotEntry
    * @return SequenceI instance created from the UniprotEntry instance
    */
-  public SequenceI uniprotEntryToSequenceI(UniprotEntry entry){
+  public SequenceI uniprotEntryToSequenceI(UniprotEntry entry)
+  {
     String id = getUniprotEntryId(entry);
     SequenceI sequence = new Sequence(id, entry.getUniprotSequence()
             .getContent());
@@ -205,10 +206,10 @@ public class Uniprot extends DbSourceProxyImpl
     {
       DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion,
               accessionId);
+
+      // mark dbRef as a primary reference for this sequence
       dbRefs.add(dbRef);
     }
-    sequence.setSourceDBRef((dbRefs != null && dbRefs.size() > 0) ? dbRefs
-            .get(0) : null);
 
     Vector<PDBEntry> onlyPdbEntries = new Vector<PDBEntry>();
     for (PDBEntry pdb : entry.getDbReference())
@@ -222,6 +223,38 @@ public class Uniprot extends DbSourceProxyImpl
       {
         onlyPdbEntries.addElement(pdb);
       }
+      if ("EMBL".equals(pdb.getType()))
+      {
+        // look for a CDS reference and add it, too.
+        String cdsId = (String) pdb.getProperty("protein sequence ID");
+        if (cdsId != null && cdsId.trim().length() > 0)
+        {
+          // remove version
+          String[] vrs = cdsId.split("\\.");
+          dbr = new DBRefEntry(DBRefSource.EMBLCDS, vrs.length > 1 ? vrs[1]
+                  : DBRefSource.UNIPROT + ":" + dbVersion, vrs[0]);
+          dbRefs.add(dbr);
+        }
+      }
+      if ("Ensembl".equals(pdb.getType()))
+      {
+        /*UniprotXML
+         * <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 = (String) pdb.getProperty("protein sequence ID");
+        if (cdsId != null && cdsId.trim().length() > 0)
+        {
+          dbr = new DBRefEntry(DBRefSource.ENSEMBL, DBRefSource.UNIPROT
+                  + ":" + dbVersion, cdsId.trim());
+          dbRefs.add(dbr);
+
+        }
+      }
+
     }
 
     sequence.setPDBId(onlyPdbEntries);
@@ -233,7 +266,10 @@ public class Uniprot extends DbSourceProxyImpl
         sequence.addSequenceFeature(sf);
       }
     }
-    sequence.setDBRefs(dbRefs.toArray(new DBRefEntry[0]));
+    for (DBRefEntry dbr : dbRefs)
+    {
+      sequence.addDBRef(dbr);
+    }
     return sequence;
   }
 
index 3f6afbc..b184ff2 100644 (file)
@@ -259,8 +259,8 @@ public class DasSourceRegistry implements DasSourceRegistryI,
   }
 
   /*
- * 
- */
+  * 
+  */
 
   @Override
   public jalviewSourceI createLocalSource(String url, String name,
index 1dff32f..f6928c4 100644 (file)
@@ -139,7 +139,8 @@ public class EBIFetchClient
     }
 
     // note: outFile is currently always specified, so return value is null
-    String[] rslt = fetchBatch(querystring.toString(), database, format, outFile);
+    String[] rslt = fetchBatch(querystring.toString(), database, format,
+            outFile);
 
     return (rslt != null && rslt.length > 0 ? rslt : null);
   }
@@ -241,8 +242,7 @@ public class EBIFetchClient
         return null;
       }
       System.err.println("Unexpected exception when retrieving from "
-              + database
-              + "\nQuery was : '" + ids + "'");
+              + database + "\nQuery was : '" + ids + "'");
       ex.printStackTrace(System.err);
       return null;
     } finally
index 3fd7c5a..e4247f7 100644 (file)
@@ -670,8 +670,8 @@ class MsaWSThread extends JWS1Thread implements WSClientI
 
             while (j < l)
             {
-              if (((AlignmentOrder) alorders.get(i))
-                      .equals((alorders.get(j))))
+              if (((AlignmentOrder) alorders.get(i)).equals((alorders
+                      .get(j))))
               {
                 alorders.remove(j);
                 l--;
index 2d83bf9..7665fec 100644 (file)
@@ -172,8 +172,7 @@ public class SeqSearchWSClient extends WS1Client
 
     try
     {
-      this.server = loc.getSeqSearchService(new java.net.URL(
-              WsURL));
+      this.server = loc.getSeqSearchService(new java.net.URL(WsURL));
       ((SeqSearchServiceSoapBindingStub) this.server).setTimeout(60000); // One
       // minute
       // timeout
index 758d941..8fa118d 100644 (file)
@@ -338,13 +338,14 @@ public class MsaWSClient extends Jws2Client
               }
 
             });
-            String tooltip = JvSwingUtils.wrapTooltip(
-                    true,
+            String tooltip = JvSwingUtils
+                    .wrapTooltip(
+                            true,
                             "<strong>"
-                            + (preset.isModifiable() ? MessageManager
-                                    .getString("label.user_preset")
-                                    : MessageManager
-                                            .getString("label.service_preset"))
+                                    + (preset.isModifiable() ? MessageManager
+                                            .getString("label.user_preset")
+                                            : MessageManager
+                                                    .getString("label.service_preset"))
                                     + "</strong><br/>"
                                     + preset.getDescription());
             methodR.setToolTipText(tooltip);
index 33a917e..31168b4 100644 (file)
@@ -112,8 +112,7 @@ public class ASequenceFetcher
         return true;
       }
     }
-    Cache.log.warn("isFetchable doesn't know about '" + source
-            + "'");
+    Cache.log.warn("isFetchable doesn't know about '" + source + "'");
     return false;
   }
 
index aa65f49..4675fb7 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.sifts;
 
 public class MappingOutputPojo
@@ -114,5 +134,4 @@ public class MappingOutputPojo
     this.type = type;
   }
 
-
 }
index 6c94723..27db604 100644 (file)
@@ -29,6 +29,8 @@ import jalview.datamodel.SequenceI;
 import jalview.io.StructureFile;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureMapping;
+import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
 import jalview.util.Format;
 import jalview.xml.binding.sifts.Entry;
 import jalview.xml.binding.sifts.Entry.Entity;
@@ -148,7 +150,6 @@ public class SiftsClient implements SiftsClientI
     siftsEntry = parseSIFTs(siftsFile);
   }
 
-
   /**
    * Parse the given SIFTs File and return a JAXB POJO of parsed data
    * 
@@ -275,21 +276,21 @@ public class SiftsClient implements SiftsClientI
     {
       siftsDownloadDir.mkdirs();
     }
-      // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
-      URL url = new URL(siftsFileFTPURL);
-      URLConnection conn = url.openConnection();
-      InputStream inputStream = conn.getInputStream();
-      FileOutputStream outputStream = new FileOutputStream(
-              downloadedSiftsFile);
-      byte[] buffer = new byte[BUFFER_SIZE];
-      int bytesRead = -1;
-      while ((bytesRead = inputStream.read(buffer)) != -1)
-      {
-        outputStream.write(buffer, 0, bytesRead);
-      }
-      outputStream.close();
-      inputStream.close();
-      // System.out.println(">>> File downloaded : " + downloadedSiftsFile);
+    // System.out.println(">> Download ftp url : " + siftsFileFTPURL);
+    URL url = new URL(siftsFileFTPURL);
+    URLConnection conn = url.openConnection();
+    InputStream inputStream = conn.getInputStream();
+    FileOutputStream outputStream = new FileOutputStream(
+            downloadedSiftsFile);
+    byte[] buffer = new byte[BUFFER_SIZE];
+    int bytesRead = -1;
+    while ((bytesRead = inputStream.read(buffer)) != -1)
+    {
+      outputStream.write(buffer, 0, bytesRead);
+    }
+    outputStream.close();
+    inputStream.close();
+    // System.out.println(">>> File downloaded : " + downloadedSiftsFile);
     return new File(downloadedSiftsFile);
   }
 
@@ -323,41 +324,29 @@ public class SiftsClient implements SiftsClientI
   public DBRefEntryI getValidSourceDBRef(SequenceI seq)
           throws SiftsException
   {
-    DBRefEntryI sourceDBRef = null;
-    sourceDBRef = seq.getSourceDBRef();
-    if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef))
+    List<DBRefEntry> dbRefs = seq.getPrimaryDBRefs();
+    if (dbRefs == null || dbRefs.size() < 1)
     {
-      return sourceDBRef;
+      throw new SiftsException(
+              "Source DBRef could not be determined. DBRefs might not have been retrieved.");
     }
-    else
+
+    for (DBRefEntry dbRef : dbRefs)
     {
-      DBRefEntry[] dbRefs = seq.getDBRefs();
-      if (dbRefs == null || dbRefs.length < 1)
+      if (dbRef == null || dbRef.getAccessionId() == null
+              || dbRef.getSource() == null)
       {
-        throw new SiftsException(
-                "Source DBRef could not be determined. DBRefs might not have been retrieved.");
+        continue;
       }
-
-      for (DBRefEntryI dbRef : dbRefs)
+      String canonicalSource = DBRefUtils.getCanonicalName(dbRef
+              .getSource());
+      if (isValidDBRefEntry(dbRef)
+              && (canonicalSource.equalsIgnoreCase(DBRefSource.UNIPROT) || canonicalSource
+                      .equalsIgnoreCase(DBRefSource.PDB)))
       {
-        if (dbRef == null || dbRef.getAccessionId() == null
-                || dbRef.getSource() == null)
-        {
-          continue;
-        }
-        if (isFoundInSiftsEntry(dbRef.getAccessionId())
-                && (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT) || dbRef
-                        .getSource().equalsIgnoreCase(DBRefSource.PDB)))
-        {
-          seq.setSourceDBRef(dbRef);
-          return dbRef;
-        }
+        return dbRef;
       }
     }
-    if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef))
-    {
-      return sourceDBRef;
-    }
     throw new SiftsException("Could not get source DB Ref");
   }
 
@@ -402,8 +391,8 @@ public class SiftsClient implements SiftsClientI
           String pdbFile, String chain) throws SiftsException
   {
     structId = (chain == null) ? pdbId : pdbId + "|" + chain;
-    System.out.println("Getting mapping for: " + pdbId + "|" + chain
-            + " : seq- " + seq.getName());
+    System.out.println("Getting SIFTS mapping for " + structId + ": seq "
+            + seq.getName());
 
     final StringBuilder mappingDetails = new StringBuilder(128);
     PrintStream ps = new PrintStream(System.out)
@@ -440,7 +429,7 @@ public class SiftsClient implements SiftsClientI
     String originalSeq = AlignSeq.extractGaps(
             jalview.util.Comparison.GapChars, seq.getSequenceAsString());
     HashMap<Integer, int[]> mapping = new HashMap<Integer, int[]>();
-    DBRefEntryI sourceDBRef = seq.getSourceDBRef();
+    DBRefEntryI sourceDBRef;
     sourceDBRef = getValidSourceDBRef(seq);
     // TODO ensure sequence start/end is in the same coordinate system and
     // consistent with the choosen sourceDBRef
@@ -482,12 +471,13 @@ public class SiftsClient implements SiftsClientI
     int pdbStart = UNASSIGNED;
     int pdbEnd = UNASSIGNED;
 
-    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
-    Arrays.sort(keys);
-    if (keys.length < 1)
+    if (mapping.isEmpty())
     {
-      throw new SiftsException(">>> Empty SIFTS mapping generated!!");
+      throw new SiftsException("SIFTS mapping failed");
     }
+
+    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
+    Arrays.sort(keys);
     seqStart = keys[0];
     seqEnd = keys[keys.length - 1];
 
@@ -521,13 +511,13 @@ public class SiftsClient implements SiftsClientI
     if (os != null)
     {
       MappingOutputPojo mop = new MappingOutputPojo();
-      mop.setSeqStart(pdbStart);
-      mop.setSeqEnd(pdbEnd);
+      mop.setSeqStart(seqStart);
+      mop.setSeqEnd(seqEnd);
       mop.setSeqName(seq.getName());
       mop.setSeqResidue(matchedSeq);
 
-      mop.setStrStart(seqStart);
-      mop.setStrEnd(seqEnd);
+      mop.setStrStart(pdbStart);
+      mop.setStrEnd(pdbEnd);
       mop.setStrName(structId);
       mop.setStrResidue(targetStrucSeqs.toString());
 
@@ -622,6 +612,7 @@ public class SiftsClient implements SiftsClientI
       }
     }
   }
+
   /**
    * 
    * @param chainId
@@ -773,8 +764,6 @@ public class SiftsClient implements SiftsClientI
     }
   }
 
-
-
   @Override
   public Entity getEntityById(String id) throws SiftsException
   {
@@ -838,6 +827,10 @@ public class SiftsClient implements SiftsClientI
 
     if (sPojo[0].entityId != null)
     {
+      if (sPojo[0].pid < 1)
+      {
+        return null;
+      }
       for (Entity entity : entities)
       {
         if (!entity.getEntityId().equalsIgnoreCase(sPojo[0].entityId))
@@ -1012,8 +1005,10 @@ public class SiftsClient implements SiftsClientI
         {
           if ((i + (j * len)) < seqRes.length())
           {
-            if (seqRes.charAt(i + (j * len)) == strRes
-                    .charAt(i + (j * len))
+            boolean sameChar = Comparison.isSameResidue(
+                    seqRes.charAt(i + (j * len)),
+                    strRes.charAt(i + (j * len)), false);
+            if (sameChar
                     && !jalview.util.Comparison.isGap(seqRes.charAt(i
                             + (j * len))))
             {
index 2923541..191aa2d 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.sifts;
 
 public class SiftsException extends Exception
index e1e3de8..5e2c526 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.sifts;
 
 import java.util.Objects;
index 54576c6..a5bbf8e 100644 (file)
@@ -26,6 +26,7 @@ import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -33,10 +34,12 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
+import jalview.structure.StructureImportSettings;
 
 import java.io.IOException;
 import java.util.List;
 
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 public class PDBfileTest
@@ -307,4 +310,17 @@ public class PDBfileTest
     pf.addAnnotations(al);
     return al.getAlignmentAnnotation();
   }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
+  {
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("ADD_TEMPFACT_ANN",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("ADD_SS_ANN",
+            Boolean.TRUE.toString());
+    StructureImportSettings.setDefaultStructureFileFormat("PDB");
+  }
 }
index eff6bbf..58601a9 100644 (file)
@@ -23,65 +23,64 @@ package jalview.analysis;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNull;
 
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.ProfileI;
+import jalview.datamodel.ProfilesI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 
-import java.util.Hashtable;
-
 import org.testng.annotations.Test;
 
 public class AAFrequencyTest
 {
-  private static final String C = AAFrequency.MAXCOUNT;
-
-  private static final String R = AAFrequency.MAXRESIDUE;
-
-  private static final String G = AAFrequency.PID_GAPS;
-
-  private static final String N = AAFrequency.PID_NOGAPS;
-
-  private static final String P = AAFrequency.PROFILE;
-
   @Test(groups = { "Functional" })
   public void testCalculate_noProfile()
   {
-    SequenceI seq1 = new Sequence("Seq1", "CAGT");
-    SequenceI seq2 = new Sequence("Seq2", "CACT");
-    SequenceI seq3 = new Sequence("Seq3", "C--G");
-    SequenceI seq4 = new Sequence("Seq4", "CA-t");
+    SequenceI seq1 = new Sequence("Seq1", "CAG-T");
+    SequenceI seq2 = new Sequence("Seq2", "CAC-T");
+    SequenceI seq3 = new Sequence("Seq3", "C---G");
+    SequenceI seq4 = new Sequence("Seq4", "CA--t");
     SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3, seq4 };
-    Hashtable[] result = new Hashtable[seq1.getLength()];
-
-    AAFrequency.calculate(seqs, 0, seq1.getLength(), result, false);
+    int width = seq1.getLength();
+    ProfilesI result = AAFrequency.calculate(seqs, width, 0, width,
+            false);
 
     // col 0 is 100% C
-    Hashtable col = result[0];
-    assertEquals(100f, (Float) col.get(G), 0.0001f);
-    assertEquals(100f, (Float) col.get(N), 0.0001f);
-    assertEquals(4, col.get(C));
-    assertEquals("C", col.get(R));
-    assertNull(col.get(P));
+    ProfileI col = result.get(0);
+    assertEquals(100f, col.getPercentageIdentity(false));
+    assertEquals(100f, col.getPercentageIdentity(true));
+    assertEquals(4, col.getMaxCount());
+    assertEquals("C", col.getModalResidue());
+    assertNull(col.getCounts());
 
     // col 1 is 75% A
-    col = result[1];
-    assertEquals(75f, (Float) col.get(G), 0.0001f);
-    assertEquals(100f, (Float) col.get(N), 0.0001f);
-    assertEquals(3, col.get(C));
-    assertEquals("A", col.get(R));
+    col = result.get(1);
+    assertEquals(75f, col.getPercentageIdentity(false));
+    assertEquals(100f, col.getPercentageIdentity(true));
+    assertEquals(3, col.getMaxCount());
+    assertEquals("A", col.getModalResidue());
 
     // col 2 is 50% G 50% C or 25/25 counting gaps
-    col = result[2];
-    assertEquals(25f, (Float) col.get(G), 0.0001f);
-    assertEquals(50f, (Float) col.get(N), 0.0001f);
-    assertEquals(1, col.get(C));
-    assertEquals("CG", col.get(R));
-
-    // col 3 is 75% T 25% G
-    col = result[3];
-    assertEquals(75f, (Float) col.get(G), 0.0001f);
-    assertEquals(75f, (Float) col.get(N), 0.0001f);
-    assertEquals(3, col.get(C));
-    assertEquals("T", col.get(R));
+    col = result.get(2);
+    assertEquals(25f, col.getPercentageIdentity(false));
+    assertEquals(50f, col.getPercentageIdentity(true));
+    assertEquals(1, col.getMaxCount());
+    assertEquals("CG", col.getModalResidue());
+
+    // col 3 is all gaps
+    col = result.get(3);
+    assertEquals(0f, col.getPercentageIdentity(false));
+    assertEquals(0f, col.getPercentageIdentity(true));
+    assertEquals(0, col.getMaxCount());
+    assertEquals("", col.getModalResidue());
+
+    // col 4 is 75% T 25% G
+    col = result.get(4);
+    assertEquals(75f, col.getPercentageIdentity(false));
+    assertEquals(75f, col.getPercentageIdentity(true));
+    assertEquals(3, col.getMaxCount());
+    assertEquals("T", col.getModalResidue());
   }
 
   @Test(groups = { "Functional" })
@@ -92,33 +91,34 @@ public class AAFrequencyTest
     SequenceI seq3 = new Sequence("Seq3", "C--G");
     SequenceI seq4 = new Sequence("Seq4", "CA-t");
     SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3, seq4 };
-    Hashtable[] result = new Hashtable[seq1.getLength()];
-
-    AAFrequency.calculate(seqs, 0, seq1.getLength(), result, true);
-    int[][] profile = (int[][]) result[0].get(P);
-    assertEquals(4, profile[0]['C']);
-    assertEquals(4, profile[1][0]); // no of seqs
-    assertEquals(4, profile[1][1]); // nongapped in column
-
-    profile = (int[][]) result[1].get(P);
-    assertEquals(3, profile[0]['A']);
-    assertEquals(4, profile[1][0]);
-    assertEquals(3, profile[1][1]);
-
-    profile = (int[][]) result[2].get(P);
-    assertEquals(1, profile[0]['G']);
-    assertEquals(1, profile[0]['C']);
-    assertEquals(4, profile[1][0]);
-    assertEquals(2, profile[1][1]);
-
-    profile = (int[][]) result[3].get(P);
-    assertEquals(3, profile[0]['T']);
-    assertEquals(1, profile[0]['G']);
-    assertEquals(4, profile[1][0]);
-    assertEquals(4, profile[1][1]);
+    int width = seq1.getLength();
+    ProfilesI result = AAFrequency.calculate(seqs, width, 0, width,
+            true);
+
+    ProfileI profile = result.get(0);
+    assertEquals(4, profile.getCounts().getCount('C'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(4, profile.getNonGapped());
+
+    profile = result.get(1);
+    assertEquals(3, profile.getCounts().getCount('A'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(3, profile.getNonGapped());
+
+    profile = result.get(2);
+    assertEquals(1, profile.getCounts().getCount('C'));
+    assertEquals(1, profile.getCounts().getCount('G'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(2, profile.getNonGapped());
+
+    profile = result.get(3);
+    assertEquals(3, profile.getCounts().getCount('T'));
+    assertEquals(1, profile.getCounts().getCount('G'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(4, profile.getNonGapped());
   }
 
-  @Test(groups = { "Functional" })
+  @Test(groups = { "Functional" }, enabled = false)
   public void testCalculate_withProfileTiming()
   {
     SequenceI seq1 = new Sequence("Seq1", "CAGT");
@@ -126,27 +126,100 @@ public class AAFrequencyTest
     SequenceI seq3 = new Sequence("Seq3", "C--G");
     SequenceI seq4 = new Sequence("Seq4", "CA-t");
     SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3, seq4 };
-    Hashtable[] result = new Hashtable[seq1.getLength()];
 
-    // ensure class loaded and initialized
-    AAFrequency.calculate(seqs, 0, seq1.getLength(), result, true);
+    // ensure class loaded and initialised
+    int width = seq1.getLength();
+    AAFrequency.calculate(seqs, width, 0, width, true);
+
     int reps = 100000;
     long start = System.currentTimeMillis();
     for (int i = 0; i < reps; i++)
     {
-      AAFrequency.calculate(seqs, 0, seq1.getLength(), result, true);
+      AAFrequency.calculate(seqs, width, 0, width, true);
     }
     System.out.println(System.currentTimeMillis() - start);
   }
 
+  /**
+   * Test generation of consensus annotation with options 'include gaps'
+   * (profile percentages are of all sequences, whether gapped or not), and
+   * 'show logo' (the full profile with all residue percentages is reported in
+   * the description for the tooltip)
+   */
   @Test(groups = { "Functional" })
-  public void testGetPercentageFormat()
+  public void testCompleteConsensus_includeGaps_showLogo()
   {
-    assertNull(AAFrequency.getPercentageFormat(0));
-    assertNull(AAFrequency.getPercentageFormat(99));
-    assertEquals("%3.1f", AAFrequency.getPercentageFormat(100).toString());
-    assertEquals("%3.1f", AAFrequency.getPercentageFormat(999).toString());
-    assertEquals("%3.2f", AAFrequency.getPercentageFormat(1000).toString());
-    assertEquals("%3.2f", AAFrequency.getPercentageFormat(9999).toString());
+    /*
+     * first compute the profiles
+     */
+    SequenceI seq1 = new Sequence("Seq1", "CAG-T");
+    SequenceI seq2 = new Sequence("Seq2", "CAC-T");
+    SequenceI seq3 = new Sequence("Seq3", "C---G");
+    SequenceI seq4 = new Sequence("Seq4", "CA--t");
+    SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3, seq4 };
+    int width = seq1.getLength();
+    ProfilesI profiles = AAFrequency.calculate(seqs, width, 0, width, true);
+
+    AlignmentAnnotation consensus = new AlignmentAnnotation("Consensus",
+            "PID", new Annotation[width]);
+    AAFrequency
+            .completeConsensus(consensus, profiles, 0, 5, false, true, 4);
+
+    Annotation ann = consensus.annotations[0];
+    assertEquals("C 100%", ann.description);
+    assertEquals("C", ann.displayCharacter);
+    ann = consensus.annotations[1];
+    assertEquals("A 75%", ann.description);
+    assertEquals("A", ann.displayCharacter);
+    ann = consensus.annotations[2];
+    assertEquals("C 25%; G 25%", ann.description);
+    assertEquals("+", ann.displayCharacter);
+    ann = consensus.annotations[3];
+    assertEquals("", ann.description);
+    assertEquals("-", ann.displayCharacter);
+    ann = consensus.annotations[4];
+    assertEquals("T 75%; G 25%", ann.description);
+    assertEquals("T", ann.displayCharacter);
+  }
+
+  /**
+   * Test generation of consensus annotation with options 'ignore gaps' (profile
+   * percentages are of the non-gapped sequences) and 'no logo' (only the modal
+   * residue[s] percentage is reported in the description for the tooltip)
+   */
+  @Test(groups = { "Functional" })
+  public void testCompleteConsensus_ignoreGaps_noLogo()
+  {
+    /*
+     * first compute the profiles
+     */
+    SequenceI seq1 = new Sequence("Seq1", "CAG-T");
+    SequenceI seq2 = new Sequence("Seq2", "CAC-T");
+    SequenceI seq3 = new Sequence("Seq3", "C---G");
+    SequenceI seq4 = new Sequence("Seq4", "CA--t");
+    SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3, seq4 };
+    int width = seq1.getLength();
+    ProfilesI profiles = AAFrequency.calculate(seqs, width, 0, width, true);
+  
+    AlignmentAnnotation consensus = new AlignmentAnnotation("Consensus",
+            "PID", new Annotation[width]);
+    AAFrequency
+            .completeConsensus(consensus, profiles, 0, 5, true, false, 4);
+  
+    Annotation ann = consensus.annotations[0];
+    assertEquals("C 100%", ann.description);
+    assertEquals("C", ann.displayCharacter);
+    ann = consensus.annotations[1];
+    assertEquals("A 100%", ann.description);
+    assertEquals("A", ann.displayCharacter);
+    ann = consensus.annotations[2];
+    assertEquals("[CG] 50%", ann.description);
+    assertEquals("+", ann.displayCharacter);
+    ann = consensus.annotations[3];
+    assertEquals("", ann.description);
+    assertEquals("-", ann.displayCharacter);
+    ann = consensus.annotations[4];
+    assertEquals("T 75%", ann.description);
+    assertEquals("T", ann.displayCharacter);
   }
 }
index f74e456..7f7ec31 100644 (file)
@@ -35,8 +35,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.Mapping;
-import jalview.datamodel.SearchResults;
-import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
@@ -443,7 +443,8 @@ public class AlignmentUtilsTests
     SequenceI alignFrom = new Sequence("Seq2", alignModel);
     alignFrom.createDatasetSequence();
     AlignedCodonFrame acf = new AlignedCodonFrame();
-    acf.addMap(alignMe.getDatasetSequence(), alignFrom.getDatasetSequence(), map);
+    acf.addMap(alignMe.getDatasetSequence(),
+            alignFrom.getDatasetSequence(), map);
 
     AlignmentUtils.alignSequenceAs(alignMe, alignFrom, acf, "---", '-',
             preserveMappedGaps, preserveUnmappedGaps);
@@ -981,7 +982,7 @@ public class AlignmentUtilsTests
     /*
      * scenario:
      *     dna1 --> [4, 6] [10,12]        --> pep1 
-     *     dna2 --> [1, 3] [7, 9] [13,15] --> pep1 
+     *     dna2 --> [1, 3] [7, 9] [13,15] --> pep2
      */
     SequenceI dna1 = new Sequence("dna1", "aaaGGGcccTTTaaa");
     SequenceI dna2 = new Sequence("dna2", "GGGcccTTTaaaCCC");
@@ -997,30 +998,51 @@ public class AlignmentUtilsTests
     dna.setDataset(null);
 
     /*
+     * put a variant feature on dna2 base 8
+     * - should transfer to cds2 base 5
+     */
+    dna2.addSequenceFeature(new SequenceFeature("variant", "hgmd", 8, 8,
+            0f, null));
+
+    /*
      * need a sourceDbRef if we are to construct dbrefs to the CDS
-     * sequence
+     * sequence from the dna contig sequences
      */
     DBRefEntry dbref = new DBRefEntry("ENSEMBL", "0", "dna1");
-    dna1.getDatasetSequence().setSourceDBRef(dbref);
+    dna1.getDatasetSequence().addDBRef(dbref);
+    org.testng.Assert.assertEquals(dbref, dna1.getPrimaryDBRefs().get(0));
     dbref = new DBRefEntry("ENSEMBL", "0", "dna2");
-    dna2.getDatasetSequence().setSourceDBRef(dbref);
+    dna2.getDatasetSequence().addDBRef(dbref);
+    org.testng.Assert.assertEquals(dbref, dna2.getPrimaryDBRefs().get(0));
 
     /*
      * CDS sequences are 'discovered' from dna-to-protein mappings on the alignment
      * dataset (e.g. added from dbrefs by CrossRef.findXrefSequences)
      */
-    MapList map = new MapList(new int[] { 4, 6, 10, 12 },
-            new int[] { 1, 2 }, 3, 1);
+    MapList mapfordna1 = new MapList(new int[] { 4, 6, 10, 12 }, new int[] {
+        1, 2 }, 3, 1);
     AlignedCodonFrame acf = new AlignedCodonFrame();
-    acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map);
+    acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(),
+            mapfordna1);
     dna.addCodonFrame(acf);
-    map = new MapList(new int[] { 1, 3, 7, 9, 13, 15 }, new int[] { 1, 3 },
-            3, 1);
+    MapList mapfordna2 = new MapList(new int[] { 1, 3, 7, 9, 13, 15 },
+            new int[] { 1, 3 }, 3, 1);
     acf = new AlignedCodonFrame();
-    acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map);
+    acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(),
+            mapfordna2);
     dna.addCodonFrame(acf);
 
     /*
+     * In this case, mappings originally came from matching Uniprot accessions - so need an xref on dna involving those regions. These are normally constructed from CDS annotation
+     */
+    DBRefEntry dna1xref = new DBRefEntry("UNIPROT", "ENSEMBL", "pep1",
+            new Mapping(mapfordna1));
+    dna1.getDatasetSequence().addDBRef(dna1xref);
+    DBRefEntry dna2xref = new DBRefEntry("UNIPROT", "ENSEMBL", "pep2",
+            new Mapping(mapfordna2));
+    dna2.getDatasetSequence().addDBRef(dna2xref);
+
+    /*
      * execute method under test:
      */
     AlignmentI cds = AlignmentUtils.makeCdsAlignment(new SequenceI[] {
@@ -1046,11 +1068,12 @@ public class AlignmentUtilsTests
      * verify CDS has a dbref with mapping to peptide
      */
     assertNotNull(cds1Dss.getDBRefs());
-    assertEquals(1, cds1Dss.getDBRefs().length);
+    assertEquals(2, cds1Dss.getDBRefs().length);
     dbref = cds1Dss.getDBRefs()[0];
-    assertEquals("UNIPROT", dbref.getSource());
-    assertEquals("0", dbref.getVersion());
-    assertEquals("pep1", dbref.getAccessionId());
+    assertEquals(dna1xref.getSource(), dbref.getSource());
+    // version is via ensembl's primary ref
+    assertEquals(dna1xref.getVersion(), dbref.getVersion());
+    assertEquals(dna1xref.getAccessionId(), dbref.getAccessionId());
     assertNotNull(dbref.getMap());
     assertSame(pep1.getDatasetSequence(), dbref.getMap().getTo());
     MapList cdsMapping = new MapList(new int[] { 1, 6 },
@@ -1061,6 +1084,7 @@ public class AlignmentUtilsTests
      * verify peptide has added a dbref with reverse mapping to CDS
      */
     assertNotNull(pep1.getDBRefs());
+    // FIXME pep1.getDBRefs() is 1 - is that the correct behaviour ?
     assertEquals(2, pep1.getDBRefs().length);
     dbref = pep1.getDBRefs()[1];
     assertEquals("ENSEMBL", dbref.getSource());
@@ -1099,9 +1123,9 @@ public class AlignmentUtilsTests
     assertEquals(1, mappings.size());
 
     // map G to GGG
-    SearchResults sr = MappingUtils.buildSearchResults(pep1, 1, mappings);
+    SearchResultsI sr = MappingUtils.buildSearchResults(pep1, 1, mappings);
     assertEquals(1, sr.getResults().size());
-    Match m = sr.getResults().get(0);
+    SearchResultMatchI m = sr.getResults().get(0);
     assertSame(cds1Dss, m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
@@ -1141,6 +1165,16 @@ public class AlignmentUtilsTests
     assertSame(cds2Dss, m.getSequence());
     assertEquals(7, m.getStart());
     assertEquals(9, m.getEnd());
+
+    /*
+     * check cds2 acquired a variant feature in position 5
+     */
+    SequenceFeature[] sfs = cds2Dss.getSequenceFeatures();
+    assertNotNull(sfs);
+    assertEquals(1, sfs.length);
+    assertEquals("variant", sfs[0].type);
+    assertEquals(5, sfs[0].begin);
+    assertEquals(5, sfs[0].end);
   }
 
   /**
@@ -1280,8 +1314,7 @@ public class AlignmentUtilsTests
             .findMappingsForSequence(cds.get(0), dnaMappings);
     Mapping mapping = dnaToCds1Mappings.get(0).getMappings().get(0)
             .getMapping();
-    assertSame(cds.get(0).getDatasetSequence(), mapping
-            .getTo());
+    assertSame(cds.get(0).getDatasetSequence(), mapping.getTo());
     assertEquals("G(1) in CDS should map to G(4) in DNA", 4, mapping
             .getMap().getToPosition(1));
 
@@ -1349,8 +1382,7 @@ public class AlignmentUtilsTests
    * @throws IOException
    */
   @Test(groups = { "Functional" })
-  public void testMapCdnaToProtein_forSubsequence()
-          throws IOException
+  public void testMapCdnaToProtein_forSubsequence() throws IOException
   {
     SequenceI prot = new Sequence("UNIPROT|V12345", "E-I--Q", 10, 12);
     prot.createDatasetSequence();
@@ -1371,7 +1403,7 @@ public class AlignmentUtilsTests
   @Test(groups = { "Functional" })
   public void testAlignSequenceAs_mappedProteinProtein()
   {
-  
+
     SequenceI alignMe = new Sequence("Match", "MGAASEV");
     alignMe.createDatasetSequence();
     SequenceI alignFrom = new Sequence("Query", "LQTGYMGAASEVMFSPTRR");
@@ -1382,7 +1414,7 @@ public class AlignmentUtilsTests
     MapList map = new MapList(new int[] { 6, 12 }, new int[] { 1, 7 }, 1, 1);
     acf.addMap(alignFrom.getDatasetSequence(),
             alignMe.getDatasetSequence(), map);
-    
+
     AlignmentUtils.alignSequenceAs(alignMe, alignFrom, acf, "-", '-', true,
             true);
     assertEquals("-----MGAASEV-------", alignMe.getSequenceAsString());
@@ -1397,7 +1429,7 @@ public class AlignmentUtilsTests
   {
     // map first 3 codons to KPF; G is a trailing unmapped residue
     MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
-  
+
     checkAlignSequenceAs("AAACCCTTT", "K-PFG", true, true, map,
             "AAA---CCCTTT---");
   }
@@ -1496,7 +1528,7 @@ public class AlignmentUtilsTests
 
     MapList map = new MapList(new int[] { 4, 6, 10, 12 },
             new int[] { 1, 6 }, 1, 1);
-  
+
     // [5, 11] maps to [2, 5]
     dna.addSequenceFeature(new SequenceFeature("type4", "desc4", 5, 11, 4f,
             null));
@@ -1506,12 +1538,12 @@ public class AlignmentUtilsTests
     // [12, 12] maps to [6, 6]
     dna.addSequenceFeature(new SequenceFeature("type8", "desc8", 12, 12,
             8f, null));
-  
+
     // desc4 and desc8 are the 'omit these' varargs
     AlignmentUtils.transferFeatures(dna, cds, map, null, "type4", "type8");
     SequenceFeature[] sfs = cds.getSequenceFeatures();
     assertEquals(1, sfs.length);
-  
+
     SequenceFeature sf = sfs[0];
     assertEquals("type5", sf.getType());
     assertEquals(1, sf.getBegin());
@@ -1526,10 +1558,10 @@ public class AlignmentUtilsTests
   {
     SequenceI dna = new Sequence("dna/20-34", "acgTAGcaaGCCcgt");
     SequenceI cds = new Sequence("cds/10-15", "TAGGCC");
-  
+
     MapList map = new MapList(new int[] { 4, 6, 10, 12 },
             new int[] { 1, 6 }, 1, 1);
-  
+
     // [5, 11] maps to [2, 5]
     dna.addSequenceFeature(new SequenceFeature("type4", "desc4", 5, 11, 4f,
             null));
@@ -1539,12 +1571,12 @@ public class AlignmentUtilsTests
     // [12, 12] maps to [6, 6]
     dna.addSequenceFeature(new SequenceFeature("type8", "desc8", 12, 12,
             8f, null));
-  
+
     // "type5" is the 'select this type' argument
     AlignmentUtils.transferFeatures(dna, cds, map, "type5");
     SequenceFeature[] sfs = cds.getSequenceFeatures();
     assertEquals(1, sfs.length);
-  
+
     SequenceFeature sf = sfs[0];
     assertEquals("type5", sf.getType());
     assertEquals(1, sf.getBegin());
@@ -1573,26 +1605,25 @@ public class AlignmentUtilsTests
 
     AlignmentI dna = new Alignment(new SequenceI[] { dna1, dna2, dna3 });
     dna.setDataset(null);
-  
+
     MapList map = new MapList(new int[] { 4, 12, 16, 18 },
             new int[] { 1, 4 }, 3, 1);
     AlignedCodonFrame acf = new AlignedCodonFrame();
     acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map);
     dna.addCodonFrame(acf);
     map = new MapList(new int[] { 4, 8, 12, 12, 16, 18 },
-            new int[] { 1, 3 },
-            3, 1);
+            new int[] { 1, 3 }, 3, 1);
     acf = new AlignedCodonFrame();
     acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map);
     dna.addCodonFrame(acf);
-  
+
     AlignmentI cds = AlignmentUtils.makeCdsAlignment(new SequenceI[] {
         dna1, dna2, dna3 }, dna.getDataset(), null);
     List<SequenceI> cdsSeqs = cds.getSequences();
     assertEquals(2, cdsSeqs.size());
     assertEquals("GGGCCCTTTGGG", cdsSeqs.get(0).getSequenceAsString());
     assertEquals("GGGCCTGGG", cdsSeqs.get(1).getSequenceAsString());
-  
+
     /*
      * verify shared, extended alignment dataset
      */
@@ -1608,7 +1639,7 @@ public class AlignmentUtilsTests
      */
     List<AlignedCodonFrame> mappings = cds.getCodonFrames();
     assertEquals(6, mappings.size());
-  
+
     /*
      * 2 mappings involve pep1
      */
@@ -1623,12 +1654,11 @@ public class AlignmentUtilsTests
     List<AlignedCodonFrame> pep1CdsMappings = MappingUtils
             .findMappingsForSequence(cds.getSequenceAt(0), pep1Mappings);
     assertEquals(1, pep1CdsMappings.size());
-    SearchResults sr = MappingUtils.buildSearchResults(pep1, 1,
+    SearchResultsI sr = MappingUtils.buildSearchResults(pep1, 1,
             pep1CdsMappings);
     assertEquals(1, sr.getResults().size());
-    Match m = sr.getResults().get(0);
-    assertEquals(cds.getSequenceAt(0).getDatasetSequence(),
-            m.getSequence());
+    SearchResultMatchI m = sr.getResults().get(0);
+    assertEquals(cds.getSequenceAt(0).getDatasetSequence(), m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
     sr = MappingUtils.buildSearchResults(pep1, 2, pep1CdsMappings);
@@ -1643,7 +1673,7 @@ public class AlignmentUtilsTests
     m = sr.getResults().get(0);
     assertEquals(10, m.getStart());
     assertEquals(12, m.getEnd());
-  
+
     /*
      * Get mapping of pep2 to cds2 and verify it
      * maps GPG in pep2 to 1-3,4-6,7-9 in second CDS sequence
@@ -1657,8 +1687,7 @@ public class AlignmentUtilsTests
     sr = MappingUtils.buildSearchResults(pep2, 1, pep2CdsMappings);
     assertEquals(1, sr.getResults().size());
     m = sr.getResults().get(0);
-    assertEquals(cds.getSequenceAt(1).getDatasetSequence(),
-            m.getSequence());
+    assertEquals(cds.getSequenceAt(1).getDatasetSequence(), m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
     sr = MappingUtils.buildSearchResults(pep2, 2, pep2CdsMappings);
@@ -1685,7 +1714,7 @@ public class AlignmentUtilsTests
     SequenceI dna3 = new Sequence("Seq3", "ccaaa-ttt-GGG-");
     AlignmentI dna = new Alignment(new SequenceI[] { dna1, dna2, dna3 });
     dna.setDataset(null);
-  
+
     // prot1 has 'X' for incomplete start codon (not mapped)
     SequenceI prot1 = new Sequence("Seq1", "XKFG"); // X for incomplete start
     SequenceI prot2 = new Sequence("Seq2", "NG");
@@ -1693,7 +1722,7 @@ public class AlignmentUtilsTests
     AlignmentI protein = new Alignment(new SequenceI[] { prot1, prot2,
         prot3 });
     protein.setDataset(null);
-  
+
     // map dna1 [3, 11] to prot1 [2, 4] KFG
     MapList map = new MapList(new int[] { 3, 11 }, new int[] { 2, 4 }, 3, 1);
     AlignedCodonFrame acf = new AlignedCodonFrame();
@@ -1732,7 +1761,7 @@ public class AlignmentUtilsTests
     SequenceI dnaSeq = new Sequence("dna", "aaagGGCCCaaaTTTttt");
     dnaSeq.createDatasetSequence();
     SequenceI ds = dnaSeq.getDatasetSequence();
-  
+
     // CDS for dna 5-6 (incomplete codon), 7-9
     SequenceFeature sf = new SequenceFeature("CDS", "", 5, 9, 0f, null);
     sf.setPhase("2"); // skip 2 bases to start of next codon
@@ -1740,9 +1769,9 @@ public class AlignmentUtilsTests
     // CDS for dna 13-15
     sf = new SequenceFeature("CDS_predicted", "", 13, 15, 0f, null);
     ds.addSequenceFeature(sf);
-  
+
     List<int[]> ranges = AlignmentUtils.findCdsPositions(dnaSeq);
-  
+
     /*
      * check the mapping starts with the first complete codon
      */
@@ -1764,7 +1793,7 @@ public class AlignmentUtilsTests
     SequenceI dnaSeq = new Sequence("dna", "aaaGGGcccAAATTTttt");
     dnaSeq.createDatasetSequence();
     SequenceI ds = dnaSeq.getDatasetSequence();
-  
+
     // CDS for dna 10-12
     SequenceFeature sf = new SequenceFeature("CDS_predicted", "", 10, 12,
             0f, null);
@@ -1777,7 +1806,7 @@ public class AlignmentUtilsTests
     // exon feature should be ignored here
     sf = new SequenceFeature("exon", "", 7, 9, 0f, null);
     ds.addSequenceFeature(sf);
-  
+
     List<int[]> ranges = AlignmentUtils.findCdsPositions(dnaSeq);
     /*
      * verify ranges { [4-6], [12-10] }
@@ -2122,7 +2151,7 @@ public class AlignmentUtilsTests
     SequenceI dnaSeq = new Sequence("dna", "aaaGGGcccAAATTTttt");
     dnaSeq.createDatasetSequence();
     SequenceI ds = dnaSeq.getDatasetSequence();
-  
+
     // CDS for dna 4-6
     SequenceFeature sf = new SequenceFeature("CDS", "", 4, 6, 0f, null);
     sf.setStrand("-");
@@ -2134,7 +2163,7 @@ public class AlignmentUtilsTests
     sf = new SequenceFeature("CDS_predicted", "", 10, 12, 0f, null);
     sf.setStrand("-");
     ds.addSequenceFeature(sf);
-  
+
     List<int[]> ranges = AlignmentUtils.findCdsPositions(dnaSeq);
     /*
      * verify ranges { [12-10], [6-4] }
@@ -2160,7 +2189,7 @@ public class AlignmentUtilsTests
     SequenceI dnaSeq = new Sequence("dna", "aaagGGCCCaaaTTTttt");
     dnaSeq.createDatasetSequence();
     SequenceI ds = dnaSeq.getDatasetSequence();
-  
+
     // CDS for dna 5-9
     SequenceFeature sf = new SequenceFeature("CDS", "", 5, 9, 0f, null);
     sf.setStrand("-");
@@ -2170,9 +2199,9 @@ public class AlignmentUtilsTests
     sf.setStrand("-");
     sf.setPhase("2"); // skip 2 bases to start of next codon
     ds.addSequenceFeature(sf);
-  
+
     List<int[]> ranges = AlignmentUtils.findCdsPositions(dnaSeq);
-  
+
     /*
      * check the mapping starts with the first complete codon
      * expect ranges [13, 13], [9, 5]
@@ -2225,8 +2254,7 @@ public class AlignmentUtilsTests
     from.createDatasetSequence();
     seq1.createDatasetSequence();
     Mapping mapping = new Mapping(seq1, new MapList(
-            new int[] { 3, 6, 9, 10 },
-            new int[] { 1, 6 }, 1, 1));
+            new int[] { 3, 6, 9, 10 }, new int[] { 1, 6 }, 1, 1));
     Map<Integer, Map<SequenceI, Character>> map = new TreeMap<Integer, Map<SequenceI, Character>>();
     AlignmentUtils.addMappedPositions(seq1, from, mapping, map);
 
@@ -2258,11 +2286,10 @@ public class AlignmentUtilsTests
     from.createDatasetSequence();
     seq1.createDatasetSequence();
     Mapping mapping = new Mapping(seq1, new MapList(
-            new int[] { 3, 6, 9, 10 },
-            new int[] { 1, 6 }, 1, 1));
+            new int[] { 3, 6, 9, 10 }, new int[] { 1, 6 }, 1, 1));
     Map<Integer, Map<SequenceI, Character>> map = new TreeMap<Integer, Map<SequenceI, Character>>();
     AlignmentUtils.addMappedPositions(seq1, from, mapping, map);
-  
+
     /*
      * verify map has seq1 residues in columns 3,4,6,7,11,12
      */
@@ -2300,7 +2327,7 @@ public class AlignmentUtilsTests
     dna.setDataset(null);
     AlignmentI emblPeptides = new Alignment(new SequenceI[] { pep3, pep4 });
     emblPeptides.setDataset(null);
-  
+
     AlignedCodonFrame acf = new AlignedCodonFrame();
     MapList map = new MapList(new int[] { 4, 6, 10, 12 },
             new int[] { 1, 2 }, 3, 1);
@@ -2314,17 +2341,17 @@ public class AlignmentUtilsTests
     acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map);
     acf.addMap(dna2.getDatasetSequence(), pep4.getDatasetSequence(), map);
     dna.addCodonFrame(acf);
-  
+
     /*
      * execute method under test to find CDS for EMBL peptides only
      */
     AlignmentI cds = AlignmentUtils.makeCdsAlignment(new SequenceI[] {
         dna1, dna2 }, dna.getDataset(), emblPeptides.getSequencesArray());
-  
+
     assertEquals(2, cds.getSequences().size());
     assertEquals("GGGTTT", cds.getSequenceAt(0).getSequenceAsString());
     assertEquals("GGGTTTCCC", cds.getSequenceAt(1).getSequenceAsString());
-  
+
     /*
      * verify shared, extended alignment dataset
      */
@@ -2333,7 +2360,7 @@ public class AlignmentUtilsTests
             .contains(cds.getSequenceAt(0).getDatasetSequence()));
     assertTrue(dna.getDataset().getSequences()
             .contains(cds.getSequenceAt(1).getDatasetSequence()));
-  
+
     /*
      * Verify mappings from CDS to peptide, cDNA to CDS, and cDNA to peptide
      * the mappings are on the shared alignment dataset
@@ -2343,7 +2370,7 @@ public class AlignmentUtilsTests
      * 6 mappings, 2*(DNA->CDS), 2*(DNA->Pep), 2*(CDS->Pep) 
      */
     assertEquals(6, cdsMappings.size());
-  
+
     /*
      * verify that mapping sets for dna and cds alignments are different
      * [not current behaviour - all mappings are on the alignment dataset]  
@@ -2352,7 +2379,7 @@ public class AlignmentUtilsTests
     // Assert.assertNotSame(dna.getCodonFrames(), cds.getCodonFrames());
     // assertEquals(4, dna.getCodonFrames().size());
     // assertEquals(4, cds.getCodonFrames().size());
-  
+
     /*
      * Two mappings involve pep3 (dna to pep3, cds to pep3)
      * Mapping from pep3 to GGGTTT in first new exon sequence
@@ -2363,11 +2390,11 @@ public class AlignmentUtilsTests
     List<AlignedCodonFrame> mappings = MappingUtils
             .findMappingsForSequence(cds.getSequenceAt(0), pep3Mappings);
     assertEquals(1, mappings.size());
-  
+
     // map G to GGG
-    SearchResults sr = MappingUtils.buildSearchResults(pep3, 1, mappings);
+    SearchResultsI sr = MappingUtils.buildSearchResults(pep3, 1, mappings);
     assertEquals(1, sr.getResults().size());
-    Match m = sr.getResults().get(0);
+    SearchResultMatchI m = sr.getResults().get(0);
     assertSame(cds.getSequenceAt(0).getDatasetSequence(), m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
@@ -2377,7 +2404,7 @@ public class AlignmentUtilsTests
     assertSame(cds.getSequenceAt(0).getDatasetSequence(), m.getSequence());
     assertEquals(4, m.getStart());
     assertEquals(6, m.getEnd());
-  
+
     /*
      * Two mappings involve pep4 (dna to pep4, cds to pep4)
      * Verify mapping from pep4 to GGGTTTCCC in second new exon sequence
@@ -2431,7 +2458,7 @@ public class AlignmentUtilsTests
     dna4.setSequence(seq2);
     AlignmentI al2 = new Alignment(new SequenceI[] { dna3, dna4 });
     ((Alignment) al2).createDatasetAlignment();
-    
+
     assertTrue(AlignmentUtils.alignAsSameSequences(al1, al2));
     assertEquals(seq1, al1.getSequenceAt(0).getSequenceAsString());
     assertEquals(seq2, al1.getSequenceAt(1).getSequenceAsString());
@@ -2488,5 +2515,5 @@ public class AlignmentUtilsTests
     assertEquals(s_as2, uas2.getSequenceAsString());
     assertEquals(s_as3, uas3.getSequenceAsString());
   }
-    
+
 }
diff --git a/test/jalview/analysis/ConservationTest.java b/test/jalview/analysis/ConservationTest.java
new file mode 100644 (file)
index 0000000..39eb309
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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.analysis;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+public class ConservationTest
+{
+  @Test(groups = "Functional")
+  public void testRecordConservation()
+  {
+    Map<String, Integer> resultMap = new HashMap<String, Integer>();
+
+    // V is hydrophobic, aliphatic, small
+    Conservation.recordConservation(resultMap, "V");
+    assertEquals(resultMap.get("hydrophobic").intValue(), 1);
+    assertEquals(resultMap.get("aliphatic").intValue(), 1);
+    assertEquals(resultMap.get("small").intValue(), 1);
+    assertEquals(resultMap.get("tiny").intValue(), 0);
+    assertEquals(resultMap.get("polar").intValue(), 0);
+    assertEquals(resultMap.get("charged").intValue(), 0);
+
+    // now add S: not hydrophobic, small, tiny, polar, not aliphatic
+    Conservation.recordConservation(resultMap, "s");
+    assertEquals(resultMap.get("hydrophobic").intValue(), -1);
+    assertEquals(resultMap.get("aliphatic").intValue(), -1);
+    assertEquals(resultMap.get("small").intValue(), 1);
+    assertEquals(resultMap.get("tiny").intValue(), -1);
+    assertEquals(resultMap.get("polar").intValue(), -1);
+    assertEquals(resultMap.get("charged").intValue(), 0);
+  }
+
+  @Test(groups = "Functional")
+  public void testCountConservationAndGaps()
+  {
+    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    seqs.add(new Sequence("seq1", "VGnY")); // not case sensitive
+    seqs.add(new Sequence("seq2", "-G-y"));
+    seqs.add(new Sequence("seq3", "VG-Y"));
+    seqs.add(new Sequence("seq4", "VGNW"));
+
+    Conservation cons = new Conservation("", seqs, 0, 50);
+    int[] counts = cons.countConservationAndGaps(0);
+    assertEquals(counts[0], 1); // conserved
+    assertEquals(counts[1], 1); // gap count
+    counts = cons.countConservationAndGaps(1);
+    assertEquals(counts[0], 1);
+    assertEquals(counts[1], 0);
+    counts = cons.countConservationAndGaps(2);
+    assertEquals(counts[0], 1);
+    assertEquals(counts[1], 2);
+    counts = cons.countConservationAndGaps(3);
+    assertEquals(counts[0], 0); // not conserved
+    assertEquals(counts[1], 0);
+  }
+
+  @Test(groups = "Functional")
+  public void testCalculate_noThreshold()
+  {
+    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    seqs.add(new Sequence("seq1", "VGIV-N"));
+    seqs.add(new Sequence("seq2", "V-iL-N")); // not case sensitive
+    seqs.add(new Sequence("seq3", "V-IW-N"));
+    seqs.add(new Sequence("seq4", "VGLH-L"));
+
+    Conservation cons = new Conservation("", 0, seqs, 0, 5);
+    cons.calculate();
+
+    /*
+     * column 0: all V (hydrophobic/aliphatic/small)
+     */
+    Map<String, Integer> colCons = cons.total[0];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 1);
+    assertEquals(colCons.get("small").intValue(), 1);
+    assertEquals(colCons.get("tiny").intValue(), 0);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), 0);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), 0);
+    assertEquals(colCons.get("positive").intValue(), 0);
+    assertEquals(colCons.get("aromatic").intValue(), 0);
+
+    /*
+     * column 1: all G (hydrophobic/small/tiny)
+     * gaps take default value of property present
+     */
+    colCons = cons.total[1];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), -1);
+    assertEquals(colCons.get("small").intValue(), 1);
+    assertEquals(colCons.get("tiny").intValue(), 1);
+    assertEquals(colCons.get("proline").intValue(), -1);
+    assertEquals(colCons.get("charged").intValue(), -1);
+    assertEquals(colCons.get("negative").intValue(), -1);
+    assertEquals(colCons.get("polar").intValue(), -1);
+    assertEquals(colCons.get("positive").intValue(), -1);
+    assertEquals(colCons.get("aromatic").intValue(), -1);
+
+    /*
+     * column 2: I/L (aliphatic/hydrophobic), all others negatively conserved
+     */
+    colCons = cons.total[2];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 1);
+    assertEquals(colCons.get("small").intValue(), 0);
+    assertEquals(colCons.get("tiny").intValue(), 0);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), 0);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), 0);
+    assertEquals(colCons.get("positive").intValue(), 0);
+    assertEquals(colCons.get("aromatic").intValue(), 0);
+
+    /*
+     * column 3: VLWH all hydrophobic, none is tiny, negative or proline
+     */
+    colCons = cons.total[3];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), -1);
+    assertEquals(colCons.get("small").intValue(), -1);
+    assertEquals(colCons.get("tiny").intValue(), 0);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), -1);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), -1);
+    assertEquals(colCons.get("positive").intValue(), -1);
+    assertEquals(colCons.get("aromatic").intValue(), -1);
+
+    /*
+     * column 4: all gaps - counted as having all properties
+     */
+    colCons = cons.total[4];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 1);
+    assertEquals(colCons.get("small").intValue(), 1);
+    assertEquals(colCons.get("tiny").intValue(), 1);
+    assertEquals(colCons.get("proline").intValue(), 1);
+    assertEquals(colCons.get("charged").intValue(), 1);
+    assertEquals(colCons.get("negative").intValue(), 1);
+    assertEquals(colCons.get("polar").intValue(), 1);
+    assertEquals(colCons.get("positive").intValue(), 1);
+    assertEquals(colCons.get("aromatic").intValue(), 1);
+
+    /*
+     * column 5: N (small polar) and L (aliphatic hydrophobic) 
+     * have nothing in common!
+     */
+    colCons = cons.total[5];
+    assertEquals(colCons.get("hydrophobic").intValue(), -1);
+    assertEquals(colCons.get("aliphatic").intValue(), -1);
+    assertEquals(colCons.get("small").intValue(), -1);
+    assertEquals(colCons.get("tiny").intValue(), 0);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), 0);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), -1);
+    assertEquals(colCons.get("positive").intValue(), 0);
+    assertEquals(colCons.get("aromatic").intValue(), 0);
+  }
+
+  /**
+   * Test for the case whether the number of non-gapped sequences in a column
+   * has to be above a threshold
+   */
+  @Test(groups = "Functional")
+  public void testCalculate_threshold()
+  {
+    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    seqs.add(new Sequence("seq1", "VGIV-"));
+    seqs.add(new Sequence("seq2", "V-iL-")); // not case sensitive
+    seqs.add(new Sequence("seq3", "V-IW-"));
+    seqs.add(new Sequence("seq4", "VGLH-"));
+    seqs.add(new Sequence("seq5", "VGLH-"));
+  
+    /*
+     * threshold 50% means a residue has to occur 3 or more times
+     * in a column to be counted for conservation
+     */
+    // TODO: ConservationThread uses a value of 3
+    // calculateConservation states it is the minimum number of sequences
+    // but it is treated as percentage threshold in calculate() ?
+    Conservation cons = new Conservation("", 50, seqs, 0, 4);
+    cons.calculate();
+  
+    /*
+     * column 0: all V (hydrophobic/aliphatic/small)
+     */
+    Map<String, Integer> colCons = cons.total[0];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 1);
+    assertEquals(colCons.get("small").intValue(), 1);
+    assertEquals(colCons.get("tiny").intValue(), 0);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), 0);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), 0);
+    assertEquals(colCons.get("positive").intValue(), 0);
+    assertEquals(colCons.get("aromatic").intValue(), 0);
+  
+    /*
+     * column 1: all G (hydrophobic/small/tiny)
+     * gaps are ignored as not above threshold
+     */
+    colCons = cons.total[1];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 0);
+    assertEquals(colCons.get("small").intValue(), 1);
+    assertEquals(colCons.get("tiny").intValue(), 1);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), 0);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), 0);
+    assertEquals(colCons.get("positive").intValue(), 0);
+    assertEquals(colCons.get("aromatic").intValue(), 0);
+  
+    /*
+     * column 2: I/L (aliphatic/hydrophobic), all others negatively conserved
+     */
+    colCons = cons.total[2];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 1);
+    assertEquals(colCons.get("small").intValue(), 0);
+    assertEquals(colCons.get("tiny").intValue(), 0);
+    assertEquals(colCons.get("proline").intValue(), 0);
+    assertEquals(colCons.get("charged").intValue(), 0);
+    assertEquals(colCons.get("negative").intValue(), 0);
+    assertEquals(colCons.get("polar").intValue(), 0);
+    assertEquals(colCons.get("positive").intValue(), 0);
+    assertEquals(colCons.get("aromatic").intValue(), 0);
+  
+    /*
+     * column 3: nothing above threshold
+     */
+    colCons = cons.total[3];
+    assertTrue(colCons.isEmpty());
+  
+    /*
+     * column 4: all gaps - counted as having all properties
+     */
+    colCons = cons.total[4];
+    assertEquals(colCons.get("hydrophobic").intValue(), 1);
+    assertEquals(colCons.get("aliphatic").intValue(), 1);
+    assertEquals(colCons.get("small").intValue(), 1);
+    assertEquals(colCons.get("tiny").intValue(), 1);
+    assertEquals(colCons.get("proline").intValue(), 1);
+    assertEquals(colCons.get("charged").intValue(), 1);
+    assertEquals(colCons.get("negative").intValue(), 1);
+    assertEquals(colCons.get("polar").intValue(), 1);
+    assertEquals(colCons.get("positive").intValue(), 1);
+    assertEquals(colCons.get("aromatic").intValue(), 1);
+  }
+
+  /**
+   * Test the method that derives the conservation 'sequence' and the mouseover
+   * tooltips from the computed conservation
+   */
+  @Test(groups = "Functional")
+  public void testVerdict()
+  {
+    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    seqs.add(new Sequence("seq1", "VGIVV-H"));
+    seqs.add(new Sequence("seq2", "VGILL-H"));
+    seqs.add(new Sequence("seq3", "VGIW--R"));
+    seqs.add(new Sequence("seq4", "VGLHH--"));
+    seqs.add(new Sequence("seq5", "VGLHH-R"));
+    seqs.add(new Sequence("seq6", "VGLHH--"));
+    seqs.add(new Sequence("seq7", "VGLHH-R"));
+    seqs.add(new Sequence("seq8", "VGLHH-R"));
+
+    // calculate with no threshold
+    Conservation cons = new Conservation("", 0, seqs, 0, 6);
+    cons.calculate();
+    // positive and negative conservation where <25% gaps in columns
+    cons.verdict(false, 25);
+
+    /*
+     * verify conservation 'sequence'
+     * cols 0 fully conserved and above threshold (*)
+     * col 2 properties fully conserved (+)
+     * col 3 VLWH 1 positively and 3 negatively conserved properties
+     * col 4 has 1 positively conserved property, but because gap contributes a
+     * 'positive' for all properties, no negative conservation is counted
+     * col 5 is all gaps
+     * col 6 has 25% gaps so fails threshold test
+     */
+    assertEquals(cons.getConsSequence().getSequenceAsString(), "**+41--");
+
+    /*
+     * verify tooltips; conserved properties are sorted alphabetically within
+     * positive followed by negative
+     */
+    assertEquals(
+            cons.getTooltip(0),
+            "aliphatic hydrophobic small !aromatic !charged !negative !polar !positive !proline !tiny");
+    assertEquals(
+            cons.getTooltip(1),
+            "hydrophobic small tiny !aliphatic !aromatic !charged !negative !polar !positive !proline");
+    assertEquals(
+            cons.getTooltip(2),
+            "aliphatic hydrophobic !aromatic !charged !negative !polar !positive !proline !small !tiny");
+    assertEquals(cons.getTooltip(3), "hydrophobic !negative !proline !tiny");
+    assertEquals(cons.getTooltip(4), "hydrophobic");
+    assertEquals(cons.getTooltip(5), "");
+    assertEquals(cons.getTooltip(6), "");
+  }
+}
index 62bcae8..a85dcef 100644 (file)
@@ -80,12 +80,11 @@ public class CrossRefTest
      * Just the protein refs:
      */
     found = DBRefUtils.selectDbRefs(false, refs);
-    assertEquals(5, found.length);
+    assertEquals(4, found.length);
     assertSame(ref1, found[0]);
     assertSame(ref2, found[1]);
-    assertSame(ref3, found[2]);
-    assertSame(ref4, found[3]);
-    assertSame(ref9, found[4]);
+    assertSame(ref4, found[2]);
+    assertSame(ref9, found[3]);
   }
 
   /**
@@ -122,8 +121,9 @@ public class CrossRefTest
     seq.addDBRef(new DBRefEntry("ENSEMBLGENOMES", "0", "E2350"));
     sources = new CrossRef(new SequenceI[] { seq }, al)
             .findXrefSourcesForSequences(false);
-    assertEquals(4, sources.size());
-    assertEquals("[EMBL, EMBLCDS, GENEDB, ENSEMBL]", sources.toString());
+    // method is patched to remove EMBL from the sources to match
+    assertEquals(3, sources.size());
+    assertEquals("[EMBLCDS, GENEDB, ENSEMBL]", sources.toString());
 
     /*
      * add a sequence to the alignment which has a dbref to UNIPROT|A1234
@@ -141,8 +141,9 @@ public class CrossRefTest
     al.addSequence(seq2);
     sources = new CrossRef(new SequenceI[] { seq, seq2 }, al)
             .findXrefSourcesForSequences(false);
-    assertEquals(3, sources.size());
-    assertEquals("[EMBLCDS, EMBL, GENEDB]", sources.toString());
+    // method removed EMBL from sources to match
+    assertEquals(2, sources.size());
+    assertEquals("[EMBLCDS, GENEDB]", sources.toString());
   }
 
   /**
@@ -250,8 +251,7 @@ public class CrossRefTest
      */
     SequenceI dna1 = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
     Mapping map = new Mapping(new Sequence("pep2", "MLAVSRG"), new MapList(
-            new int[] { 1, 21 }, new int[] {
-        1, 7 }, 3, 1));
+            new int[] { 1, 21 }, new int[] { 1, 7 }, 3, 1));
     DBRefEntry dbref = new DBRefEntry("UNIPROT", "0", "Q9ZTS2", map);
     dna1.addDBRef(dbref);
     dna1.addDBRef(new DBRefEntry("EMBL", "0", "AF039662"));
@@ -281,7 +281,7 @@ public class CrossRefTest
     dbref = new DBRefEntry("UNIPROT", "0", "Q9ZTS2");
     found = testee.searchDataset(!dna1.isProtein(), dna1, dbref, result,
             acf, false); // search dataset with a protein xref from a dna
-                          // sequence to locate the protein product
+                         // sequence to locate the protein product
     assertTrue(found);
     assertEquals(1, result.size());
     assertSame(pep1, result.get(0));
@@ -295,7 +295,7 @@ public class CrossRefTest
     dbref = new DBRefEntry("UNIPROT", "0", "Q9ZTS2");
     found = testee.searchDataset(!pep1.isProtein(), pep1, dbref, result,
             acf, false); // search dataset with a protein's direct dbref to
-                          // locate dna sequences with matching xref
+                         // locate dna sequences with matching xref
     assertTrue(found);
     assertEquals(1, result.size());
     assertSame(dna1, result.get(0));
@@ -403,11 +403,14 @@ public class CrossRefTest
   public void testFindXrefSequences_withFetch()
   {
     SequenceI dna1 = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
-    dna1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
-    dna1.addDBRef(new DBRefEntry("UNIPROT", "0", "P30419"));
-    dna1.addDBRef(new DBRefEntry("UNIPROT", "0", "P00314"));
+    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"));
+
     final SequenceI pep2 = new Sequence("P00314", "MRKLLAASG");
+    pep2.addDBRef(new DBRefEntry("UNIPROT", "0", "P00314"));
 
     /*
      * argument false suppresses adding DAS sources
@@ -472,7 +475,7 @@ public class CrossRefTest
      * 'spliced transcript' with CDS ranges
      */
     SequenceI braf002 = new Sequence("ENST00000497784", "gCAGGCtaTCTGTTCaa");
-    braf002.addDBRef(new DBRefEntry("UNIPROT", "0", "H7C5K3"));
+    braf002.addDBRef(new DBRefEntry("UNIPROT", "ENSEMBL|0", "H7C5K3"));
     braf002.addSequenceFeature(new SequenceFeature("CDS", "", 2, 6, 0f,
             null));
     braf002.addSequenceFeature(new SequenceFeature("CDS", "", 9, 15, 0f,
@@ -484,8 +487,9 @@ public class CrossRefTest
      * which happens to be true for Uniprot,PDB,EMBL but not Pfam,Rfam,Ensembl 
      */
     final SequenceI pep1 = new Sequence("UNIPROT|P15056", "MAAL");
+    pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "P15056"));
     final SequenceI pep2 = new Sequence("UNIPROT|H7C5K3", "QALF");
-
+    pep2.addDBRef(new DBRefEntry("UNIPROT", "0", "H7C5K3"));
     /*
      * argument false suppresses adding DAS sources
      * todo: define an interface type SequenceFetcherI and mock that
@@ -621,7 +625,7 @@ public class CrossRefTest
      */
     final SequenceI x07547 = new Sequence("EMBL|X07547", "cccAAACCCTTTGGG");
     DBRefEntry dbref7 = new DBRefEntry("UNIPROT", "0", "P0CE20");
-    dbref7.setMap(new Mapping(new Sequence("UNIPROT|P0CE19", "KPFG"),
+    dbref7.setMap(new Mapping(new Sequence("UNIPROT|P0CE20", "PFGK"),
             new MapList(map2)));
     x07547.addDBRef(dbref7);
     DBRefEntry dbref8 = new DBRefEntry("UNIPROT", "0", "B0BCM4");
index 31c9839..ba91d37 100644 (file)
@@ -527,7 +527,7 @@ public class DnaTest
     String seqDsRev = new StringBuilder(seqDs).reverse().toString();
 
     SequenceI dna = new Sequence("Seq1", seq);
-    Alignment al = new Alignment(new SequenceI[] {dna});
+    Alignment al = new Alignment(new SequenceI[] { dna });
     al.createDatasetAlignment();
     assertEquals(seqDs, al.getSequenceAt(0).getDatasetSequence()
             .getSequenceAsString());
diff --git a/test/jalview/analysis/FinderTest.java b/test/jalview/analysis/FinderTest.java
new file mode 100644 (file)
index 0000000..4fdafde
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * 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.analysis;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.Sequence;
+import jalview.gui.AlignFrame;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class FinderTest
+{
+  private AlignFrame af;
+
+  private AlignmentI al;
+
+  @BeforeClass(groups = "Functional")
+  public void setUp()
+  {
+    String seqData = "seq1 ABCD--EF-GHI\n" + "seq2 A--BCDefHI\n"
+            + "seq3 --bcdEFH\n" + "seq4 aa---aMMMMMaaa\n";
+    af = new FileLoader().LoadFileWaitTillLoaded(seqData,
+            DataSourceType.PASTE);
+    al = af.getViewport().getAlignment();
+  }
+
+  /**
+   * Test for find all matches of a regular expression
+   */
+  @Test(groups = "Functional")
+  public void testFindAll_regex()
+  {
+    Finder f = new Finder(al, null);
+    f.setFindAll(true);
+    f.find("E.H"); // 'E, any character, H'
+
+    // should match seq2 efH and seq3 EFH
+    SearchResultsI sr = f.getSearchResults();
+    assertEquals(sr.getSize(), 2);
+    List<SearchResultMatchI> matches = sr.getResults();
+    assertSame(al.getSequenceAt(1), matches.get(0).getSequence());
+    assertSame(al.getSequenceAt(2), matches.get(1).getSequence());
+    assertEquals(matches.get(0).getStart(), 5);
+    assertEquals(matches.get(0).getEnd(), 7);
+    assertEquals(matches.get(1).getStart(), 4);
+    assertEquals(matches.get(1).getEnd(), 6);
+  }
+
+  /**
+   * Test for (undocumented) find residue by position
+   */
+  @Test(groups = "Functional")
+  public void testFind_residueNumber()
+  {
+    Finder f = new Finder(al, null);
+    f.setFindAll(true);
+    f.find("9");
+
+    // seq1 and seq4 have 9 residues; no match in other sequences
+    SearchResultsI sr = f.getSearchResults();
+    assertEquals(sr.getSize(), 2);
+    List<SearchResultMatchI> matches = sr.getResults();
+    assertSame(al.getSequenceAt(0), matches.get(0).getSequence());
+    assertSame(al.getSequenceAt(3), matches.get(1).getSequence());
+    assertEquals(matches.get(0).getStart(), 9);
+    assertEquals(matches.get(0).getEnd(), 9);
+    assertEquals(matches.get(1).getStart(), 9);
+    assertEquals(matches.get(1).getEnd(), 9);
+  }
+
+  /**
+   * Test for find next action
+   */
+  @Test(groups = "Functional")
+  public void testFindNext()
+  {
+    /*
+     * start at second sequence; resIndex of -1
+     * means sequence id / description is searched
+     */
+    Finder f = new Finder(al, null, 1, -1);
+    f.find("e"); // matches id
+
+    assertTrue(f.getSearchResults().isEmpty());
+    assertEquals(f.getIdMatch().size(), 1);
+    assertSame(f.getIdMatch().get(0), al.getSequenceAt(1));
+
+    // resIndex is now 0 - for use in next find next
+    assertEquals(f.getResIndex(), 0);
+    f = new Finder(al, null, 1, 0);
+    f.find("e"); // matches in sequence
+    assertTrue(f.getIdMatch().isEmpty());
+    assertEquals(f.getSearchResults().getSize(), 1);
+    List<SearchResultMatchI> matches = f.getSearchResults().getResults();
+    assertEquals(matches.get(0).getStart(), 5);
+    assertEquals(matches.get(0).getEnd(), 5);
+    assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
+    // still in the second sequence
+    assertEquals(f.getSeqIndex(), 1);
+    // next residue position to search from is 5
+    // (used as base 0 by RegEx so the same as 6 if base 1)
+    assertEquals(f.getResIndex(), 5);
+
+    // find next from end of sequence - finds next sequence id
+    f = new Finder(al, null, 1, 5);
+    f.find("e");
+    assertEquals(f.getIdMatch().size(), 1);
+    assertSame(f.getIdMatch().get(0), al.getSequenceAt(2));
+  }
+
+  /**
+   * Test for matching within sequence descriptions
+   */
+  @Test(groups = "Functional")
+  public void testFindAll_inDescription()
+  {
+    AlignmentI al2 = new Alignment(al);
+    al2.getSequenceAt(0).setDescription("BRAF");
+    al2.getSequenceAt(1).setDescription("braf");
+    Finder f = new Finder(al2, null);
+    f.setFindAll(true);
+    f.setIncludeDescription(true);
+
+    f.find("rAF");
+    assertEquals(f.getIdMatch().size(), 2);
+    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
+    assertSame(f.getIdMatch().get(1), al2.getSequenceAt(1));
+    assertTrue(f.getSearchResults().isEmpty());
+
+    /*
+     * case sensitive
+     */
+    f = new Finder(al2, null);
+    f.setFindAll(true);
+    f.setCaseSensitive(true);
+    f.setIncludeDescription(true);
+
+    f.find("RAF");
+    assertEquals(f.getIdMatch().size(), 1);
+    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
+    assertTrue(f.getSearchResults().isEmpty());
+
+    /*
+     * match sequence id, description and sequence!
+     */
+    al2.getSequenceAt(0).setDescription("the efh sequence");
+    al2.getSequenceAt(0).setName("mouseEFHkinase");
+    al2.getSequenceAt(1).setName("humanEFHkinase");
+    f = new Finder(al2, null);
+    f.setFindAll(true);
+    f.setIncludeDescription(true);
+
+    /*
+     * sequence matches should have no duplicates
+     */
+    f.find("EFH");
+    assertEquals(f.getIdMatch().size(), 2);
+    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
+    assertSame(f.getIdMatch().get(1), al2.getSequenceAt(1));
+
+    assertEquals(f.getSearchResults().getSize(), 2);
+    SearchResultMatchI match = f.getSearchResults().getResults().get(0);
+    assertSame(al2.getSequenceAt(1), match.getSequence());
+    assertEquals(5, match.getStart());
+    assertEquals(7, match.getEnd());
+    match = f.getSearchResults().getResults().get(1);
+    assertSame(al2.getSequenceAt(2), match.getSequence());
+    assertEquals(4, match.getStart());
+    assertEquals(6, match.getEnd());
+  }
+
+  /**
+   * Test for matching within sequence ids
+   */
+  @Test(groups = "Functional")
+  public void testFindAll_sequenceIds()
+  {
+    Finder f = new Finder(al, null);
+    f.setFindAll(true);
+
+    /*
+     * case insensitive
+     */
+    f.find("SEQ1");
+    assertEquals(f.getIdMatch().size(), 1);
+    assertSame(f.getIdMatch().get(0), al.getSequenceAt(0));
+    assertTrue(f.getSearchResults().isEmpty());
+
+    /*
+     * case sensitive
+     */
+    f = new Finder(al, null);
+    f.setFindAll(true);
+    f.setCaseSensitive(true);
+    f.find("SEQ1");
+    assertTrue(f.getSearchResults().isEmpty());
+
+    /*
+     * match both sequence id and sequence
+     */
+    AlignmentI al2 = new Alignment(al);
+    al2.addSequence(new Sequence("aBz", "xyzabZpqrAbZ"));
+    f = new Finder(al2, null);
+    f.setFindAll(true);
+    f.find("ABZ");
+    assertEquals(f.getIdMatch().size(), 1);
+    assertSame(f.getIdMatch().get(0), al2.getSequenceAt(4));
+    assertEquals(f.getSearchResults().getSize(), 2);
+    SearchResultMatchI match = f.getSearchResults().getResults().get(0);
+    assertSame(al2.getSequenceAt(4), match.getSequence());
+    assertEquals(4, match.getStart());
+    assertEquals(6, match.getEnd());
+    match = f.getSearchResults().getResults().get(1);
+    assertSame(al2.getSequenceAt(4), match.getSequence());
+    assertEquals(10, match.getStart());
+    assertEquals(12, match.getEnd());
+  }
+
+  /**
+   * Test finding all matches of a sequence pattern in an alignment
+   */
+  @Test(groups = "Functional")
+  public void testFindAll_simpleMatch()
+  {
+    Finder f = new Finder(al, null);
+    f.setFindAll(true);
+
+    /*
+     * case insensitive first
+     */
+    f.find("EfH");
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 2);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(al.getSequenceAt(1), match.getSequence());
+    assertEquals(5, match.getStart());
+    assertEquals(7, match.getEnd());
+    match = searchResults.getResults().get(1);
+    assertSame(al.getSequenceAt(2), match.getSequence());
+    assertEquals(4, match.getStart());
+    assertEquals(6, match.getEnd());
+
+    /*
+     * case sensitive
+     */
+    f = new Finder(al, null);
+    f.setFindAll(true);
+    f.setCaseSensitive(true);
+    f.find("BC");
+    searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 2);
+    match = searchResults.getResults().get(0);
+    assertSame(al.getSequenceAt(0), match.getSequence());
+    assertEquals(2, match.getStart());
+    assertEquals(3, match.getEnd());
+    match = searchResults.getResults().get(1);
+    assertSame(al.getSequenceAt(1), match.getSequence());
+    assertEquals(2, match.getStart());
+    assertEquals(3, match.getEnd());
+  }
+
+  /**
+   * Test for JAL-2302 to verify that sub-matches are not included in a find all
+   * result
+   */
+  @Test(groups = "Functional")
+  public void testFind_maximalResultOnly()
+  {
+    Finder f = new Finder(al, null);
+    f.setFindAll(true);
+    f.find("M+");
+    SearchResultsI searchResults = f.getSearchResults();
+    assertEquals(searchResults.getSize(), 1);
+    SearchResultMatchI match = searchResults.getResults().get(0);
+    assertSame(al.getSequenceAt(3), match.getSequence());
+    assertEquals(4, match.getStart()); // dataset sequence positions
+    assertEquals(8, match.getEnd()); // base 1
+  }
+}
index df39b81..cea8ae4 100644 (file)
@@ -44,11 +44,11 @@ public class GroupingTest
 
   Sequence s5 = new Sequence("s5", "AAAADDEDTTEE");
 
-  SequenceGroup sg_12 = new SequenceGroup(Arrays.asList(new SequenceI[] { s1,
-      s2 }), "Group1", null, false, false, false, 0, 5);
+  SequenceGroup sg_12 = new SequenceGroup(Arrays.asList(new SequenceI[] {
+      s1, s2 }), "Group1", null, false, false, false, 0, 5);
 
-  SequenceGroup sg_345 = new SequenceGroup(Arrays.asList(new SequenceI[] { s3,
-      s4, s5 }), "Group2", null, false, false, false, 0, 5);
+  SequenceGroup sg_345 = new SequenceGroup(Arrays.asList(new SequenceI[] {
+      s3, s4, s5 }), "Group2", null, false, false, false, 0, 5);
 
   AlignmentI alignment = new Alignment(
           new SequenceI[] { s1, s2, s3, s4, s5 });
index f33525f..9d35a19 100644 (file)
@@ -105,7 +105,7 @@ public class RnaTest
     {
       String s = String.valueOf((char) i);
       String ss = Rna.getRNASecStrucState(s);
-  
+
       /*
        * valid SS chars are a-z, A-Z, and various brackets;
        * anything else is returned as a space
@@ -120,7 +120,7 @@ public class RnaTest
         assertEquals(" ", ss);
       }
     }
-  
+
     /*
      * a string is processed character by character
      */
@@ -188,6 +188,33 @@ public class RnaTest
     }
   }
 
+  @Test(groups = { "Functional" })
+  public void testIsCanonicalPair()
+  {
+    String bases = "acgtuACGTU";
+    for (int i = 0; i < bases.length(); i++)
+    {
+      for (int j = 0; j < bases.length(); j++)
+      {
+        char first = bases.charAt(i);
+        char second = bases.charAt(j);
+        boolean result = Rna.isCanonicalPair(first, second);
+        String pair = new String(new char[] { first, second })
+                .toUpperCase();
+        if (pair.equals("AT") || pair.equals("TA") || pair.equals("AU")
+                || pair.equals("UA") || pair.equals("GC")
+                || pair.equals("CG"))
+        {
+          assertTrue(pair + " should be valid", result);
+        }
+        else
+        {
+          assertFalse(pair + " should be invalid", result);
+        }
+      }
+    }
+  }
+
   /**
    * Tests for isOpeningParenthesis with char or String argument
    */
@@ -251,7 +278,7 @@ public class RnaTest
   public void testIsRnaSecondaryStructureSymbol()
   {
     assertFalse(Rna.isRnaSecondaryStructureSymbol(null));
-  
+
     /*
      * only A-Z,  a-z, ()[]{}<> are valid symbols
      */
index a17270d..b071080 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.analysis;
 
 import static org.testng.AssertJUnit.assertFalse;
index 1a95081..59985f3 100644 (file)
@@ -27,6 +27,8 @@ import jalview.gui.AlignFrame;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 
+import java.util.Arrays;
+
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -82,8 +84,8 @@ public class FeatureScoreModelTest
   {
     AlignFrame alf = getTestAlignmentFrame();
     FeatureScoreModel fsm = new FeatureScoreModel();
-    Assert.assertTrue(fsm.configureFromAlignmentView(alf
-            .getCurrentView().getAlignPanel()));
+    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+            .getAlignPanel()));
     alf.selectAllSequenceMenuItem_actionPerformed(null);
     float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
             true));
@@ -124,15 +126,58 @@ public class FeatureScoreModelTest
     alf.selectAllSequenceMenuItem_actionPerformed(null);
     float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
             true));
-    Assert.assertTrue(dm[0][2] == 0f,
+    Assert.assertTrue(
+            dm[0][2] == 0f,
             "After hiding last two columns FER1_MESCR (0) should still be identical with RAPSA (2)");
-    Assert.assertTrue(dm[0][1] == 0f,
+    Assert.assertTrue(
+            dm[0][1] == 0f,
             "After hiding last two columns FER1_MESCR (0) should now also be identical with SPIOL (1)");
-    for (int s=0;s<3;s++)
+    for (int s = 0; s < 3; s++)
     {
       Assert.assertTrue(dm[s][3] > 0f, "After hiding last two columns "
               + alf.getViewport().getAlignment().getSequenceAt(s).getName()
               + "(" + s + ") should still be distinct from FER1_MAIZE (3)");
     }
   }
+
+  /**
+   * Check findFeatureAt doesn't return contact features except at contact
+   * points TODO:move to under the FeatureRendererModel test suite
+   */
+  @Test(groups = { "Functional" })
+  public void testFindFeatureAt_PointFeature() throws Exception
+  {
+    String alignment = "a CCCCCCGGGGGGCCCCCC\n" + "b CCCCCCGGGGGGCCCCCC\n"
+            + "c CCCCCCGGGGGGCCCCCC\n";
+    AlignFrame af = new jalview.io.FileLoader(false)
+            .LoadFileWaitTillLoaded(alignment, DataSourceType.PASTE);
+    SequenceI aseq = af.getViewport().getAlignment().getSequenceAt(0);
+    SequenceFeature sf = null;
+    sf = new SequenceFeature("disulphide bond", "", 2, 5, Float.NaN, "");
+    aseq.addSequenceFeature(sf);
+    Assert.assertTrue(sf.isContactFeature());
+    af.refreshFeatureUI(true);
+    af.getFeatureRenderer().setAllVisible(Arrays.asList("disulphide bond"));
+    Assert.assertEquals(af.getFeatureRenderer().getDisplayedFeatureTypes()
+            .size(), 1, "Should be just one feature type displayed");
+    // step through and check for pointwise feature presence/absence
+    Assert.assertEquals(af.getFeatureRenderer().findFeaturesAtRes(aseq, 1)
+            .size(), 0);
+    // step through and check for pointwise feature presence/absence
+    Assert.assertEquals(af.getFeatureRenderer().findFeaturesAtRes(aseq, 2)
+            .size(), 1);
+    // step through and check for pointwise feature presence/absence
+    Assert.assertEquals(af.getFeatureRenderer().findFeaturesAtRes(aseq, 3)
+            .size(), 0);
+    // step through and check for pointwise feature presence/absence
+    Assert.assertEquals(af.getFeatureRenderer().findFeaturesAtRes(aseq, 4)
+            .size(), 0);
+    // step through and check for pointwise feature presence/absence
+    Assert.assertEquals(af.getFeatureRenderer().findFeaturesAtRes(aseq, 5)
+            .size(), 1);
+    // step through and check for pointwise feature presence/absence
+    Assert.assertEquals(af.getFeatureRenderer().findFeaturesAtRes(aseq, 6)
+            .size(), 0);
+  }
+
 }
index 06e79de..20e43b8 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.bin;
 
 import static org.testng.AssertJUnit.assertEquals;
index a37370f..803139f 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.bin;
 
 import static org.testng.AssertJUnit.assertEquals;
index b85536e..c79a043 100644 (file)
@@ -34,6 +34,15 @@ import org.testng.annotations.Test;
 
 public class CommandLineOperations
 {
+  private static final int TEST_TIMEOUT = 4500; // Note longer timeout needed on
+                                                // full test run than on
+                                                // individual tests
+
+  private static final int SETUP_TIMEOUT = 9000;
+
+  private static final int MINFILESIZE_SMALL = 2096;
+
+  private static final int MINFILESIZE_BIG = 4096;
 
   private ArrayList<String> successfulCMDs = new ArrayList<String>();
 
@@ -60,6 +69,7 @@ public class CommandLineOperations
       this.process = process;
     }
 
+    @Override
     public void run()
     {
       try
@@ -142,7 +152,7 @@ public class CommandLineOperations
     String cmds = "nodisplay -open examples/uniref50.fa -sortbytree -props FILE -colour zappo "
             + "-jabaws http://www.compbio.dundee.ac.uk/jabaws -nosortbytree -dasserver nickname=www.test.com "
             + "-features examples/testdata/plantfdx.features -annotations examples/testdata/plantfdx.annotations -tree examples/testdata/uniref50_test_tree";
-    Worker worker = jalviewDesktopRunner(true, cmds, 9000);
+    Worker worker = jalviewDesktopRunner(true, cmds, SETUP_TIMEOUT);
     String ln = null;
     while ((ln = worker.getOutputReader().readLine()) != null)
     {
@@ -155,7 +165,7 @@ public class CommandLineOperations
   public void setUpForCommandLineInputOperations() throws IOException
   {
     String cmds = "-open examples/uniref50.fa -noquestionnaire -nousagestats";
-    Worker worker = jalviewDesktopRunner(false, cmds, 9000);
+    Worker worker = jalviewDesktopRunner(false, cmds, SETUP_TIMEOUT);
     String ln = null;
     int count = 0;
     while ((ln = worker.getErrorReader().readLine()) != null)
@@ -204,7 +214,8 @@ public class CommandLineOperations
       worker.process.destroy();
       Assert.fail("Jalview did not exit after "
               + type
-              + " generation (try running test again to verify - timeout at 9000ms). ["
+              + " generation (try running test again to verify - timeout at "
+              + SETUP_TIMEOUT + "ms). ["
               + harg + "]");
     }
     new File(fileName).delete();
@@ -252,36 +263,36 @@ public class CommandLineOperations
   {
     return new Object[][] {
         { "nodisplay -open examples/uniref50.fa", " -eps",
-            "test_uniref50_out.eps", true, 4096, 4000 },
+            "test_uniref50_out.eps", true, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "nodisplay -open examples/uniref50.fa", " -eps",
-            "test_uniref50_out.eps", false, 4096, 4000 },
+            "test_uniref50_out.eps", false, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "nogui -open examples/uniref50.fa", " -eps",
-            "test_uniref50_out.eps", true, 4096, 4000 },
+            "test_uniref50_out.eps", true, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "nogui -open examples/uniref50.fa", " -eps",
-            "test_uniref50_out.eps", false, 4096, 4000 },
+            "test_uniref50_out.eps", false, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -eps",
-            "test_uniref50_out.eps", true, 4096, 4000 },
+            "test_uniref50_out.eps", true, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -svg",
-            "test_uniref50_out.svg", false, 4096, 3000 },
+            "test_uniref50_out.svg", false, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -png",
-            "test_uniref50_out.png", true, 4096, 3000 },
+            "test_uniref50_out.png", true, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -html",
-            "test_uniref50_out.html", true, 4096, 3000 },
+            "test_uniref50_out.html", true, MINFILESIZE_BIG, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -fasta",
-            "test_uniref50_out.mfa", true, 2096, 3000 },
+            "test_uniref50_out.mfa", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -clustal",
-            "test_uniref50_out.aln", true, 2096, 3000 },
+            "test_uniref50_out.aln", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -msf",
-            "test_uniref50_out.msf", true, 2096, 3000 },
+            "test_uniref50_out.msf", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -pileup",
-            "test_uniref50_out.aln", true, 2096, 3000 },
+            "test_uniref50_out.aln", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -pir",
-            "test_uniref50_out.pir", true, 2096, 3000 },
+            "test_uniref50_out.pir", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -pfam",
-            "test_uniref50_out.pfam", true, 2096, 3000 },
+            "test_uniref50_out.pfam", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -blc",
-            "test_uniref50_out.blc", true, 2096, 3000 },
+            "test_uniref50_out.blc", true, MINFILESIZE_SMALL, TEST_TIMEOUT },
         { "headless -open examples/uniref50.fa", " -jalview",
-            "test_uniref50_out.jvp", true, 2096, 3000 }, };
+            "test_uniref50_out.jvp", true, MINFILESIZE_SMALL, TEST_TIMEOUT }, };
   }
 }
index 9afae37..7fb80fb 100644 (file)
@@ -239,7 +239,7 @@ public class EditCommandTest
   public void testReplace()
   {
     // seem to need a dataset sequence on the edited sequence here
-    seqs[1].setDatasetSequence(seqs[1]);
+    seqs[1].createDatasetSequence();
     new EditCommand("", Action.REPLACE, "ZXY", new SequenceI[] { seqs[1] },
             4, 8, al);
     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
index 3eefada..f037599 100644 (file)
@@ -1,13 +1,41 @@
+/*
+ * 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.controller;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.analysis.Finder;
+import jalview.api.AlignViewControllerI;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
 
+import java.util.Arrays;
 import java.util.BitSet;
 
 import org.testng.annotations.Test;
@@ -17,10 +45,10 @@ public class AlignViewControllerTest
   @Test(groups = "Functional")
   public void testFindColumnsWithFeature()
   {
-    SequenceI seq1 = new Sequence("seq1", "aMMMaaaaaaaaaaaaaaaa");
-    SequenceI seq2 = new Sequence("seq2", "aaaMMMMMMMaaaaaaaaaa");
-    SequenceI seq3 = new Sequence("seq3", "aaaaaaaaaaMMMMMaaaaa");
-    SequenceI seq4 = new Sequence("seq3", "aaaaaaaaaaaaaaaaaaaa");
+    SequenceI seq1 = new Sequence("seq1", "-a-MMMaaaaaaaaaaaaaaaa");
+    SequenceI seq2 = new Sequence("seq2", "aa--aMM-MMMMMaaaaaaaaaa");
+    SequenceI seq3 = new Sequence("seq3", "abcab-caD-aaMMMMMaaaaa");
+    SequenceI seq4 = new Sequence("seq4", "abc--abcaaaaaaaaaaaaaa");
 
     /*
      * features start/end are base 1
@@ -33,13 +61,16 @@ public class AlignViewControllerTest
             null));
     seq3.addSequenceFeature(new SequenceFeature("Metal", "desc", 11, 15,
             0f, null));
+    // disulfide bond is a 'contact feature' - only select its 'start' and 'end'
+    seq3.addSequenceFeature(new SequenceFeature("disulfide bond", "desc", 8, 12,
+            0f, null));
 
     /*
-     * select the first three columns --> Metal in seq1 2-3
+     * select the first five columns --> Metal in seq1 cols 4-5
      */
     SequenceGroup sg = new SequenceGroup();
     sg.setStartRes(0); // base 0
-    sg.setEndRes(2);
+    sg.setEndRes(4);
     sg.addSequence(seq1, false);
     sg.addSequence(seq2, false);
     sg.addSequence(seq3, false);
@@ -50,37 +81,37 @@ public class AlignViewControllerTest
             bs);
     assertEquals(1, seqCount);
     assertEquals(2, bs.cardinality());
-    assertTrue(bs.get(1));
-    assertTrue(bs.get(2));
-    
+    assertTrue(bs.get(3)); // base 0
+    assertTrue(bs.get(4));
+
     /*
-     * select the first four columns: Metal in seq1 2:4, seq2 4:4
+     * select the first seven columns: Metal in seq1 cols 4-6, seq2 cols 6-7 
      */
-    sg.setEndRes(3);
+    sg.setEndRes(6);
     bs.clear();
-    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg,
-            bs);
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
     assertEquals(2, seqCount);
-    assertEquals(3, bs.cardinality());
-    assertTrue(bs.get(1));
-    assertTrue(bs.get(2));
+    assertEquals(4, bs.cardinality());
     assertTrue(bs.get(3));
+    assertTrue(bs.get(4));
+    assertTrue(bs.get(5));
+    assertTrue(bs.get(6));
 
     /*
-     * select column 11: Metal in seq3 only
+     * select column 14: Metal in seq3 only
      */
-    sg.setStartRes(10);
-    sg.setEndRes(10);
+    sg.setStartRes(13);
+    sg.setEndRes(13);
     bs.clear();
     seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
     assertEquals(1, seqCount);
     assertEquals(1, bs.cardinality());
-    assertTrue(bs.get(10));
+    assertTrue(bs.get(13));
 
     /*
-     * select columns 16-20: no Metal feature
+     * select columns 18-20: no Metal feature
      */
-    sg.setStartRes(15);
+    sg.setStartRes(17);
     sg.setEndRes(19);
     bs.clear();
     seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
@@ -88,6 +119,30 @@ public class AlignViewControllerTest
     assertEquals(0, bs.cardinality());
 
     /*
+     * columns 11-13 should not match disulfide bond at 8/12
+     */
+    sg.setStartRes(10);
+    sg.setEndRes(12);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("disulfide bond",
+            sg, bs);
+    assertEquals(0, seqCount);
+    assertEquals(0, bs.cardinality());
+
+    /*
+     * columns 6-18 should match disulfide bond at columns 9, 14
+     */
+    sg.setStartRes(5);
+    sg.setEndRes(17);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("disulfide bond",
+            sg, bs);
+    assertEquals(1, seqCount);
+    assertEquals(2, bs.cardinality());
+    assertTrue(bs.get(8));
+    assertTrue(bs.get(13));
+
+    /*
      * look for a feature that isn't there
      */
     sg.setStartRes(0);
@@ -97,4 +152,53 @@ public class AlignViewControllerTest
     assertEquals(0, seqCount);
     assertEquals(0, bs.cardinality());
   }
+
+  /**
+   * shameless copy of test data from findFeature for testing mark columns from
+   * highlight
+   */
+  @Test(groups = "Functional")
+  public void testSelectColumnsWithHighlight()
+  {
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "seq1 aMMMaaaaaaaaaaaaaaaa\n" + "seq2 aaaMMMMMMMaaaaaaaaaa\n"
+                    + "seq3 aaaaaaaaaaMMMMMaaaaa\n"
+                    + "seq4 aaaaaaaaaaaaaaaaaaaa\n", DataSourceType.PASTE);
+
+    SearchResultsI sr = new SearchResults();
+    SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
+    SequenceI seq1 = sqs[0];
+    SequenceI seq2 = sqs[1];
+    SequenceI seq3 = sqs[2];
+    SequenceI seq4 = sqs[3];
+
+    /*
+     * features start/end are base 1
+     */
+    sr.addResult(seq1, 2, 4);
+    sr.addResult(seq2, 4, 10);
+    sr.addResult(seq3, 11, 15);
+
+    /*
+     *  test Match/Find works first
+     */
+    Finder f = new Finder(af.getViewport().getAlignment(), null);
+    f.setFindAll(true);
+    f.setCaseSensitive(true);
+    f.find("M+");
+    assertEquals(
+            "Finder found different set of results to manually created SearchResults",
+            sr, f.getSearchResults());
+
+    /*
+     * now check simple mark columns from find operation
+     */
+    af.getViewport().setSearchResults(sr);
+    AlignViewControllerI avc = af.avc;
+
+    avc.markHighlightedColumns(false, false, false);
+    assertTrue("Didn't select highlighted columns", Arrays.deepEquals(af
+            .getViewport().getColumnSelection().getSelectedRanges()
+            .toArray(), new int[][] { { 1, 14 } }));
+  }
 }
index f2dd968..2e0793e 100644 (file)
@@ -462,7 +462,7 @@ public class AlignedCodonFrameTest
     seq1.createDatasetSequence();
     final Sequence aseq1 = new Sequence("Seq1", "-V-L");
     aseq1.createDatasetSequence();
-  
+
     AlignedCodonFrame acf = new AlignedCodonFrame();
     MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
         1, 2 }, 3, 1);
index 756bf71..42cdc8c 100644 (file)
@@ -27,6 +27,7 @@ import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
 import jalview.io.FileFormatI;
@@ -39,6 +40,7 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
+import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -103,6 +105,473 @@ public class AlignmentTest
     return a;
   }
 
+  /**
+   * assert wrapper: tests all references in the given alignment are consistent
+   * 
+   * @param alignment
+   */
+  public static void assertAlignmentDatasetRefs(AlignmentI alignment)
+  {
+    verifyAlignmentDatasetRefs(alignment, true, null);
+  }
+
+  /**
+   * assert wrapper: tests all references in the given alignment are consistent
+   * 
+   * @param alignment
+   * @param message
+   *          - prefixed to any assert failed messages
+   */
+  public static void assertAlignmentDatasetRefs(AlignmentI alignment,
+          String message)
+  {
+    verifyAlignmentDatasetRefs(alignment, true, message);
+  }
+
+  /**
+   * verify sequence and dataset references are properly contained within
+   * dataset
+   * 
+   * @param alignment
+   *          - the alignmentI object to verify (either alignment or dataset)
+   * @param raiseAssert
+   *          - when set, testng assertions are raised.
+   * @param message
+   *          - null or a string message to prepend to the assert failed
+   *          messages.
+   * @return true if alignment references were in order, otherwise false.
+   */
+  public static boolean verifyAlignmentDatasetRefs(AlignmentI alignment,
+          boolean raiseAssert, String message)
+  {
+    if (message == null)
+    {
+      message = "";
+    }
+    if (alignment == null)
+    {
+      if (raiseAssert)
+      {
+        Assert.fail(message + "Alignment for verification was null.");
+      }
+      return false;
+    }
+    if (alignment.getDataset() != null)
+    {
+      AlignmentI dataset = alignment.getDataset();
+      // check all alignment sequences have their dataset within the dataset
+      for (SequenceI seq : alignment.getSequences())
+      {
+        SequenceI seqds = seq.getDatasetSequence();
+        if (seqds.getDatasetSequence() != null)
+        {
+          if (raiseAssert)
+          {
+            Assert.fail(message
+                    + " Alignment contained a sequence who's dataset sequence has a second dataset reference.");
+          }
+          return false;
+        }
+        if (dataset.findIndex(seqds) == -1)
+        {
+          if (raiseAssert)
+          {
+            Assert.fail(message
+                    + " Alignment contained a sequence who's dataset sequence was not in the dataset.");
+          }
+          return false;
+        }
+      }
+      return verifyAlignmentDatasetRefs(alignment.getDataset(),
+              raiseAssert, message);
+    }
+    else
+    {
+      int dsp = -1;
+      // verify all dataset sequences
+      for (SequenceI seqds : alignment.getSequences())
+      {
+        dsp++;
+        if (seqds.getDatasetSequence() != null)
+        {
+          if (raiseAssert)
+          {
+            Assert.fail(message
+                    + " Dataset contained a sequence with non-null dataset reference (ie not a dataset sequence!)");
+          }
+          return false;
+        }
+        int foundp = alignment.findIndex(seqds);
+        if (foundp != dsp)
+        {
+          if (raiseAssert)
+          {
+            Assert.fail(message
+                    + " Dataset sequence array contains a reference at "
+                    + dsp + " to a sequence first seen at " + foundp + " ("
+                    + seqds.toString() + ")");
+          }
+          return false;
+        }
+        if (seqds.getDBRefs() != null)
+        {
+          for (DBRefEntry dbr : seqds.getDBRefs())
+          {
+            if (dbr.getMap() != null)
+            {
+              SequenceI seqdbrmapto = dbr.getMap().getTo();
+              if (seqdbrmapto != null)
+              {
+                if (seqdbrmapto.getDatasetSequence() != null)
+                {
+                  if (raiseAssert)
+                  {
+                    Assert.fail(message
+                            + " DBRefEntry for sequence in alignment had map to sequence which was not a dataset sequence");
+                  }
+                  return false;
+
+                }
+                if (alignment.findIndex(dbr.getMap().getTo()) == -1)
+                {
+                  if (raiseAssert)
+                  {
+                    Assert.fail(message
+                            + " DBRefEntry for sequence in alignment had map to sequence not in dataset");
+                  }
+                  return false;
+                }
+              }
+            }
+          }
+        }
+      }
+      // finally, verify codonmappings involve only dataset sequences.
+      if (alignment.getCodonFrames() != null)
+      {
+        for (AlignedCodonFrame alc : alignment.getCodonFrames())
+        {
+          for (SequenceToSequenceMapping ssm : alc.getMappings())
+          {
+            if (ssm.getFromSeq().getDatasetSequence() != null)
+            {
+              if (raiseAssert)
+              {
+                Assert.fail(message
+                        + " CodonFrame-SSM-FromSeq is not a dataset sequence");
+              }
+              return false;
+            }
+            if (alignment.findIndex(ssm.getFromSeq()) == -1)
+            {
+
+              if (raiseAssert)
+              {
+                Assert.fail(message
+                        + " CodonFrame-SSM-FromSeq is not contained in dataset");
+              }
+              return false;
+            }
+            if (ssm.getMapping().getTo().getDatasetSequence() != null)
+            {
+              if (raiseAssert)
+              {
+                Assert.fail(message
+                        + " CodonFrame-SSM-Mapping-ToSeq is not a dataset sequence");
+              }
+              return false;
+            }
+            if (alignment.findIndex(ssm.getMapping().getTo()) == -1)
+            {
+
+              if (raiseAssert)
+              {
+                Assert.fail(message
+                        + " CodonFrame-SSM-Mapping-ToSeq is not contained in dataset");
+              }
+              return false;
+            }
+          }
+        }
+      }
+    }
+    return true; // all relationships verified!
+  }
+
+  /**
+   * call verifyAlignmentDatasetRefs with and without assertion raising enabled,
+   * to check expected pass/fail actually occurs in both conditions
+   * 
+   * @param al
+   * @param expected
+   * @param msg
+   */
+  private void assertVerifyAlignment(AlignmentI al, boolean expected,
+          String msg)
+  {
+    if (expected)
+    {
+      try
+      {
+
+        Assert.assertTrue(verifyAlignmentDatasetRefs(al, true, null),
+                "Valid test alignment failed when raiseAsserts enabled:"
+                        + msg);
+      } catch (AssertionError ae)
+      {
+        ae.printStackTrace();
+        Assert.fail(
+                "Valid test alignment raised assertion errors when raiseAsserts enabled: "
+                        + msg, ae);
+      }
+      // also check validation passes with asserts disabled
+      Assert.assertTrue(verifyAlignmentDatasetRefs(al, false, null),
+              "Valid test alignment tested false when raiseAsserts disabled:"
+                      + msg);
+    }
+    else
+    {
+      boolean assertRaised = false;
+      try
+      {
+        verifyAlignmentDatasetRefs(al, true, null);
+      } catch (AssertionError ae)
+      {
+        // expected behaviour
+        assertRaised = true;
+      }
+      if (!assertRaised)
+      {
+        Assert.fail("Invalid test alignment passed when raiseAsserts enabled:"
+                + msg);
+      }
+      // also check validation passes with asserts disabled
+      Assert.assertFalse(verifyAlignmentDatasetRefs(al, false, null),
+              "Invalid test alignment tested true when raiseAsserts disabled:"
+                      + msg);
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testVerifyAlignmentDatasetRefs()
+  {
+    SequenceI sq1 = new Sequence("sq1", "ASFDD"), sq2 = new Sequence("sq2",
+            "TTTTTT");
+
+    // construct simple valid alignment dataset
+    Alignment al = new Alignment(new SequenceI[] { sq1, sq2 });
+    // expect this to pass
+    assertVerifyAlignment(al, true, "Simple valid alignment didn't verify");
+
+    // check test for sequence->datasetSequence validity
+    sq1.setDatasetSequence(sq2);
+    assertVerifyAlignment(al, false,
+            "didn't detect dataset sequence with a dataset sequence reference.");
+
+    sq1.setDatasetSequence(null);
+    assertVerifyAlignment(
+            al,
+            true,
+            "didn't reinstate validity after nulling dataset sequence dataset reference");
+
+    // now create dataset and check again
+    al.createDatasetAlignment();
+    assertNotNull(al.getDataset());
+
+    assertVerifyAlignment(al, true,
+            "verify failed after createDatasetAlignment");
+
+    // create a dbref on sq1 with a sequence ref to sq2
+    DBRefEntry dbrs1tos2 = new DBRefEntry("UNIPROT", "1", "Q111111");
+    dbrs1tos2.setMap(new Mapping(sq2.getDatasetSequence(),
+            new int[] { 1, 5 }, new int[] { 2, 6 }, 1, 1));
+    sq1.getDatasetSequence().addDBRef(dbrs1tos2);
+    assertVerifyAlignment(al, true,
+            "verify failed after addition of valid DBRefEntry/map");
+    // now create a dbref on a new sequence which maps to another sequence
+    // outside of the dataset
+    SequenceI sqout = new Sequence("sqout", "ututututucagcagcag"), sqnew = new Sequence(
+            "sqnew", "EEERRR");
+    DBRefEntry sqnewsqout = new DBRefEntry("ENAFOO", "1", "R000001");
+    sqnewsqout.setMap(new Mapping(sqout, new int[] { 1, 6 }, new int[] { 1,
+        18 }, 1, 3));
+    al.getDataset().addSequence(sqnew);
+
+    assertVerifyAlignment(al, true,
+            "verify failed after addition of new sequence to dataset");
+    // now start checking exception conditions
+    sqnew.addDBRef(sqnewsqout);
+    assertVerifyAlignment(
+            al,
+            false,
+            "verify passed when a dbref with map to sequence outside of dataset was added");
+    // make the verify pass by adding the outsider back in
+    al.getDataset().addSequence(sqout);
+    assertVerifyAlignment(al, true,
+            "verify should have passed after adding dbref->to sequence in to dataset");
+    // and now the same for a codon mapping...
+    SequenceI sqanotherout = new Sequence("sqanotherout",
+            "aggtutaggcagcagcag");
+
+    AlignedCodonFrame alc = new AlignedCodonFrame();
+    alc.addMap(sqanotherout, sqnew, new MapList(new int[] { 1, 6 },
+            new int[] { 1, 18 }, 3, 1));
+
+    al.addCodonFrame(alc);
+    Assert.assertEquals(al.getDataset().getCodonFrames().size(), 1);
+
+    assertVerifyAlignment(
+            al,
+            false,
+            "verify passed when alCodonFrame mapping to sequence outside of dataset was added");
+    // make the verify pass by adding the outsider back in
+    al.getDataset().addSequence(sqanotherout);
+    assertVerifyAlignment(
+            al,
+            true,
+            "verify should have passed once all sequences involved in alCodonFrame were added to dataset");
+    al.getDataset().addSequence(sqanotherout);
+    assertVerifyAlignment(al, false,
+            "verify should have failed when a sequence was added twice to the dataset");
+    al.getDataset().deleteSequence(sqanotherout);
+    assertVerifyAlignment(al, true,
+            "verify should have passed after duplicate entry for sequence was removed");
+  }
+
+  /**
+   * checks that the sequence data for an alignment's dataset is non-redundant.
+   * Fails if there are sequences with same id, sequence, start, and.
+   */
+
+  public static void assertDatasetIsNormalised(AlignmentI al)
+  {
+    assertDatasetIsNormalised(al, null);
+  }
+
+  /**
+   * checks that the sequence data for an alignment's dataset is non-redundant.
+   * Fails if there are sequences with same id, sequence, start, and.
+   * 
+   * @param al
+   *          - alignment to verify
+   * @param message
+   *          - null or message prepended to exception message.
+   */
+  public static void assertDatasetIsNormalised(AlignmentI al, String message)
+  {
+    if (al.getDataset() != null)
+    {
+      assertDatasetIsNormalised(al.getDataset(), message);
+      return;
+    }
+    /*
+     * look for pairs of sequences with same ID, start, end, and sequence
+     */
+    List<SequenceI> seqSet = al.getSequences();
+    for (int p = 0; p < seqSet.size(); p++)
+    {
+      SequenceI pSeq = seqSet.get(p);
+      for (int q = p + 1; q < seqSet.size(); q++)
+      {
+        SequenceI qSeq = seqSet.get(q);
+        if (pSeq.getStart() != qSeq.getStart())
+        {
+          continue;
+        }
+        if (pSeq.getEnd() != qSeq.getEnd())
+        {
+          continue;
+        }
+        if (!pSeq.getName().equals(qSeq.getName()))
+        {
+          continue;
+        }
+        if (!Arrays.equals(pSeq.getSequence(), qSeq.getSequence()))
+        {
+          continue;
+        }
+        Assert.fail((message == null ? "" : message + " :")
+                + "Found similar sequences at position " + p + " and " + q
+                + "\n" + pSeq.toString());
+      }
+    }
+  }
+
+  @Test(groups = { "Functional", "Asserts" })
+  public void testAssertDatasetIsNormalised()
+  {
+    Sequence sq1 = new Sequence("s1/1-4", "asdf");
+    Sequence sq1shift = new Sequence("s1/2-5", "asdf");
+    Sequence sq1seqd = new Sequence("s1/1-4", "asdt");
+    Sequence sq2 = new Sequence("s2/1-4", "asdf");
+    Sequence sq1dup = new Sequence("s1/1-4", "asdf");
+
+    Alignment al = new Alignment(new SequenceI[] { sq1 });
+    al.setDataset(null);
+
+    try
+    {
+      assertDatasetIsNormalised(al);
+    } catch (AssertionError ae)
+    {
+      Assert.fail("Single sequence should be valid normalised dataset.");
+    }
+    al.addSequence(sq2);
+    try
+    {
+      assertDatasetIsNormalised(al);
+    } catch (AssertionError ae)
+    {
+      Assert.fail("Two different sequences should be valid normalised dataset.");
+    }
+    /*
+     * now change sq2's name in the alignment. should still be valid
+     */
+    al.findName(sq2.getName()).setName("sq1");
+    try
+    {
+      assertDatasetIsNormalised(al);
+    } catch (AssertionError ae)
+    {
+      Assert.fail("Two different sequences in dataset, but same name in alignment, should be valid normalised dataset.");
+    }
+
+    al.addSequence(sq1seqd);
+    try
+    {
+      assertDatasetIsNormalised(al);
+    } catch (AssertionError ae)
+    {
+      Assert.fail("sq1 and sq1 with different sequence should be distinct.");
+    }
+
+    al.addSequence(sq1shift);
+    try
+    {
+      assertDatasetIsNormalised(al);
+    } catch (AssertionError ae)
+    {
+      Assert.fail("sq1 and sq1 with different start/end should be distinct.");
+    }
+    /*
+     * finally, the failure case
+     */
+    al.addSequence(sq1dup);
+    boolean ssertRaised = false;
+    try
+    {
+      assertDatasetIsNormalised(al);
+
+    } catch (AssertionError ae)
+    {
+      ssertRaised = true;
+    }
+    if (!ssertRaised)
+    {
+      Assert.fail("Expected identical sequence to raise exception.");
+    }
+  }
+
   /*
    * Read in Stockholm format test data including secondary structure
    * annotations.
@@ -462,6 +931,60 @@ public class AlignmentTest
     assertTrue(ds.getCodonFrames().contains(acf));
   }
 
+  /**
+   * tests the addition of *all* sequences referred to by a sequence being added
+   * to the dataset
+   */
+  @Test(groups = "Functional")
+  public void testCreateDatasetAlignmentWithMappedToSeqs()
+  {
+    // Alignment with two sequences, gapped.
+    SequenceI sq1 = new Sequence("sq1", "A--SDF");
+    SequenceI sq2 = new Sequence("sq2", "G--TRQ");
+
+    // cross-references to two more sequences.
+    DBRefEntry dbr = new DBRefEntry("SQ1", "", "sq3");
+    SequenceI sq3 = new Sequence("sq3", "VWANG");
+    dbr.setMap(new Mapping(sq3, new MapList(new int[] { 1, 4 }, new int[] {
+        2, 5 }, 1, 1)));
+    sq1.addDBRef(dbr);
+
+    SequenceI sq4 = new Sequence("sq4", "ERKWI");
+    DBRefEntry dbr2 = new DBRefEntry("SQ2", "", "sq4");
+    dbr2.setMap(new Mapping(sq4, new MapList(new int[] { 1, 4 }, new int[] {
+        2, 5 }, 1, 1)));
+    sq2.addDBRef(dbr2);
+    // and a 1:1 codonframe mapping between them.
+    AlignedCodonFrame alc = new AlignedCodonFrame();
+    alc.addMap(sq1, sq2, new MapList(new int[] { 1, 4 },
+            new int[] { 1, 4 }, 1, 1));
+
+    AlignmentI protein = new Alignment(new SequenceI[] { sq1, sq2 });
+
+    /*
+     * create the alignment dataset
+     * note this creates sequence datasets where missing
+     * as a side-effect (in this case, on seq2
+     */
+
+    // TODO promote this method to AlignmentI
+    ((Alignment) protein).createDatasetAlignment();
+
+    AlignmentI ds = protein.getDataset();
+
+    // should be 4 sequences in dataset - two materialised, and two propagated
+    // from dbref
+    assertEquals(4, ds.getHeight());
+    assertTrue(ds.getSequences().contains(sq1.getDatasetSequence()));
+    assertTrue(ds.getSequences().contains(sq2.getDatasetSequence()));
+    assertTrue(ds.getSequences().contains(sq3));
+    assertTrue(ds.getSequences().contains(sq4));
+    // Should have one codon frame mapping between sq1 and sq2 via dataset
+    // sequences
+    assertEquals(ds.getCodonFrame(sq1.getDatasetSequence()),
+            ds.getCodonFrame(sq2.getDatasetSequence()));
+  }
+
   @Test(groups = "Functional")
   public void testAddCodonFrame()
   {
@@ -485,6 +1008,28 @@ public class AlignmentTest
   }
 
   @Test(groups = "Functional")
+  public void testAddSequencePreserveDatasetIntegrity()
+  {
+    Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    Alignment align = new Alignment(new SequenceI[] { seq });
+    align.createDatasetAlignment();
+    AlignmentI ds = align.getDataset();
+    SequenceI copy = new Sequence(seq);
+    copy.insertCharAt(3, 5, '-');
+    align.addSequence(copy);
+    Assert.assertEquals(align.getDataset().getHeight(), 1,
+            "Dataset shouldn't have more than one sequence.");
+
+    Sequence seq2 = new Sequence("newtestSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    align.addSequence(seq2);
+    Assert.assertEquals(align.getDataset().getHeight(), 2,
+            "Dataset should now have two sequences.");
+
+    assertAlignmentDatasetRefs(align,
+            "addSequence broke dataset reference integrity");
+  }
+
+  @Test(groups = "Functional")
   public void getVisibleStartAndEndIndexTest()
   {
     Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -512,4 +1057,68 @@ public class AlignmentTest
     assertEquals(1, startEnd[0]);
     assertEquals(23, startEnd[1]);
   }
+
+  /**
+   * Tests that dbrefs with mappings to sequence get updated if the sequence
+   * acquires a dataset sequence
+   */
+  @Test(groups = "Functional")
+  public void testCreateDataset_updateDbrefMappings()
+  {
+    SequenceI pep = new Sequence("pep", "ASD");
+    SequenceI dna = new Sequence("dna", "aaaGCCTCGGATggg");
+    SequenceI cds = new Sequence("cds", "GCCTCGGAT");
+
+    // add dbref from dna to peptide
+    DBRefEntry dbr = new DBRefEntry("UNIPROT", "", "pep");
+    dbr.setMap(new Mapping(pep, new MapList(new int[] { 4, 15 }, new int[] {
+        1, 4 }, 3, 1)));
+    dna.addDBRef(dbr);
+
+    // add dbref from dna to peptide
+    DBRefEntry dbr2 = new DBRefEntry("UNIPROT", "", "pep");
+    dbr2.setMap(new Mapping(pep, new MapList(new int[] { 1, 12 }, new int[]
+    { 1, 4 }, 3, 1)));
+    cds.addDBRef(dbr2);
+
+    // add dbref from peptide to dna
+    DBRefEntry dbr3 = new DBRefEntry("EMBL", "", "dna");
+    dbr3.setMap(new Mapping(dna, new MapList(new int[] { 1, 4 }, new int[] {
+        4, 15 }, 1, 3)));
+    pep.addDBRef(dbr3);
+
+    // add dbref from peptide to cds
+    DBRefEntry dbr4 = new DBRefEntry("EMBLCDS", "", "cds");
+    dbr4.setMap(new Mapping(cds, new MapList(new int[] { 1, 4 }, new int[] {
+        1, 12 }, 1, 3)));
+    pep.addDBRef(dbr4);
+
+    AlignmentI protein = new Alignment(new SequenceI[] { pep });
+
+    /*
+     * create the alignment dataset
+     */
+    ((Alignment) protein).createDatasetAlignment();
+
+    AlignmentI ds = protein.getDataset();
+
+    // should be 3 sequences in dataset
+    assertEquals(3, ds.getHeight());
+    assertTrue(ds.getSequences().contains(pep.getDatasetSequence()));
+    assertTrue(ds.getSequences().contains(dna));
+    assertTrue(ds.getSequences().contains(cds));
+
+    /*
+     * verify peptide.cdsdbref.peptidedbref is now mapped to peptide dataset
+     */
+    DBRefEntry[] dbRefs = pep.getDBRefs();
+    assertEquals(2, dbRefs.length);
+    assertSame(dna, dbRefs[0].map.to);
+    assertSame(cds, dbRefs[1].map.to);
+    assertEquals(1, dna.getDBRefs().length);
+    assertSame(pep.getDatasetSequence(), dna.getDBRefs()[0].map.to);
+    assertEquals(1, cds.getDBRefs().length);
+    assertSame(pep.getDatasetSequence(), cds.getDBRefs()[0].map.to);
+  }
+
 }
index e59719c..ec528c5 100644 (file)
@@ -22,12 +22,14 @@ package jalview.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
-import static org.testng.AssertJUnit.assertNotSame;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
 
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.List;
 
 import org.testng.annotations.Test;
@@ -68,8 +70,8 @@ public class ColumnSelectionTest
 
     // removing an element in the list removes it
     cs.removeElement(2);
-    // ...but not from the copy list!
-    assertEquals(2, sel.size());
+    // ...and also from the read-only view
+    assertEquals(1, sel.size());
     sel = cs.getSelected();
     assertEquals(1, sel.size());
     assertEquals(new Integer(5), sel.get(0));
@@ -160,11 +162,12 @@ public class ColumnSelectionTest
 
   }
 
-  @Test(groups={"Functional"})
+  @Test(groups = { "Functional" })
   public void testLocateVisibleBoundsPathologicals()
   {
     // test some pathological cases we missed
-    AlignmentI al = new Alignment(new SequenceI[] { new Sequence("refseqGaptest","KTDVTI----------NFI-----G----L")});
+    AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
+            "refseqGaptest", "KTDVTI----------NFI-----G----L") });
     ColumnSelection cs = new ColumnSelection();
     cs.hideInsertionsFor(al.getSequenceAt(0));
     assertEquals(
@@ -173,8 +176,8 @@ public class ColumnSelectionTest
                     + al.getSequenceAt(0).getCharAt(
                             cs.adjustForHiddenColumns(9)));
 
-
   }
+
   @Test(groups = { "Functional" })
   public void testHideColumns()
   {
@@ -497,7 +500,7 @@ public class ColumnSelectionTest
     cs.addElement(1);
     cs.hideColumns(3);
     cs.hideColumns(7);
-    cs.hideColumns(5,9);
+    cs.hideColumns(5, 9);
 
     // same selections added in a different order
     ColumnSelection cs2 = new ColumnSelection();
@@ -513,7 +516,7 @@ public class ColumnSelectionTest
     cs2.hideColumns(6, 9);
     cs2.hideColumns(5, 8);
     cs2.hideColumns(3);
-    
+
     assertTrue(cs.equals(cs2));
     assertTrue(cs.equals(cs));
     assertTrue(cs2.equals(cs));
@@ -542,7 +545,7 @@ public class ColumnSelectionTest
    * were added
    */
   @Test(groups = { "Functional" })
-  public void testGetSelection()
+  public void testGetSelected()
   {
     ColumnSelection cs = new ColumnSelection();
     int[] sel = { 4, 3, 7, 21 };
@@ -551,32 +554,90 @@ public class ColumnSelectionTest
       cs.addElement(col);
     }
 
-    List<Integer> selected1 = cs.getSelected();
-    assertEquals(4, selected1.size());
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertEquals("[4, 3, 7, 21]", selected.toString());
 
     /*
-     * getSelected returns a copy, verify the list
-     * is externally immutable
+     * getSelected returns a read-only view of the list
+     * verify the view follows any changes in it
      */
-    selected1.clear();
-    List<Integer> selected2 = cs.getSelected();
-    assertNotSame(selected1, selected2);
-    assertEquals(4, selected2.size());
-    int i = 0;
-    for (int col : sel)
+    cs.removeElement(7);
+    cs.addElement(1);
+    cs.removeElement(4);
+    assertEquals("[3, 21, 1]", selected.toString());
+  }
+
+  /**
+   * Test to verify that the list returned by getSelection cannot be modified
+   */
+  @Test(groups = { "Functional" })
+  public void testGetSelected_isReadOnly()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(3);
+
+    List<Integer> selected = cs.getSelected();
+    try
+    {
+      selected.clear();
+      fail("expected exception");
+    } catch (UnsupportedOperationException e)
+    {
+      // expected
+    }
+    try
+    {
+      selected.add(1);
+      fail("expected exception");
+    } catch (UnsupportedOperationException e)
     {
-      assertEquals(col, selected2.get(i++).intValue());
+      // expected
     }
+    try
+    {
+      selected.remove(3);
+      fail("expected exception");
+    } catch (UnsupportedOperationException e)
+    {
+      // expected
+    }
+    try
+    {
+      Collections.sort(selected);
+      fail("expected exception");
+    } catch (UnsupportedOperationException e)
+    {
+      // expected
+    }
+  }
 
-    cs.removeElement(7);
+  /**
+   * Test that demonstrates a ConcurrentModificationException is thrown if you
+   * change the selection while iterating over it
+   */
+  @Test(
+    groups = "Functional",
+    expectedExceptions = { ConcurrentModificationException.class })
+  public void testGetSelected_concurrentModification()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(0);
     cs.addElement(1);
-    cs.removeElement(4);
+    cs.addElement(2);
 
-    List<Integer> selected3 = cs.getSelected();
-    assertEquals(3, selected3.size());
-    assertEquals(3, selected3.get(0).intValue());
-    assertEquals(21, selected3.get(1).intValue());
-    assertEquals(1, selected3.get(2).intValue());
+    /*
+     * simulate changing the list under us (e.g. in a separate
+     * thread) while iterating over it -> ConcurrentModificationException
+     */
+    List<Integer> selected = cs.getSelected();
+    for (Integer col : selected)
+    {
+      if (col.intValue() == 0)
+      {
+        cs.removeElement(1);
+      }
+    }
   }
 
   @Test(groups = "Functional")
@@ -669,4 +730,25 @@ public class ColumnSelectionTest
     assertTrue(selected.contains(6));
     assertTrue(selected.contains(10));
   }
+
+  @Test(groups = "Functional")
+  public void testCopyConstructor()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(3);
+    cs.addElement(1);
+    cs.hideColumns(10, 11);
+    cs.hideColumns(5, 7);
+    assertEquals("[5, 7]", Arrays.toString(cs.getHiddenColumns().get(0)));
+
+    ColumnSelection cs2 = new ColumnSelection(cs);
+    assertTrue(cs2.hasSelectedColumns());
+    assertTrue(cs2.hasHiddenColumns());
+    // order of column selection is preserved
+    assertEquals("[3, 1]", cs2.getSelected().toString());
+    assertEquals(2, cs2.getHiddenColumns().size());
+    // hidden columns are held in column order
+    assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenColumns().get(0)));
+    assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenColumns().get(1)));
+  }
 }
index ae6dcda..87e7082 100644 (file)
@@ -81,7 +81,7 @@ public class DBRefEntryTest
     assertTrue(ref1.updateFrom(ref2));
     assertEquals("UNIPROT", ref1.getSource()); // unchanged
     assertEquals("V71633", ref1.getAccessionId()); // unchanged
-  
+
     /*
      * ref1 has no mapping, acquires mapping from ref2
      */
@@ -138,4 +138,82 @@ public class DBRefEntryTest
     assertFalse(ref1.updateFrom(ref2));
     assertEquals("10", ref1.getVersion());
   }
+
+  @Test(groups = { "Functional" })
+  public void testIsPrimaryCandidate()
+  {
+    DBRefEntry dbr = new DBRefEntry(DBRefSource.UNIPROT, "", "Q12345");
+    assertTrue(dbr.isPrimaryCandidate());
+
+    /*
+     *  1:1 mapping - ok
+     */
+    dbr.setMap(new Mapping(null, new int[] { 1, 3 }, new int[] { 1, 3 }, 1,
+            1));
+    assertTrue(dbr.isPrimaryCandidate());
+
+    /*
+     *  1:1 mapping of identical split ranges - not ok
+     */
+    dbr.setMap(new Mapping(null, new int[] { 1, 3, 6, 9 }, new int[] { 1,
+        3, 6, 9 }, 1, 1));
+    assertFalse(dbr.isPrimaryCandidate());
+
+    /*
+     *  1:1 mapping of different ranges - not ok
+     */
+    dbr.setMap(new Mapping(null, new int[] { 1, 4 }, new int[] { 2, 5 }, 1,
+            1));
+    assertFalse(dbr.isPrimaryCandidate());
+
+    /*
+     *  1:1 mapping of 'isoform' ranges - not ok
+     */
+    dbr.setMap(new Mapping(null, new int[] { 1, 2, 6, 9 }, new int[] { 1,
+        3, 7, 9 }, 1, 1));
+    assertFalse(dbr.isPrimaryCandidate());
+    dbr.setMap(null);
+    assertTrue(dbr.isPrimaryCandidate());
+
+    /*
+     * Version string is prefixed with another dbref source string (fail)
+     */
+    dbr.setVersion(DBRefSource.EMBL + ":0");
+    assertFalse(dbr.isPrimaryCandidate());
+
+    /*
+     * Version string is alphanumeric
+     */
+    dbr.setVersion("0.1.b");
+    assertTrue(dbr.isPrimaryCandidate());
+
+    /*
+     * null version string can't be primary ref
+     */
+    dbr.setVersion(null);
+    assertFalse(dbr.isPrimaryCandidate());
+    dbr.setVersion("");
+    assertTrue(dbr.isPrimaryCandidate());
+
+    /*
+     *  1:1 mapping and sequenceRef (fail)
+     */
+    dbr.setMap(new Mapping(new Sequence("foo", "ASDF"), new int[] { 1, 3 },
+            new int[] { 1, 3 }, 1, 1));
+    assertFalse(dbr.isPrimaryCandidate());
+
+    /*
+     * 1:3 mapping (fail)
+     */
+    dbr.setMap(new Mapping(null, new int[] { 1, 3 }, new int[] { 1, 3 }, 1,
+            3));
+    assertFalse(dbr.isPrimaryCandidate());
+
+    /*
+     * 2:2 mapping with shift (expected fail, but maybe use case for a pass)
+     */
+    dbr.setMap(new Mapping(null, new int[] { 1, 4 }, new int[] { 1, 4 }, 2,
+            2));
+    assertFalse(dbr.isPrimaryCandidate());
+  }
 }
index 8b50a8b..42fc58b 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -22,7 +42,7 @@ public class HiddenSequencesTest
   static int SEQ_COUNT = 10;
 
   SequenceI[] seqs;
-  
+
   /**
    * Set up an alignment of 10 sequences
    */
index 64dc793..a7b28a7 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
index 6f3c7a9..95764d0 100644 (file)
@@ -24,8 +24,6 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.SearchResults.Match;
-
 import org.testng.annotations.Test;
 
 public class MatchTest
@@ -34,17 +32,9 @@ public class MatchTest
   @Test(groups = { "Functional" })
   public void testToString()
   {
-    SequenceI seq = new Sequence("", "abcdefghijklm");
-    Match m = new SearchResults().new Match(seq, 3, 5);
-    assertEquals("2cde", m.toString());
-  }
-
-  @Test(groups = { "Functional" })
-  public void testGetCharacters()
-  {
-    SequenceI seq = new Sequence("", "abcdefghijklm");
-    Match m = new SearchResults().new Match(seq, 3, 5);
-    assertEquals("cde", m.getCharacters());
+    SequenceI seq = new Sequence("Seq1", "abcdefghijklm");
+    SearchResultMatchI m = new SearchResults().new Match(seq, 3, 5);
+    assertEquals("Seq1/3-5", m.toString());
   }
 
   @Test(groups = { "Functional" })
@@ -52,8 +42,8 @@ public class MatchTest
   {
     SequenceI seq1 = new Sequence("", "abcdefghijklm");
     SequenceI seq2 = new Sequence("", "abcdefghijklm");
-    SearchResults sr1 = new SearchResults();
-    SearchResults sr2 = new SearchResults();
+    SearchResultsI sr1 = new SearchResults();
+    SearchResultsI sr2 = new SearchResults();
 
     assertFalse(sr1.equals(null));
     assertFalse(sr1.equals(seq1));
@@ -72,7 +62,7 @@ public class MatchTest
     /*
      * same match but on different sequences - not equal
      */
-    SearchResults sr3 = new SearchResults();
+    SearchResultsI sr3 = new SearchResults();
     sr3.addResult(seq2, 1, 1);
     assertFalse(sr1.equals(sr3));
     assertFalse(sr3.equals(sr1));
index 42bb091..e9d5cb2 100644 (file)
@@ -1,4 +1,5 @@
 /*
+    assertEquals(case7, case9);
  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  */
 package jalview.datamodel;
 
-import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
+import jalview.datamodel.PDBEntry.Type;
+
+//import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -40,52 +51,251 @@ public class PDBEntryTest
   }
 
   @Test(groups = { "Functional" })
-  public void test()
+  public void testEquals()
+  {
+    PDBEntry pdbEntry = new PDBEntry("1xyz", "A", PDBEntry.Type.PDB,
+            "x/y/z/File");
+
+    // id comparison is not case sensitive
+    PDBEntry case1 = new PDBEntry("1XYZ", "A", PDBEntry.Type.PDB,
+            "x/y/z/File");
+    // chain code comparison is not case sensitive
+    PDBEntry case2 = new PDBEntry("1xyz", "a", PDBEntry.Type.PDB,
+            "x/y/z/File");
+    // different type
+    PDBEntry case3 = new PDBEntry("1xyz", "A", PDBEntry.Type.FILE,
+            "x/y/z/File");
+    // different everything
+    PDBEntry case4 = new PDBEntry(null, null, null, null);
+    // null id
+    PDBEntry case5 = new PDBEntry(null, "A", PDBEntry.Type.PDB,
+            "x/y/z/File");
+    // null chain
+    PDBEntry case6 = new PDBEntry("1xyz", null, PDBEntry.Type.PDB,
+            "x/y/z/File");
+    // null type
+    PDBEntry case7 = new PDBEntry("1xyz", "A", null, "x/y/z/File");
+    // null file
+    PDBEntry case8 = new PDBEntry("1xyz", "A", PDBEntry.Type.PDB, null);
+    // identical to case7
+    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()
+     */
+    assertFalse(pdbEntry.equals(null));
+    assertFalse(pdbEntry.equals("a"));
+    assertEquals(case1, pdbEntry);
+    assertEquals(case2, pdbEntry);
+    assertNotEquals(case3, pdbEntry);
+    assertNotEquals(case4, pdbEntry);
+    assertNotEquals(case5, pdbEntry);
+    assertNotEquals(case6, pdbEntry);
+    assertNotEquals(case7, pdbEntry);
+    assertNotEquals(case8, pdbEntry);
+    assertEquals(case7, case9);
+    assertNotEquals(case9, case10);
+
+    // add properties
+    case7.setProperty("hello", "world");
+    assertNotEquals(case7, case9);
+    case9.setProperty("hello", "world");
+    assertEquals(case7, case9);
+    case9.setProperty("hello", "WORLD");
+    assertNotEquals(case7, case9);
+
+    /*
+     * change string wrapper property to string...
+     */
+    case1.setProperty("chain_code", "a");
+    assertFalse(pdbEntry.equals(case1));
+    assertFalse(case1.equals(pdbEntry));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetChainCode()
+  {
+    PDBEntry pdbEntry = new PDBEntry("1xyz", null, PDBEntry.Type.PDB,
+            "x/y/z/File");
+    assertNull(pdbEntry.getChainCode());
+
+    pdbEntry.setChainCode("a");
+    assertEquals("a", pdbEntry.getChainCode());
+
+    pdbEntry.setChainCode(null);
+    assertNull(pdbEntry.getChainCode());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetType()
+  {
+    assertSame(PDBEntry.Type.FILE, PDBEntry.Type.getType("FILE"));
+    assertSame(PDBEntry.Type.FILE, PDBEntry.Type.getType("File"));
+    assertSame(PDBEntry.Type.FILE, PDBEntry.Type.getType("file"));
+    assertNotSame(PDBEntry.Type.FILE, PDBEntry.Type.getType("file "));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testTypeMatches()
+  {
+    // TODO Type.matches() is not used - delete?
+    assertTrue(PDBEntry.Type.FILE.matches("FILE"));
+    assertTrue(PDBEntry.Type.FILE.matches("File"));
+    assertTrue(PDBEntry.Type.FILE.matches("file"));
+    assertFalse(PDBEntry.Type.FILE.matches("FILE "));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testUpdateFrom()
+  {
+    PDBEntry pdb1 = new PDBEntry("3A6S", null, null, null);
+    PDBEntry pdb2 = new PDBEntry("3A6S", null, null, null);
+    assertTrue(pdb1.updateFrom(pdb2));
+
+    /*
+     * mismatch of pdb id not allowed
+     */
+    pdb2 = new PDBEntry("1A70", "A", null, null);
+    assertFalse(pdb1.updateFrom(pdb2));
+    assertNull(pdb1.getChainCode());
+
+    /*
+     * match of pdb id is not case sensitive
+     */
+    pdb2 = new PDBEntry("3a6s", "A", null, null);
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getChainCode(), "A");
+    assertEquals(pdb1.getId(), "3A6S");
+
+    /*
+     * add chain - with differing case for id
+     */
+    pdb1 = new PDBEntry("3A6S", null, null, null);
+    pdb2 = new PDBEntry("3a6s", "A", null, null);
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getChainCode(), "A");
+
+    /*
+     * change of chain is not allowed
+     */
+    pdb2 = new PDBEntry("3A6S", "B", null, null);
+    assertFalse(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getChainCode(), "A");
+
+    /*
+     * change chain from null
+     */
+    pdb1 = new PDBEntry("3A6S", null, null, null);
+    pdb2 = new PDBEntry("3A6S", "B", null, null);
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getChainCode(), "B");
+
+    /*
+     * set file and type
+     */
+    pdb2 = new PDBEntry("3A6S", "B", Type.FILE, "filePath");
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getFile(), "filePath");
+    assertEquals(pdb1.getType(), Type.FILE.toString());
+
+    /*
+     * change of file is not allowed
+     */
+    pdb1 = new PDBEntry("3A6S", null, null, "file1");
+    pdb2 = new PDBEntry("3A6S", "A", null, "file2");
+    assertFalse(pdb1.updateFrom(pdb2));
+    assertNull(pdb1.getChainCode());
+    assertEquals(pdb1.getFile(), "file1");
+
+    /*
+     * set type without change of file
+     */
+    pdb1 = new PDBEntry("3A6S", null, null, "file1");
+    pdb2 = new PDBEntry("3A6S", null, Type.PDB, "file1");
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getType(), Type.PDB.toString());
+
+    /*
+     * set file with differing case of id and chain code
+     */
+    pdb1 = new PDBEntry("3A6S", "A", null, null);
+    pdb2 = new PDBEntry("3a6s", "a", Type.PDB, "file1");
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getType(), Type.PDB.toString());
+    assertEquals(pdb1.getId(), "3A6S"); // unchanged
+    assertEquals(pdb1.getFile(), "file1"); // updated
+    assertEquals(pdb1.getChainCode(), "A"); // unchanged
+
+    /*
+     * changing nothing returns true
+     */
+    pdb1 = new PDBEntry("3A6S", "A", Type.PDB, "file1");
+    pdb2 = new PDBEntry("3A6S", null, null, null);
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getChainCode(), "A");
+    assertEquals(pdb1.getType(), Type.PDB.toString());
+    assertEquals(pdb1.getFile(), "file1");
+
+    /*
+     * add and update properties only
+     */
+    pdb1 = new PDBEntry("3A6S", null, null, null);
+    pdb2 = new PDBEntry("3A6S", null, null, null);
+    pdb1.setProperty("destination", "mars");
+    pdb1.setProperty("hello", "world");
+    pdb2.setProperty("hello", "moon");
+    pdb2.setProperty("goodbye", "world");
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getProperty("destination"), "mars");
+    assertEquals(pdb1.getProperty("hello"), "moon");
+    assertEquals(pdb1.getProperty("goodbye"), "world");
+
+    /*
+     * add properties only
+     */
+    pdb1 = new PDBEntry("3A6S", null, null, null);
+    pdb2 = new PDBEntry("3A6S", null, null, null);
+    pdb2.setProperty("hello", "moon");
+    assertTrue(pdb1.updateFrom(pdb2));
+    assertEquals(pdb1.getProperty("hello"), "moon");
+  }
+
+  @Test(groups = { "Functional" })
+  public void testConstructor_fromDbref()
   {
+    PDBEntry pdb = new PDBEntry(new DBRefEntry("PDB", "0", "1A70"));
+    assertEquals(pdb.getId(), "1A70");
+    assertNull(pdb.getChainCode());
+    assertNull(pdb.getType());
+    assertNull(pdb.getFile());
+
+    /*
+     * from dbref with chain code appended
+     */
+    pdb = new PDBEntry(new DBRefEntry("PDB", "0", "1A70B"));
+    assertEquals(pdb.getId(), "1A70");
+    assertEquals(pdb.getChainCode(), "B");
+
+    /*
+     * from dbref with overlong accession
+     */
+    pdb = new PDBEntry(new DBRefEntry("PDB", "0", "1A70BC"));
+    assertEquals(pdb.getId(), "1A70BC");
+    assertNull(pdb.getChainCode());
+
+    /*
+     * from dbref which is not for PDB
+     */
     try
     {
-
-      PDBEntry pdbEntry = new PDBEntry("1xyz", "A", PDBEntry.Type.PDB,
-              "x/y/z/File");
-
-      PDBEntry case1 = new PDBEntry("1XYZ", "A", PDBEntry.Type.PDB,
-              "x/y/z/File");
-      PDBEntry case2 = new PDBEntry("1xyz", "a", PDBEntry.Type.PDB,
-              "x/y/z/File");
-      PDBEntry case3 = new PDBEntry("1xyz", "A", PDBEntry.Type.FILE,
-              "x/y/z/File");
-      PDBEntry case4 = new PDBEntry(null, null, null, null);
-      PDBEntry case5 = new PDBEntry(null, "A", PDBEntry.Type.PDB,
-              "x/y/z/File");
-      PDBEntry case6 = new PDBEntry("1xyz", null, PDBEntry.Type.PDB,
-              "x/y/z/File");
-      PDBEntry case7 = new PDBEntry("1xyz", "A", null, "x/y/z/File");
-      PDBEntry case8 = new PDBEntry("1xyz", "A", PDBEntry.Type.PDB, null);
-      PDBEntry case9 = new PDBEntry("1xyz", "A", null, "x/y/z/File");
-
-      // System.out.println(">>>> Testing case 1");
-      assertTrue(pdbEntry.equals(case1));
-      // System.out.println(">>>> Testing case 2");
-      assertTrue(pdbEntry.equals(case2));
-      // System.out.println(">>>> Testing case 3");
-      assertTrue(!pdbEntry.equals(case3));
-      // System.out.println(">>>> Testing case 4");
-      assertTrue(!pdbEntry.equals(case4));
-      // System.out.println(">>>> Testing case 5");
-      assertTrue(!pdbEntry.equals(case5));
-      // System.out.println(">>>> Testing case 6");
-      assertTrue(!pdbEntry.equals(case6));
-      // System.out.println(">>>> Testing case 7");
-      assertTrue(!pdbEntry.equals(case7));
-      // System.out.println(">>>> Testing case 8");
-      assertTrue(pdbEntry.equals(case8));
-      assertTrue(pdbEntry.equals(case8));
-      assertTrue(case7.equals(case9));
-    } catch (Exception e)
+      pdb = new PDBEntry(new DBRefEntry("PDBe", "0", "1A70"));
+      fail("Expected exception");
+    } catch (IllegalArgumentException e)
     {
-      e.printStackTrace();
+      // expected;
     }
-
   }
 
 }
diff --git a/test/jalview/datamodel/ResidueCountTest.java b/test/jalview/datamodel/ResidueCountTest.java
new file mode 100644 (file)
index 0000000..6c6e36a
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * 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.datamodel;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.ResidueCount.SymbolCounts;
+
+import org.junit.Assert;
+import org.testng.annotations.Test;
+
+public class ResidueCountTest
+{
+  /**
+   * Test a mix of add and put for nucleotide counting
+   */
+  @Test(groups = "Functional")
+  public void test_countNucleotide()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    assertEquals(rc.getCount('A'), 0);
+    assertEquals(rc.getGapCount(), 0);
+    // add then add
+    assertEquals(rc.add('A'), 1);
+    assertEquals(rc.add('a'), 2);
+    // put then add
+    rc.put('g', 3);
+    assertEquals(rc.add('G'), 4);
+    // add then put
+    assertEquals(rc.add('c'), 1);
+    rc.put('C', 4);
+    assertEquals(rc.add('N'), 1);
+
+    assertEquals(rc.getCount('a'), 2);
+    assertEquals(rc.getCount('A'), 2);
+    assertEquals(rc.getCount('G'), 4);
+    assertEquals(rc.getCount('c'), 4);
+    assertEquals(rc.getCount('T'), 0); // never seen
+    assertEquals(rc.getCount('N'), 1);
+    assertEquals(rc.getCount('?'), 0);
+    assertEquals(rc.getCount('-'), 0);
+
+    assertFalse(rc.isCountingInts());
+    assertFalse(rc.isUsingOtherData());
+  }
+
+  /**
+   * Test adding to gap count (either using addGap or add)
+   */
+  @Test(groups = "Functional")
+  public void testAddGap()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    rc.addGap();
+    rc.add('-');
+    rc.add('.');
+    rc.add(' ');
+    
+    assertEquals(rc.getGapCount(), 4);
+    assertEquals(rc.getCount(' '), 4);
+    assertEquals(rc.getCount('-'), 4);
+    assertEquals(rc.getCount('.'), 4);
+    assertFalse(rc.isUsingOtherData());
+    assertFalse(rc.isCountingInts());
+  }
+
+  @Test(groups = "Functional")
+  public void testOverflow()
+  {
+    /*
+     * overflow from add
+     */
+    ResidueCount rc = new ResidueCount(true);
+    rc.addGap();
+    rc.put('A', Short.MAX_VALUE - 1);
+    assertFalse(rc.isCountingInts());
+    rc.add('A');
+    assertFalse(rc.isCountingInts());
+    rc.add('A');
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('a'), Short.MAX_VALUE + 1);
+    rc.add('A');
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('a'), Short.MAX_VALUE + 2);
+    assertEquals(rc.getGapCount(), 1);
+    rc.addGap();
+    assertEquals(rc.getGapCount(), 2);
+
+    /*
+     * overflow from put
+     */
+    rc = new ResidueCount(true);
+    rc.put('G', Short.MAX_VALUE + 1);
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('g'), Short.MAX_VALUE + 1);
+    rc.put('G', 1);
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('g'), 1);
+
+    /*
+     * underflow from put
+     */
+    rc = new ResidueCount(true);
+    rc.put('G', Short.MIN_VALUE - 1);
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('g'), Short.MIN_VALUE - 1);
+  }
+
+  /**
+   * Test a mix of add and put for peptide counting
+   */
+  @Test(groups = "Functional")
+  public void test_countPeptide()
+  {
+    ResidueCount rc = new ResidueCount(false);
+    rc.put('q', 4);
+    rc.add('Q');
+    rc.add('X');
+    rc.add('x');
+    rc.add('W');
+    rc.put('w', 7);
+    rc.put('m', 12);
+    rc.put('M', 13);
+
+    assertEquals(rc.getCount('q'), 5);
+    assertEquals(rc.getCount('X'), 2);
+    assertEquals(rc.getCount('W'), 7);
+    assertEquals(rc.getCount('m'), 13);
+    assertEquals(rc.getCount('G'), 0);
+    assertEquals(rc.getCount('-'), 0);
+
+    assertFalse(rc.isCountingInts());
+    assertFalse(rc.isUsingOtherData());
+  }
+
+  @Test(groups = "Functional")
+  public void test_unexpectedPeptide()
+  {
+    ResidueCount rc = new ResidueCount(false);
+    // expected characters (upper or lower case):
+    String aas = "ACDEFGHIKLMNPQRSTVWXY";
+    String lower = aas.toLowerCase();
+    for (int i = 0; i < aas.length(); i++)
+    {
+      rc.put(aas.charAt(i), i);
+      rc.add(lower.charAt(i));
+    }
+    for (int i = 0; i < aas.length(); i++)
+    {
+      assertEquals(rc.getCount(aas.charAt(i)), i + 1);
+    }
+    assertFalse(rc.isUsingOtherData());
+
+    rc.put('J', 4);
+    assertTrue(rc.isUsingOtherData());
+    assertEquals(rc.getCount('J'), 4);
+    rc.add('j');
+    assertEquals(rc.getCount('J'), 5);
+  }
+
+  @Test(groups = "Functional")
+  public void test_unexpectedNucleotide()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    // expected characters (upper or lower case):
+    String nucs = "ACGTUN";
+    String lower = nucs.toLowerCase();
+    for (int i = 0; i < nucs.length(); i++)
+    {
+      rc.put(nucs.charAt(i), i);
+      rc.add(lower.charAt(i));
+    }
+    for (int i = 0; i < nucs.length(); i++)
+    {
+      assertEquals(rc.getCount(nucs.charAt(i)), i + 1);
+    }
+    assertFalse(rc.isUsingOtherData());
+
+    rc.add('J');
+    assertTrue(rc.isUsingOtherData());
+  }
+
+  @Test(groups = "Functional")
+  public void testGetModalCount()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    rc.add('c');
+    rc.add('g');
+    rc.add('c');
+    assertEquals(rc.getModalCount(), 2);
+
+    // modal count is in the 'short overflow' counts
+    rc = new ResidueCount();
+    rc.add('c');
+    rc.put('g', Short.MAX_VALUE);
+    rc.add('G');
+    assertEquals(rc.getModalCount(), Short.MAX_VALUE + 1);
+
+    // modal count is in the 'other data' counts
+    rc = new ResidueCount(false);
+    rc.add('Q');
+    rc.add('{');
+    rc.add('{');
+    assertEquals(rc.getModalCount(), 2);
+
+    // verify modal count excludes gap
+    rc = new ResidueCount();
+    rc.add('Q');
+    rc.add('P');
+    rc.add('Q');
+    rc.addGap();
+    rc.addGap();
+    rc.addGap();
+    assertEquals(rc.getModalCount(), 2);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetResiduesForCount()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    rc.add('c');
+    rc.add('g');
+    rc.add('c');
+    assertEquals(rc.getResiduesForCount(2), "C");
+    assertEquals(rc.getResiduesForCount(1), "G");
+    assertEquals(rc.getResiduesForCount(3), "");
+    assertEquals(rc.getResiduesForCount(0), "");
+    assertEquals(rc.getResiduesForCount(-1), "");
+
+    // modal count is in the 'short overflow' counts
+    rc = new ResidueCount(true);
+    rc.add('c');
+    rc.put('g', Short.MAX_VALUE);
+    rc.add('G');
+    assertEquals(rc.getResiduesForCount(Short.MAX_VALUE + 1), "G");
+    assertEquals(rc.getResiduesForCount(1), "C");
+
+    // peptide modal count is in the 'short overflow' counts
+    rc = new ResidueCount(false);
+    rc.add('c');
+    rc.put('p', Short.MAX_VALUE);
+    rc.add('P');
+    assertEquals(rc.getResiduesForCount(Short.MAX_VALUE + 1), "P");
+    assertEquals(rc.getResiduesForCount(1), "C");
+  
+    // modal count is in the 'other data' counts
+    rc = new ResidueCount();
+    rc.add('Q');
+    rc.add('{');
+    rc.add('{');
+    assertEquals(rc.getResiduesForCount(1), "Q");
+    assertEquals(rc.getResiduesForCount(2), "{");
+
+    // residues share modal count
+    rc = new ResidueCount();
+    rc.add('G');
+    rc.add('G');
+    rc.add('c');
+    rc.add('C');
+    rc.add('U');
+    assertEquals(rc.getResiduesForCount(1), "U");
+    assertEquals(rc.getResiduesForCount(2), "CG");
+
+    // expected and unexpected symbols share modal count
+    rc = new ResidueCount();
+    rc.add('G');
+    rc.add('t');
+    rc.add('[');
+    rc.add('[');
+    rc.add('t');
+    rc.add('G');
+    rc.add('c');
+    rc.add('C');
+    rc.add('U');
+    assertEquals(rc.getResiduesForCount(1), "U");
+    assertEquals(rc.getResiduesForCount(2), "CGT[");
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSymbolCounts_nucleotide()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    rc.add('g');
+    rc.add('c');
+    rc.add('G');
+    rc.add('J'); // 'otherData'
+    rc.add('g');
+    rc.add('N');
+    rc.put('[', 0); // 'otherdata'
+
+    SymbolCounts sc = rc.getSymbolCounts();
+    Assert.assertArrayEquals(new char[] { 'C', 'G', 'N', 'J', '[' },
+            sc.symbols);
+    Assert.assertArrayEquals(new int[] { 1, 3, 1, 1, 0 }, sc.values);
+
+    // now with overflow to int counts
+    rc.put('U', Short.MAX_VALUE);
+    rc.add('u');
+    sc = rc.getSymbolCounts();
+    Assert.assertArrayEquals(new char[] { 'C', 'G', 'N', 'U', 'J', '[' },
+            sc.symbols);
+    Assert.assertArrayEquals(new int[] { 1, 3, 1, 32768, 1, 0 }, sc.values);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSymbolCounts_peptide()
+  {
+    ResidueCount rc = new ResidueCount(false);
+    rc.add('W');
+    rc.add('q');
+    rc.add('W');
+    rc.add('Z'); // 'otherData'
+    rc.add('w');
+    rc.add('L');
+
+    SymbolCounts sc = rc.getSymbolCounts();
+    Assert.assertArrayEquals(new char[] { 'L', 'Q', 'W', 'Z' }, sc.symbols);
+    Assert.assertArrayEquals(new int[] { 1, 1, 3, 1 }, sc.values);
+
+    // now with overflow to int counts
+    rc.put('W', Short.MAX_VALUE);
+    rc.add('W');
+    sc = rc.getSymbolCounts();
+    Assert.assertArrayEquals(new char[] { 'L', 'Q', 'W', 'Z' }, sc.symbols);
+    Assert.assertArrayEquals(new int[] { 1, 1, 32768, 1 }, sc.values);
+  }
+
+  @Test(groups = "Functional")
+  public void testToString()
+  {
+    ResidueCount rc = new ResidueCount();
+    rc.add('q');
+    rc.add('c');
+    rc.add('Q');
+    assertEquals(rc.toString(), "[ C:1 Q:2 ]");
+
+    // add 'other data'
+    rc.add('{');
+    assertEquals(rc.toString(), "[ C:1 Q:2 {:1 ]");
+
+    // switch from short to int counting:
+    rc.put('G', Short.MAX_VALUE);
+    rc.add('g');
+    assertEquals(rc.toString(), "[ C:1 G:32768 Q:2 {:1 ]");
+  }
+
+  @Test(groups = "Functional")
+  public void testGetTooltip()
+  {
+    ResidueCount rc = new ResidueCount();
+
+    // no counts!
+    assertEquals(rc.getTooltip(20, 1), "");
+
+    /*
+     * count 7 C, 6 K, 7 Q, 10 P, 9 W, 1 F (total 40)
+     */
+    for (int i = 0; i < 7; i++)
+    {
+      rc.add('c');
+      rc.add('q');
+    }
+    for (int i = 0; i < 10; i++)
+    {
+      rc.add('p');
+    }
+    for (int i = 0; i < 9; i++)
+    {
+      rc.add('W');
+    }
+    for (int i = 0; i < 6; i++)
+    {
+      rc.add('K');
+    }
+    rc.add('F');
+    
+    /*
+     * percentages are rounded (0.5 rounded up)
+     * 10/40 9/40 7/40 6/40 1/40
+     */
+    assertEquals(rc.getTooltip(40, 0),
+            "P 25%; W 23%; C 18%; Q 18%; K 15%; F 3%");
+
+    rc.add('Q');
+    /*
+     * 10/30 9/30 8/30 7/30 6/30 1/30
+     */
+    assertEquals(rc.getTooltip(30, 1),
+            "P 33.3%; W 30.0%; Q 26.7%; C 23.3%; K 20.0%; F 3.3%");
+  }
+
+  @Test(groups = "Functional")
+  public void testPut()
+  {
+    ResidueCount rc = new ResidueCount();
+    rc.put('q', 3);
+    assertEquals(rc.getCount('Q'), 3);
+    rc.put(' ', 4);
+    assertEquals(rc.getGapCount(), 4);
+    rc.put('.', 5);
+    assertEquals(rc.getGapCount(), 5);
+    rc.put('-', 6);
+    assertEquals(rc.getGapCount(), 6);
+
+    rc.put('?', 5);
+    assertEquals(rc.getCount('?'), 5);
+    rc.put('?', 6);
+    rc.put('!', 7);
+    assertEquals(rc.getCount('?'), 6);
+    assertEquals(rc.getCount('!'), 7);
+  }
+}
index ffcaa26..19e89d2 100644 (file)
@@ -25,8 +25,9 @@ import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.SearchResults.Match;
+import java.util.BitSet;
 
+import org.junit.Assert;
 import org.testng.annotations.Test;
 
 public class SearchResultsTest
@@ -35,39 +36,24 @@ public class SearchResultsTest
   @Test(groups = { "Functional" })
   public void testToString()
   {
-    SequenceI seq = new Sequence("", "abcdefghijklm");
-    SearchResults sr = new SearchResults();
+    SequenceI seq = new Sequence("Seq1", "abcdefghijklm");
+    SearchResultsI sr = new SearchResults();
     sr.addResult(seq, 1, 1);
-    assertEquals("0a", sr.toString());
+    assertEquals("[Seq1/1-1]", sr.toString());
     sr.addResult(seq, 3, 5);
-    assertEquals("0a2cde", sr.toString());
+    assertEquals("[Seq1/1-1, Seq1/3-5]", sr.toString());
 
-    seq = new Sequence("", "pqrstuvwxy");
+    seq = new Sequence("Seq2", "pqrstuvwxy");
     sr.addResult(seq, 6, 7);
-    assertEquals("0a2cde5uv", sr.toString());
-  }
-
-  @Test(groups = { "Functional" })
-  public void testGetCharacters()
-  {
-    SequenceI seq = new Sequence("", "abcdefghijklm");
-    SearchResults sr = new SearchResults();
-    sr.addResult(seq, 1, 1);
-    assertEquals("a", sr.getCharacters());
-    sr.addResult(seq, 3, 5);
-    assertEquals("acde", sr.getCharacters());
-
-    seq = new Sequence("", "pqrstuvwxy");
-    sr.addResult(seq, 6, 7);
-    assertEquals("acdeuv", sr.getCharacters());
+    assertEquals("[Seq1/1-1, Seq1/3-5, Seq2/6-7]", sr.toString());
   }
 
   @Test(groups = { "Functional" })
   public void testEquals()
   {
     SequenceI seq1 = new Sequence("", "abcdefghijklm");
-    SearchResults sr1 = new SearchResults();
-    SearchResults sr2 = new SearchResults();
+    SearchResultsI sr1 = new SearchResults();
+    SearchResultsI sr2 = new SearchResults();
 
     assertFalse(sr1.equals(null)); // null object
     assertFalse(sr1.equals(seq1)); // wrong type
@@ -76,7 +62,7 @@ public class SearchResultsTest
     assertTrue(sr2.equals(sr1)); // reflexive
 
     /*
-     * only one result is not empty
+     * if only one result is not empty
      */
     sr1.addResult(seq1, 1, 1);
     assertTrue(sr1.equals(sr1));
@@ -111,8 +97,8 @@ public class SearchResultsTest
   {
     SequenceI seq1 = new Sequence("", "abcdefghijklm");
     SequenceI seq2 = new Sequence("", "abcdefghijklm");
-    SearchResults sr1 = new SearchResults();
-    SearchResults sr2 = new SearchResults();
+    SearchResultsI sr1 = new SearchResults();
+    SearchResultsI sr2 = new SearchResults();
 
     sr1.addResult(seq1, 1, 1);
     sr2.addResult(seq2, 1, 1);
@@ -127,8 +113,8 @@ public class SearchResultsTest
   public void testEquals_orderDiffers()
   {
     SequenceI seq1 = new Sequence("", "abcdefghijklm");
-    SearchResults sr1 = new SearchResults();
-    SearchResults sr2 = new SearchResults();
+    SearchResultsI sr1 = new SearchResults();
+    SearchResultsI sr2 = new SearchResults();
 
     sr1.addResult(seq1, 1, 1);
     sr1.addResult(seq1, 2, 2);
@@ -145,8 +131,8 @@ public class SearchResultsTest
   public void testHashcode()
   {
     SequenceI seq1 = new Sequence("", "abcdefghijklm");
-    SearchResults sr1 = new SearchResults();
-    SearchResults sr2 = new SearchResults();
+    SearchResultsI sr1 = new SearchResults();
+    SearchResultsI sr2 = new SearchResults();
 
     /*
      * both empty
@@ -169,7 +155,7 @@ public class SearchResultsTest
     sr2.addResult(seq1, 6, 8);
     assertEquals(sr1.hashCode(), sr2.hashCode());
   }
-  
+
   /**
    * Verify that SearchResults$Match constructor normalises start/end to the
    * 'forwards' direction
@@ -178,7 +164,7 @@ public class SearchResultsTest
   public void testMatchConstructor()
   {
     SequenceI seq1 = new Sequence("", "abcdefghijklm");
-    Match m = new SearchResults().new Match(seq1, 2, 5);
+    SearchResultMatchI m = new SearchResults().new Match(seq1, 2, 5);
     assertSame(seq1, m.getSequence());
     assertEquals(2, m.getStart());
     assertEquals(5, m.getEnd());
@@ -189,4 +175,87 @@ public class SearchResultsTest
     assertEquals(2, m.getStart());
     assertEquals(5, m.getEnd());
   }
+
+  /**
+   * test markColumns for creating column selections
+   */
+  @Test(groups = { "Functional" })
+  public void testMarkColumns()
+  {
+    int marked = 0;
+    SequenceI seq1 = new Sequence("", "abcdefghijklm");
+    SequenceI seq2 = new Sequence("", "abcdefghijklm");
+    SequenceGroup s1g=new SequenceGroup(), s2g=new SequenceGroup(), sallg=new SequenceGroup();
+    s1g.addSequence(seq1, false);
+    s2g.addSequence(seq2, false);
+    sallg.addSequence(seq1, false);
+    sallg.addSequence(seq2, false);
+    
+    SearchResultsI sr = new SearchResults();
+    BitSet bs = new BitSet();
+    
+    SearchResultMatchI srm = null;
+    srm = sr.addResult(seq1, 1, 1);
+    Assert.assertNotNull("addResult didn't return Match", srm);
+    srm = sr.addResult(seq2, 1, 2);
+    assertEquals("Sequence reference not set", seq2, srm.getSequence());
+    assertEquals("match start incorrect", 1, srm.getStart());
+    assertEquals("match end incorrect", 2, srm.getEnd());
+    
+    // set start/end range for groups to cover matches
+
+    s1g.setStartRes(0);
+    s1g.setEndRes(5);
+    s2g.setStartRes(0);
+    s2g.setEndRes(5);
+    sallg.setStartRes(0);
+    sallg.setEndRes(5);
+
+    /*
+     * just seq1
+     */
+    marked = sr.markColumns(s1g, bs);
+    // check the bitset cardinality before checking the return value
+    assertEquals("Didn't mark expected number", 1, bs.cardinality());
+    assertEquals("Didn't return count of number of bits marked", 1, marked);
+    assertTrue("Didn't mark expected position", bs.get(0));
+    // now check return value for marking the same again
+    assertEquals(
+            "Didn't count number of bits marked for existing marked set",
+            0,
+            sr.markColumns(s1g, bs));
+    bs.clear();
+    
+    /*
+     * just seq2
+     */
+    marked = sr.markColumns(s2g, bs);
+    assertEquals("Didn't mark expected number", 2, bs.cardinality());
+    assertEquals("Didn't return count of number of bits marked", 2, marked);
+    assertTrue("Didn't mark expected position (1)", bs.get(0));
+    assertTrue("Didn't mark expected position (2)", bs.get(1));
+    
+    /*
+     * both seq1 and seq2 
+     * should be same as seq2
+     */
+    BitSet allbs = new BitSet();
+    assertEquals(2, sr.markColumns(sallg, allbs));
+    assertEquals(bs, allbs);
+
+    // now check range selection
+
+    /*
+     * limit s2g to just the second column, sallg to the first column
+     */
+    s2g.setStartRes(1);
+    s2g.setEndRes(1);
+    sallg.setEndRes(0);
+    BitSet tbs = new BitSet();
+    assertEquals("Group start/end didn't select columns to mark",1, sr.markColumns(s2g, tbs));
+    assertEquals("Group start/end didn't select columns to mark", 1, sr.markColumns(sallg, tbs));
+    assertEquals(
+            "Didn't set expected number of columns in total for two successive marks",
+            2, tbs.cardinality());
+  }
 }
index 8d3c878..bb6581f 100644 (file)
@@ -55,6 +55,7 @@ public class SeqCigarTest
       }
     }
   }
+
   /*
    * refactored 'as is' from main method
    * 
index 82b260e..23812ea 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -92,56 +112,83 @@ public class SequenceFeatureTest
     assertEquals(sf1.hashCode(), sf2.hashCode());
 
     // changing type breaks equals:
+    String restores = sf2.getType();
     sf2.setType("Type");
     assertFalse(sf1.equals(sf2));
+    sf2.setType(restores);
 
     // changing description breaks equals:
-    sf2.setType("type");
+    restores = sf2.getDescription();
     sf2.setDescription("Desc");
     assertFalse(sf1.equals(sf2));
+    sf2.setDescription(restores);
+
+    // changing score breaks equals:
+    float restoref = sf2.getScore();
+    sf2.setScore(12.4f);
+    assertFalse(sf1.equals(sf2));
+    sf2.setScore(restoref);
+
+    // NaN doesn't match a number
+    restoref = sf2.getScore();
+    sf2.setScore(Float.NaN);
+    assertFalse(sf1.equals(sf2));
+
+    // NaN matches NaN
+    sf1.setScore(Float.NaN);
+    assertTrue(sf1.equals(sf2));
+    sf1.setScore(restoref);
+    sf2.setScore(restoref);
 
     // changing start position breaks equals:
-    sf2.setDescription("desc");
+    int restorei = sf2.getBegin();
     sf2.setBegin(21);
     assertFalse(sf1.equals(sf2));
+    sf2.setBegin(restorei);
 
     // changing end position breaks equals:
-    sf2.setBegin(22);
+    restorei = sf2.getEnd();
     sf2.setEnd(32);
     assertFalse(sf1.equals(sf2));
+    sf2.setEnd(restorei);
 
     // changing feature group breaks equals:
-    sf2.setEnd(33);
+    restores = sf2.getFeatureGroup();
     sf2.setFeatureGroup("Group");
     assertFalse(sf1.equals(sf2));
+    sf2.setFeatureGroup(restores);
 
     // changing ID breaks equals:
-    sf2.setFeatureGroup("group");
+    restores = (String) sf2.getValue("ID");
     sf2.setValue("ID", "id2");
     assertFalse(sf1.equals(sf2));
+    sf2.setValue("ID", restores);
 
     // changing Name breaks equals:
-    sf2.setValue("ID", "id");
+    restores = (String) sf2.getValue("Name");
     sf2.setValue("Name", "Name");
     assertFalse(sf1.equals(sf2));
+    sf2.setValue("Name", restores);
 
     // changing Parent breaks equals:
-    sf2.setValue("Name", "name");
+    restores = (String) sf1.getValue("Parent");
     sf1.setValue("Parent", "Parent");
     assertFalse(sf1.equals(sf2));
+    sf1.setValue("Parent", restores);
 
     // changing strand breaks equals:
-    sf1.setValue("Parent", "parent");
+    restorei = sf2.getStrand();
     sf2.setStrand("-");
     assertFalse(sf1.equals(sf2));
+    sf2.setStrand(restorei == 1 ? "+" : "-");
 
     // changing phase breaks equals:
-    sf2.setStrand("+");
+    restores = sf1.getPhase();
     sf1.setPhase("2");
     assertFalse(sf1.equals(sf2));
+    sf1.setPhase(restores);
 
     // restore equality as sanity check:
-    sf1.setPhase("1");
     assertTrue(sf1.equals(sf2));
     assertTrue(sf2.equals(sf1));
     assertEquals(sf1.hashCode(), sf2.hashCode());
@@ -150,4 +197,24 @@ public class SequenceFeatureTest
     sf1.setStatus("new");
     assertTrue(sf1.equals(sf2));
   }
+
+  @Test(groups = { "Functional" })
+  public void testIsContactFeature()
+  {
+    SequenceFeature sf = new SequenceFeature("type", "desc", 22, 33, 12.5f,
+            "group");
+    assertFalse(sf.isContactFeature());
+    sf.setType("");
+    assertFalse(sf.isContactFeature());
+    sf.setType(null);
+    assertFalse(sf.isContactFeature());
+    sf.setType("Disulfide Bond");
+    assertTrue(sf.isContactFeature());
+    sf.setType("disulfide bond");
+    assertTrue(sf.isContactFeature());
+    sf.setType("Disulphide Bond");
+    assertTrue(sf.isContactFeature());
+    sf.setType("disulphide bond");
+    assertTrue(sf.isContactFeature());
+  }
 }
index cfc4cbb..065bed7 100644 (file)
@@ -31,6 +31,7 @@ import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 import jalview.datamodel.PDBEntry.Type;
 import jalview.util.MapList;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -69,11 +70,11 @@ public class SequenceTest
   public void testIsProtein()
   {
     // test Protein
-    assertTrue(new Sequence("prot","ASDFASDFASDF").isProtein());
+    assertTrue(new Sequence("prot", "ASDFASDFASDF").isProtein());
     // test DNA
-    assertFalse(new Sequence("prot","ACGTACGTACGT").isProtein());
+    assertFalse(new Sequence("prot", "ACGTACGTACGT").isProtein());
     // test RNA
-    SequenceI sq = new Sequence("prot","ACGUACGUACGU");
+    SequenceI sq = new Sequence("prot", "ACGUACGUACGU");
     assertFalse(sq.isProtein());
     // change sequence, should trigger an update of cached result
     sq.setSequence("ASDFASDFADSF");
@@ -335,7 +336,6 @@ public class SequenceTest
     assertEquals(1, sfs.length);
     assertSame(sf, sfs[0]);
 
-
     /*
      * SequenceFeature on sequence and dataset sequence; returns that on
      * sequence
@@ -365,7 +365,16 @@ public class SequenceTest
      * is there a usecase for this ? setDatasetSequence should throw an error if
      * this actually occurs.
      */
-    sq.getDatasetSequence().setDatasetSequence(sq); // loop!
+    try
+    {
+      sq.getDatasetSequence().setDatasetSequence(sq); // loop!
+      Assert.fail("Expected Error to be raised when calling setDatasetSequence with self reference");
+    } catch (IllegalArgumentException e)
+    {
+      // TODO Jalview error/exception class for raising implementation errors
+      assertTrue(e.getMessage().toLowerCase()
+              .contains("implementation error"));
+    }
     assertNull(sq.getSequenceFeatures());
   }
 
@@ -415,7 +424,7 @@ public class SequenceTest
   @Test(groups = { "Functional" })
   public void testCreateDatasetSequence()
   {
-    SequenceI sq = new Sequence("my","ASDASD");
+    SequenceI sq = new Sequence("my", "ASDASD");
     assertNull(sq.getDatasetSequence());
     SequenceI rds = sq.createDatasetSequence();
     assertNotNull(rds);
@@ -438,36 +447,56 @@ public class SequenceTest
 
     sq.setDescription("Test sequence description..");
     sq.setVamsasId("TestVamsasId");
-    sq.setSourceDBRef(new DBRefEntry("PDB", "version0", "1TST"));
+    sq.addDBRef(new DBRefEntry("PDB", "version0", "1TST"));
 
-    sq.addDBRef(new DBRefEntry("PDB", "version1", "1Tst"));
-    sq.addDBRef(new DBRefEntry("PDB", "version2", "2Tst"));
-    sq.addDBRef(new DBRefEntry("PDB", "version3", "3Tst"));
-    sq.addDBRef(new DBRefEntry("PDB", "version4", "4Tst"));
+    sq.addDBRef(new DBRefEntry("PDB", "version1", "1PDB"));
+    sq.addDBRef(new DBRefEntry("PDB", "version2", "2PDB"));
+    sq.addDBRef(new DBRefEntry("PDB", "version3", "3PDB"));
+    sq.addDBRef(new DBRefEntry("PDB", "version4", "4PDB"));
 
     sq.addPDBId(new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
     sq.addPDBId(new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
     sq.addPDBId(new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
     sq.addPDBId(new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
 
+    // these are the same as ones already added
+    DBRefEntry pdb1pdb = new DBRefEntry("PDB", "version1", "1PDB");
+    DBRefEntry pdb2pdb = new DBRefEntry("PDB", "version2", "2PDB");
+
+    List<DBRefEntry> primRefs = Arrays.asList(new DBRefEntry[] { pdb1pdb,
+        pdb2pdb });
+
+    sq.getDatasetSequence().addDBRef(pdb1pdb); // should do nothing
+    sq.getDatasetSequence().addDBRef(pdb2pdb); // should do nothing
     sq.getDatasetSequence().addDBRef(
-            new DBRefEntry("PDB", "version1", "1Tst"));
-    sq.getDatasetSequence().addDBRef(
-            new DBRefEntry("PDB", "version2", "2Tst"));
-    sq.getDatasetSequence().addDBRef(
-            new DBRefEntry("PDB", "version3", "3Tst"));
+            new DBRefEntry("PDB", "version3", "3PDB")); // should do nothing
     sq.getDatasetSequence().addDBRef(
-            new DBRefEntry("PDB", "version4", "4Tst"));
+            new DBRefEntry("PDB", "version4", "4PDB")); // should do nothing
+
+    PDBEntry pdbe1a = new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1");
+    PDBEntry pdbe1b = new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1");
+    PDBEntry pdbe2a = new PDBEntry("2PDB", "A", Type.MMCIF,
+            "filePath/test2");
+    PDBEntry pdbe2b = new PDBEntry("2PDB", "B", Type.MMCIF,
+            "filePath/test2");
+    sq.getDatasetSequence().addPDBId(pdbe1a);
+    sq.getDatasetSequence().addPDBId(pdbe1b);
+    sq.getDatasetSequence().addPDBId(pdbe2a);
+    sq.getDatasetSequence().addPDBId(pdbe2b);
 
-    sq.getDatasetSequence().addPDBId(
-            new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
-    sq.getDatasetSequence().addPDBId(
-            new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
-    sq.getDatasetSequence().addPDBId(
-            new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
-    sq.getDatasetSequence().addPDBId(
-            new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
+    /*
+     * test we added pdb entries to the dataset sequence
+     */
+    Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries(), Arrays
+            .asList(new PDBEntry[] { pdbe1a, pdbe1b, pdbe2a, pdbe2b }),
+            "PDB Entries were not found on dataset sequence.");
 
+    /*
+     * we should recover a pdb entry that is on the dataset sequence via PDBEntry
+     */
+    Assert.assertEquals(pdbe1a,
+            sq.getDatasetSequence().getPDBEntry("1PDB"),
+            "PDB Entry '1PDB' not found on dataset sequence via getPDBEntry.");
     ArrayList<Annotation> annotsList = new ArrayList<Annotation>();
     System.out.println(">>>>>> " + sq.getSequenceAsString().length());
     annotsList.add(new Annotation("A", "A", 'X', 0.1f));
@@ -479,11 +508,14 @@ public class SequenceTest
             new AlignmentAnnotation("Test annot", "Test annot description",
                     annots));
     Assert.assertEquals(sq.getDescription(), "Test sequence description..");
-    Assert.assertEquals(sq.getDBRefs().length, 4);
+    Assert.assertEquals(sq.getDBRefs().length, 5); // DBRefs are on dataset
+                                                   // sequence
     Assert.assertEquals(sq.getAllPDBEntries().size(), 4);
     Assert.assertNotNull(sq.getAnnotation());
     Assert.assertEquals(sq.getAnnotation()[0].annotations.length, 2);
-    Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 4);
+    Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 5); // same
+                                                                        // as
+                                                                        // sq.getDBRefs()
     Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries().size(),
             4);
     Assert.assertNotNull(sq.getDatasetSequence().getAnnotation());
@@ -492,11 +524,11 @@ public class SequenceTest
 
     Assert.assertEquals(derived.getDescription(),
             "Test sequence description..");
-    Assert.assertEquals(derived.getDBRefs().length, 4);
+    Assert.assertEquals(derived.getDBRefs().length, 5); // come from dataset
     Assert.assertEquals(derived.getAllPDBEntries().size(), 4);
     Assert.assertNotNull(derived.getAnnotation());
     Assert.assertEquals(derived.getAnnotation()[0].annotations.length, 2);
-    Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 4);
+    Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 5);
     Assert.assertEquals(derived.getDatasetSequence().getAllPDBEntries()
             .size(), 4);
     Assert.assertNotNull(derived.getDatasetSequence().getAnnotation());
@@ -510,6 +542,17 @@ public class SequenceTest
     assertNotNull(sq.getSequenceFeatures());
     assertArrayEquals(sq.getSequenceFeatures(),
             derived.getSequenceFeatures());
+
+    /*
+     *  verify we have primary db refs *just* for PDB IDs with associated
+     *  PDBEntry objects
+     */
+
+    assertEquals(primRefs, sq.getPrimaryDBRefs());
+    assertEquals(primRefs, sq.getDatasetSequence().getPrimaryDBRefs());
+
+    assertEquals(sq.getPrimaryDBRefs(), derived.getPrimaryDBRefs());
+
   }
 
   /**
@@ -554,7 +597,7 @@ public class SequenceTest
             12.4f, "group"));
     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
     seq1.addDBRef(new DBRefEntry("EMBL", "1.2", "AZ12345"));
-    
+
     SequenceI copy = new Sequence(seq1);
 
     assertNull(copy.getDatasetSequence());
@@ -630,9 +673,13 @@ public class SequenceTest
     // copy has a copy of the sequence feature:
     SequenceFeature[] sfs = copy.getSequenceFeatures();
     assertEquals(1, sfs.length);
-    if (seq1.getDatasetSequence()!=null && copy.getDatasetSequence()==seq1.getDatasetSequence()) {
+    if (seq1.getDatasetSequence() != null
+            && copy.getDatasetSequence() == seq1.getDatasetSequence())
+    {
       assertTrue(sfs[0] == seq1.getSequenceFeatures()[0]);
-    } else {
+    }
+    else
+    {
       assertFalse(sfs[0] == seq1.getSequenceFeatures()[0]);
     }
     assertTrue(sfs[0].equals(seq1.getSequenceFeatures()[0]));
@@ -734,4 +781,223 @@ public class SequenceTest
     assertSame(dbref3, sq.getDBRefs()[2]);
     assertEquals("3", dbref2.getVersion());
   }
+
+  @Test(groups = { "Functional" })
+  public void testGetPrimaryDBRefs_peptide()
+  {
+    SequenceI sq = new Sequence("aseq", "ASDFKYLMQPRST", 10, 22);
+
+    // no dbrefs
+    List<DBRefEntry> primaryDBRefs = sq.getPrimaryDBRefs();
+    assertTrue(primaryDBRefs.isEmpty());
+
+    // empty dbrefs
+    sq.setDBRefs(new DBRefEntry[] {});
+    primaryDBRefs = sq.getPrimaryDBRefs();
+    assertTrue(primaryDBRefs.isEmpty());
+
+    // primary - uniprot
+    DBRefEntry upentry1 = new DBRefEntry("UNIPROT", "0", "Q04760");
+    sq.addDBRef(upentry1);
+
+    // primary - uniprot with congruent map
+    DBRefEntry upentry2 = new DBRefEntry("UNIPROT", "0", "Q04762");
+    upentry2.setMap(new Mapping(null, new MapList(new int[] { 10, 22 },
+            new int[] { 10, 22 }, 1, 1)));
+    sq.addDBRef(upentry2);
+
+    // primary - uniprot with map of enclosing sequence
+    DBRefEntry upentry3 = new DBRefEntry("UNIPROT", "0", "Q04763");
+    upentry3.setMap(new Mapping(null, new MapList(new int[] { 8, 24 },
+            new int[] { 8, 24 }, 1, 1)));
+    sq.addDBRef(upentry3);
+
+    // not primary - uniprot with map of sub-sequence (5')
+    DBRefEntry upentry4 = new DBRefEntry("UNIPROT", "0", "Q04764");
+    upentry4.setMap(new Mapping(null, new MapList(new int[] { 10, 18 },
+            new int[] { 10, 18 }, 1, 1)));
+    sq.addDBRef(upentry4);
+
+    // not primary - uniprot with map that overlaps 3'
+    DBRefEntry upentry5 = new DBRefEntry("UNIPROT", "0", "Q04765");
+    upentry5.setMap(new Mapping(null, new MapList(new int[] { 12, 22 },
+            new int[] { 12, 22 }, 1, 1)));
+    sq.addDBRef(upentry5);
+
+    // not primary - uniprot with map to different coordinates frame
+    DBRefEntry upentry6 = new DBRefEntry("UNIPROT", "0", "Q04766");
+    upentry6.setMap(new Mapping(null, new MapList(new int[] { 12, 18 },
+            new int[] { 112, 118 }, 1, 1)));
+    sq.addDBRef(upentry6);
+
+    // not primary - dbref to 'non-core' database
+    DBRefEntry upentry7 = new DBRefEntry("Pfam", "0", "PF00903");
+    sq.addDBRef(upentry7);
+
+    // primary - type is PDB
+    DBRefEntry pdbentry = new DBRefEntry("PDB", "0", "1qip");
+    sq.addDBRef(pdbentry);
+
+    // not primary - PDBEntry has no file
+    sq.addDBRef(new DBRefEntry("PDB", "0", "1AAA"));
+
+    // not primary - no PDBEntry
+    sq.addDBRef(new DBRefEntry("PDB", "0", "1DDD"));
+
+    // add corroborating PDB entry for primary DBref -
+    // needs to have a file as well as matching ID
+    // note PDB ID is not treated as case sensitive
+    sq.addPDBId(new PDBEntry("1QIP", null, Type.PDB, new File("/blah")
+            .toString()));
+
+    // not valid DBRef - no file..
+    sq.addPDBId(new PDBEntry("1AAA", null, null, null));
+
+    primaryDBRefs = sq.getPrimaryDBRefs();
+    assertEquals(4, primaryDBRefs.size());
+    assertTrue("Couldn't find simple primary reference (UNIPROT)",
+            primaryDBRefs.contains(upentry1));
+    assertTrue("Couldn't find mapped primary reference (UNIPROT)",
+            primaryDBRefs.contains(upentry2));
+    assertTrue("Couldn't find mapped context reference (UNIPROT)",
+            primaryDBRefs.contains(upentry3));
+    assertTrue("Couldn't find expected PDB primary reference",
+            primaryDBRefs.contains(pdbentry));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetPrimaryDBRefs_nucleotide()
+  {
+    SequenceI sq = new Sequence("aseq", "TGATCACTCGACTAGCATCAGCATA", 10, 34);
+
+    // primary - Ensembl
+    DBRefEntry dbr1 = new DBRefEntry("ENSEMBL", "0", "ENSG1234");
+    sq.addDBRef(dbr1);
+
+    // not primary - Ensembl 'transcript' mapping of sub-sequence
+    DBRefEntry dbr2 = new DBRefEntry("ENSEMBL", "0", "ENST1234");
+    dbr2.setMap(new Mapping(null, new MapList(new int[] { 15, 25 },
+            new int[] { 1, 11 }, 1, 1)));
+    sq.addDBRef(dbr2);
+
+    // primary - EMBL with congruent map
+    DBRefEntry dbr3 = new DBRefEntry("EMBL", "0", "J1234");
+    dbr3.setMap(new Mapping(null, new MapList(new int[] { 10, 34 },
+            new int[] { 10, 34 }, 1, 1)));
+    sq.addDBRef(dbr3);
+
+    // not primary - to non-core database
+    DBRefEntry dbr4 = new DBRefEntry("CCDS", "0", "J1234");
+    sq.addDBRef(dbr4);
+
+    // not primary - to protein
+    DBRefEntry dbr5 = new DBRefEntry("UNIPROT", "0", "Q87654");
+    sq.addDBRef(dbr5);
+
+    List<DBRefEntry> primaryDBRefs = sq.getPrimaryDBRefs();
+    assertEquals(2, primaryDBRefs.size());
+    assertTrue(primaryDBRefs.contains(dbr1));
+    assertTrue(primaryDBRefs.contains(dbr3));
+  }
+
+  /**
+   * Test the method that updates the list of PDBEntry from any new DBRefEntry
+   * for PDB
+   */
+  @Test(groups = { "Functional" })
+  public void testUpdatePDBIds()
+  {
+    PDBEntry pdbe1 = new PDBEntry("3A6S", null, null, null);
+    seq.addPDBId(pdbe1);
+    seq.addDBRef(new DBRefEntry("Ensembl", "8", "ENST1234"));
+    seq.addDBRef(new DBRefEntry("PDB", "0", "1A70"));
+    seq.addDBRef(new DBRefEntry("PDB", "0", "4BQGa"));
+    seq.addDBRef(new DBRefEntry("PDB", "0", "3a6sB"));
+    // 7 is not a valid chain code:
+    seq.addDBRef(new DBRefEntry("PDB", "0", "2GIS7"));
+
+    seq.updatePDBIds();
+    List<PDBEntry> pdbIds = seq.getAllPDBEntries();
+    assertEquals(4, pdbIds.size());
+    assertSame(pdbe1, pdbIds.get(0));
+    // chain code got added to 3A6S:
+    assertEquals("B", pdbe1.getChainCode());
+    assertEquals("1A70", pdbIds.get(1).getId());
+    // 4BQGA is parsed into id + chain
+    assertEquals("4BQG", pdbIds.get(2).getId());
+    assertEquals("a", pdbIds.get(2).getChainCode());
+    assertEquals("2GIS7", pdbIds.get(3).getId());
+    assertNull(pdbIds.get(3).getChainCode());
+  }
+
+  /**
+   * Test the method that either adds a pdbid or updates an existing one
+   */
+  @Test(groups = { "Functional" })
+  public void testAddPDBId()
+  {
+    PDBEntry pdbe = new PDBEntry("3A6S", null, null, null);
+    seq.addPDBId(pdbe);
+    assertEquals(1, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getPDBEntry("3A6S"));
+    assertSame(pdbe, seq.getPDBEntry("3a6s")); // case-insensitive
+
+    // add the same entry
+    seq.addPDBId(pdbe);
+    assertEquals(1, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getPDBEntry("3A6S"));
+
+    // add an identical entry
+    seq.addPDBId(new PDBEntry("3A6S", null, null, null));
+    assertEquals(1, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getPDBEntry("3A6S"));
+
+    // add a different entry
+    PDBEntry pdbe2 = new PDBEntry("1A70", null, null, null);
+    seq.addPDBId(pdbe2);
+    assertEquals(2, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getAllPDBEntries().get(0));
+    assertSame(pdbe2, seq.getAllPDBEntries().get(1));
+
+    // update pdbe with chain code, file, type
+    PDBEntry pdbe3 = new PDBEntry("3a6s", "A", Type.PDB, "filepath");
+    seq.addPDBId(pdbe3);
+    assertEquals(2, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getAllPDBEntries().get(0)); // updated in situ
+    assertEquals("3A6S", pdbe.getId()); // unchanged
+    assertEquals("A", pdbe.getChainCode()); // updated
+    assertEquals(Type.PDB.toString(), pdbe.getType()); // updated
+    assertEquals("filepath", pdbe.getFile()); // updated
+    assertSame(pdbe2, seq.getAllPDBEntries().get(1));
+
+    // add with a different file path
+    PDBEntry pdbe4 = new PDBEntry("3a6s", "A", Type.PDB, "filepath2");
+    seq.addPDBId(pdbe4);
+    assertEquals(3, seq.getAllPDBEntries().size());
+    assertSame(pdbe4, seq.getAllPDBEntries().get(2));
+
+    // add with a different chain code
+    PDBEntry pdbe5 = new PDBEntry("3a6s", "B", Type.PDB, "filepath");
+    seq.addPDBId(pdbe5);
+    assertEquals(4, seq.getAllPDBEntries().size());
+    assertSame(pdbe5, seq.getAllPDBEntries().get(3));
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { IllegalArgumentException.class })
+  public void testSetDatasetSequence_toSelf()
+  {
+    seq.setDatasetSequence(seq);
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { IllegalArgumentException.class })
+  public void testSetDatasetSequence_cascading()
+  {
+    SequenceI seq2 = new Sequence("Seq2", "xyz");
+    seq2.createDatasetSequence();
+    seq.setDatasetSequence(seq2);
+  }
 }
index 4b71417..8ed5cc4 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.datamodel.xdb.embl;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -128,6 +148,7 @@ public class EmblEntryTest
     assertEquals(5, dbrefs.length);
     assertEquals(DBRefSource.EMBL, dbrefs[0].getSource());
     assertEquals("CAA30420.1", dbrefs[0].getAccessionId());
+    // TODO: verify getPrimaryDBRefs() for peptide products
     assertEquals(cds1Map.getInverse(), dbrefs[0].getMap().getMap());
     assertEquals(DBRefSource.EMBLCDS, dbrefs[1].getSource());
     assertEquals("CAA30420.1", dbrefs[1].getAccessionId());
@@ -215,8 +236,7 @@ public class EmblEntryTest
 
     // truncate last exon by 6bp
     int[] truncated = EmblEntry.adjustForProteinLength(4, exons);
-    assertEquals("[11, 15, 21, 25, 31, 32]",
-            Arrays.toString(truncated));
+    assertEquals("[11, 15, 21, 25, 31, 32]", Arrays.toString(truncated));
 
     // remove last exon and truncate preceding by 1bp
     truncated = EmblEntry.adjustForProteinLength(3, exons);
index 6349164..0c7624f 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.datamodel.xdb.embl;
 
 import java.io.StringReader;
diff --git a/test/jalview/ext/android/SparseIntArrayTest.java b/test/jalview/ext/android/SparseIntArrayTest.java
new file mode 100644 (file)
index 0000000..be95d6e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.ext.android;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+/*
+ * Tests for SparseIntArray. Unlike SparseShortArray, SparseIntArray does not throw
+ * any exception for overflow.
+ */
+public class SparseIntArrayTest
+{
+  @Test(groups = "Functional")
+  public void testPut()
+  {
+    SparseIntArray counter = new SparseIntArray();
+
+    /*
+     * either key or value may be in the range of int
+     */
+    counter.put(Integer.MAX_VALUE, Integer.MIN_VALUE);
+    counter.put(Integer.MIN_VALUE, Integer.MAX_VALUE);
+    assertEquals(counter.get(Integer.MAX_VALUE), Integer.MIN_VALUE);
+    assertEquals(counter.get(Integer.MIN_VALUE), Integer.MAX_VALUE);
+  }
+
+  @Test(groups = "Functional")
+  public void testAdd()
+  {
+    SparseIntArray counter = new SparseIntArray();
+  
+    assertEquals(counter.add('P', 2), 2);
+    assertEquals(counter.add('P', 3), 5);
+    counter.put('Q', 7);
+    assertEquals(counter.add('Q', 4), 11);
+
+    counter.put('x', Integer.MAX_VALUE);
+    try
+    {
+      counter.add('x', 1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+  
+    counter.put('y', Integer.MIN_VALUE);
+    try
+    {
+      counter.add('y', -1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testCheckOverflow()
+  {
+    // things that don't overflow:
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, 0);
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, -1);
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, Integer.MIN_VALUE);
+    SparseIntArray.checkOverflow(Integer.MAX_VALUE, -Integer.MAX_VALUE);
+    SparseIntArray.checkOverflow(0, -Integer.MAX_VALUE);
+    SparseIntArray.checkOverflow(0, Integer.MIN_VALUE);
+    SparseIntArray.checkOverflow(Integer.MIN_VALUE, 0);
+    SparseIntArray.checkOverflow(Integer.MIN_VALUE, 1);
+    SparseIntArray.checkOverflow(Integer.MIN_VALUE, Integer.MAX_VALUE);
+
+    // and some that do
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MAX_VALUE, 1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MAX_VALUE - 1, 2);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(1, Integer.MAX_VALUE);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MIN_VALUE, -1);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(Integer.MIN_VALUE + 1, -2);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+    try
+    {
+      SparseIntArray.checkOverflow(-1, Integer.MIN_VALUE);
+      fail("expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected
+    }
+  }
+
+}
diff --git a/test/jalview/ext/android/SparseShortArrayTest.java b/test/jalview/ext/android/SparseShortArrayTest.java
new file mode 100644 (file)
index 0000000..df161b7
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.ext.android;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+public class SparseShortArrayTest
+{
+  @Test(groups = "Functional")
+  public void testPut()
+  {
+    SparseShortArray counter = new SparseShortArray();
+
+    /*
+     * either key or value may be in the range of short
+     */
+    counter.put(Short.MAX_VALUE, Short.MIN_VALUE);
+    counter.put(Short.MIN_VALUE, Short.MAX_VALUE);
+
+    // put a too large value
+    try
+    {
+      counter.put(0, Short.MAX_VALUE + 1);
+      fail("Expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected;
+    }
+
+    // put a too small value
+    try
+    {
+      counter.put(1, Short.MIN_VALUE - 1);
+      fail("Expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected;
+    }
+
+    // put a too large key
+    try
+    {
+      counter.put(Short.MAX_VALUE + 1, 0);
+      fail("Expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected;
+    }
+
+    // put a too small key
+    try
+    {
+      counter.put(Short.MIN_VALUE - 1, 2);
+      fail("Expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected;
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testAdd()
+  {
+    SparseShortArray counter = new SparseShortArray();
+  
+    assertEquals(counter.add('P', 2), 2);
+    assertEquals(counter.add('P', 3), 5);
+    counter.put('Q', 7);
+    assertEquals(counter.add('Q', 4), 11);
+
+    // increment giving overflow
+    counter.put('x', Short.MAX_VALUE);
+    try
+    {
+      counter.add('x', 1);
+      fail("Expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected;
+    }
+  
+    // decrement giving underflow
+    counter.put('y', Short.MIN_VALUE);
+    try
+    {
+      counter.add('y', -1);
+      fail("Expected exception");
+    } catch (ArithmeticException e)
+    {
+      // expected;
+    }
+  }
+}
index fb7e143..95d371a 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -32,6 +52,7 @@ public class EnsemblCdnaTest
   {
     SequenceOntologyFactory.setInstance(null);
   }
+
   /**
    * Test that the cdna part of genomic sequence is correctly identified by
    * 'exon' features (or subtypes) - reverse strand case.
@@ -99,30 +120,30 @@ public class EnsemblCdnaTest
     genomic.setStart(10000);
     genomic.setEnd(50000);
     String transcriptId = "ABC123";
-  
+
     // exon at (start+10000) length 501
     SequenceFeature sf = new SequenceFeature("exon", "", 20000, 20500, 0f,
             null);
     sf.setValue("Parent", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     // exon (sub-type) at (start + exon_variant) length 101
     sf = new SequenceFeature("coding_exon", "", 10500, 10600, 0f, null);
     sf.setValue("Parent", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     // exon belonging to a different transcript doesn't count
     sf = new SequenceFeature("exon", "", 11500, 12600, 0f, null);
     sf.setValue("Parent", "transcript:anotherOne");
     genomic.addSequenceFeature(sf);
-  
+
     // transcript feature doesn't count
     sf = new SequenceFeature("transcript", "", 10000, 50000, 0f, null);
     sf.setStrand("-"); // weird but ignored
     genomic.addSequenceFeature(sf);
-  
+
     MapList ranges = testee.getGenomicRangesFromFeatures(genomic,
             transcriptId, 23);
     List<int[]> fromRanges = ranges.getFromRanges();
@@ -151,18 +172,18 @@ public class EnsemblCdnaTest
     genomic.setStart(10000);
     genomic.setEnd(50000);
     String transcriptId = "ABC123";
-  
+
     SequenceFeature sf = new SequenceFeature("exon", "", 20000, 20500, 0f,
             null);
     sf.setValue("Parent", "transcript:" + transcriptId);
     sf.setStrand("-");
     genomic.addSequenceFeature(sf);
-  
+
     sf = new SequenceFeature("coding_exon", "", 10500, 10600, 0f, null);
     sf.setValue("Parent", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     MapList ranges = testee.getGenomicRangesFromFeatures(genomic,
             transcriptId, 23);
     assertNull(ranges);
index 5344575..c644e83 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -44,25 +64,25 @@ public class EnsemblCdsTest
     genomic.setStart(10000);
     genomic.setEnd(50000);
     String transcriptId = "ABC123";
-  
+
     // CDS at (start+10000) length 501
     SequenceFeature sf = new SequenceFeature("CDS", "", 20000, 20500, 0f,
             null);
     sf.setValue("Parent", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     // CDS (sub-type) at (start + 10500) length 101
     sf = new SequenceFeature("CDS_predicted", "", 10500, 10600, 0f, null);
     sf.setValue("Parent", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     // CDS belonging to a different transcript doesn't count
     sf = new SequenceFeature("CDS", "", 11500, 12600, 0f, null);
     sf.setValue("Parent", "transcript:anotherOne");
     genomic.addSequenceFeature(sf);
-  
+
     // exon feature doesn't count
     sf = new SequenceFeature("exon", "", 10000, 50000, 0f, null);
     genomic.addSequenceFeature(sf);
@@ -70,7 +90,7 @@ public class EnsemblCdsTest
     // mRNA_region feature doesn't count (parent of CDS)
     sf = new SequenceFeature("mRNA_region", "", 10000, 50000, 0f, null);
     genomic.addSequenceFeature(sf);
-  
+
     MapList ranges = testee.getGenomicRangesFromFeatures(genomic,
             transcriptId, 23);
     List<int[]> fromRanges = ranges.getFromRanges();
@@ -96,22 +116,22 @@ public class EnsemblCdsTest
   {
     String accId = "ABC123";
     EnsemblCds testee = new EnsemblCds();
-  
-    SequenceFeature sf = new SequenceFeature("CDS", "", 20000,
-            20500, 0f, null);
+
+    SequenceFeature sf = new SequenceFeature("CDS", "", 20000, 20500, 0f,
+            null);
     assertFalse(testee.retainFeature(sf, accId));
-  
+
     sf.setType("CDS_predicted");
     assertFalse(testee.retainFeature(sf, accId));
-  
+
     // other feature with no parent is retained
     sf.setType("sequence_variant");
     assertTrue(testee.retainFeature(sf, accId));
-  
+
     // other feature with desired parent is retained
     sf.setValue("Parent", "transcript:" + accId);
     assertTrue(testee.retainFeature(sf, accId));
-  
+
     // feature with wrong parent is not retained
     sf.setValue("Parent", "transcript:XYZ");
     assertFalse(testee.retainFeature(sf, accId));
@@ -126,27 +146,27 @@ public class EnsemblCdsTest
   {
     String accId = "ABC123";
     EnsemblCds testee = new EnsemblCds();
-  
+
     // cds with no parent not valid
     SequenceFeature sf = new SequenceFeature("CDS", "", 1, 2, 0f, null);
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // cds with wrong parent not valid
     sf.setValue("Parent", "transcript:XYZ");
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // cds with right parent is valid
     sf.setValue("Parent", "transcript:" + accId);
     assertTrue(testee.identifiesSequence(sf, accId));
-  
+
     // cds sub-type with right parent is valid
     sf.setType("CDS_predicted");
     assertTrue(testee.identifiesSequence(sf, accId));
-  
+
     // transcript not valid:
     sf.setType("transcript");
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // exon not valid:
     sf.setType("exon");
     assertFalse(testee.identifiesSequence(sf, accId));
index 4e815d1..33bb189 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -135,8 +155,8 @@ public class EnsemblGeneTest
     genomic.addSequenceFeature(sf1);
 
     // transcript sub-type feature
-    SequenceFeature sf2 = new SequenceFeature("snRNA", "", 20000,
-            20500, 0f, null);
+    SequenceFeature sf2 = new SequenceFeature("snRNA", "", 20000, 20500,
+            0f, null);
     sf2.setValue("Parent", "gene:" + geneId);
     sf2.setValue("transcript_id", "transcript2");
     genomic.addSequenceFeature(sf2);
@@ -177,8 +197,8 @@ public class EnsemblGeneTest
   {
     String geneId = "ABC123";
     EnsemblGene testee = new EnsemblGene();
-    SequenceFeature sf = new SequenceFeature("gene", "", 20000,
-            20500, 0f, null);
+    SequenceFeature sf = new SequenceFeature("gene", "", 20000, 20500, 0f,
+            null);
     sf.setValue("ID", "gene:" + geneId);
     assertFalse(testee.retainFeature(sf, geneId));
 
@@ -210,27 +230,27 @@ public class EnsemblGeneTest
   {
     String accId = "ABC123";
     EnsemblGene testee = new EnsemblGene();
-  
+
     // gene with no ID not valid
     SequenceFeature sf = new SequenceFeature("gene", "", 1, 2, 0f, null);
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // gene with wrong ID not valid
     sf.setValue("ID", "gene:XYZ");
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // gene with right ID is valid
     sf.setValue("ID", "gene:" + accId);
     assertTrue(testee.identifiesSequence(sf, accId));
-  
+
     // gene sub-type with right ID is valid
     sf.setType("snRNA_gene");
     assertTrue(testee.identifiesSequence(sf, accId));
-  
+
     // transcript not valid:
     sf.setType("transcript");
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // exon not valid:
     sf.setType("exon");
     assertFalse(testee.identifiesSequence(sf, accId));
index c711279..991cd96 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -43,15 +63,14 @@ public class EnsemblGenomeTest
     genomic.setStart(10000);
     genomic.setEnd(50000);
     String transcriptId = "ABC123";
-  
+
     // transcript at (start+10000) length 501
     SequenceFeature sf = new SequenceFeature("transcript", "", 20000,
-            20500, 0f,
-            null);
+            20500, 0f, null);
     sf.setValue("ID", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     // transcript (sub-type) at (start + 10500) length 101
     sf = new SequenceFeature("ncRNA", "", 10500, 10600, 0f, null);
     sf.setValue("ID", "transcript:" + transcriptId);
@@ -65,12 +84,12 @@ public class EnsemblGenomeTest
     sf.setValue("ID", "transcript:" + transcriptId);
     sf.setStrand("+");
     genomic.addSequenceFeature(sf);
-  
+
     // transcript with a different ID doesn't count
     sf = new SequenceFeature("transcript", "", 11500, 12600, 0f, null);
     sf.setValue("ID", "transcript:anotherOne");
     genomic.addSequenceFeature(sf);
-  
+
     // parent of transcript feature doesn't count
     sf = new SequenceFeature("gene_member_region", "", 10000, 50000, 0f,
             null);
@@ -107,13 +126,13 @@ public class EnsemblGenomeTest
     SequenceFeature sf = new SequenceFeature("transcript", "", 20000,
             20500, 0f, null);
     assertFalse(testee.retainFeature(sf, accId));
-  
+
     sf.setType("mature_transcript");
     assertFalse(testee.retainFeature(sf, accId));
-  
+
     sf.setType("NMD_transcript_variant");
     assertFalse(testee.retainFeature(sf, accId));
-  
+
     // other feature with no parent is kept
     sf.setType("anything");
     assertTrue(testee.retainFeature(sf, accId));
@@ -136,20 +155,20 @@ public class EnsemblGenomeTest
   {
     String accId = "ABC123";
     EnsemblGenome testee = new EnsemblGenome();
-  
+
     // transcript with no ID not valid
     SequenceFeature sf = new SequenceFeature("transcript", "", 1, 2, 0f,
             null);
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // transcript with wrong ID not valid
     sf.setValue("ID", "transcript");
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // transcript with right ID is valid
     sf.setValue("ID", "transcript:" + accId);
     assertTrue(testee.identifiesSequence(sf, accId));
-  
+
     // transcript sub-type with right ID is valid
     sf.setType("ncRNA");
     assertTrue(testee.identifiesSequence(sf, accId));
@@ -157,11 +176,11 @@ public class EnsemblGenomeTest
     // Ensembl treats NMD_transcript_variant as if a transcript
     sf.setType("NMD_transcript_variant");
     assertTrue(testee.identifiesSequence(sf, accId));
-  
+
     // gene not valid:
     sf.setType("gene");
     assertFalse(testee.identifiesSequence(sf, accId));
-  
+
     // exon not valid:
     sf.setType("exon");
     assertFalse(testee.identifiesSequence(sf, accId));
index e6f6683..d44a82b 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
index 56e1339..31001da 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.AlignmentI;
@@ -16,43 +36,43 @@ public class EnsemblRestClientTest
   {
     EnsemblRestClient sf = new EnsemblRestClient()
     {
-  
+
       @Override
       public String getDbName()
       {
         return null;
       }
-  
+
       @Override
       public AlignmentI getSequenceRecords(String queries) throws Exception
       {
         return null;
       }
-  
+
       @Override
       protected URL getUrl(List<String> ids) throws MalformedURLException
       {
         return null;
       }
-  
+
       @Override
       protected boolean useGetRequest()
       {
         return false;
       }
-  
+
       @Override
       protected String getRequestMimeType(boolean b)
       {
         return null;
       }
-  
+
       @Override
       protected String getResponseMimeType()
       {
         return null;
       }
-  
+
     };
     boolean isAvailable = sf.isEnsemblAvailable();
     if (isAvailable)
index 510e072..9fad30e 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import jalview.datamodel.SequenceFeature;
index b1ebdf8..aee79fe 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -23,7 +43,6 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
-
 public class EnsemblSeqProxyTest
 {
   private static final Object[][] allSeqs = new Object[][] {
@@ -125,12 +144,11 @@ public class EnsemblSeqProxyTest
   }
 
   @Test(dataProvider = "ens_seqs", suiteName = "live")
-  public void testGetOneSeqs(EnsemblRestClient proxy, String sq, String fastasq)
-          throws Exception
+  public void testGetOneSeqs(EnsemblRestClient proxy, String sq,
+          String fastasq) throws Exception
   {
     FileParse fp = proxy.getSequenceReader(Arrays
-            .asList(new String[]
-    { sq }));
+            .asList(new String[] { sq }));
     SequenceI[] sqs = new FastaFile(fp).getSeqsAsArray();
     FastaFile trueRes = new FastaFile(fastasq, DataSourceType.PASTE);
     SequenceI[] trueSqs = trueRes.getSeqsAsArray();
@@ -152,7 +170,7 @@ public class EnsemblSeqProxyTest
               "Sequences differ for " + tr.getName() + "\n" + "Exp:"
                       + tr.getSequenceAsString() + "\n" + "Got:"
                       + rseq[0].getSequenceAsString());
-  
+
     }
   }
 
@@ -253,4 +271,4 @@ public class EnsemblSeqProxyTest
     EnsemblSeqProxy.sortFeatures(sfs, false);
     assertArrayEquals(new SequenceFeature[] { sf1, sf3, sf2, sf4 }, sfs);
   }
-}
\ No newline at end of file
+}
index 1dc9b8d..9ef2843 100644 (file)
@@ -1,6 +1,27 @@
+/*
+ * 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.ext.ensembl;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
 
 import jalview.datamodel.DBRefEntry;
 
@@ -24,8 +45,11 @@ public class EnsemblXrefTest
   @Test(groups = "Functional")
   public void testGetCrossReferences()
   {
+    String dbName = "ENSEMBL";
+    String dbVers = "0.6.2b1";
     System.out.println(JSON);
-    EnsemblXref testee = new EnsemblXref("http://rest.ensembl.org")
+    EnsemblXref testee = new EnsemblXref("http://rest.ensembl.org", dbName,
+            dbVers)
     {
       @Override
       protected BufferedReader getHttpResponse(URL url, List<String> ids)
@@ -40,8 +64,12 @@ public class EnsemblXrefTest
     assertEquals(2, dbrefs.size());
     assertEquals("CCDS", dbrefs.get(0).getSource());
     assertEquals("CCDS5863", dbrefs.get(0).getAccessionId());
+    assertFalse(dbrefs.get(0).isPrimaryCandidate());
+    assertEquals(dbName + ":" + dbVers, dbrefs.get(0).getVersion());
     // Uniprot name should get converted to Jalview canonical form
     assertEquals("UNIPROT", dbrefs.get(1).getSource());
     assertEquals("P15056", dbrefs.get(1).getAccessionId());
+    assertEquals(dbName + ":" + dbVers, dbrefs.get(1).getVersion());
+    assertFalse(dbrefs.get(1).isPrimaryCandidate());
   }
 }
index 5e0f99a..bdc14db 100644 (file)
@@ -1,5 +1,22 @@
-/**
+/*
+ * 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.ext.htsjdk;
 
@@ -16,7 +33,7 @@ import org.testng.annotations.Test;
  */
 public class TestHtsContigDb
 {
-  @Test
+  @Test(groups = "Functional")
   public final void testHTSReferenceSequence() throws Exception
   {
     HtsContigDb remmadb = new HtsContigDb("REEMADB", new File(
index 46fa241..89ab580 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.jmol;
 
 import jalview.datamodel.Alignment;
index f2b32c6..75b27c7 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.ext.jmol;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.bin.Cache;
@@ -86,8 +87,11 @@ public class JmolParserTest
   @BeforeMethod(alwaysRun = true)
   public void setUp()
   {
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
     Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("ADD_TEMPFACT_ANN",
+            Boolean.FALSE.toString());
     Cache.applicationProperties.setProperty("ADD_SS_ANN",
             Boolean.TRUE.toString());
     StructureImportSettings.setDefaultStructureFileFormat("PDB");
@@ -113,8 +117,7 @@ public class JmolParserTest
     {
       PDBfile mctest = new PDBfile(false, false, false, pdbStr,
               DataSourceType.FILE);
-      JmolParser jtest = new JmolParser(false, false, false, pdbStr,
-              DataSourceType.FILE);
+      JmolParser jtest = new JmolParser(pdbStr, DataSourceType.FILE);
       Vector<SequenceI> seqs = jtest.getSeqs(), mcseqs = mctest.getSeqs();
 
       assertTrue(
@@ -162,7 +165,8 @@ public class JmolParserTest
 
   private void checkFirstAAIsAssoc(SequenceI sq)
   {
-    assertTrue("No secondary structure assigned for protein sequence.",
+    assertTrue("No secondary structure assigned for protein sequence for "
+            + sq.getName(),
             sq.getAnnotation() != null && sq.getAnnotation().length >= 1
                     && sq.getAnnotation()[0].hasIcons);
     assertTrue(
@@ -180,12 +184,7 @@ public class JmolParserTest
   {
     PDBfile mctest = new PDBfile(false, false, false,
             pastePDBDataWithChainBreak, DataSourceType.PASTE);
-    boolean annotFromStructure = false;
-    boolean localSecondaryStruct = false;
-    boolean serviceSecondaryStruct = false;
-    JmolParser jtest = new JmolParser(annotFromStructure,
-            localSecondaryStruct, serviceSecondaryStruct,
-            pastePDBDataWithChainBreak, DataSourceType.PASTE);
+    JmolParser jtest = new JmolParser(pastePDBDataWithChainBreak, DataSourceType.PASTE);
     Vector<SequenceI> seqs = jtest.getSeqs();
     Vector<SequenceI> mcseqs = mctest.getSeqs();
 
@@ -207,15 +206,11 @@ public class JmolParserTest
   {
     PDBfile mctest = new PDBfile(false, false, false, pdbWithAltLoc,
             DataSourceType.PASTE);
-    boolean annotFromStructure = false;
-    boolean localSecondaryStruct = false;
-    boolean serviceSecondaryStruct = false;
-    JmolParser jtest = new JmolParser(annotFromStructure,
-            localSecondaryStruct, serviceSecondaryStruct, pdbWithAltLoc,
+    JmolParser jtest = new JmolParser(pdbWithAltLoc,
             DataSourceType.PASTE);
     Vector<SequenceI> seqs = jtest.getSeqs();
     Vector<SequenceI> mcseqs = mctest.getSeqs();
-  
+
     assertEquals("Failed to find 1 sequence\n", 1, seqs.size());
     assertEquals("Failed to find 1 sequence\n", 1, mcseqs.size());
     assertEquals("ALC", seqs.get(0).getSequenceAsString());
@@ -252,4 +247,30 @@ public class JmolParserTest
     assertEquals('H', structCode[4]);
     assertEquals('E', structCode[5]);
   }
+
+  @Test(groups = "Functional")
+  public void testLocalPDBId() throws Exception
+  {
+    JmolParser structureData;
+    /*
+     * reads a local structure
+     */
+    structureData = new JmolParser("examples/testdata/localstruct.pdb",
+            DataSourceType.FILE);
+    assertNotNull(structureData);
+    /*
+     * local structure files should yield a false ID based on the filename
+     */
+    assertNotNull(structureData.getId());
+    assertEquals(structureData.getId(), "localstruct.pdb");
+    assertNotNull(structureData.getSeqs());
+    /*
+     * the ID is also the group for features derived from structure data 
+     */
+    assertNotNull(structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup);
+    assertEquals(
+            structureData.getSeqs().get(0).getSequenceFeatures()[0].featureGroup,
+            "localstruct.pdb");
+
+  }
 }
index 01b4adf..6baa1dd 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.jmol;
 
 import jalview.datamodel.SequenceI;
@@ -51,10 +71,8 @@ public class JmolVsJalviewPDBParserEndToEndTest
       JmolParser jtest = null;
       try
       {
-        mctest = new PDBfile(false, false, false, testFile,
-                DataSourceType.FILE);
-        jtest = new JmolParser(false, false, false, testFile,
-                DataSourceType.FILE);
+        mctest = new PDBfile(false, false, false, testFile, DataSourceType.FILE);
+        jtest = new JmolParser(testFile, DataSourceType.FILE);
       } catch (IOException e)
       {
         System.err.println("Exception thrown while parsing : " + pdbStr);
@@ -66,15 +84,15 @@ public class JmolVsJalviewPDBParserEndToEndTest
       {
         try
         {
-        String testSeq = mcseqs.remove(0).getSequenceAsString();
+          String testSeq = mcseqs.remove(0).getSequenceAsString();
           if (!sq.getSequenceAsString().equals(testSeq))
-        {
-          ++totalFail;
+          {
+            ++totalFail;
             System.err.println("Test Failed for " + pdbStr + ". Diff:");
-          System.err.println(sq.getSequenceAsString());
-          System.err.println(testSeq);
-          failedFiles.add(pdbStr);
-        }
+            System.err.println(sq.getSequenceAsString());
+            System.err.println(testSeq);
+            failedFiles.add(pdbStr);
+          }
           ++totalSeqScanned;
         } catch (Exception e)
         {
index ea92e3c..1bc802e 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ext.so;
 
 import static org.testng.AssertJUnit.assertFalse;
@@ -13,7 +33,8 @@ public class SequenceOntologyTest
   private SequenceOntologyI so;
 
   @BeforeClass(alwaysRun = true)
-  public void setUp() {
+  public void setUp()
+  {
     long now = System.currentTimeMillis();
     try
     {
index eae5575..b751b77 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.fts.core;
 
 import jalview.fts.api.FTSDataColumnI;
@@ -61,11 +81,12 @@ public class FTSRestClientTest
   @Test(groups = { "Functional" })
   public void getAllDefaulDisplayedDataColumns()
   {
-    Assert.assertNotNull(ftsRestClient.getAllDefaultDisplayedFTSDataColumns());
+    Assert.assertNotNull(ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns());
     Assert.assertTrue(!ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
             .isEmpty());
-    Assert.assertEquals(ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
-            .size(), 7);
+    Assert.assertEquals(ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns().size(), 7);
   }
 
   @Test(groups = { "Functional" })
@@ -79,7 +100,6 @@ public class FTSRestClientTest
             "id,entry name,protein names,genes,organism,reviewed,length");
   }
 
-
   @Test(groups = { "Functional" })
   public void getAllFTSDataColumns()
   {
index ed248bb..8faec58 100644 (file)
@@ -72,13 +72,11 @@ public class PDBFTSRestClientTest
     {
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("molecule_type"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("pdb_id"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("genus"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("gene_name"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("title"));
@@ -117,13 +115,11 @@ public class PDBFTSRestClientTest
     {
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("molecule_type"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("pdb_id"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("genus"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("gene_name"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("title"));
@@ -147,13 +143,11 @@ public class PDBFTSRestClientTest
     {
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("molecule_type"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("pdb_id"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("genus"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("gene_name"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("title"));
@@ -190,9 +184,7 @@ public class PDBFTSRestClientTest
     assertEquals(expectedErrorMsg, parsedErrorResponse);
   }
 
-  @Test(
-    groups = { "External" },
-    expectedExceptions = Exception.class)
+  @Test(groups = { "External" }, expectedExceptions = Exception.class)
   public void testForExpectedRuntimeException() throws Exception
   {
     List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
@@ -206,7 +198,7 @@ public class PDBFTSRestClientTest
     PDBFTSRestClient.getInstance().executeRequest(request);
   }
 
-    // JBP: Is this actually external ?  Looks like it is mocked
+  // JBP: Is this actually external ? Looks like it is mocked
   @Test(groups = { "External" })
   public void parsePDBJsonResponseTest()
   {
@@ -215,13 +207,11 @@ public class PDBFTSRestClientTest
     {
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("molecule_type"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("pdb_id"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("genus"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("gene_name"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("title"));
@@ -259,13 +249,11 @@ public class PDBFTSRestClientTest
               .getDataColumnByNameOrCode("molecule_type"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("genus"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("gene_name"));
       wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("title"));
-      wantedFields
-.add(PDBFTSRestClient.getInstance()
+      wantedFields.add(PDBFTSRestClient.getInstance()
               .getDataColumnByNameOrCode("pdb_id"));
     } catch (Exception e)
     {
@@ -273,11 +261,9 @@ public class PDBFTSRestClientTest
     }
     try
     {
-      assertEquals(5,
- PDBFTSRestClient.getInstance()
+      assertEquals(5, PDBFTSRestClient.getInstance()
               .getPrimaryKeyColumIndex(wantedFields, true));
-      assertEquals(4,
- PDBFTSRestClient.getInstance()
+      assertEquals(4, PDBFTSRestClient.getInstance()
               .getPrimaryKeyColumIndex(wantedFields, false));
     } catch (Exception e)
     {
index 80e3d5a..b2ef3f7 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -17,7 +37,7 @@ import org.testng.annotations.Test;
 public class AlignFrameTest
 {
 
-  @Test
+  @Test(groups = "Functional")
   public void testHideFeatureColumns()
   {
     SequenceI seq1 = new Sequence("Seq1", "ABCDEFGHIJ");
@@ -60,8 +80,7 @@ public class AlignFrameTest
      * [1-3], [6-8] base zero
      */
     assertTrue(af.hideFeatureColumns("Turn", true));
-    hidden = af.getViewport().getColumnSelection()
-            .getHiddenColumns();
+    hidden = af.getViewport().getColumnSelection().getHiddenColumns();
     assertEquals(2, hidden.size());
     assertEquals(1, hidden.get(0)[0]);
     assertEquals(3, hidden.get(0)[1]);
index 8c540b0..d6b2454 100644 (file)
@@ -26,15 +26,23 @@ import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.bin.Cache;
+import jalview.bin.Jalview;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.PIDColourScheme;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MapList;
 
@@ -55,8 +63,7 @@ public class AlignViewportTest
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-    jalview.bin.Jalview.main(new String[] { "-props",
-        "test/jalview/testProps.jvprops" });
+    Jalview.main(new String[] { "-props", "test/jalview/testProps.jvprops" });
   }
 
   @BeforeMethod(alwaysRun = true)
@@ -74,6 +81,7 @@ public class AlignViewportTest
   @Test(groups = { "Functional" })
   public void testCollateForPdb()
   {
+    // JBP: What behaviour is this supposed to test ?
     /*
      * Set up sequence pdb ids
      */
@@ -296,4 +304,73 @@ public class AlignViewportTest
     assertTrue(ssmMappings.contains(acf2));
     assertFalse(ssmMappings.contains(acf3));
   }
+
+  /**
+   * Test for JAL-1306 - conservation thread should run even when only Quality
+   * (and not Conservation) is enabled in Preferences
+   */
+  @Test(groups = { "Functional" })
+  public void testUpdateConservation_qualityOnly()
+  {
+    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("SHOW_QUALITY",
+            Boolean.TRUE.toString());
+    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+            Boolean.FALSE.toString());
+    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+            Boolean.FALSE.toString());
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+    AlignmentAnnotation[] anns = af.viewport.getAlignment()
+            .getAlignmentAnnotation();
+    assertNotNull("No annotations found", anns);
+    assertEquals("More than one annotation found", 1, anns.length);
+    assertTrue("Annotation is not Quality",
+            anns[0].description.startsWith("Alignment Quality"));
+    Annotation[] annotations = anns[0].annotations;
+    assertNotNull("Quality annotations are null", annotations);
+    assertNotNull("Quality in column 1 is null", annotations[0]);
+    assertTrue("No quality value in column 1", annotations[0].value > 10f);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetGlobalColourScheme()
+  {
+    /*
+     * test for JAL-2283 don't inadvertently turn on colour by conservation
+     */
+    Cache.applicationProperties.setProperty("DEFAULT_COLOUR_PROT", "NONE");
+    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+            Boolean.TRUE.toString());
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+    ColourSchemeI cs = new PIDColourScheme();
+    af.getViewport().setGlobalColourScheme(cs);
+    assertFalse(cs.conservationApplied());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSetGetHasSearchResults()
+  {
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+    SearchResultsI sr = new SearchResults();
+    SequenceI s1 = af.getViewport().getAlignment().getSequenceAt(0);
+
+    // create arbitrary range on first sequence
+    sr.addResult(s1, s1.getStart() + 10, s1.getStart() + 15);
+
+    // test set
+    af.getViewport().setSearchResults(sr);
+    // has -> true
+    assertTrue(af.getViewport().hasSearchResults());
+    // get == original
+    assertEquals(sr, af.getViewport().getSearchResults());
+
+    // set(null) results in has -> false
+
+    af.getViewport().setSearchResults(null);
+    assertFalse(af.getViewport().hasSearchResults());
+  }
 }
index 1a61c3e..14c01f9 100644 (file)
@@ -77,6 +77,7 @@ public class AnnotationChooserTest
   @BeforeMethod(alwaysRun = true)
   public void setUp() throws IOException
   {
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // pin down annotation sort order for test
     Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS,
             SequenceAnnotationOrder.NONE.name());
index 5bc0ddf..92770d5 100644 (file)
@@ -28,7 +28,7 @@ import org.testng.annotations.Test;
 
 public class AppVarnaTest
 {
-  @Test
+  @Test(groups = "Functional")
   public void testReplaceOddGaps()
   {
     String struct = "{(<]}>)";
index 9d0cedb..489fe4f 100644 (file)
@@ -23,16 +23,12 @@ package jalview.gui;
 import jalview.bin.Cache;
 
 import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
 
 import javax.swing.JDesktopPane;
 import javax.swing.JFrame;
 import javax.swing.JInternalFrame;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
 import javax.swing.JTextArea;
 
 import org.testng.annotations.AfterClass;
@@ -64,49 +60,29 @@ public class JAL1353bugdemo
     foo.setPreferredSize(new Dimension(600, 800));
     cfoo.setSize(600, 800);
     final JInternalFrame cont = new JInternalFrame("My Frame");
-    JTextArea evt;
-    cont.setPreferredSize(new Dimension(400, 300));
-    cont.add(evt = new JTextArea(
-            "Click here and drag text over this window to freeze java.\n\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\nThis is a dummy string. See teh dummy string go.\n"));
+    cont.setPreferredSize(new Dimension(400, 400));
+    String msg = "This is a dummy string. See the dummy string go.\n";
+    msg += msg; // 2
+    msg += msg; // 4
+    msg += msg; // 8
+    msg += msg; // 16
+    JTextArea evt = new JTextArea(
+            "Click here and drag text over this window to freeze java.\n\n"
+                    + msg);
+    cont.add(evt);
     cont.pack();
     foo.add("A frame", cont);
     foo.setVisible(true);
     foo.setEnabled(true);
     foo.doLayout();
     cfoo.add(foo);
-    final JMenu jm = new JMenu("Do");
-    JMenuItem jmi = new JMenuItem("this");
-    jm.add(jmi);
-    evt.addMouseListener(new MouseListener()
+    // final JMenu jm = new JMenu("Do");
+    // JMenuItem jmi = new JMenuItem("this");
+    // jm.add(jmi);
+    evt.addMouseListener(new MouseAdapter()
     {
 
       @Override
-      public void mouseReleased(MouseEvent e)
-      {
-      }
-
-      @Override
-      public void mousePressed(MouseEvent e)
-      {
-        // TODO Auto-generated method stub
-
-      }
-
-      @Override
-      public void mouseExited(MouseEvent e)
-      {
-        // TODO Auto-generated method stub
-
-      }
-
-      @Override
-      public void mouseEntered(MouseEvent e)
-      {
-        // TODO Auto-generated method stub
-
-      }
-
-      @Override
       public void mouseClicked(MouseEvent e)
       {
         // JFrame parent = new JFrame();
@@ -124,19 +100,19 @@ public class JAL1353bugdemo
     });
     cont.setVisible(true);
 
-    jmi.addActionListener(new ActionListener()
-    {
-
-      @Override
-      public void actionPerformed(ActionEvent arg0)
-      {
-        EditNameDialog end = new EditNameDialog("Sequence Name",
-                "Sequence Description", "label 1", "Label 2",
-                "Try and drag between the two text fields", cont);
-        assert (end != null);
-        finish = true;
-      }
-    });
+    // jmi.addActionListener(new ActionListener()
+    // {
+    //
+    // @Override
+    // public void actionPerformed(ActionEvent arg0)
+    // {
+    // EditNameDialog end = new EditNameDialog("Sequence Name",
+    // "Sequence Description", "label 1", "Label 2",
+    // "Try and drag between the two text fields", cont);
+    // assert (end != null);
+    // finish = true;
+    // }
+    // });
     foo.setVisible(true);
     cfoo.setVisible(true);
     while (!finish)
diff --git a/test/jalview/gui/MouseEventDemo.java b/test/jalview/gui/MouseEventDemo.java
new file mode 100644 (file)
index 0000000..6d154de
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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;
+
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle or the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+* MouseEventDemo.java
+*/
+
+import jalview.util.Platform;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+
+/**
+ * Sourced from Oracle and adapted
+ * 
+ * @see https
+ *      ://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
+ */
+public class MouseEventDemo extends JPanel implements MouseListener
+{
+  private class BlankArea extends JLabel
+  {
+    Dimension minSize = new Dimension(200, 100);
+
+    public BlankArea(Color color)
+    {
+      setBackground(color);
+      setOpaque(true);
+      setBorder(BorderFactory.createLineBorder(Color.black));
+    }
+
+    @Override
+    public Dimension getMinimumSize()
+    {
+      return minSize;
+    }
+
+    @Override
+    public Dimension getPreferredSize()
+    {
+      return minSize;
+    }
+  }
+
+  static int counter = 0;
+
+  BlankArea blankArea;
+
+  JTextArea textArea;
+
+  static final String NEWLINE = System.getProperty("line.separator");
+
+  public static void main(String[] args)
+  {
+    // Schedule a job for the event dispatch thread:
+    // creating and showing this application's GUI.
+    javax.swing.SwingUtilities.invokeLater(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        createAndShowGUI();
+      }
+    });
+  }
+
+  /**
+   * Create the GUI and show it. For thread safety, this method should be
+   * invoked from the event dispatch thread.
+   */
+  private static void createAndShowGUI()
+  {
+    // Create and set up the window.
+    JFrame frame = new JFrame("MouseEventDemo (C to clear)");
+    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+    // Create and set up the content pane.
+    JComponent newContentPane = new MouseEventDemo();
+    newContentPane.setOpaque(true); // content panes must be opaque
+    frame.setContentPane(newContentPane);
+
+    // Display the window.
+    frame.pack();
+    frame.setVisible(true);
+  }
+
+  public MouseEventDemo()
+  {
+    super(new GridLayout(0, 1));
+
+    textArea = new JTextArea();
+    textArea.setEditable(false);
+    JScrollPane scrollPane = new JScrollPane(textArea);
+    scrollPane
+            .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+    scrollPane.setPreferredSize(new Dimension(400, 75));
+
+    blankArea = new BlankArea(Color.YELLOW);
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+            blankArea, scrollPane);
+    splitPane.setVisible(true);
+    splitPane.setDividerLocation(0.2d);
+    splitPane.setResizeWeight(0.5d);
+    add(splitPane);
+
+    addKeyBinding();
+
+    blankArea.addMouseListener(this);
+    addMouseListener(this);
+    setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+  }
+
+  private void addKeyBinding()
+  {
+    addKeyBinding(KeyStroke.getKeyStroke('C'));
+    addKeyBinding(KeyStroke.getKeyStroke('c'));
+  }
+
+  /**
+   * @param ks
+   */
+  void addKeyBinding(final KeyStroke ks)
+  {
+    InputMap inputMap = this.getInputMap(JComponent.WHEN_FOCUSED);
+    inputMap.put(ks, ks);
+    this.getActionMap().put(ks, new AbstractAction()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        textArea.setText("");
+        log("");
+      }
+    });
+  }
+
+  void logEvent(String eventDescription, MouseEvent e)
+  {
+    log("------- " + counter++ + ": " + eventDescription);
+    log("e.isPopupTrigger: " + e.isPopupTrigger());
+    log("SwingUtilities.isRightMouseButton: "
+            + SwingUtilities.isRightMouseButton(e));
+    log("SwingUtilities.isLeftMouseButton: "
+            + SwingUtilities.isLeftMouseButton(e));
+    log("Platform.isControlDown: " + Platform.isControlDown(e));
+    log("e.isControlDown: " + e.isControlDown());
+    log("e.isAltDown: " + e.isAltDown());
+    log("e.isMetaDown: " + e.isMetaDown());
+    log("e.isShiftDown: " + e.isShiftDown());
+    log("e.getClickCount: " + e.getClickCount());
+  }
+
+  /**
+   * @param msg
+   */
+  void log(String msg)
+  {
+    textArea.append(msg + NEWLINE);
+    textArea.setCaretPosition(textArea.getDocument().getLength());
+  }
+
+  @Override
+  public void mousePressed(MouseEvent e)
+  {
+    logEvent("Mouse pressed", e);
+  }
+
+  @Override
+  public void mouseReleased(MouseEvent e)
+  {
+    logEvent("Mouse released", e);
+  }
+
+  @Override
+  public void mouseEntered(MouseEvent e)
+  {
+  }
+
+  @Override
+  public void mouseExited(MouseEvent e)
+  {
+  }
+
+  @Override
+  public void mouseClicked(MouseEvent e)
+  {
+    logEvent("Mouse clicked", e);
+  }
+}
index 0ad75e8..38c0de3 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
@@ -27,6 +29,9 @@ import static org.testng.AssertJUnit.assertTrue;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
@@ -441,4 +446,105 @@ public class PopupMenuTest
     assertEquals(JSeparator.HORIZONTAL,
             ((JSeparator) hideOptions[1]).getOrientation());
   }
+
+  /**
+   * Test for adding feature links
+   */
+  @Test(groups = { "Functional" })
+  public void testAddFeatureLinks()
+  {
+    // sequences from the alignment
+    List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
+    // create list of links and list of DBRefs
+    List<String> links = new ArrayList<String>();
+    List<DBRefEntry> refs = new ArrayList<DBRefEntry>();
+
+    // links as might be added into Preferences | Connections dialog
+    links.add("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
+            + SEQUENCE_ID + "$");
+    links.add("UNIPROT | http://www.uniprot.org/uniprot/$" + DB_ACCESSION
+            + "$");
+    links.add("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$"
+            + DB_ACCESSION + "$");
+    // Gene3D entry tests for case (in)sensitivity
+    links.add("Gene3D | http://gene3d.biochem.ucl.ac.uk/Gene3D/search?sterm=$"
+            + DB_ACCESSION + "$&mode=protein");
+
+    // make seq0 dbrefs
+    refs.add(new DBRefEntry(DBRefSource.UNIPROT, "1", "P83527"));
+    refs.add(new DBRefEntry("INTERPRO", "1", "IPR001041"));
+    refs.add(new DBRefEntry("INTERPRO", "1", "IPR006058"));
+    refs.add(new DBRefEntry("INTERPRO", "1", "IPR012675"));
+    
+    // make seq1 dbrefs
+    refs.add(new DBRefEntry(DBRefSource.UNIPROT, "1", "Q9ZTS2"));
+    refs.add(new DBRefEntry("GENE3D", "1", "3.10.20.30"));
+
+    // add all the dbrefs to the sequences: Uniprot 1 each, Interpro all 3 to
+    // seq0, Gene3D to seq1
+    seqs.get(0).addDBRef(refs.get(0));
+
+    seqs.get(0).addDBRef(refs.get(1));
+    seqs.get(0).addDBRef(refs.get(2));
+    seqs.get(0).addDBRef(refs.get(3));
+    
+    seqs.get(1).addDBRef(refs.get(4));
+    seqs.get(1).addDBRef(refs.get(5));
+    
+    // get the Popup Menu for first sequence
+    testee = new PopupMenu(parentPanel, (Sequence) seqs.get(0), links);
+    Component[] seqItems = testee.sequenceMenu.getMenuComponents();
+    JMenu linkMenu = (JMenu) seqItems[6];
+    Component[] linkItems = linkMenu.getMenuComponents();
+    
+    // check the number of links are the expected number
+    assertEquals(5, linkItems.length);
+
+    // first entry is EMBL-EBI which just uses sequence id not accession id?
+    assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
+
+    // sequence id for each link should match corresponding DB accession id
+    for (int i = 1; i < 4; i++)
+    {
+      assertEquals(refs.get(i - 1).getSource(), ((JMenuItem) linkItems[i])
+              .getText().split("\\|")[0]);
+      assertEquals(refs.get(i - 1).getAccessionId(),
+              ((JMenuItem) linkItems[i])
+              .getText().split("\\|")[1]);
+    }
+
+    // get the Popup Menu for second sequence
+    testee = new PopupMenu(parentPanel, (Sequence) seqs.get(1), links);
+    seqItems = testee.sequenceMenu.getMenuComponents();
+    linkMenu = (JMenu) seqItems[6];
+    linkItems = linkMenu.getMenuComponents();
+    
+    // check the number of links are the expected number
+    assertEquals(3, linkItems.length);
+
+    // first entry is EMBL-EBI which just uses sequence id not accession id?
+    assertEquals("EMBL-EBI Search", ((JMenuItem) linkItems[0]).getText());
+
+    // sequence id for each link should match corresponding DB accession id
+    for (int i = 1; i < 3; i++)
+    {
+      assertEquals(refs.get(i + 3).getSource(), ((JMenuItem) linkItems[i])
+              .getText().split("\\|")[0].toUpperCase());
+      assertEquals(refs.get(i + 3).getAccessionId(),
+              ((JMenuItem) linkItems[i]).getText().split("\\|")[1]);
+    }
+
+    // if there are no valid links the Links submenu is disabled
+    List<String> nomatchlinks = new ArrayList<String>();
+    nomatchlinks.add("NOMATCH | http://www.uniprot.org/uniprot/$"
+            + DB_ACCESSION + "$");
+
+    testee = new PopupMenu(parentPanel, (Sequence) seqs.get(0),
+            nomatchlinks);
+    seqItems = testee.sequenceMenu.getMenuComponents();
+    linkMenu = (JMenu) seqItems[6];
+    assertFalse(linkMenu.isEnabled());
+
+  }
 }
index bad536b..446d32d 100644 (file)
@@ -28,6 +28,7 @@ import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.jbgui.GStructureChooser.FilterOption;
 
 import java.util.Vector;
 
@@ -44,7 +45,7 @@ public class StructureChooserTest
   {
     seq = new Sequence("PDB|4kqy|4KQY|A", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1,
             26);
-    seq.setDatasetSequence(seq);
+    seq.createDatasetSequence();
     for (int x = 1; x < 5; x++)
     {
       DBRefEntry dbRef = new DBRefEntry();
@@ -105,27 +106,25 @@ public class StructureChooserTest
   }
 
   @Test(groups = { "Functional" })
-  public void populateFilterComboBoxTest()
+  public void populateFilterComboBoxTest() throws InterruptedException
   {
     SequenceI[] selectedSeqs = new SequenceI[] { seq };
     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
-    sc.populateFilterComboBox();
+    sc.populateFilterComboBox(false, false);
     int optionsSize = sc.getCmbFilterOption().getItemCount();
     assertEquals(3, optionsSize); // if structures are not discovered then don't
                                   // populate filter options
 
-    sc.setStructuresDiscovered(true);
-    sc.populateFilterComboBox();
-    try
-    {
-      Thread.sleep(2000);
-    } catch (InterruptedException e)
-    {
-      e.printStackTrace();
-    }
+    sc.populateFilterComboBox(true, false);
     optionsSize = sc.getCmbFilterOption().getItemCount();
     assertTrue(optionsSize > 3); // if structures are found, filter options
                                  // should be populated
+
+    sc.populateFilterComboBox(true, true);
+    assertTrue(sc.getCmbFilterOption().getSelectedItem() != null);
+    FilterOption filterOpt = (FilterOption) sc.getCmbFilterOption()
+            .getSelectedItem();
+    assertEquals("Cached PDB Entries", filterOpt.getName());
   }
 
   @Test(groups = { "Functional" })
diff --git a/test/jalview/gui/StructureViewerTest.java b/test/jalview/gui/StructureViewerTest.java
new file mode 100644 (file)
index 0000000..f8e9133
--- /dev/null
@@ -0,0 +1,33 @@
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.PDBEntry.Type;
+
+import org.testng.annotations.Test;
+
+public class StructureViewerTest
+{
+  @Test(groups = "Functional")
+  public void testGetUniquePdbFiles()
+  {
+    assertNull(StructureViewer.getUniquePdbFiles(null));
+
+    PDBEntry pdbe1 = new PDBEntry("1A70", "A", Type.PDB, "path1");
+    PDBEntry pdbe2 = new PDBEntry("3A6S", "A", Type.PDB, "path2");
+    PDBEntry pdbe3 = new PDBEntry("1A70", "B", Type.PDB, "path1");
+    PDBEntry pdbe4 = new PDBEntry("1GAQ", "A", Type.PDB, null);
+    PDBEntry pdbe5 = new PDBEntry("3A6S", "B", Type.PDB, "path2");
+    PDBEntry pdbe6 = new PDBEntry("1GAQ", "B", Type.PDB, null);
+
+    /*
+     * pdbe2 and pdbe5 get removed as having a duplicate file path
+     */
+    PDBEntry[] uniques = StructureViewer.getUniquePdbFiles(new PDBEntry[] {
+        pdbe1, pdbe2, pdbe3, pdbe4, pdbe5, pdbe6 });
+    assertEquals(uniques,
+ new PDBEntry[] { pdbe1, pdbe2, pdbe4, pdbe6 });
+  }
+}
diff --git a/test/jalview/io/3ucu.cif b/test/jalview/io/3ucu.cif
new file mode 100644 (file)
index 0000000..5255f53
--- /dev/null
@@ -0,0 +1,4828 @@
+data_3UCU
+#
+_entry.id       3UCU
+#
+_citation.id                            primary
+_citation.title                         "Structural and biochemical characterization of linear dinucleotide analogues bound to the c-di-GMP-I aptamer."
+_citation.journal_abbrev                Biochemistry
+_citation.journal_volume                51
+_citation.page_first                    425
+_citation.page_last                     432
+_citation.year                          2012
+_citation.journal_id_ASTM               BICHAW
+_citation.country                       US
+_citation.journal_id_ISSN               0006-2960
+_citation.journal_id_CSD                0033
+_citation.book_publisher                ?
+_citation.pdbx_database_id_PubMed       22148472
+_citation.pdbx_database_id_DOI          10.1021/bi2016662
+#
+loop_
+_citation_author.citation_id       
+_citation_author.name              
+_citation_author.ordinal           
+primary "Smith, K.D." 1
+primary "Lipchock, S.V." 2
+primary "Strobel, S.A." 3
+#
+_cell.entry_id               3UCU
+_cell.length_a               49.088
+_cell.length_b               45.350
+_cell.length_c               77.243
+_cell.angle_alpha            90.00
+_cell.angle_beta             96.24
+_cell.angle_gamma            90.00
+_cell.Z_PDB                  2
+_cell.pdbx_unique_axis       ?
+_cell.length_a_esd           ?
+_cell.length_b_esd           ?
+_cell.length_c_esd           ?
+_cell.angle_alpha_esd        ?
+_cell.angle_beta_esd         ?
+_cell.angle_gamma_esd        ?
+#
+_symmetry.entry_id                             3UCU
+_symmetry.space_group_name_H-M                 "P 1 21 1"
+_symmetry.pdbx_full_space_group_name_H-M       ?
+_symmetry.cell_setting                         ?
+_symmetry.Int_Tables_number                    ?
+_symmetry.space_group_name_Hall                ?
+#
+loop_
+_entity.id                             
+_entity.type                           
+_entity.src_method                     
+_entity.pdbx_description               
+_entity.formula_weight                 
+_entity.pdbx_number_of_molecules       
+_entity.details                        
+_entity.pdbx_mutation                  
+_entity.pdbx_fragment                  
+_entity.pdbx_ec                        
+1 polymer man "U1 small nuclear ribonucleoprotein A" 11340.407 1 ? "Y31H, Q36R" "RNA binding domain, UNP residues 1-98" ?
+2 polymer syn "RNA (92-MER)" 29942.965 1 "c-di-GMP-I riboswitch" ? ? ?
+3 polymer syn "diguanosine monophosphate" 645.458 1 ? ? ? ?
+4 non-polymer syn "MAGNESIUM ION" 24.305 1 ? ? ? ?
+5 water nat water 18.015 14 ? ? ? ?
+#
+loop_
+_entity_keywords.entity_id       
+_entity_keywords.text            
+1 ?
+2 ?
+3 ?
+4 ?
+5 ?
+#
+loop_
+_entity_name_com.entity_id       
+_entity_name_com.name            
+1 "U1 snRNP A, U1-A, U1A"
+2 ?
+3 ?
+4 ?
+5 ?
+#
+loop_
+_entity_poly.entity_id                          
+_entity_poly.type                               
+_entity_poly.nstd_linkage                       
+_entity_poly.nstd_monomer                       
+_entity_poly.pdbx_seq_one_letter_code           
+_entity_poly.pdbx_seq_one_letter_code_can       
+_entity_poly.pdbx_strand_id                     
+1 polypeptide(L) no no 
+;MAVPETRPNHTIYINNLNEKIKKDELKKSLHAIFSRFGQILDILVSRSLKMRGQAFVIFKEVSSATNALRSMQGFPFYDK
+PMRIQYAKTDSDIIAKMK
+;
+;MAVPETRPNHTIYINNLNEKIKKDELKKSLHAIFSRFGQILDILVSRSLKMRGQAFVIFKEVSSATNALRSMQGFPFYDK
+PMRIQYAKTDSDIIAKMK
+;
+ P
+2 polyribonucleotide no yes 
+;(GTP)GUCACGCACAGGGCAAACCAUUCGAAAGAGUGGGACGCAAAGCCUCCGGCCUAAACCAUUGCACUCCGGUAGGUA
+GCGGGGUUACCGAUGG
+;
+;GGUCACGCACAGGGCAAACCAUUCGAAAGAGUGGGACGCAAAGCCUCCGGCCUAAACCAUUGCACUCCGGUAGGUAGCGG
+GGUUACCGAUGG
+;
+ R
+3 polyribonucleotide no no GG GG A
+#
+loop_
+_entity_poly_seq.entity_id       
+_entity_poly_seq.num             
+_entity_poly_seq.mon_id          
+_entity_poly_seq.hetero          
+1 1 MET n
+1 2 ALA n
+1 3 VAL n
+1 4 PRO n
+1 5 GLU n
+1 6 THR n
+1 7 ARG n
+1 8 PRO n
+1 9 ASN n
+1 10 HIS n
+1 11 THR n
+1 12 ILE n
+1 13 TYR n
+1 14 ILE n
+1 15 ASN n
+1 16 ASN n
+1 17 LEU n
+1 18 ASN n
+1 19 GLU n
+1 20 LYS n
+1 21 ILE n
+1 22 LYS n
+1 23 LYS n
+1 24 ASP n
+1 25 GLU n
+1 26 LEU n
+1 27 LYS n
+1 28 LYS n
+1 29 SER n
+1 30 LEU n
+1 31 HIS n
+1 32 ALA n
+1 33 ILE n
+1 34 PHE n
+1 35 SER n
+1 36 ARG n
+1 37 PHE n
+1 38 GLY n
+1 39 GLN n
+1 40 ILE n
+1 41 LEU n
+1 42 ASP n
+1 43 ILE n
+1 44 LEU n
+1 45 VAL n
+1 46 SER n
+1 47 ARG n
+1 48 SER n
+1 49 LEU n
+1 50 LYS n
+1 51 MET n
+1 52 ARG n
+1 53 GLY n
+1 54 GLN n
+1 55 ALA n
+1 56 PHE n
+1 57 VAL n
+1 58 ILE n
+1 59 PHE n
+1 60 LYS n
+1 61 GLU n
+1 62 VAL n
+1 63 SER n
+1 64 SER n
+1 65 ALA n
+1 66 THR n
+1 67 ASN n
+1 68 ALA n
+1 69 LEU n
+1 70 ARG n
+1 71 SER n
+1 72 MET n
+1 73 GLN n
+1 74 GLY n
+1 75 PHE n
+1 76 PRO n
+1 77 PHE n
+1 78 TYR n
+1 79 ASP n
+1 80 LYS n
+1 81 PRO n
+1 82 MET n
+1 83 ARG n
+1 84 ILE n
+1 85 GLN n
+1 86 TYR n
+1 87 ALA n
+1 88 LYS n
+1 89 THR n
+1 90 ASP n
+1 91 SER n
+1 92 ASP n
+1 93 ILE n
+1 94 ILE n
+1 95 ALA n
+1 96 LYS n
+1 97 MET n
+1 98 LYS n
+2 1 GTP n
+2 2 G n
+2 3 U n
+2 4 C n
+2 5 A n
+2 6 C n
+2 7 G n
+2 8 C n
+2 9 A n
+2 10 C n
+2 11 A n
+2 12 G n
+2 13 G n
+2 14 G n
+2 15 C n
+2 16 A n
+2 17 A n
+2 18 A n
+2 19 C n
+2 20 C n
+2 21 A n
+2 22 U n
+2 23 U n
+2 24 C n
+2 25 G n
+2 26 A n
+2 27 A n
+2 28 A n
+2 29 G n
+2 30 A n
+2 31 G n
+2 32 U n
+2 33 G n
+2 34 G n
+2 35 G n
+2 36 A n
+2 37 C n
+2 38 G n
+2 39 C n
+2 40 A n
+2 41 A n
+2 42 A n
+2 43 G n
+2 44 C n
+2 45 C n
+2 46 U n
+2 47 C n
+2 48 C n
+2 49 G n
+2 50 G n
+2 51 C n
+2 52 C n
+2 53 U n
+2 54 A n
+2 55 A n
+2 56 A n
+2 57 C n
+2 58 C n
+2 59 A n
+2 60 U n
+2 61 U n
+2 62 G n
+2 63 C n
+2 64 A n
+2 65 C n
+2 66 U n
+2 67 C n
+2 68 C n
+2 69 G n
+2 70 G n
+2 71 U n
+2 72 A n
+2 73 G n
+2 74 G n
+2 75 U n
+2 76 A n
+2 77 G n
+2 78 C n
+2 79 G n
+2 80 G n
+2 81 G n
+2 82 G n
+2 83 U n
+2 84 U n
+2 85 A n
+2 86 C n
+2 87 C n
+2 88 G n
+2 89 A n
+2 90 U n
+2 91 G n
+2 92 G n
+3 1 G n
+3 2 G n
+#
+_entity_src_gen.entity_id                              1
+_entity_src_gen.gene_src_common_name                   human
+_entity_src_gen.gene_src_genus                         ?
+_entity_src_gen.pdbx_gene_src_gene                     SNRPA
+_entity_src_gen.gene_src_species                       ?
+_entity_src_gen.gene_src_strain                        ?
+_entity_src_gen.gene_src_tissue                        ?
+_entity_src_gen.gene_src_tissue_fraction               ?
+_entity_src_gen.gene_src_details                       ?
+_entity_src_gen.pdbx_gene_src_fragment                 ?
+_entity_src_gen.pdbx_gene_src_scientific_name          "Homo sapiens"
+_entity_src_gen.pdbx_gene_src_ncbi_taxonomy_id         9606
+_entity_src_gen.pdbx_gene_src_variant                  ?
+_entity_src_gen.pdbx_gene_src_cell_line                ?
+_entity_src_gen.pdbx_gene_src_atcc                     ?
+_entity_src_gen.pdbx_gene_src_organ                    ?
+_entity_src_gen.pdbx_gene_src_organelle                ?
+_entity_src_gen.pdbx_gene_src_cell                     ?
+_entity_src_gen.pdbx_gene_src_cellular_location        ?
+_entity_src_gen.host_org_common_name                   ?
+_entity_src_gen.pdbx_host_org_scientific_name          "Escherichia coli"
+_entity_src_gen.pdbx_host_org_ncbi_taxonomy_id         511693
+_entity_src_gen.host_org_genus                         ?
+_entity_src_gen.pdbx_host_org_gene                     ?
+_entity_src_gen.pdbx_host_org_organ                    ?
+_entity_src_gen.host_org_species                       ?
+_entity_src_gen.pdbx_host_org_tissue                   ?
+_entity_src_gen.pdbx_host_org_tissue_fraction          ?
+_entity_src_gen.pdbx_host_org_strain                   BL21
+_entity_src_gen.pdbx_host_org_variant                  ?
+_entity_src_gen.pdbx_host_org_cell_line                ?
+_entity_src_gen.pdbx_host_org_atcc                     ?
+_entity_src_gen.pdbx_host_org_culture_collection       ?
+_entity_src_gen.pdbx_host_org_cell                     ?
+_entity_src_gen.pdbx_host_org_organelle                ?
+_entity_src_gen.pdbx_host_org_cellular_location        ?
+_entity_src_gen.pdbx_host_org_vector_type              plasmid
+_entity_src_gen.pdbx_host_org_vector                   ?
+_entity_src_gen.plasmid_name                           pET11
+_entity_src_gen.plasmid_details                        ?
+_entity_src_gen.pdbx_description                       ?
+#
+_pdbx_entity_src_syn.entity_id                  2
+_pdbx_entity_src_syn.organism_scientific        ?
+_pdbx_entity_src_syn.organism_common_name       ?
+_pdbx_entity_src_syn.ncbi_taxonomy_id           ?
+_pdbx_entity_src_syn.details                    "in vitro transcribed RNA transcript"
+#
+loop_
+_struct_ref.id                             
+_struct_ref.db_name                        
+_struct_ref.db_code                        
+_struct_ref.pdbx_db_accession              
+_struct_ref.entity_id                      
+_struct_ref.pdbx_seq_one_letter_code       
+_struct_ref.pdbx_align_begin               
+_struct_ref.biol_id                        
+1 UNP SNRPA_HUMAN P09012 1 
+;MAVPETRPNHTIYINNLNEKIKKDELKKSLYAIFSQFGQILDILVSRSLKMRGQAFVIFK 
+EVSSATNALRSMQGFPFYDKPMRIQYAKTDSDIIAKMK
+;
+ 1 .
+2 PDB 3UCU 3UCU 2 ? ? .
+3 PDB 3UCU 3UCU 3 ? ? .
+#
+loop_
+_struct_ref_seq.align_id                          
+_struct_ref_seq.ref_id                            
+_struct_ref_seq.pdbx_PDB_id_code                  
+_struct_ref_seq.pdbx_strand_id                    
+_struct_ref_seq.seq_align_beg                     
+_struct_ref_seq.pdbx_seq_align_beg_ins_code       
+_struct_ref_seq.seq_align_end                     
+_struct_ref_seq.pdbx_seq_align_end_ins_code       
+_struct_ref_seq.pdbx_db_accession                 
+_struct_ref_seq.db_align_beg                      
+_struct_ref_seq.db_align_end                      
+_struct_ref_seq.pdbx_auth_seq_align_beg           
+_struct_ref_seq.pdbx_auth_seq_align_end           
+1 1 3UCU P 1 ? 98 ? P09012 1 98 1 98
+2 2 3UCU R 1 ? 92 ? 3UCU 8 98 8 98
+3 3 3UCU A 1 ? 2 ? 3UCU 1 2 1 2
+#
+loop_
+_struct_ref_seq_dif.align_id                         
+_struct_ref_seq_dif.pdbx_pdb_id_code                 
+_struct_ref_seq_dif.mon_id                           
+_struct_ref_seq_dif.pdbx_pdb_strand_id               
+_struct_ref_seq_dif.seq_num                          
+_struct_ref_seq_dif.pdbx_pdb_ins_code                
+_struct_ref_seq_dif.pdbx_seq_db_name                 
+_struct_ref_seq_dif.pdbx_seq_db_accession_code       
+_struct_ref_seq_dif.db_mon_id                        
+_struct_ref_seq_dif.pdbx_seq_db_seq_num              
+_struct_ref_seq_dif.details                          
+_struct_ref_seq_dif.pdbx_auth_seq_num                
+_struct_ref_seq_dif.pdbx_ordinal                     
+1 3UCU HIS P 31 ? UNP P09012 TYR 31 "Engineered mutation" 31 1
+1 3UCU ARG P 36 ? UNP P09012 GLN 36 "Engineered mutation" 36 2
+#
+loop_
+_chem_comp.id                   
+_chem_comp.type                 
+_chem_comp.mon_nstd_flag        
+_chem_comp.name                 
+_chem_comp.pdbx_synonyms        
+_chem_comp.formula              
+_chem_comp.formula_weight       
+ARG "L-peptide linking" y ARGININE ? "C6 H15 N4 O2 1" 175.210
+PRO "L-peptide linking" y PROLINE ? "C5 H9 N O2" 115.132
+ASN "L-peptide linking" y ASPARAGINE ? "C4 H8 N2 O3" 132.119
+HIS "L-peptide linking" y HISTIDINE ? "C6 H10 N3 O2 1" 156.164
+THR "L-peptide linking" y THREONINE ? "C4 H9 N O3" 119.120
+ILE "L-peptide linking" y ISOLEUCINE ? "C6 H13 N O2" 131.174
+TYR "L-peptide linking" y TYROSINE ? "C9 H11 N O3" 181.191
+LEU "L-peptide linking" y LEUCINE ? "C6 H13 N O2" 131.174
+GLU "L-peptide linking" y "GLUTAMIC ACID" ? "C5 H9 N O4" 147.130
+LYS "L-peptide linking" y LYSINE ? "C6 H15 N2 O2 1" 147.197
+ASP "L-peptide linking" y "ASPARTIC ACID" ? "C4 H7 N O4" 133.104
+SER "L-peptide linking" y SERINE ? "C3 H7 N O3" 105.093
+ALA "L-peptide linking" y ALANINE ? "C3 H7 N O2" 89.094
+PHE "L-peptide linking" y PHENYLALANINE ? "C9 H11 N O2" 165.191
+GLY "PEPTIDE LINKING" y GLYCINE ? "C2 H5 N O2" 75.067
+GLN "L-peptide linking" y GLUTAMINE ? "C5 H10 N2 O3" 146.146
+VAL "L-peptide linking" y VALINE ? "C5 H11 N O2" 117.147
+MET "L-peptide linking" y METHIONINE ? "C5 H11 N O2 S" 149.207
+GTP "RNA linking" n "GUANOSINE-5'-TRIPHOSPHATE" ? "C10 H16 N5 O14 P3" 523.183
+G "RNA linking" y "GUANOSINE-5'-MONOPHOSPHATE" ? "C10 H14 N5 O8 P" 363.223
+U "RNA linking" y "URIDINE-5'-MONOPHOSPHATE" ? "C9 H13 N2 O9 P" 324.183
+C "RNA linking" y "CYTIDINE-5'-MONOPHOSPHATE" ? "C9 H14 N3 O8 P" 323.199
+A "RNA linking" y "ADENOSINE-5'-MONOPHOSPHATE" ? "C10 H14 N5 O7 P" 347.224
+MG NON-POLYMER . "MAGNESIUM ION" ? "MG 2" 24.305
+HOH NON-POLYMER . WATER ? "H2 O" 18.015
+#
+_exptl.entry_id              3UCU
+_exptl.method                "X-ray diffraction"
+_exptl.crystals_number       1
+#
+_exptl_crystal.id                        1
+_exptl_crystal.density_meas              ?
+_exptl_crystal.density_Matthews          2.04
+_exptl_crystal.density_percent_sol       39.66
+_exptl_crystal.description               ?
+_exptl_crystal.F_000                     ?
+_exptl_crystal.preparation               ?
+#
+_exptl_crystal_grow.crystal_id          1
+_exptl_crystal_grow.method              "VAPOR DIFFUSION, HANGING DROP"
+_exptl_crystal_grow.temp                298
+_exptl_crystal_grow.temp_details        ?
+_exptl_crystal_grow.pH                  6
+_exptl_crystal_grow.pdbx_details        "24% PEG550mme, 50 mM MES, pH 6.0, 5 mM MgSO4, 300 mM NaCl, VAPOR DIFFUSION, HANGING DROP, temperature 298K"
+_exptl_crystal_grow.pdbx_pH_range       ?
+#
+_diffrn.id                         1
+_diffrn.ambient_temp               100
+_diffrn.ambient_temp_details       ?
+_diffrn.crystal_id                 1
+#
+_diffrn_detector.diffrn_id                  1
+_diffrn_detector.detector                   CCD
+_diffrn_detector.type                       "ADSC QUANTUM 315"
+_diffrn_detector.pdbx_collection_date       2009-10-01
+_diffrn_detector.details                    ?
+#
+_diffrn_radiation.diffrn_id                            1
+_diffrn_radiation.wavelength_id                        1
+_diffrn_radiation.pdbx_monochromatic_or_laue_m_l       M
+_diffrn_radiation.monochromator                        Si(111)
+_diffrn_radiation.pdbx_diffrn_protocol                 "Single wavelength"
+_diffrn_radiation.pdbx_scattering_type                 x-ray
+#
+_diffrn_radiation_wavelength.id               1
+_diffrn_radiation_wavelength.wavelength       1.1
+_diffrn_radiation_wavelength.wt               1.0
+#
+_diffrn_source.diffrn_id                       1
+_diffrn_source.source                          Synchrotron
+_diffrn_source.type                            "NSLS BEAMLINE X25"
+_diffrn_source.pdbx_synchrotron_site           NSLS
+_diffrn_source.pdbx_synchrotron_beamline       X25
+_diffrn_source.pdbx_wavelength                 ?
+_diffrn_source.pdbx_wavelength_list            1.1
+#
+_reflns.entry_id                         3UCU
+_reflns.observed_criterion_sigma_I       2.0
+_reflns.observed_criterion_sigma_F       2.0
+_reflns.d_resolution_low                 50
+_reflns.d_resolution_high                2.8
+_reflns.number_obs                       8584
+_reflns.number_all                       8612
+_reflns.percent_possible_obs             99.7
+_reflns.pdbx_Rmerge_I_obs                0.086
+_reflns.pdbx_Rsym_value                  ?
+_reflns.pdbx_netI_over_sigmaI            21.8
+_reflns.B_iso_Wilson_estimate            ?
+_reflns.pdbx_redundancy                  7.0
+_reflns.R_free_details                   ?
+_reflns.limit_h_max                      ?
+_reflns.limit_h_min                      ?
+_reflns.limit_k_max                      ?
+_reflns.limit_k_min                      ?
+_reflns.limit_l_max                      ?
+_reflns.limit_l_min                      ?
+_reflns.observed_criterion_F_max         ?
+_reflns.observed_criterion_F_min         ?
+_reflns.pdbx_chi_squared                 ?
+_reflns.pdbx_scaling_rejects             ?
+_reflns.pdbx_ordinal                     1
+_reflns.pdbx_diffrn_id                   1
+#
+_reflns_shell.d_res_high                 2.80
+_reflns_shell.d_res_low                  2.85
+_reflns_shell.percent_possible_all       99.8
+_reflns_shell.Rmerge_I_obs               0.85
+_reflns_shell.pdbx_Rsym_value            ?
+_reflns_shell.meanI_over_sigI_obs        2.3
+_reflns_shell.pdbx_redundancy            6.6
+_reflns_shell.percent_possible_obs       ?
+_reflns_shell.number_unique_all          ?
+_reflns_shell.number_measured_all        ?
+_reflns_shell.number_measured_obs        ?
+_reflns_shell.number_unique_obs          ?
+_reflns_shell.pdbx_chi_squared           ?
+_reflns_shell.pdbx_ordinal               1
+_reflns_shell.pdbx_diffrn_id             1
+#
+_computing.entry_id                               3UCU
+_computing.pdbx_data_reduction_ii                 HKL-2000
+_computing.pdbx_data_reduction_ds                 HKL-2000
+_computing.data_collection                        CBASS
+_computing.structure_solution                     Phaser
+_computing.structure_refinement                   REFMAC5
+_computing.pdbx_structure_refinement_method       ?
+#
+_refine.entry_id                                   3UCU
+_refine.ls_number_reflns_obs                       8150
+_refine.ls_number_reflns_all                       8150
+_refine.pdbx_ls_sigma_I                            ?
+_refine.pdbx_ls_sigma_F                            ?
+_refine.pdbx_data_cutoff_high_absF                 ?
+_refine.pdbx_data_cutoff_low_absF                  ?
+_refine.pdbx_data_cutoff_high_rms_absF             ?
+_refine.ls_d_res_low                               ?
+_refine.ls_d_res_high                              2.8
+_refine.ls_percent_reflns_obs                      98.73
+_refine.ls_R_factor_obs                            0.21709
+_refine.ls_R_factor_all                            0.21709
+_refine.ls_R_factor_R_work                         0.21486
+_refine.ls_R_factor_R_free                         0.26208
+_refine.ls_R_factor_R_free_error                   ?
+_refine.ls_R_factor_R_free_error_details           ?
+_refine.ls_percent_reflns_R_free                   4.7
+_refine.ls_number_reflns_R_free                    406
+_refine.ls_number_parameters                       ?
+_refine.ls_number_restraints                       ?
+_refine.occupancy_min                              ?
+_refine.occupancy_max                              ?
+_refine.correlation_coeff_Fo_to_Fc                 0.942
+_refine.correlation_coeff_Fo_to_Fc_free            0.911
+_refine.B_iso_mean                                 62.151
+_refine.aniso_B[1][1]                              2.72
+_refine.aniso_B[2][2]                              -5.60
+_refine.aniso_B[3][3]                              3.88
+_refine.aniso_B[1][2]                              0.00
+_refine.aniso_B[1][3]                              4.57
+_refine.aniso_B[2][3]                              -0.00
+_refine.solvent_model_details                      MASK
+_refine.solvent_model_param_ksol                   ?
+_refine.solvent_model_param_bsol                   ?
+_refine.pdbx_solvent_vdw_probe_radii               1.40
+_refine.pdbx_solvent_ion_probe_radii               0.80
+_refine.pdbx_solvent_shrinkage_radii               0.80
+_refine.pdbx_ls_cross_valid_method                 THROUGHOUT
+_refine.details                                    "HYDROGENS HAVE BEEN ADDED IN THE RIDING POSITIONS"
+_refine.pdbx_starting_model                        ?
+_refine.pdbx_method_to_determine_struct            "MOLECULAR REPLACEMENT"
+_refine.pdbx_isotropic_thermal_model               ?
+_refine.pdbx_stereochemistry_target_values         "MAXIMUM LIKELIHOOD"
+_refine.pdbx_stereochem_target_val_spec_case       ?
+_refine.pdbx_R_Free_selection_details              RANDOM
+_refine.pdbx_overall_ESU_R_Free                    0.433
+_refine.overall_SU_ML                              0.380
+_refine.pdbx_overall_phase_error                   ?
+_refine.overall_SU_B                               19.510
+_refine.overall_SU_R_Cruickshank_DPI               ?
+_refine.ls_redundancy_reflns_obs                   ?
+_refine.B_iso_min                                  ?
+_refine.B_iso_max                                  ?
+_refine.overall_SU_R_free                          ?
+_refine.ls_wR_factor_R_free                        ?
+_refine.ls_wR_factor_R_work                        ?
+_refine.overall_FOM_free_R_set                     ?
+_refine.overall_FOM_work_R_set                     ?
+_refine.pdbx_diffrn_id                             1
+_refine.pdbx_refine_id                             "X-ray diffraction"
+_refine.pdbx_overall_ESU_R                         ?
+#
+_refine_hist.pdbx_refine_id                       "X-ray diffraction"
+_refine_hist.cycle_id                             LAST
+_refine_hist.pdbx_number_atoms_protein            712
+_refine_hist.pdbx_number_atoms_nucleic_acid       2031
+_refine_hist.pdbx_number_atoms_ligand             1
+_refine_hist.number_atoms_solvent                 14
+_refine_hist.number_atoms_total                   2758
+_refine_hist.d_res_high                           2.8
+_refine_hist.d_res_low                            .
+#
+loop_
+_refine_ls_restr.type                          
+_refine_ls_restr.dev_ideal                     
+_refine_ls_restr.dev_ideal_target              
+_refine_ls_restr.weight                        
+_refine_ls_restr.number                        
+_refine_ls_restr.pdbx_restraint_function       
+_refine_ls_restr.pdbx_refine_id                
+r_bond_refined_d 0.006 0.021 ? 3002 ? "X-ray diffraction"
+r_angle_refined_deg 1.038 2.775 ? 4526 ? "X-ray diffraction"
+r_dihedral_angle_1_deg 4.492 5.000 ? 86 ? "X-ray diffraction"
+r_dihedral_angle_2_deg 33.872 23.235 ? 34 ? "X-ray diffraction"
+r_dihedral_angle_3_deg 15.786 15.000 ? 144 ? "X-ray diffraction"
+r_dihedral_angle_4_deg 14.062 15.000 ? 6 ? "X-ray diffraction"
+r_chiral_restr 0.055 0.200 ? 575 ? "X-ray diffraction"
+r_gen_planes_refined 0.002 0.020 ? 1519 ? "X-ray diffraction"
+r_mcbond_it 1.210 6.000 ? 434 ? "X-ray diffraction"
+r_mcangle_it 2.149 8.000 ? 703 ? "X-ray diffraction"
+r_scbond_it 1.331 6.000 ? 2568 ? "X-ray diffraction"
+r_scangle_it 2.184 8.000 ? 3822 ? "X-ray diffraction"
+#
+_refine_ls_shell.pdbx_total_number_of_bins_used       20
+_refine_ls_shell.d_res_high                           2.785
+_refine_ls_shell.d_res_low                            2.857
+_refine_ls_shell.number_reflns_R_work                 530
+_refine_ls_shell.R_factor_R_work                      0.420
+_refine_ls_shell.percent_reflns_obs                   88.80
+_refine_ls_shell.R_factor_R_free                      0.444
+_refine_ls_shell.R_factor_R_free_error                ?
+_refine_ls_shell.percent_reflns_R_free                ?
+_refine_ls_shell.number_reflns_R_free                 33
+_refine_ls_shell.number_reflns_all                    ?
+_refine_ls_shell.R_factor_all                         ?
+_refine_ls_shell.number_reflns_obs                    566
+_refine_ls_shell.redundancy_reflns_obs                ?
+_refine_ls_shell.pdbx_refine_id                       "X-ray diffraction"
+#
+_struct.entry_id                      3UCU
+_struct.title                         "The c-di-GMP-I riboswitch bound to pGpG"
+_struct.pdbx_descriptor               "U1 small nuclear ribonucleoprotein A/RNA"
+_struct.pdbx_model_details            ?
+_struct.pdbx_CASP_flag                ?
+_struct.pdbx_model_type_details       ?
+#
+_struct_keywords.entry_id            3UCU
+_struct_keywords.pdbx_keywords       "SIGNALING PROTEIN/RNA"
+_struct_keywords.text                "riboswitch, SIGNALING PROTEIN-RNA complex"
+#
+loop_
+_struct_asym.id                                
+_struct_asym.pdbx_blank_PDB_chainid_flag       
+_struct_asym.pdbx_modified                     
+_struct_asym.entity_id                         
+_struct_asym.details                           
+A N N 1 ?
+B N N 2 ?
+C N N 3 ?
+D N N 4 ?
+E N N 5 ?
+F N N 5 ?
+G N N 5 ?
+#
+_struct_biol.id            1
+_struct_biol.details       "THE PROTEIN IS NOT BIOLOGICALLY RELEVANT AND HAS BEEN USED AS A CRYSTALLIZATION CHAPERONE."
+#
+loop_
+_struct_conf.conf_type_id                
+_struct_conf.id                          
+_struct_conf.pdbx_PDB_helix_id           
+_struct_conf.beg_label_comp_id           
+_struct_conf.beg_label_asym_id           
+_struct_conf.beg_label_seq_id            
+_struct_conf.pdbx_beg_PDB_ins_code       
+_struct_conf.end_label_comp_id           
+_struct_conf.end_label_asym_id           
+_struct_conf.end_label_seq_id            
+_struct_conf.pdbx_end_PDB_ins_code       
+_struct_conf.beg_auth_comp_id            
+_struct_conf.beg_auth_asym_id            
+_struct_conf.beg_auth_seq_id             
+_struct_conf.end_auth_comp_id            
+_struct_conf.end_auth_asym_id            
+_struct_conf.end_auth_seq_id             
+_struct_conf.pdbx_PDB_helix_class        
+_struct_conf.details                     
+_struct_conf.pdbx_PDB_helix_length       
+HELX_P HELX_P1 1 LYS A 22 ? SER A 35 ? LYS P 22 SER P 35 1 ? 14
+HELX_P HELX_P2 2 GLU A 61 ? GLN A 73 ? GLU P 61 GLN P 73 1 ? 13
+#
+_struct_conf_type.id              HELX_P
+_struct_conf_type.criteria        ?
+_struct_conf_type.reference       ?
+#
+loop_
+_struct_conn.id                                
+_struct_conn.conn_type_id                      
+_struct_conn.pdbx_PDB_id                       
+_struct_conn.ptnr1_label_asym_id               
+_struct_conn.ptnr1_label_comp_id               
+_struct_conn.ptnr1_label_seq_id                
+_struct_conn.ptnr1_label_atom_id               
+_struct_conn.pdbx_ptnr1_label_alt_id           
+_struct_conn.pdbx_ptnr1_PDB_ins_code           
+_struct_conn.pdbx_ptnr1_standard_comp_id       
+_struct_conn.ptnr1_symmetry                    
+_struct_conn.ptnr2_label_asym_id               
+_struct_conn.ptnr2_label_comp_id               
+_struct_conn.ptnr2_label_seq_id                
+_struct_conn.ptnr2_label_atom_id               
+_struct_conn.pdbx_ptnr2_label_alt_id           
+_struct_conn.pdbx_ptnr2_PDB_ins_code           
+_struct_conn.ptnr1_auth_asym_id                
+_struct_conn.ptnr1_auth_comp_id                
+_struct_conn.ptnr1_auth_seq_id                 
+_struct_conn.ptnr2_auth_asym_id                
+_struct_conn.ptnr2_auth_comp_id                
+_struct_conn.ptnr2_auth_seq_id                 
+_struct_conn.ptnr2_symmetry                    
+_struct_conn.pdbx_ptnr3_label_atom_id          
+_struct_conn.pdbx_ptnr3_label_seq_id           
+_struct_conn.pdbx_ptnr3_label_comp_id          
+_struct_conn.pdbx_ptnr3_label_asym_id          
+_struct_conn.pdbx_ptnr3_label_alt_id           
+_struct_conn.pdbx_ptnr3_PDB_ins_code           
+_struct_conn.details                           
+_struct_conn.pdbx_dist_value                   
+_struct_conn.pdbx_value_order                  
+covale1 covale ? B GTP 1 "O3'" ? ? ? 1_555 B G 2 P ? ? R GTP 8 R G 9 1_555 ? ? ? ? ? ? ? 1.600 ?
+covale2 covale ? B C 58 "O3'" ? ? ? 1_555 B A 59 P ? ? R C 65 R A 660 1_555 ? ? ? ? ? ? ? 1.605 ?
+metalc1 metalc ? D MG . MG ? ? ? 1_555 G HOH . O ? ? R MG 1 A HOH 3 1_555 ? ? ? ? ? ? ? 2.176 ?
+metalc2 metalc ? D MG . MG ? ? ? 1_555 F HOH . O ? ? R MG 1 R HOH 676 1_555 ? ? ? ? ? ? ? 2.179 ?
+metalc3 metalc ? D MG . MG ? ? ? 1_555 F HOH . O ? ? R MG 1 R HOH 673 1_555 ? ? ? ? ? ? ? 2.179 ?
+metalc4 metalc ? D MG . MG ? ? ? 1_555 F HOH . O ? ? R MG 1 R HOH 674 1_555 ? ? ? ? ? ? ? 2.180 ?
+metalc5 metalc ? D MG . MG ? ? ? 1_555 F HOH . O ? ? R MG 1 R HOH 675 1_555 ? ? ? ? ? ? ? 2.182 ?
+mismat1 mismat ? B A 5 ? ? ? ? 1_555 B G 91 ? ? ? R A 12 R G 97 1_555 ? ? ? ? ? ? ? ? ?
+mismat2 mismat ? B G 7 ? ? ? ? 1_555 B A 9 ? ? ? R G 14 R A 16 1_555 ? ? ? ? ? ? ? ? ?
+mismat3 mismat ? B A 9 ? ? ? ? 1_555 B C 87 ? ? ? R A 16 R C 93 1_555 ? ? ? ? ? ? ? ? ?
+mismat4 mismat ? B C 10 ? ? ? ? 1_555 B C 87 ? ? ? R C 17 R C 93 1_555 ? ? ? ? ? ? ? ? ?
+mismat5 mismat ? B G 12 ? ? ? ? 1_555 B A 40 ? ? ? R G 19 R A 47 1_555 ? ? ? ? ? ? ? ? ?
+mismat6 mismat ? B G 13 ? ? ? ? 1_555 C G 1 ? ? ? R G 20 A G 1 1_555 ? ? ? ? ? ? ? ? ?
+mismat7 mismat ? B A 16 ? ? ? ? 1_555 B C 37 ? ? ? R A 23 R C 44 1_555 ? ? ? ? ? ? ? ? ?
+mismat8 mismat ? B A 18 ? ? ? ? 1_555 B G 35 ? ? ? R A 25 R G 42 1_555 ? ? ? ? ? ? ? ? ?
+mismat9 mismat ? B U 22 ? ? ? ? 1_555 B G 31 ? ? ? R U 29 R G 38 1_555 ? ? ? ? ? ? ? ? ?
+mismat10 mismat ? B G 25 ? ? ? ? 1_555 B A 28 ? ? ? R G 32 R A 35 1_555 ? ? ? ? ? ? ? ? ?
+mismat11 mismat ? B A 28 ? ? ? ? 1_555 B G 73 ? ? ? R A 35 R G 79 1_555 ? ? ? ? ? ? ? ? ?
+mismat12 mismat ? B G 38 ? ? ? ? 1_555 B A 42 ? ? ? R G 45 R A 49 1_555 ? ? ? ? ? ? ? ? ?
+mismat13 mismat ? B G 43 ? ? ? ? 1_555 B U 83 ? ? ? R G 50 R U 89 1_555 ? ? ? ? ? ? ? ? ?
+mismat14 mismat ? B U 46 ? ? ? ? 1_555 B C 48 ? ? ? R U 53 R C 55 1_555 ? ? ? ? ? ? ? ? ?
+mismat15 mismat ? B C 47 ? ? ? ? 1_555 B A 76 ? ? ? R C 54 R A 82 1_555 ? ? ? ? ? ? ? ? ?
+mismat16 mismat ? B G 50 ? ? ? ? 1_555 B U 75 ? ? ? R G 57 R U 81 1_555 ? ? ? ? ? ? ? ? ?
+mismat17 mismat ? B A 54 ? ? ? ? 1_555 B A 55 ? ? ? R A 61 R A 62 1_555 ? ? ? ? ? ? ? ? ?
+mismat18 mismat ? B G 88 ? ? ? ? 1_555 B A 89 ? ? ? R G 94 R A 95 1_555 ? ? ? ? ? ? ? ? ?
+hydrog1 hydrog ? B C 4 N3 ? ? ? 1_555 B G 92 N1 ? ? R C 11 R G 98 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog2 hydrog ? B C 4 N4 ? ? ? 1_555 B G 92 O6 ? ? R C 11 R G 98 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog3 hydrog ? B C 4 O2 ? ? ? 1_555 B G 92 N2 ? ? R C 11 R G 98 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog4 hydrog ? B A 5 N1 ? ? ? 1_555 B G 91 N1 ? ? R A 12 R G 97 1_555 ? ? ? ? ? ? TYPE_8_PAIR ? ?
+hydrog5 hydrog ? B A 5 N6 ? ? ? 1_555 B G 91 O6 ? ? R A 12 R G 97 1_555 ? ? ? ? ? ? TYPE_8_PAIR ? ?
+hydrog6 hydrog ? B C 6 N3 ? ? ? 1_555 B G 88 N1 ? ? R C 13 R G 94 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog7 hydrog ? B C 6 N4 ? ? ? 1_555 B G 88 O6 ? ? R C 13 R G 94 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog8 hydrog ? B C 6 O2 ? ? ? 1_555 B G 88 N2 ? ? R C 13 R G 94 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog9 hydrog ? B G 7 N2 ? ? ? 1_555 B A 9 N7 ? ? R G 14 R A 16 1_555 ? ? ? ? ? ? "G-A MISPAIR" ? ?
+hydrog10 hydrog ? B G 7 N1 ? ? ? 1_555 B C 87 N3 ? ? R G 14 R C 93 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog11 hydrog ? B G 7 N2 ? ? ? 1_555 B C 87 O2 ? ? R G 14 R C 93 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog12 hydrog ? B G 7 O6 ? ? ? 1_555 B C 87 N4 ? ? R G 14 R C 93 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog13 hydrog ? B A 9 N6 ? ? ? 1_555 B C 87 O2 ? ? R A 16 R C 93 1_555 ? ? ? ? ? ? "A-C MISPAIR" ? ?
+hydrog14 hydrog ? B C 10 N4 ? ? ? 1_555 B C 87 O2 ? ? R C 17 R C 93 1_555 ? ? ? ? ? ? "C-C MISPAIR" ? ?
+hydrog15 hydrog ? B C 10 N4 ? ? ? 1_555 C G 2 N3 ? ? R C 17 A G 2 1_555 ? ? ? ? ? ? "C-G PAIR" ? ?
+hydrog16 hydrog ? B G 12 O6 ? ? ? 1_555 B A 40 N6 ? ? R G 19 R A 47 1_555 ? ? ? ? ? ? "G-A MISPAIR" ? ?
+hydrog17 hydrog ? B G 13 N1 ? ? ? 1_555 C G 1 N7 ? ? R G 20 A G 1 1_555 ? ? ? ? ? ? TYPE_7_PAIR ? ?
+hydrog18 hydrog ? B G 13 N2 ? ? ? 1_555 C G 1 O6 ? ? R G 20 A G 1 1_555 ? ? ? ? ? ? TYPE_7_PAIR ? ?
+hydrog19 hydrog ? B G 14 N1 ? ? ? 1_555 B C 39 N3 ? ? R G 21 R C 46 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog20 hydrog ? B G 14 N2 ? ? ? 1_555 B C 39 O2 ? ? R G 21 R C 46 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog21 hydrog ? B G 14 O6 ? ? ? 1_555 B C 39 N4 ? ? R G 21 R C 46 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog22 hydrog ? B C 15 N3 ? ? ? 1_555 B G 38 N1 ? ? R C 22 R G 45 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog23 hydrog ? B C 15 N4 ? ? ? 1_555 B G 38 O6 ? ? R C 22 R G 45 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog24 hydrog ? B C 15 O2 ? ? ? 1_555 B G 38 N2 ? ? R C 22 R G 45 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog25 hydrog ? B A 16 N3 ? ? ? 1_555 B C 37 N4 ? ? R A 23 R C 44 1_555 ? ? ? ? ? ? "A-C MISPAIR" ? ?
+hydrog26 hydrog ? B A 18 N6 ? ? ? 1_555 B G 35 N3 ? ? R A 25 R G 42 1_555 ? ? ? ? ? ? TYPE_11_PAIR ? ?
+hydrog27 hydrog ? B A 18 N7 ? ? ? 1_555 B G 35 N2 ? ? R A 25 R G 42 1_555 ? ? ? ? ? ? TYPE_11_PAIR ? ?
+hydrog28 hydrog ? B C 19 N3 ? ? ? 1_555 B G 34 N1 ? ? R C 26 R G 41 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog29 hydrog ? B C 19 N4 ? ? ? 1_555 B G 34 O6 ? ? R C 26 R G 41 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog30 hydrog ? B C 19 O2 ? ? ? 1_555 B G 34 N2 ? ? R C 26 R G 41 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog31 hydrog ? B C 20 N3 ? ? ? 1_555 B G 33 N1 ? ? R C 27 R G 40 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog32 hydrog ? B C 20 N4 ? ? ? 1_555 B G 33 O6 ? ? R C 27 R G 40 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog33 hydrog ? B C 20 O2 ? ? ? 1_555 B G 33 N2 ? ? R C 27 R G 40 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog34 hydrog ? B A 21 N1 ? ? ? 1_555 B U 32 N3 ? ? R A 28 R U 39 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog35 hydrog ? B A 21 N6 ? ? ? 1_555 B U 32 O4 ? ? R A 28 R U 39 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog36 hydrog ? B U 22 N3 ? ? ? 1_555 B G 31 O6 ? ? R U 29 R G 38 1_555 ? ? ? ? ? ? TYPE_28_PAIR ? ?
+hydrog37 hydrog ? B U 22 O2 ? ? ? 1_555 B G 31 N1 ? ? R U 29 R G 38 1_555 ? ? ? ? ? ? TYPE_28_PAIR ? ?
+hydrog38 hydrog ? B U 23 N3 ? ? ? 1_555 B A 30 N1 ? ? R U 30 R A 37 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog39 hydrog ? B U 23 O4 ? ? ? 1_555 B A 30 N6 ? ? R U 30 R A 37 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog40 hydrog ? B C 24 N3 ? ? ? 1_555 B G 29 N1 ? ? R C 31 R G 36 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog41 hydrog ? B C 24 N4 ? ? ? 1_555 B G 29 O6 ? ? R C 31 R G 36 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog42 hydrog ? B C 24 O2 ? ? ? 1_555 B G 29 N2 ? ? R C 31 R G 36 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog43 hydrog ? B G 25 N2 ? ? ? 1_555 B A 28 N7 ? ? R G 32 R A 35 1_555 ? ? ? ? ? ? "G-A MISPAIR" ? ?
+hydrog44 hydrog ? B A 28 N3 ? ? ? 1_555 B G 73 N2 ? ? R A 35 R G 79 1_555 ? ? ? ? ? ? "A-G MISPAIR" ? ?
+hydrog45 hydrog ? B C 37 N3 ? ? ? 1_555 B G 77 N1 ? ? R C 44 R G 83 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog46 hydrog ? B C 37 N4 ? ? ? 1_555 B G 77 O6 ? ? R C 44 R G 83 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog47 hydrog ? B C 37 O2 ? ? ? 1_555 B G 77 N2 ? ? R C 44 R G 83 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog48 hydrog ? B G 38 N2 ? ? ? 1_555 B A 42 N3 ? ? R G 45 R A 49 1_555 ? ? ? ? ? ? "G-A MISPAIR" ? ?
+hydrog49 hydrog ? B A 41 N6 ? ? ? 1_555 B U 84 O2 ? ? R A 48 R U 90 1_555 ? ? ? ? ? ? "REVERSED HOOGSTEEN" ? ?
+hydrog50 hydrog ? B A 41 N7 ? ? ? 1_555 B U 84 N3 ? ? R A 48 R U 90 1_555 ? ? ? ? ? ? "REVERSED HOOGSTEEN" ? ?
+hydrog51 hydrog ? B G 43 N1 ? ? ? 1_555 B U 83 O2 ? ? R G 50 R U 89 1_555 ? ? ? ? ? ? TYPE_28_PAIR ? ?
+hydrog52 hydrog ? B G 43 O6 ? ? ? 1_555 B U 83 N3 ? ? R G 50 R U 89 1_555 ? ? ? ? ? ? TYPE_28_PAIR ? ?
+hydrog53 hydrog ? B C 44 N3 ? ? ? 1_555 B G 82 N1 ? ? R C 51 R G 88 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog54 hydrog ? B C 44 N4 ? ? ? 1_555 B G 82 O6 ? ? R C 51 R G 88 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog55 hydrog ? B C 44 O2 ? ? ? 1_555 B G 82 N2 ? ? R C 51 R G 88 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog56 hydrog ? B C 45 N3 ? ? ? 1_555 B G 81 N1 ? ? R C 52 R G 87 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog57 hydrog ? B C 45 N4 ? ? ? 1_555 B G 81 O6 ? ? R C 52 R G 87 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog58 hydrog ? B C 45 O2 ? ? ? 1_555 B G 81 N2 ? ? R C 52 R G 87 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog59 hydrog ? B U 46 O2 ? ? ? 1_555 B C 48 N4 ? ? R U 53 R C 55 1_555 ? ? ? ? ? ? "U-C MISPAIR" ? ?
+hydrog60 hydrog ? B C 47 N4 ? ? ? 1_555 B A 76 N1 ? ? R C 54 R A 82 1_555 ? ? ? ? ? ? "C-A MISPAIR" ? ?
+hydrog61 hydrog ? B C 47 N3 ? ? ? 1_555 B G 80 N1 ? ? R C 54 R G 86 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog62 hydrog ? B C 47 N4 ? ? ? 1_555 B G 80 O6 ? ? R C 54 R G 86 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog63 hydrog ? B C 47 O2 ? ? ? 1_555 B G 80 N2 ? ? R C 54 R G 86 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog64 hydrog ? B C 48 N3 ? ? ? 1_555 B G 79 N1 ? ? R C 55 R G 85 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog65 hydrog ? B C 48 N4 ? ? ? 1_555 B G 79 O6 ? ? R C 55 R G 85 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog66 hydrog ? B C 48 O2 ? ? ? 1_555 B G 79 N2 ? ? R C 55 R G 85 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog67 hydrog ? B G 49 N1 ? ? ? 1_555 B C 78 N3 ? ? R G 56 R C 84 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog68 hydrog ? B G 49 N2 ? ? ? 1_555 B C 78 O2 ? ? R G 56 R C 84 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog69 hydrog ? B G 49 O6 ? ? ? 1_555 B C 78 N4 ? ? R G 56 R C 84 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog70 hydrog ? B G 50 N1 ? ? ? 1_555 B U 75 O2 ? ? R G 57 R U 81 1_555 ? ? ? ? ? ? TYPE_28_PAIR ? ?
+hydrog71 hydrog ? B G 50 O6 ? ? ? 1_555 B U 75 N3 ? ? R G 57 R U 81 1_555 ? ? ? ? ? ? TYPE_28_PAIR ? ?
+hydrog72 hydrog ? B C 51 N3 ? ? ? 1_555 B G 74 N1 ? ? R C 58 R G 80 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog73 hydrog ? B C 51 N4 ? ? ? 1_555 B G 74 O6 ? ? R C 58 R G 80 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog74 hydrog ? B C 51 O2 ? ? ? 1_555 B G 74 N2 ? ? R C 58 R G 80 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog75 hydrog ? B C 52 N3 ? ? ? 1_555 B G 73 N1 ? ? R C 59 R G 79 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog76 hydrog ? B C 52 N4 ? ? ? 1_555 B G 73 O6 ? ? R C 59 R G 79 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog77 hydrog ? B C 52 O2 ? ? ? 1_555 B G 73 N2 ? ? R C 59 R G 79 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog78 hydrog ? B U 53 N3 ? ? ? 1_555 B A 72 N1 ? ? R U 60 R A 78 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog79 hydrog ? B U 53 O4 ? ? ? 1_555 B A 72 N6 ? ? R U 60 R A 78 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog80 hydrog ? B A 54 N3 ? ? ? 1_555 B A 55 N6 ? ? R A 61 R A 62 1_555 ? ? ? ? ? ? "A-A MISPAIR" ? ?
+hydrog81 hydrog ? B A 54 N1 ? ? ? 1_555 B U 71 N3 ? ? R A 61 R U 77 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog82 hydrog ? B A 54 N6 ? ? ? 1_555 B U 71 O4 ? ? R A 61 R U 77 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog83 hydrog ? B A 56 N6 ? ? ? 1_555 B U 71 O2 ? ? R A 63 R U 77 1_555 ? ? ? ? ? ? "A-U PAIR" ? ?
+hydrog84 hydrog ? B C 57 N3 ? ? ? 1_555 B G 70 N1 ? ? R C 64 R G 76 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog85 hydrog ? B C 57 N4 ? ? ? 1_555 B G 70 O6 ? ? R C 64 R G 76 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog86 hydrog ? B C 57 O2 ? ? ? 1_555 B G 70 N2 ? ? R C 64 R G 76 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog87 hydrog ? B C 58 N3 ? ? ? 1_555 B G 69 N1 ? ? R C 65 R G 75 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog88 hydrog ? B C 58 N4 ? ? ? 1_555 B G 69 O6 ? ? R C 65 R G 75 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog89 hydrog ? B C 58 O2 ? ? ? 1_555 B G 69 N2 ? ? R C 65 R G 75 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog90 hydrog ? B C 86 N3 ? ? ? 1_555 C G 2 N1 ? ? R C 92 A G 2 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog91 hydrog ? B C 86 N4 ? ? ? 1_555 C G 2 O6 ? ? R C 92 A G 2 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog92 hydrog ? B C 86 O2 ? ? ? 1_555 C G 2 N2 ? ? R C 92 A G 2 1_555 ? ? ? ? ? ? WATSON-CRICK ? ?
+hydrog93 hydrog ? B G 88 N2 ? ? ? 1_555 B A 89 N1 ? ? R G 94 R A 95 1_555 ? ? ? ? ? ? "G-A MISPAIR" ? ?
+#
+loop_
+_struct_conn_type.id              
+_struct_conn_type.criteria        
+_struct_conn_type.reference       
+covale ? ?
+metalc ? ?
+hydrog "For hydrogen bonding between nucleic acid bases, donor to acceptor distance of 2.2 -3.5 Angstroms was used." ?
+mismat ? ?
+#
+_struct_sheet.id                   A
+_struct_sheet.type                 ?
+_struct_sheet.number_strands       4
+_struct_sheet.details              ?
+#
+loop_
+_struct_sheet_order.sheet_id         
+_struct_sheet_order.range_id_1       
+_struct_sheet_order.range_id_2       
+_struct_sheet_order.offset           
+_struct_sheet_order.sense            
+A 1 2 ? anti-parallel
+A 2 3 ? anti-parallel
+A 3 4 ? anti-parallel
+#
+loop_
+_struct_sheet_range.sheet_id                    
+_struct_sheet_range.id                          
+_struct_sheet_range.beg_label_comp_id           
+_struct_sheet_range.beg_label_asym_id           
+_struct_sheet_range.beg_label_seq_id            
+_struct_sheet_range.pdbx_beg_PDB_ins_code       
+_struct_sheet_range.end_label_comp_id           
+_struct_sheet_range.end_label_asym_id           
+_struct_sheet_range.end_label_seq_id            
+_struct_sheet_range.pdbx_end_PDB_ins_code       
+_struct_sheet_range.symmetry                    
+_struct_sheet_range.beg_auth_comp_id            
+_struct_sheet_range.beg_auth_asym_id            
+_struct_sheet_range.beg_auth_seq_id             
+_struct_sheet_range.end_auth_comp_id            
+_struct_sheet_range.end_auth_asym_id            
+_struct_sheet_range.end_auth_seq_id             
+A 1 ILE A 40 ? LEU A 44 ? ? ILE P 40 LEU P 44
+A 2 ALA A 55 ? PHE A 59 ? ? ALA P 55 PHE P 59
+A 3 THR A 11 ? ASN A 15 ? ? THR P 11 ASN P 15
+A 4 ARG A 83 ? TYR A 86 ? ? ARG P 83 TYR P 86
+#
+loop_
+_pdbx_struct_sheet_hbond.sheet_id                    
+_pdbx_struct_sheet_hbond.range_id_1                  
+_pdbx_struct_sheet_hbond.range_id_2                  
+_pdbx_struct_sheet_hbond.range_1_label_atom_id       
+_pdbx_struct_sheet_hbond.range_1_label_comp_id       
+_pdbx_struct_sheet_hbond.range_1_label_asym_id       
+_pdbx_struct_sheet_hbond.range_1_label_seq_id        
+_pdbx_struct_sheet_hbond.range_1_PDB_ins_code        
+_pdbx_struct_sheet_hbond.range_1_auth_atom_id        
+_pdbx_struct_sheet_hbond.range_1_auth_comp_id        
+_pdbx_struct_sheet_hbond.range_1_auth_asym_id        
+_pdbx_struct_sheet_hbond.range_1_auth_seq_id         
+_pdbx_struct_sheet_hbond.range_2_label_atom_id       
+_pdbx_struct_sheet_hbond.range_2_label_comp_id       
+_pdbx_struct_sheet_hbond.range_2_label_asym_id       
+_pdbx_struct_sheet_hbond.range_2_label_seq_id        
+_pdbx_struct_sheet_hbond.range_2_PDB_ins_code        
+_pdbx_struct_sheet_hbond.range_2_auth_atom_id        
+_pdbx_struct_sheet_hbond.range_2_auth_comp_id        
+_pdbx_struct_sheet_hbond.range_2_auth_asym_id        
+_pdbx_struct_sheet_hbond.range_2_auth_seq_id         
+A 1 2 N LEU A 44 ? N LEU P 44 O PHE A 56 ? O PHE P 56
+A 2 3 O ALA A 55 ? O ALA P 55 N ILE A 14 ? N ILE P 14
+A 3 4 N TYR A 13 ? N TYR P 13 O GLN A 85 ? O GLN P 85
+#
+_struct_site.id                       AC1
+_struct_site.details                  "BINDING SITE FOR RESIDUE MG R 1"
+_struct_site.pdbx_evidence_code       SOFTWARE
+#
+loop_
+_struct_site_gen.id                       
+_struct_site_gen.site_id                  
+_struct_site_gen.pdbx_num_res             
+_struct_site_gen.label_comp_id            
+_struct_site_gen.label_asym_id            
+_struct_site_gen.label_seq_id             
+_struct_site_gen.pdbx_auth_ins_code       
+_struct_site_gen.auth_comp_id             
+_struct_site_gen.auth_asym_id             
+_struct_site_gen.auth_seq_id              
+_struct_site_gen.label_atom_id            
+_struct_site_gen.label_alt_id             
+_struct_site_gen.symmetry                 
+_struct_site_gen.details                  
+1 AC1 7 HOH G . ? HOH A 3 . . 1_555 ?
+2 AC1 7 A B 40 ? A R 47 . . 1_555 ?
+3 AC1 7 A B 41 ? A R 48 . . 1_555 ?
+4 AC1 7 HOH F . ? HOH R 673 . . 1_555 ?
+5 AC1 7 HOH F . ? HOH R 674 . . 1_555 ?
+6 AC1 7 HOH F . ? HOH R 675 . . 1_555 ?
+7 AC1 7 HOH F . ? HOH R 676 . . 1_555 ?
+#
+_atom_sites.entry_id                        3UCU
+_atom_sites.Cartn_transform_axes            ?
+_atom_sites.fract_transf_matrix[1][1]       0.020372
+_atom_sites.fract_transf_matrix[1][2]       0.000000
+_atom_sites.fract_transf_matrix[1][3]       0.002227
+_atom_sites.fract_transf_matrix[2][1]       -0.000000
+_atom_sites.fract_transf_matrix[2][2]       0.022051
+_atom_sites.fract_transf_matrix[2][3]       0.000000
+_atom_sites.fract_transf_matrix[3][1]       0.000000
+_atom_sites.fract_transf_matrix[3][2]       -0.000000
+_atom_sites.fract_transf_matrix[3][3]       0.013023
+_atom_sites.fract_transf_vector[1]          0.00000
+_atom_sites.fract_transf_vector[2]          0.00000
+_atom_sites.fract_transf_vector[3]          0.00000
+#
+loop_
+_atom_type.symbol       
+N
+C
+O
+S
+P
+MG
+#
+loop_
+_atom_site.group_PDB                
+_atom_site.id                       
+_atom_site.type_symbol              
+_atom_site.label_atom_id            
+_atom_site.label_alt_id             
+_atom_site.label_comp_id            
+_atom_site.label_asym_id            
+_atom_site.label_entity_id          
+_atom_site.label_seq_id             
+_atom_site.pdbx_PDB_ins_code        
+_atom_site.Cartn_x                  
+_atom_site.Cartn_y                  
+_atom_site.Cartn_z                  
+_atom_site.occupancy                
+_atom_site.B_iso_or_equiv           
+_atom_site.Cartn_x_esd              
+_atom_site.Cartn_y_esd              
+_atom_site.Cartn_z_esd              
+_atom_site.occupancy_esd            
+_atom_site.B_iso_or_equiv_esd       
+_atom_site.pdbx_formal_charge       
+_atom_site.auth_seq_id              
+_atom_site.auth_comp_id             
+_atom_site.auth_asym_id             
+_atom_site.auth_atom_id             
+_atom_site.pdbx_PDB_model_num       
+_atom_site.pdbe_label_seq_id        
+ATOM 1 N N . ARG A 1 7 ? 3.282 29.355 -6.805 1.00 77.39 ? ? ? ? ? ? 7 ARG P N 1 7
+ATOM 2 C CA . ARG A 1 7 ? 3.842 27.969 -6.824 1.00 76.12 ? ? ? ? ? ? 7 ARG P CA 1 7
+ATOM 3 C C . ARG A 1 7 ? 5.170 27.792 -6.062 1.00 74.61 ? ? ? ? ? ? 7 ARG P C 1 7
+ATOM 4 O O . ARG A 1 7 ? 5.300 26.839 -5.293 1.00 74.64 ? ? ? ? ? ? 7 ARG P O 1 7
+ATOM 5 C CB . ARG A 1 7 ? 3.967 27.446 -8.260 1.00 76.94 ? ? ? ? ? ? 7 ARG P CB 1 7
+ATOM 6 C CG . ARG A 1 7 ? 2.734 26.712 -8.767 1.00 77.92 ? ? ? ? ? ? 7 ARG P CG 1 7
+ATOM 7 C CD . ARG A 1 7 ? 3.102 25.692 -9.840 1.00 78.78 ? ? ? ? ? ? 7 ARG P CD 1 7
+ATOM 8 N NE . ARG A 1 7 ? 4.202 24.827 -9.411 1.00 79.23 ? ? ? ? ? ? 7 ARG P NE 1 7
+ATOM 9 C CZ . ARG A 1 7 ? 4.780 23.898 -10.169 1.00 80.34 ? ? ? ? ? ? 7 ARG P CZ 1 7
+ATOM 10 N NH1 . ARG A 1 7 ? 4.370 23.689 -11.415 1.00 80.85 ? ? ? ? ? ? 7 ARG P NH1 1 7
+ATOM 11 N NH2 . ARG A 1 7 ? 5.774 23.173 -9.676 1.00 80.08 ? ? ? ? ? ? 7 ARG P NH2 1 7
+ATOM 12 N N . PRO A 1 8 ? 6.156 28.698 -6.267 1.00 73.28 ? ? ? ? ? ? 8 PRO P N 1 8
+ATOM 13 C CA . PRO A 1 8 ? 7.454 28.531 -5.598 1.00 72.17 ? ? ? ? ? ? 8 PRO P CA 1 8
+ATOM 14 C C . PRO A 1 8 ? 7.404 28.719 -4.080 1.00 71.22 ? ? ? ? ? ? 8 PRO P C 1 8
+ATOM 15 O O . PRO A 1 8 ? 6.475 29.336 -3.559 1.00 71.67 ? ? ? ? ? ? 8 PRO P O 1 8
+ATOM 16 C CB . PRO A 1 8 ? 8.317 29.623 -6.235 1.00 72.40 ? ? ? ? ? ? 8 PRO P CB 1 8
+ATOM 17 C CG . PRO A 1 8 ? 7.351 30.654 -6.669 1.00 73.06 ? ? ? ? ? ? 8 PRO P CG 1 8
+ATOM 18 C CD . PRO A 1 8 ? 6.155 29.890 -7.137 1.00 73.11 ? ? ? ? ? ? 8 PRO P CD 1 8
+ATOM 19 N N . ASN A 1 9 ? 8.414 28.190 -3.391 1.00 70.44 ? ? ? ? ? ? 9 ASN P N 1 9
+ATOM 20 C CA . ASN A 1 9 ? 8.463 28.184 -1.929 1.00 69.18 ? ? ? ? ? ? 9 ASN P CA 1 9
+ATOM 21 C C . ASN A 1 9 ? 9.904 28.146 -1.414 1.00 68.38 ? ? ? ? ? ? 9 ASN P C 1 9
+ATOM 22 O O . ASN A 1 9 ? 10.807 27.696 -2.122 1.00 69.28 ? ? ? ? ? ? 9 ASN P O 1 9
+ATOM 23 C CB . ASN A 1 9 ? 7.688 26.974 -1.393 1.00 69.51 ? ? ? ? ? ? 9 ASN P CB 1 9
+ATOM 24 C CG . ASN A 1 9 ? 7.174 27.177 0.021 1.00 69.76 ? ? ? ? ? ? 9 ASN P CG 1 9
+ATOM 25 O OD1 . ASN A 1 9 ? 7.804 27.848 0.839 1.00 71.77 ? ? ? ? ? ? 9 ASN P OD1 1 9
+ATOM 26 N ND2 . ASN A 1 9 ? 6.020 26.590 0.315 1.00 68.93 ? ? ? ? ? ? 9 ASN P ND2 1 9
+ATOM 27 N N . HIS A 1 10 ? 10.109 28.617 -0.184 1.00 66.82 ? ? ? ? ? ? 10 HIS P N 1 10
+ATOM 28 C CA . HIS A 1 10 ? 11.412 28.538 0.486 1.00 66.08 ? ? ? ? ? ? 10 HIS P CA 1 10
+ATOM 29 C C . HIS A 1 10 ? 11.863 27.090 0.668 1.00 65.03 ? ? ? ? ? ? 10 HIS P C 1 10
+ATOM 30 O O . HIS A 1 10 ? 13.062 26.797 0.685 1.00 64.70 ? ? ? ? ? ? 10 HIS P O 1 10
+ATOM 31 C CB . HIS A 1 10 ? 11.351 29.199 1.865 1.00 67.33 ? ? ? ? ? ? 10 HIS P CB 1 10
+ATOM 32 C CG . HIS A 1 10 ? 11.091 30.670 1.825 1.00 67.56 ? ? ? ? ? ? 10 HIS P CG 1 10
+ATOM 33 N ND1 . HIS A 1 10 ? 12.103 31.603 1.849 1.00 68.36 ? ? ? ? ? ? 10 HIS P ND1 1 10
+ATOM 34 C CD2 . HIS A 1 10 ? 9.933 31.370 1.779 1.00 68.42 ? ? ? ? ? ? 10 HIS P CD2 1 10
+ATOM 35 C CE1 . HIS A 1 10 ? 11.581 32.816 1.812 1.00 68.48 ? ? ? ? ? ? 10 HIS P CE1 1 10
+ATOM 36 N NE2 . HIS A 1 10 ? 10.267 32.703 1.768 1.00 68.45 ? ? ? ? ? ? 10 HIS P NE2 1 10
+ATOM 37 N N . THR A 1 11 ? 10.887 26.198 0.814 1.00 63.00 ? ? ? ? ? ? 11 THR P N 1 11
+ATOM 38 C CA . THR A 1 11 ? 11.134 24.790 1.084 1.00 60.82 ? ? ? ? ? ? 11 THR P CA 1 11
+ATOM 39 C C . THR A 1 11 ? 10.971 23.958 -0.184 1.00 59.43 ? ? ? ? ? ? 11 THR P C 1 11
+ATOM 40 O O . THR A 1 11 ? 10.107 24.239 -1.015 1.00 60.52 ? ? ? ? ? ? 11 THR P O 1 11
+ATOM 41 C CB . THR A 1 11 ? 10.176 24.268 2.176 1.00 61.19 ? ? ? ? ? ? 11 THR P CB 1 11
+ATOM 42 O OG1 . THR A 1 11 ? 10.174 25.178 3.283 1.00 61.69 ? ? ? ? ? ? 11 THR P OG1 1 11
+ATOM 43 C CG2 . THR A 1 11 ? 10.598 22.888 2.666 1.00 61.40 ? ? ? ? ? ? 11 THR P CG2 1 11
+ATOM 44 N N . ILE A 1 12 ? 11.819 22.943 -0.327 1.00 57.83 ? ? ? ? ? ? 12 ILE P N 1 12
+ATOM 45 C CA . ILE A 1 12 ? 11.712 21.984 -1.424 1.00 55.69 ? ? ? ? ? ? 12 ILE P CA 1 12
+ATOM 46 C C . ILE A 1 12 ? 11.417 20.580 -0.902 1.00 55.32 ? ? ? ? ? ? 12 ILE P C 1 12
+ATOM 47 O O . ILE A 1 12 ? 11.992 20.134 0.097 1.00 54.83 ? ? ? ? ? ? 12 ILE P O 1 12
+ATOM 48 C CB . ILE A 1 12 ? 12.966 21.974 -2.332 1.00 55.89 ? ? ? ? ? ? 12 ILE P CB 1 12
+ATOM 49 C CG1 . ILE A 1 12 ? 14.249 21.850 -1.499 1.00 55.80 ? ? ? ? ? ? 12 ILE P CG1 1 12
+ATOM 50 C CG2 . ILE A 1 12 ? 12.995 23.227 -3.206 1.00 55.63 ? ? ? ? ? ? 12 ILE P CG2 1 12
+ATOM 51 C CD1 . ILE A 1 12 ? 15.436 21.305 -2.266 1.00 56.47 ? ? ? ? ? ? 12 ILE P CD1 1 12
+ATOM 52 N N . TYR A 1 13 ? 10.503 19.900 -1.586 1.00 53.47 ? ? ? ? ? ? 13 TYR P N 1 13
+ATOM 53 C CA . TYR A 1 13 ? 10.067 18.570 -1.201 1.00 51.15 ? ? ? ? ? ? 13 TYR P CA 1 13
+ATOM 54 C C . TYR A 1 13 ? 10.810 17.526 -2.014 1.00 51.67 ? ? ? ? ? ? 13 TYR P C 1 13
+ATOM 55 O O . TYR A 1 13 ? 10.506 17.307 -3.189 1.00 52.90 ? ? ? ? ? ? 13 TYR P O 1 13
+ATOM 56 C CB . TYR A 1 13 ? 8.559 18.430 -1.407 1.00 50.24 ? ? ? ? ? ? 13 TYR P CB 1 13
+ATOM 57 C CG . TYR A 1 13 ? 7.995 17.085 -1.013 1.00 48.48 ? ? ? ? ? ? 13 TYR P CG 1 13
+ATOM 58 C CD1 . TYR A 1 13 ? 7.675 16.810 0.310 1.00 48.54 ? ? ? ? ? ? 13 TYR P CD1 1 13
+ATOM 59 C CD2 . TYR A 1 13 ? 7.772 16.095 -1.965 1.00 49.30 ? ? ? ? ? ? 13 TYR P CD2 1 13
+ATOM 60 C CE1 . TYR A 1 13 ? 7.156 15.581 0.683 1.00 50.28 ? ? ? ? ? ? 13 TYR P CE1 1 13
+ATOM 61 C CE2 . TYR A 1 13 ? 7.251 14.859 -1.605 1.00 50.24 ? ? ? ? ? ? 13 TYR P CE2 1 13
+ATOM 62 C CZ . TYR A 1 13 ? 6.943 14.610 -0.278 1.00 50.26 ? ? ? ? ? ? 13 TYR P CZ 1 13
+ATOM 63 O OH . TYR A 1 13 ? 6.426 13.392 0.097 1.00 51.27 ? ? ? ? ? ? 13 TYR P OH 1 13
+ATOM 64 N N . ILE A 1 14 ? 11.790 16.891 -1.380 1.00 52.72 ? ? ? ? ? ? 14 ILE P N 1 14
+ATOM 65 C CA . ILE A 1 14 ? 12.554 15.824 -2.020 1.00 53.08 ? ? ? ? ? ? 14 ILE P CA 1 14
+ATOM 66 C C . ILE A 1 14 ? 11.854 14.493 -1.781 1.00 54.93 ? ? ? ? ? ? 14 ILE P C 1 14
+ATOM 67 O O . ILE A 1 14 ? 11.422 14.189 -0.665 1.00 54.75 ? ? ? ? ? ? 14 ILE P O 1 14
+ATOM 68 C CB . ILE A 1 14 ? 14.018 15.793 -1.539 1.00 50.75 ? ? ? ? ? ? 14 ILE P CB 1 14
+ATOM 69 C CG1 . ILE A 1 14 ? 14.691 17.129 -1.849 1.00 49.83 ? ? ? ? ? ? 14 ILE P CG1 1 14
+ATOM 70 C CG2 . ILE A 1 14 ? 14.786 14.670 -2.221 1.00 50.96 ? ? ? ? ? ? 14 ILE P CG2 1 14
+ATOM 71 C CD1 . ILE A 1 14 ? 15.762 17.515 -0.872 1.00 51.18 ? ? ? ? ? ? 14 ILE P CD1 1 14
+ATOM 72 N N . ASN A 1 15 ? 11.749 13.714 -2.851 1.00 56.95 ? ? ? ? ? ? 15 ASN P N 1 15
+ATOM 73 C CA . ASN A 1 15 ? 10.951 12.501 -2.872 1.00 60.17 ? ? ? ? ? ? 15 ASN P CA 1 15
+ATOM 74 C C . ASN A 1 15 ? 11.800 11.318 -3.327 1.00 60.77 ? ? ? ? ? ? 15 ASN P C 1 15
+ATOM 75 O O . ASN A 1 15 ? 12.890 11.509 -3.876 1.00 62.14 ? ? ? ? ? ? 15 ASN P O 1 15
+ATOM 76 C CB . ASN A 1 15 ? 9.773 12.710 -3.831 1.00 63.33 ? ? ? ? ? ? 15 ASN P CB 1 15
+ATOM 77 C CG . ASN A 1 15 ? 8.558 11.882 -3.469 1.00 66.30 ? ? ? ? ? ? 15 ASN P CG 1 15
+ATOM 78 O OD1 . ASN A 1 15 ? 7.895 11.324 -4.348 1.00 68.07 ? ? ? ? ? ? 15 ASN P OD1 1 15
+ATOM 79 N ND2 . ASN A 1 15 ? 8.248 11.806 -2.178 1.00 66.31 ? ? ? ? ? ? 15 ASN P ND2 1 15
+ATOM 80 N N . ASN A 1 16 ? 11.303 10.104 -3.092 1.00 59.64 ? ? ? ? ? ? 16 ASN P N 1 16
+ATOM 81 C CA . ASN A 1 16 ? 11.931 8.883 -3.602 1.00 60.22 ? ? ? ? ? ? 16 ASN P CA 1 16
+ATOM 82 C C . ASN A 1 16 ? 13.369 8.685 -3.083 1.00 60.60 ? ? ? ? ? ? 16 ASN P C 1 16
+ATOM 83 O O . ASN A 1 16 ? 14.333 8.496 -3.867 1.00 62.95 ? ? ? ? ? ? 16 ASN P O 1 16
+ATOM 84 C CB . ASN A 1 16 ? 11.875 8.863 -5.143 1.00 59.98 ? ? ? ? ? ? 16 ASN P CB 1 16
+ATOM 85 C CG . ASN A 1 16 ? 12.281 7.527 -5.734 1.00 59.13 ? ? ? ? ? ? 16 ASN P CG 1 16
+ATOM 86 O OD1 . ASN A 1 16 ? 11.670 6.497 -5.452 1.00 58.94 ? ? ? ? ? ? 16 ASN P OD1 1 16
+ATOM 87 N ND2 . ASN A 1 16 ? 13.318 7.540 -6.566 1.00 58.95 ? ? ? ? ? ? 16 ASN P ND2 1 16
+ATOM 88 N N . LEU A 1 17 ? 13.500 8.729 -1.751 1.00 59.36 ? ? ? ? ? ? 17 LEU P N 1 17
+ATOM 89 C CA . LEU A 1 17 ? 14.815 8.588 -1.120 1.00 57.68 ? ? ? ? ? ? 17 LEU P CA 1 17
+ATOM 90 C C . LEU A 1 17 ? 15.016 7.195 -0.544 1.00 58.55 ? ? ? ? ? ? 17 LEU P C 1 17
+ATOM 91 O O . LEU A 1 17 ? 14.056 6.541 -0.131 1.00 58.44 ? ? ? ? ? ? 17 LEU P O 1 17
+ATOM 92 C CB . LEU A 1 17 ? 14.993 9.624 -0.009 1.00 54.86 ? ? ? ? ? ? 17 LEU P CB 1 17
+ATOM 93 C CG . LEU A 1 17 ? 15.024 11.105 -0.383 1.00 54.27 ? ? ? ? ? ? 17 LEU P CG 1 17
+ATOM 94 C CD1 . LEU A 1 17 ? 14.809 11.960 0.857 1.00 53.68 ? ? ? ? ? ? 17 LEU P CD1 1 17
+ATOM 95 C CD2 . LEU A 1 17 ? 16.327 11.467 -1.075 1.00 53.69 ? ? ? ? ? ? 17 LEU P CD2 1 17
+ATOM 96 N N . ASN A 1 18 ? 16.272 6.752 -0.523 1.00 59.90 ? ? ? ? ? ? 18 ASN P N 1 18
+ATOM 97 C CA . ASN A 1 18 ? 16.646 5.501 0.123 1.00 60.60 ? ? ? ? ? ? 18 ASN P CA 1 18
+ATOM 98 C C . ASN A 1 18 ? 16.255 5.552 1.595 1.00 62.35 ? ? ? ? ? ? 18 ASN P C 1 18
+ATOM 99 O O . ASN A 1 18 ? 16.767 6.371 2.362 1.00 62.63 ? ? ? ? ? ? 18 ASN P O 1 18
+ATOM 100 C CB . ASN A 1 18 ? 18.149 5.251 -0.034 1.00 61.17 ? ? ? ? ? ? 18 ASN P CB 1 18
+ATOM 101 C CG . ASN A 1 18 ? 18.556 3.824 0.318 1.00 61.79 ? ? ? ? ? ? 18 ASN P CG 1 18
+ATOM 102 O OD1 . ASN A 1 18 ? 17.827 3.093 0.995 1.00 62.04 ? ? ? ? ? ? 18 ASN P OD1 1 18
+ATOM 103 N ND2 . ASN A 1 18 ? 19.738 3.425 -0.141 1.00 61.43 ? ? ? ? ? ? 18 ASN P ND2 1 18
+ATOM 104 N N . GLU A 1 19 ? 15.333 4.675 1.976 1.00 64.29 ? ? ? ? ? ? 19 GLU P N 1 19
+ATOM 105 C CA . GLU A 1 19 ? 14.754 4.686 3.317 1.00 64.71 ? ? ? ? ? ? 19 GLU P CA 1 19
+ATOM 106 C C . GLU A 1 19 ? 15.668 4.026 4.346 1.00 65.51 ? ? ? ? ? ? 19 GLU P C 1 19
+ATOM 107 O O . GLU A 1 19 ? 15.414 4.101 5.552 1.00 66.45 ? ? ? ? ? ? 19 GLU P O 1 19
+ATOM 108 C CB . GLU A 1 19 ? 13.382 4.011 3.302 1.00 64.85 ? ? ? ? ? ? 19 GLU P CB 1 19
+ATOM 109 C CG . GLU A 1 19 ? 12.405 4.625 2.305 1.00 66.67 ? ? ? ? ? ? 19 GLU P CG 1 19
+ATOM 110 C CD . GLU A 1 19 ? 11.296 3.672 1.902 1.00 68.11 ? ? ? ? ? ? 19 GLU P CD 1 19
+ATOM 111 O OE1 . GLU A 1 19 ? 10.483 3.295 2.773 1.00 68.88 ? ? ? ? ? ? 19 GLU P OE1 1 19
+ATOM 112 O OE2 . GLU A 1 19 ? 11.233 3.305 0.709 1.00 69.92 ? ? ? ? ? ? 19 GLU P OE2 1 19
+ATOM 113 N N . LYS A 1 20 ? 16.737 3.395 3.864 1.00 66.19 ? ? ? ? ? ? 20 LYS P N 1 20
+ATOM 114 C CA . LYS A 1 20 ? 17.672 2.671 4.726 1.00 66.48 ? ? ? ? ? ? 20 LYS P CA 1 20
+ATOM 115 C C . LYS A 1 20 ? 18.696 3.579 5.407 1.00 66.60 ? ? ? ? ? ? 20 LYS P C 1 20
+ATOM 116 O O . LYS A 1 20 ? 19.346 3.172 6.373 1.00 66.83 ? ? ? ? ? ? 20 LYS P O 1 20
+ATOM 117 C CB . LYS A 1 20 ? 18.375 1.557 3.945 1.00 66.85 ? ? ? ? ? ? 20 LYS P CB 1 20
+ATOM 118 C CG . LYS A 1 20 ? 17.452 0.418 3.544 1.00 69.82 ? ? ? ? ? ? 20 LYS P CG 1 20
+ATOM 119 C CD . LYS A 1 20 ? 18.193 -0.907 3.474 1.00 72.14 ? ? ? ? ? ? 20 LYS P CD 1 20
+ATOM 120 C CE . LYS A 1 20 ? 17.218 -2.078 3.535 1.00 73.89 ? ? ? ? ? ? 20 LYS P CE 1 20
+ATOM 121 N NZ . LYS A 1 20 ? 17.905 -3.370 3.828 1.00 74.59 ? ? ? ? ? ? 20 LYS P NZ 1 20
+ATOM 122 N N . ILE A 1 21 ? 18.826 4.806 4.908 1.00 66.63 ? ? ? ? ? ? 21 ILE P N 1 21
+ATOM 123 C CA . ILE A 1 21 ? 19.771 5.776 5.463 1.00 67.18 ? ? ? ? ? ? 21 ILE P CA 1 21
+ATOM 124 C C . ILE A 1 21 ? 19.315 6.224 6.848 1.00 67.73 ? ? ? ? ? ? 21 ILE P C 1 21
+ATOM 125 O O . ILE A 1 21 ? 18.141 6.538 7.050 1.00 67.09 ? ? ? ? ? ? 21 ILE P O 1 21
+ATOM 126 C CB . ILE A 1 21 ? 19.937 7.035 4.553 1.00 66.89 ? ? ? ? ? ? 21 ILE P CB 1 21
+ATOM 127 C CG1 . ILE A 1 21 ? 19.962 6.669 3.061 1.00 66.21 ? ? ? ? ? ? 21 ILE P CG1 1 21
+ATOM 128 C CG2 . ILE A 1 21 ? 21.169 7.851 4.959 1.00 67.31 ? ? ? ? ? ? 21 ILE P CG2 1 21
+ATOM 129 C CD1 . ILE A 1 21 ? 21.055 5.705 2.649 1.00 67.59 ? ? ? ? ? ? 21 ILE P CD1 1 21
+ATOM 130 N N . LYS A 1 22 ? 20.246 6.244 7.797 1.00 70.10 ? ? ? ? ? ? 22 LYS P N 1 22
+ATOM 131 C CA . LYS A 1 22 ? 19.963 6.749 9.136 1.00 72.14 ? ? ? ? ? ? 22 LYS P CA 1 22
+ATOM 132 C C . LYS A 1 22 ? 19.669 8.247 9.097 1.00 72.02 ? ? ? ? ? ? 22 LYS P C 1 22
+ATOM 133 O O . LYS A 1 22 ? 20.360 9.011 8.414 1.00 72.88 ? ? ? ? ? ? 22 LYS P O 1 22
+ATOM 134 C CB . LYS A 1 22 ? 21.121 6.452 10.095 1.00 73.72 ? ? ? ? ? ? 22 LYS P CB 1 22
+ATOM 135 C CG . LYS A 1 22 ? 21.105 5.048 10.685 1.00 75.74 ? ? ? ? ? ? 22 LYS P CG 1 22
+ATOM 136 C CD . LYS A 1 22 ? 21.957 4.974 11.948 1.00 77.58 ? ? ? ? ? ? 22 LYS P CD 1 22
+ATOM 137 C CE . LYS A 1 22 ? 21.768 3.651 12.675 1.00 78.80 ? ? ? ? ? ? 22 LYS P CE 1 22
+ATOM 138 N NZ . LYS A 1 22 ? 22.372 3.667 14.040 1.00 79.25 ? ? ? ? ? ? 22 LYS P NZ 1 22
+ATOM 139 N N . LYS A 1 23 ? 18.632 8.646 9.831 1.00 71.68 ? ? ? ? ? ? 23 LYS P N 1 23
+ATOM 140 C CA . LYS A 1 23 ? 18.194 10.041 9.936 1.00 71.22 ? ? ? ? ? ? 23 LYS P CA 1 23
+ATOM 141 C C . LYS A 1 23 ? 19.358 11.042 10.014 1.00 70.30 ? ? ? ? ? ? 23 LYS P C 1 23
+ATOM 142 O O . LYS A 1 23 ? 19.318 12.117 9.383 1.00 70.36 ? ? ? ? ? ? 23 LYS P O 1 23
+ATOM 143 C CB . LYS A 1 23 ? 17.264 10.196 11.149 1.00 72.38 ? ? ? ? ? ? 23 LYS P CB 1 23
+ATOM 144 C CG . LYS A 1 23 ? 16.655 11.578 11.342 1.00 73.48 ? ? ? ? ? ? 23 LYS P CG 1 23
+ATOM 145 C CD . LYS A 1 23 ? 15.606 11.566 12.447 1.00 74.43 ? ? ? ? ? ? 23 LYS P CD 1 23
+ATOM 146 C CE . LYS A 1 23 ? 15.165 12.983 12.792 1.00 75.99 ? ? ? ? ? ? 23 LYS P CE 1 23
+ATOM 147 N NZ . LYS A 1 23 ? 13.907 13.014 13.592 1.00 75.30 ? ? ? ? ? ? 23 LYS P NZ 1 23
+ATOM 148 N N . ASP A 1 24 ? 20.391 10.672 10.780 1.00 69.62 ? ? ? ? ? ? 24 ASP P N 1 24
+ATOM 149 C CA . ASP A 1 24 ? 21.549 11.539 11.002 1.00 68.79 ? ? ? ? ? ? 24 ASP P CA 1 24
+ATOM 150 C C . ASP A 1 24 ? 22.321 11.767 9.710 1.00 67.58 ? ? ? ? ? ? 24 ASP P C 1 24
+ATOM 151 O O . ASP A 1 24 ? 22.617 12.908 9.356 1.00 66.30 ? ? ? ? ? ? 24 ASP P O 1 24
+ATOM 152 C CB . ASP A 1 24 ? 22.481 10.937 12.062 1.00 70.00 ? ? ? ? ? ? 24 ASP P CB 1 24
+ATOM 153 C CG . ASP A 1 24 ? 21.732 10.415 13.272 1.00 70.21 ? ? ? ? ? ? 24 ASP P CG 1 24
+ATOM 154 O OD1 . ASP A 1 24 ? 21.278 11.236 14.097 1.00 69.90 ? ? ? ? ? ? 24 ASP P OD1 1 24
+ATOM 155 O OD2 . ASP A 1 24 ? 21.602 9.178 13.398 1.00 71.39 ? ? ? ? ? ? 24 ASP P OD2 1 24
+ATOM 156 N N . GLU A 1 25 ? 22.637 10.675 9.016 1.00 66.70 ? ? ? ? ? ? 25 GLU P N 1 25
+ATOM 157 C CA . GLU A 1 25 ? 23.394 10.734 7.769 1.00 67.02 ? ? ? ? ? ? 25 GLU P CA 1 25
+ATOM 158 C C . GLU A 1 25 ? 22.588 11.404 6.661 1.00 65.66 ? ? ? ? ? ? 25 GLU P C 1 25
+ATOM 159 O O . GLU A 1 25 ? 23.133 12.180 5.873 1.00 63.20 ? ? ? ? ? ? 25 GLU P O 1 25
+ATOM 160 C CB . GLU A 1 25 ? 23.836 9.334 7.330 1.00 70.58 ? ? ? ? ? ? 25 GLU P CB 1 25
+ATOM 161 C CG . GLU A 1 25 ? 24.819 8.646 8.277 1.00 75.58 ? ? ? ? ? ? 25 GLU P CG 1 25
+ATOM 162 C CD . GLU A 1 25 ? 26.128 9.411 8.450 1.00 78.43 ? ? ? ? ? ? 25 GLU P CD 1 25
+ATOM 163 O OE1 . GLU A 1 25 ? 26.717 9.841 7.433 1.00 79.52 ? ? ? ? ? ? 25 GLU P OE1 1 25
+ATOM 164 O OE2 . GLU A 1 25 ? 26.572 9.575 9.608 1.00 80.01 ? ? ? ? ? ? 25 GLU P OE2 1 25
+ATOM 165 N N . LEU A 1 26 ? 21.290 11.106 6.620 1.00 64.01 ? ? ? ? ? ? 26 LEU P N 1 26
+ATOM 166 C CA . LEU A 1 26 ? 20.392 11.665 5.615 1.00 63.38 ? ? ? ? ? ? 26 LEU P CA 1 26
+ATOM 167 C C . LEU A 1 26 ? 20.417 13.198 5.622 1.00 63.82 ? ? ? ? ? ? 26 LEU P C 1 26
+ATOM 168 O O . LEU A 1 26 ? 20.719 13.815 4.598 1.00 62.41 ? ? ? ? ? ? 26 LEU P O 1 26
+ATOM 169 C CB . LEU A 1 26 ? 18.969 11.115 5.796 1.00 62.60 ? ? ? ? ? ? 26 LEU P CB 1 26
+ATOM 170 C CG . LEU A 1 26 ? 17.858 11.397 4.770 1.00 61.96 ? ? ? ? ? ? 26 LEU P CG 1 26
+ATOM 171 C CD1 . LEU A 1 26 ? 18.338 11.310 3.321 1.00 61.38 ? ? ? ? ? ? 26 LEU P CD1 1 26
+ATOM 172 C CD2 . LEU A 1 26 ? 16.693 10.441 4.996 1.00 61.28 ? ? ? ? ? ? 26 LEU P CD2 1 26
+ATOM 173 N N . LYS A 1 27 ? 20.127 13.802 6.775 1.00 64.51 ? ? ? ? ? ? 27 LYS P N 1 27
+ATOM 174 C CA . LYS A 1 27 ? 20.209 15.258 6.925 1.00 66.21 ? ? ? ? ? ? 27 LYS P CA 1 27
+ATOM 175 C C . LYS A 1 27 ? 21.602 15.751 6.537 1.00 67.46 ? ? ? ? ? ? 27 LYS P C 1 27
+ATOM 176 O O . LYS A 1 27 ? 21.742 16.634 5.684 1.00 67.87 ? ? ? ? ? ? 27 LYS P O 1 27
+ATOM 177 C CB . LYS A 1 27 ? 19.886 15.694 8.359 1.00 66.81 ? ? ? ? ? ? 27 LYS P CB 1 27
+ATOM 178 C CG . LYS A 1 27 ? 18.460 15.421 8.808 1.00 68.72 ? ? ? ? ? ? 27 LYS P CG 1 27
+ATOM 179 C CD . LYS A 1 27 ? 18.100 16.247 10.033 1.00 69.14 ? ? ? ? ? ? 27 LYS P CD 1 27
+ATOM 180 C CE . LYS A 1 27 ? 16.707 15.901 10.539 1.00 70.46 ? ? ? ? ? ? 27 LYS P CE 1 27
+ATOM 181 N NZ . LYS A 1 27 ? 16.140 16.984 11.392 1.00 70.41 ? ? ? ? ? ? 27 LYS P NZ 1 27
+ATOM 182 N N . LYS A 1 28 ? 22.617 15.148 7.160 1.00 67.07 ? ? ? ? ? ? 28 LYS P N 1 28
+ATOM 183 C CA . LYS A 1 28 ? 24.022 15.482 6.944 1.00 65.95 ? ? ? ? ? ? 28 LYS P CA 1 28
+ATOM 184 C C . LYS A 1 28 ? 24.361 15.546 5.452 1.00 63.96 ? ? ? ? ? ? 28 LYS P C 1 28
+ATOM 185 O O . LYS A 1 28 ? 24.862 16.563 4.970 1.00 62.21 ? ? ? ? ? ? 28 LYS P O 1 28
+ATOM 186 C CB . LYS A 1 28 ? 24.910 14.456 7.657 1.00 68.03 ? ? ? ? ? ? 28 LYS P CB 1 28
+ATOM 187 C CG . LYS A 1 28 ? 26.276 14.965 8.094 1.00 69.74 ? ? ? ? ? ? 28 LYS P CG 1 28
+ATOM 188 C CD . LYS A 1 28 ? 27.231 13.799 8.328 1.00 71.03 ? ? ? ? ? ? 28 LYS P CD 1 28
+ATOM 189 C CE . LYS A 1 28 ? 28.535 14.239 8.983 1.00 71.65 ? ? ? ? ? ? 28 LYS P CE 1 28
+ATOM 190 N NZ . LYS A 1 28 ? 28.434 14.278 10.470 1.00 71.45 ? ? ? ? ? ? 28 LYS P NZ 1 28
+ATOM 191 N N . SER A 1 29 ? 24.062 14.465 4.732 1.00 62.97 ? ? ? ? ? ? 29 SER P N 1 29
+ATOM 192 C CA . SER A 1 29 ? 24.323 14.378 3.292 1.00 62.46 ? ? ? ? ? ? 29 SER P CA 1 29
+ATOM 193 C C . SER A 1 29 ? 23.541 15.422 2.495 1.00 63.18 ? ? ? ? ? ? 29 SER P C 1 29
+ATOM 194 O O . SER A 1 29 ? 24.109 16.091 1.634 1.00 65.29 ? ? ? ? ? ? 29 SER P O 1 29
+ATOM 195 C CB . SER A 1 29 ? 24.013 12.978 2.765 1.00 61.42 ? ? ? ? ? ? 29 SER P CB 1 29
+ATOM 196 O OG . SER A 1 29 ? 24.614 11.985 3.572 1.00 61.08 ? ? ? ? ? ? 29 SER P OG 1 29
+ATOM 197 N N . LEU A 1 30 ? 22.248 15.563 2.787 1.00 62.10 ? ? ? ? ? ? 30 LEU P N 1 30
+ATOM 198 C CA . LEU A 1 30 ? 21.409 16.567 2.125 1.00 60.90 ? ? ? ? ? ? 30 LEU P CA 1 30
+ATOM 199 C C . LEU A 1 30 ? 21.945 17.979 2.342 1.00 61.95 ? ? ? ? ? ? 30 LEU P C 1 30
+ATOM 200 O O . LEU A 1 30 ? 21.902 18.811 1.435 1.00 60.80 ? ? ? ? ? ? 30 LEU P O 1 30
+ATOM 201 C CB . LEU A 1 30 ? 19.957 16.473 2.603 1.00 57.93 ? ? ? ? ? ? 30 LEU P CB 1 30
+ATOM 202 C CG . LEU A 1 30 ? 19.133 15.272 2.128 1.00 55.91 ? ? ? ? ? ? 30 LEU P CG 1 30
+ATOM 203 C CD1 . LEU A 1 30 ? 17.927 15.085 3.022 1.00 56.03 ? ? ? ? ? ? 30 LEU P CD1 1 30
+ATOM 204 C CD2 . LEU A 1 30 ? 18.708 15.406 0.675 1.00 54.70 ? ? ? ? ? ? 30 LEU P CD2 1 30
+ATOM 205 N N . HIS A 1 31 ? 22.454 18.234 3.544 1.00 64.40 ? ? ? ? ? ? 31 HIS P N 1 31
+ATOM 206 C CA . HIS A 1 31 ? 23.106 19.499 3.862 1.00 66.73 ? ? ? ? ? ? 31 HIS P CA 1 31
+ATOM 207 C C . HIS A 1 31 ? 24.406 19.639 3.078 1.00 67.17 ? ? ? ? ? ? 31 HIS P C 1 31
+ATOM 208 O O . HIS A 1 31 ? 24.723 20.717 2.572 1.00 67.39 ? ? ? ? ? ? 31 HIS P O 1 31
+ATOM 209 C CB . HIS A 1 31 ? 23.382 19.600 5.364 1.00 68.23 ? ? ? ? ? ? 31 HIS P CB 1 31
+ATOM 210 C CG . HIS A 1 31 ? 23.744 20.978 5.820 1.00 70.27 ? ? ? ? ? ? 31 HIS P CG 1 31
+ATOM 211 N ND1 . HIS A 1 31 ? 22.812 21.870 6.306 1.00 71.21 ? ? ? ? ? ? 31 HIS P ND1 1 31
+ATOM 212 C CD2 . HIS A 1 31 ? 24.936 21.620 5.862 1.00 71.57 ? ? ? ? ? ? 31 HIS P CD2 1 31
+ATOM 213 C CE1 . HIS A 1 31 ? 23.413 23.002 6.626 1.00 72.11 ? ? ? ? ? ? 31 HIS P CE1 1 31
+ATOM 214 N NE2 . HIS A 1 31 ? 24.703 22.876 6.367 1.00 72.30 ? ? ? ? ? ? 31 HIS P NE2 1 31
+ATOM 215 N N . ALA A 1 32 ? 25.144 18.537 2.969 1.00 66.61 ? ? ? ? ? ? 32 ALA P N 1 32
+ATOM 216 C CA . ALA A 1 32 ? 26.419 18.518 2.258 1.00 67.14 ? ? ? ? ? ? 32 ALA P CA 1 32
+ATOM 217 C C . ALA A 1 32 ? 26.266 18.676 0.740 1.00 67.12 ? ? ? ? ? ? 32 ALA P C 1 32
+ATOM 218 O O . ALA A 1 32 ? 27.247 18.914 0.036 1.00 68.42 ? ? ? ? ? ? 32 ALA P O 1 32
+ATOM 219 C CB . ALA A 1 32 ? 27.182 17.242 2.587 1.00 67.01 ? ? ? ? ? ? 32 ALA P CB 1 32
+ATOM 220 N N . ILE A 1 33 ? 25.038 18.551 0.245 1.00 66.22 ? ? ? ? ? ? 33 ILE P N 1 33
+ATOM 221 C CA . ILE A 1 33 ? 24.779 18.577 -1.192 1.00 66.21 ? ? ? ? ? ? 33 ILE P CA 1 33
+ATOM 222 C C . ILE A 1 33 ? 24.008 19.825 -1.634 1.00 65.72 ? ? ? ? ? ? 33 ILE P C 1 33
+ATOM 223 O O . ILE A 1 33 ? 24.216 20.325 -2.741 1.00 65.62 ? ? ? ? ? ? 33 ILE P O 1 33
+ATOM 224 C CB . ILE A 1 33 ? 24.048 17.279 -1.653 1.00 67.78 ? ? ? ? ? ? 33 ILE P CB 1 33
+ATOM 225 C CG1 . ILE A 1 33 ? 24.893 16.028 -1.351 1.00 69.97 ? ? ? ? ? ? 33 ILE P CG1 1 33
+ATOM 226 C CG2 . ILE A 1 33 ? 23.676 17.329 -3.132 1.00 67.72 ? ? ? ? ? ? 33 ILE P CG2 1 33
+ATOM 227 C CD1 . ILE A 1 33 ? 26.364 16.077 -1.816 1.00 72.17 ? ? ? ? ? ? 33 ILE P CD1 1 33
+ATOM 228 N N . PHE A 1 34 ? 23.136 20.329 -0.764 1.00 65.46 ? ? ? ? ? ? 34 PHE P N 1 34
+ATOM 229 C CA . PHE A 1 34 ? 22.262 21.453 -1.108 1.00 64.57 ? ? ? ? ? ? 34 PHE P CA 1 34
+ATOM 230 C C . PHE A 1 34 ? 22.737 22.822 -0.613 1.00 65.26 ? ? ? ? ? ? 34 PHE P C 1 34
+ATOM 231 O O . PHE A 1 34 ? 22.223 23.850 -1.063 1.00 65.25 ? ? ? ? ? ? 34 PHE P O 1 34
+ATOM 232 C CB . PHE A 1 34 ? 20.830 21.192 -0.622 1.00 62.75 ? ? ? ? ? ? 34 PHE P CB 1 34
+ATOM 233 C CG . PHE A 1 34 ? 20.070 20.209 -1.468 1.00 60.53 ? ? ? ? ? ? 34 PHE P CG 1 34
+ATOM 234 C CD1 . PHE A 1 34 ? 19.527 20.596 -2.691 1.00 59.24 ? ? ? ? ? ? 34 PHE P CD1 1 34
+ATOM 235 C CD2 . PHE A 1 34 ? 19.892 18.899 -1.041 1.00 59.15 ? ? ? ? ? ? 34 PHE P CD2 1 34
+ATOM 236 C CE1 . PHE A 1 34 ? 18.825 19.691 -3.479 1.00 57.79 ? ? ? ? ? ? 34 PHE P CE1 1 34
+ATOM 237 C CE2 . PHE A 1 34 ? 19.189 17.987 -1.823 1.00 58.66 ? ? ? ? ? ? 34 PHE P CE2 1 34
+ATOM 238 C CZ . PHE A 1 34 ? 18.654 18.385 -3.044 1.00 57.78 ? ? ? ? ? ? 34 PHE P CZ 1 34
+ATOM 239 N N . SER A 1 35 ? 23.711 22.838 0.298 1.00 66.13 ? ? ? ? ? ? 35 SER P N 1 35
+ATOM 240 C CA . SER A 1 35 ? 24.194 24.093 0.898 1.00 67.08 ? ? ? ? ? ? 35 SER P CA 1 35
+ATOM 241 C C . SER A 1 35 ? 24.891 25.020 -0.097 1.00 65.70 ? ? ? ? ? ? 35 SER P C 1 35
+ATOM 242 O O . SER A 1 35 ? 25.042 26.215 0.164 1.00 66.47 ? ? ? ? ? ? 35 SER P O 1 35
+ATOM 243 C CB . SER A 1 35 ? 25.109 23.824 2.099 1.00 68.50 ? ? ? ? ? ? 35 SER P CB 1 35
+ATOM 244 O OG . SER A 1 35 ? 26.304 23.176 1.701 1.00 71.12 ? ? ? ? ? ? 35 SER P OG 1 35
+ATOM 245 N N . ARG A 1 36 ? 25.302 24.467 -1.236 1.00 64.91 ? ? ? ? ? ? 36 ARG P N 1 36
+ATOM 246 C CA . ARG A 1 36 ? 25.956 25.244 -2.286 1.00 64.08 ? ? ? ? ? ? 36 ARG P CA 1 36
+ATOM 247 C C . ARG A 1 36 ? 24.983 26.130 -3.070 1.00 63.63 ? ? ? ? ? ? 36 ARG P C 1 36
+ATOM 248 O O . ARG A 1 36 ? 25.395 26.887 -3.952 1.00 64.13 ? ? ? ? ? ? 36 ARG P O 1 36
+ATOM 249 C CB . ARG A 1 36 ? 26.751 24.332 -3.232 1.00 65.69 ? ? ? ? ? ? 36 ARG P CB 1 36
+ATOM 250 C CG . ARG A 1 36 ? 25.968 23.181 -3.854 1.00 67.06 ? ? ? ? ? ? 36 ARG P CG 1 36
+ATOM 251 C CD . ARG A 1 36 ? 26.789 22.490 -4.938 1.00 68.94 ? ? ? ? ? ? 36 ARG P CD 1 36
+ATOM 252 N NE . ARG A 1 36 ? 26.791 23.249 -6.190 1.00 70.61 ? ? ? ? ? ? 36 ARG P NE 1 36
+ATOM 253 C CZ . ARG A 1 36 ? 26.169 22.870 -7.306 1.00 71.80 ? ? ? ? ? ? 36 ARG P CZ 1 36
+ATOM 254 N NH1 . ARG A 1 36 ? 26.229 23.632 -8.390 1.00 71.50 ? ? ? ? ? ? 36 ARG P NH1 1 36
+ATOM 255 N NH2 . ARG A 1 36 ? 25.495 21.728 -7.350 1.00 72.57 ? ? ? ? ? ? 36 ARG P NH2 1 36
+ATOM 256 N N . PHE A 1 37 ? 23.697 26.033 -2.744 1.00 62.13 ? ? ? ? ? ? 37 PHE P N 1 37
+ATOM 257 C CA . PHE A 1 37 ? 22.666 26.814 -3.422 1.00 60.59 ? ? ? ? ? ? 37 PHE P CA 1 37
+ATOM 258 C C . PHE A 1 37 ? 22.213 28.016 -2.599 1.00 62.21 ? ? ? ? ? ? 37 PHE P C 1 37
+ATOM 259 O O . PHE A 1 37 ? 21.757 29.017 -3.154 1.00 62.93 ? ? ? ? ? ? 37 PHE P O 1 37
+ATOM 260 C CB . PHE A 1 37 ? 21.470 25.929 -3.775 1.00 57.92 ? ? ? ? ? ? 37 PHE P CB 1 37
+ATOM 261 C CG . PHE A 1 37 ? 21.791 24.843 -4.759 1.00 56.27 ? ? ? ? ? ? 37 PHE P CG 1 37
+ATOM 262 C CD1 . PHE A 1 37 ? 21.945 25.133 -6.110 1.00 55.82 ? ? ? ? ? ? 37 PHE P CD1 1 37
+ATOM 263 C CD2 . PHE A 1 37 ? 21.939 23.527 -4.337 1.00 55.93 ? ? ? ? ? ? 37 PHE P CD2 1 37
+ATOM 264 C CE1 . PHE A 1 37 ? 22.242 24.130 -7.023 1.00 55.73 ? ? ? ? ? ? 37 PHE P CE1 1 37
+ATOM 265 C CE2 . PHE A 1 37 ? 22.234 22.515 -5.246 1.00 55.14 ? ? ? ? ? ? 37 PHE P CE2 1 37
+ATOM 266 C CZ . PHE A 1 37 ? 22.386 22.818 -6.590 1.00 55.40 ? ? ? ? ? ? 37 PHE P CZ 1 37
+ATOM 267 N N . GLY A 1 38 ? 22.351 27.911 -1.279 1.00 63.47 ? ? ? ? ? ? 38 GLY P N 1 38
+ATOM 268 C CA . GLY A 1 38 ? 21.933 28.963 -0.356 1.00 64.83 ? ? ? ? ? ? 38 GLY P CA 1 38
+ATOM 269 C C . GLY A 1 38 ? 21.995 28.505 1.087 1.00 66.45 ? ? ? ? ? ? 38 GLY P C 1 38
+ATOM 270 O O . GLY A 1 38 ? 22.129 27.311 1.364 1.00 66.85 ? ? ? ? ? ? 38 GLY P O 1 38
+ATOM 271 N N . GLN A 1 39 ? 21.897 29.460 2.007 1.00 68.03 ? ? ? ? ? ? 39 GLN P N 1 39
+ATOM 272 C CA . GLN A 1 39 ? 21.910 29.174 3.442 1.00 69.07 ? ? ? ? ? ? 39 GLN P CA 1 39
+ATOM 273 C C . GLN A 1 39 ? 20.644 28.413 3.830 1.00 68.49 ? ? ? ? ? ? 39 GLN P C 1 39
+ATOM 274 O O . GLN A 1 39 ? 19.545 28.752 3.383 1.00 69.87 ? ? ? ? ? ? 39 GLN P O 1 39
+ATOM 275 C CB . GLN A 1 39 ? 22.028 30.471 4.252 1.00 70.75 ? ? ? ? ? ? 39 GLN P CB 1 39
+ATOM 276 C CG . GLN A 1 39 ? 23.298 31.299 3.975 1.00 74.26 ? ? ? ? ? ? 39 GLN P CG 1 39
+ATOM 277 C CD . GLN A 1 39 ? 23.243 32.107 2.670 1.00 74.93 ? ? ? ? ? ? 39 GLN P CD 1 39
+ATOM 278 O OE1 . GLN A 1 39 ? 22.190 32.250 2.044 1.00 75.34 ? ? ? ? ? ? 39 GLN P OE1 1 39
+ATOM 279 N NE2 . GLN A 1 39 ? 24.389 32.640 2.266 1.00 75.22 ? ? ? ? ? ? 39 GLN P NE2 1 39
+ATOM 280 N N . ILE A 1 40 ? 20.804 27.380 4.650 1.00 65.88 ? ? ? ? ? ? 40 ILE P N 1 40
+ATOM 281 C CA . ILE A 1 40 ? 19.679 26.533 5.034 1.00 65.76 ? ? ? ? ? ? 40 ILE P CA 1 40
+ATOM 282 C C . ILE A 1 40 ? 19.252 26.794 6.475 1.00 67.11 ? ? ? ? ? ? 40 ILE P C 1 40
+ATOM 283 O O . ILE A 1 40 ? 20.080 26.790 7.389 1.00 67.67 ? ? ? ? ? ? 40 ILE P O 1 40
+ATOM 284 C CB . ILE A 1 40 ? 19.998 25.032 4.816 1.00 64.90 ? ? ? ? ? ? 40 ILE P CB 1 40
+ATOM 285 C CG1 . ILE A 1 40 ? 20.232 24.754 3.326 1.00 64.01 ? ? ? ? ? ? 40 ILE P CG1 1 40
+ATOM 286 C CG2 . ILE A 1 40 ? 18.876 24.143 5.364 1.00 63.92 ? ? ? ? ? ? 40 ILE P CG2 1 40
+ATOM 287 C CD1 . ILE A 1 40 ? 21.022 23.496 3.039 1.00 63.60 ? ? ? ? ? ? 40 ILE P CD1 1 40
+ATOM 288 N N . LEU A 1 41 ? 17.955 27.030 6.661 1.00 68.35 ? ? ? ? ? ? 41 LEU P N 1 41
+ATOM 289 C CA . LEU A 1 41 ? 17.369 27.212 7.987 1.00 70.51 ? ? ? ? ? ? 41 LEU P CA 1 41
+ATOM 290 C C . LEU A 1 41 ? 17.447 25.908 8.782 1.00 71.19 ? ? ? ? ? ? 41 LEU P C 1 41
+ATOM 291 O O . LEU A 1 41 ? 18.153 25.826 9.789 1.00 72.12 ? ? ? ? ? ? 41 LEU P O 1 41
+ATOM 292 C CB . LEU A 1 41 ? 15.913 27.684 7.872 1.00 71.76 ? ? ? ? ? ? 41 LEU P CB 1 41
+ATOM 293 C CG . LEU A 1 41 ? 15.569 29.180 7.807 1.00 72.63 ? ? ? ? ? ? 41 LEU P CG 1 41
+ATOM 294 C CD1 . LEU A 1 41 ? 16.293 29.912 6.691 1.00 72.37 ? ? ? ? ? ? 41 LEU P CD1 1 41
+ATOM 295 C CD2 . LEU A 1 41 ? 14.063 29.363 7.656 1.00 73.26 ? ? ? ? ? ? 41 LEU P CD2 1 41
+ATOM 296 N N . ASP A 1 42 ? 16.721 24.896 8.314 1.00 70.65 ? ? ? ? ? ? 42 ASP P N 1 42
+ATOM 297 C CA . ASP A 1 42 ? 16.770 23.559 8.891 1.00 70.54 ? ? ? ? ? ? 42 ASP P CA 1 42
+ATOM 298 C C . ASP A 1 42 ? 16.354 22.551 7.830 1.00 69.26 ? ? ? ? ? ? 42 ASP P C 1 42
+ATOM 299 O O . ASP A 1 42 ? 15.696 22.907 6.852 1.00 69.42 ? ? ? ? ? ? 42 ASP P O 1 42
+ATOM 300 C CB . ASP A 1 42 ? 15.847 23.459 10.115 1.00 72.25 ? ? ? ? ? ? 42 ASP P CB 1 42
+ATOM 301 C CG . ASP A 1 42 ? 16.182 22.270 11.017 1.00 73.64 ? ? ? ? ? ? 42 ASP P CG 1 42
+ATOM 302 O OD1 . ASP A 1 42 ? 17.379 22.044 11.311 1.00 74.48 ? ? ? ? ? ? 42 ASP P OD1 1 42
+ATOM 303 O OD2 . ASP A 1 42 ? 15.240 21.566 11.443 1.00 72.67 ? ? ? ? ? ? 42 ASP P OD2 1 42
+ATOM 304 N N . ILE A 1 43 ? 16.755 21.297 8.015 1.00 67.83 ? ? ? ? ? ? 43 ILE P N 1 43
+ATOM 305 C CA . ILE A 1 43 ? 16.316 20.217 7.143 1.00 66.49 ? ? ? ? ? ? 43 ILE P CA 1 43
+ATOM 306 C C . ILE A 1 43 ? 15.410 19.268 7.923 1.00 66.22 ? ? ? ? ? ? 43 ILE P C 1 43
+ATOM 307 O O . ILE A 1 43 ? 15.827 18.669 8.916 1.00 66.44 ? ? ? ? ? ? 43 ILE P O 1 43
+ATOM 308 C CB . ILE A 1 43 ? 17.506 19.458 6.509 1.00 66.63 ? ? ? ? ? ? 43 ILE P CB 1 43
+ATOM 309 C CG1 . ILE A 1 43 ? 18.313 20.399 5.609 1.00 66.94 ? ? ? ? ? ? 43 ILE P CG1 1 43
+ATOM 310 C CG2 . ILE A 1 43 ? 17.013 18.246 5.718 1.00 66.60 ? ? ? ? ? ? 43 ILE P CG2 1 43
+ATOM 311 C CD1 . ILE A 1 43 ? 19.555 19.774 4.999 1.00 67.64 ? ? ? ? ? ? 43 ILE P CD1 1 43
+ATOM 312 N N . LEU A 1 44 ? 14.166 19.151 7.470 1.00 66.04 ? ? ? ? ? ? 44 LEU P N 1 44
+ATOM 313 C CA . LEU A 1 44 ? 13.185 18.297 8.122 1.00 66.09 ? ? ? ? ? ? 44 LEU P CA 1 44
+ATOM 314 C C . LEU A 1 44 ? 13.199 16.900 7.517 1.00 65.09 ? ? ? ? ? ? 44 LEU P C 1 44
+ATOM 315 O O . LEU A 1 44 ? 12.866 16.717 6.346 1.00 65.42 ? ? ? ? ? ? 44 LEU P O 1 44
+ATOM 316 C CB . LEU A 1 44 ? 11.781 18.910 8.023 1.00 68.08 ? ? ? ? ? ? 44 LEU P CB 1 44
+ATOM 317 C CG . LEU A 1 44 ? 11.299 19.984 9.013 1.00 69.60 ? ? ? ? ? ? 44 LEU P CG 1 44
+ATOM 318 C CD1 . LEU A 1 44 ? 11.063 19.395 10.405 1.00 71.01 ? ? ? ? ? ? 44 LEU P CD1 1 44
+ATOM 319 C CD2 . LEU A 1 44 ? 12.223 21.203 9.084 1.00 69.42 ? ? ? ? ? ? 44 LEU P CD2 1 44
+ATOM 320 N N . VAL A 1 45 ? 13.601 15.923 8.324 1.00 63.60 ? ? ? ? ? ? 45 VAL P N 1 45
+ATOM 321 C CA . VAL A 1 45 ? 13.624 14.522 7.916 1.00 62.92 ? ? ? ? ? ? 45 VAL P CA 1 45
+ATOM 322 C C . VAL A 1 45 ? 13.030 13.667 9.032 1.00 63.65 ? ? ? ? ? ? 45 VAL P C 1 45
+ATOM 323 O O . VAL A 1 45 ? 13.415 13.797 10.193 1.00 65.60 ? ? ? ? ? ? 45 VAL P O 1 45
+ATOM 324 C CB . VAL A 1 45 ? 15.067 14.041 7.588 1.00 61.93 ? ? ? ? ? ? 45 VAL P CB 1 45
+ATOM 325 C CG1 . VAL A 1 45 ? 15.094 12.549 7.326 1.00 61.28 ? ? ? ? ? ? 45 VAL P CG1 1 45
+ATOM 326 C CG2 . VAL A 1 45 ? 15.631 14.786 6.391 1.00 61.76 ? ? ? ? ? ? 45 VAL P CG2 1 45
+ATOM 327 N N . SER A 1 46 ? 12.083 12.804 8.677 1.00 64.18 ? ? ? ? ? ? 46 SER P N 1 46
+ATOM 328 C CA . SER A 1 46 ? 11.467 11.892 9.636 1.00 64.69 ? ? ? ? ? ? 46 SER P CA 1 46
+ATOM 329 C C . SER A 1 46 ? 11.265 10.524 8.994 1.00 65.06 ? ? ? ? ? ? 46 SER P C 1 46
+ATOM 330 O O . SER A 1 46 ? 11.017 10.431 7.791 1.00 65.32 ? ? ? ? ? ? 46 SER P O 1 46
+ATOM 331 C CB . SER A 1 46 ? 10.138 12.459 10.132 1.00 65.49 ? ? ? ? ? ? 46 SER P CB 1 46
+ATOM 332 O OG . SER A 1 46 ? 9.620 11.684 11.196 1.00 66.95 ? ? ? ? ? ? 46 SER P OG 1 46
+ATOM 333 N N . ARG A 1 47 ? 11.372 9.468 9.795 1.00 66.39 ? ? ? ? ? ? 47 ARG P N 1 47
+ATOM 334 C CA . ARG A 1 47 ? 11.339 8.099 9.267 1.00 67.79 ? ? ? ? ? ? 47 ARG P CA 1 47
+ATOM 335 C C . ARG A 1 47 ? 10.098 7.293 9.660 1.00 68.16 ? ? ? ? ? ? 47 ARG P C 1 47
+ATOM 336 O O . ARG A 1 47 ? 10.147 6.061 9.729 1.00 69.44 ? ? ? ? ? ? 47 ARG P O 1 47
+ATOM 337 C CB . ARG A 1 47 ? 12.621 7.346 9.641 1.00 68.54 ? ? ? ? ? ? 47 ARG P CB 1 47
+ATOM 338 C CG . ARG A 1 47 ? 13.850 7.809 8.870 1.00 70.75 ? ? ? ? ? ? 47 ARG P CG 1 47
+ATOM 339 C CD . ARG A 1 47 ? 15.100 7.063 9.303 1.00 71.97 ? ? ? ? ? ? 47 ARG P CD 1 47
+ATOM 340 N NE . ARG A 1 47 ? 15.141 5.702 8.772 1.00 73.06 ? ? ? ? ? ? 47 ARG P NE 1 47
+ATOM 341 C CZ . ARG A 1 47 ? 16.059 4.796 9.094 1.00 74.07 ? ? ? ? ? ? 47 ARG P CZ 1 47
+ATOM 342 N NH1 . ARG A 1 47 ? 17.026 5.093 9.956 1.00 74.03 ? ? ? ? ? ? 47 ARG P NH1 1 47
+ATOM 343 N NH2 . ARG A 1 47 ? 16.010 3.585 8.552 1.00 74.22 ? ? ? ? ? ? 47 ARG P NH2 1 47
+ATOM 344 N N . SER A 1 48 ? 8.990 7.987 9.905 1.00 67.76 ? ? ? ? ? ? 48 SER P N 1 48
+ATOM 345 C CA . SER A 1 48 ? 7.708 7.329 10.147 1.00 66.74 ? ? ? ? ? ? 48 SER P CA 1 48
+ATOM 346 C C . SER A 1 48 ? 7.106 6.881 8.820 1.00 67.60 ? ? ? ? ? ? 48 SER P C 1 48
+ATOM 347 O O . SER A 1 48 ? 7.478 7.395 7.766 1.00 68.37 ? ? ? ? ? ? 48 SER P O 1 48
+ATOM 348 C CB . SER A 1 48 ? 6.749 8.262 10.891 1.00 66.41 ? ? ? ? ? ? 48 SER P CB 1 48
+ATOM 349 O OG . SER A 1 48 ? 6.604 9.499 10.219 1.00 64.76 ? ? ? ? ? ? 48 SER P OG 1 48
+ATOM 350 N N . LEU A 1 49 ? 6.178 5.926 8.878 1.00 68.66 ? ? ? ? ? ? 49 LEU P N 1 49
+ATOM 351 C CA . LEU A 1 49 ? 5.533 5.365 7.682 1.00 68.33 ? ? ? ? ? ? 49 LEU P CA 1 49
+ATOM 352 C C . LEU A 1 49 ? 5.019 6.444 6.726 1.00 68.08 ? ? ? ? ? ? 49 LEU P C 1 49
+ATOM 353 O O . LEU A 1 49 ? 5.067 6.285 5.507 1.00 67.25 ? ? ? ? ? ? 49 LEU P O 1 49
+ATOM 354 C CB . LEU A 1 49 ? 4.383 4.439 8.090 1.00 68.60 ? ? ? ? ? ? 49 LEU P CB 1 49
+ATOM 355 C CG . LEU A 1 49 ? 3.707 3.606 6.996 1.00 69.29 ? ? ? ? ? ? 49 LEU P CG 1 49
+ATOM 356 C CD1 . LEU A 1 49 ? 4.452 2.304 6.765 1.00 69.11 ? ? ? ? ? ? 49 LEU P CD1 1 49
+ATOM 357 C CD2 . LEU A 1 49 ? 2.254 3.329 7.353 1.00 70.29 ? ? ? ? ? ? 49 LEU P CD2 1 49
+ATOM 358 N N . LYS A 1 50 ? 4.539 7.539 7.303 1.00 69.37 ? ? ? ? ? ? 50 LYS P N 1 50
+ATOM 359 C CA . LYS A 1 50 ? 3.982 8.657 6.556 1.00 70.58 ? ? ? ? ? ? 50 LYS P CA 1 50
+ATOM 360 C C . LYS A 1 50 ? 5.077 9.592 6.033 1.00 69.87 ? ? ? ? ? ? 50 LYS P C 1 50
+ATOM 361 O O . LYS A 1 50 ? 4.845 10.381 5.116 1.00 69.14 ? ? ? ? ? ? 50 LYS P O 1 50
+ATOM 362 C CB . LYS A 1 50 ? 3.025 9.433 7.468 1.00 72.95 ? ? ? ? ? ? 50 LYS P CB 1 50
+ATOM 363 C CG . LYS A 1 50 ? 1.919 10.186 6.754 1.00 75.40 ? ? ? ? ? ? 50 LYS P CG 1 50
+ATOM 364 C CD . LYS A 1 50 ? 1.063 10.945 7.753 1.00 76.49 ? ? ? ? ? ? 50 LYS P CD 1 50
+ATOM 365 C CE . LYS A 1 50 ? -0.052 11.706 7.059 1.00 77.39 ? ? ? ? ? ? 50 LYS P CE 1 50
+ATOM 366 N NZ . LYS A 1 50 ? -0.787 12.572 8.019 1.00 78.07 ? ? ? ? ? ? 50 LYS P NZ 1 50
+ATOM 367 N N . MET A 1 51 ? 6.270 9.495 6.614 1.00 68.96 ? ? ? ? ? ? 51 MET P N 1 51
+ATOM 368 C CA . MET A 1 51 ? 7.346 10.447 6.331 1.00 69.07 ? ? ? ? ? ? 51 MET P CA 1 51
+ATOM 369 C C . MET A 1 51 ? 8.580 9.842 5.655 1.00 68.01 ? ? ? ? ? ? 51 MET P C 1 51
+ATOM 370 O O . MET A 1 51 ? 9.479 10.574 5.239 1.00 68.98 ? ? ? ? ? ? 51 MET P O 1 51
+ATOM 371 C CB . MET A 1 51 ? 7.755 11.167 7.617 1.00 70.99 ? ? ? ? ? ? 51 MET P CB 1 51
+ATOM 372 C CG . MET A 1 51 ? 6.684 12.088 8.186 1.00 72.46 ? ? ? ? ? ? 51 MET P CG 1 51
+ATOM 373 S SD . MET A 1 51 ? 6.282 13.463 7.091 1.00 75.65 ? ? ? ? ? ? 51 MET P SD 1 51
+ATOM 374 C CE . MET A 1 51 ? 7.805 14.414 7.159 1.00 74.62 ? ? ? ? ? ? 51 MET P CE 1 51
+ATOM 375 N N . ARG A 1 52 ? 8.606 8.515 5.538 1.00 65.85 ? ? ? ? ? ? 52 ARG P N 1 52
+ATOM 376 C CA . ARG A 1 52 ? 9.739 7.783 4.964 1.00 63.78 ? ? ? ? ? ? 52 ARG P CA 1 52
+ATOM 377 C C . ARG A 1 52 ? 10.053 8.171 3.523 1.00 62.25 ? ? ? ? ? ? 52 ARG P C 1 52
+ATOM 378 O O . ARG A 1 52 ? 9.146 8.426 2.730 1.00 63.55 ? ? ? ? ? ? 52 ARG P O 1 52
+ATOM 379 C CB . ARG A 1 52 ? 9.489 6.277 5.051 1.00 65.46 ? ? ? ? ? ? 52 ARG P CB 1 52
+ATOM 380 C CG . ARG A 1 52 ? 9.761 5.709 6.425 1.00 68.07 ? ? ? ? ? ? 52 ARG P CG 1 52
+ATOM 381 C CD . ARG A 1 52 ? 9.093 4.366 6.656 1.00 68.80 ? ? ? ? ? ? 52 ARG P CD 1 52
+ATOM 382 N NE . ARG A 1 52 ? 9.089 4.040 8.082 1.00 69.38 ? ? ? ? ? ? 52 ARG P NE 1 52
+ATOM 383 C CZ . ARG A 1 52 ? 8.948 2.818 8.586 1.00 69.95 ? ? ? ? ? ? 52 ARG P CZ 1 52
+ATOM 384 N NH1 . ARG A 1 52 ? 8.797 1.769 7.787 1.00 70.80 ? ? ? ? ? ? 52 ARG P NH1 1 52
+ATOM 385 N NH2 . ARG A 1 52 ? 8.962 2.643 9.900 1.00 71.50 ? ? ? ? ? ? 52 ARG P NH2 1 52
+ATOM 386 N N . GLY A 1 53 ? 11.345 8.216 3.203 1.00 59.84 ? ? ? ? ? ? 53 GLY P N 1 53
+ATOM 387 C CA . GLY A 1 53 ? 11.820 8.506 1.846 1.00 57.52 ? ? ? ? ? ? 53 GLY P CA 1 53
+ATOM 388 C C . GLY A 1 53 ? 11.596 9.933 1.380 1.00 55.96 ? ? ? ? ? ? 53 GLY P C 1 53
+ATOM 389 O O . GLY A 1 53 ? 11.617 10.211 0.182 1.00 56.35 ? ? ? ? ? ? 53 GLY P O 1 53
+ATOM 390 N N . GLN A 1 54 ? 11.395 10.841 2.331 1.00 55.63 ? ? ? ? ? ? 54 GLN P N 1 54
+ATOM 391 C CA . GLN A 1 54 ? 11.038 12.225 2.026 1.00 55.28 ? ? ? ? ? ? 54 GLN P CA 1 54
+ATOM 392 C C . GLN A 1 54 ? 11.924 13.212 2.780 1.00 53.06 ? ? ? ? ? ? 54 GLN P C 1 54
+ATOM 393 O O . GLN A 1 54 ? 12.485 12.875 3.823 1.00 51.99 ? ? ? ? ? ? 54 GLN P O 1 54
+ATOM 394 C CB . GLN A 1 54 ? 9.564 12.472 2.368 1.00 56.99 ? ? ? ? ? ? 54 GLN P CB 1 54
+ATOM 395 C CG . GLN A 1 54 ? 8.597 11.512 1.686 1.00 58.64 ? ? ? ? ? ? 54 GLN P CG 1 54
+ATOM 396 C CD . GLN A 1 54 ? 7.285 11.371 2.427 1.00 60.02 ? ? ? ? ? ? 54 GLN P CD 1 54
+ATOM 397 O OE1 . GLN A 1 54 ? 6.492 12.312 2.499 1.00 62.25 ? ? ? ? ? ? 54 GLN P OE1 1 54
+ATOM 398 N NE2 . GLN A 1 54 ? 7.041 10.186 2.973 1.00 59.54 ? ? ? ? ? ? 54 GLN P NE2 1 54
+ATOM 399 N N . ALA A 1 55 ? 12.043 14.428 2.248 1.00 51.60 ? ? ? ? ? ? 55 ALA P N 1 55
+ATOM 400 C CA . ALA A 1 55 ? 12.855 15.476 2.874 1.00 50.86 ? ? ? ? ? ? 55 ALA P CA 1 55
+ATOM 401 C C . ALA A 1 55 ? 12.371 16.890 2.566 1.00 51.02 ? ? ? ? ? ? 55 ALA P C 1 55
+ATOM 402 O O . ALA A 1 55 ? 12.000 17.207 1.434 1.00 51.77 ? ? ? ? ? ? 55 ALA P O 1 55
+ATOM 403 C CB . ALA A 1 55 ? 14.317 15.328 2.479 1.00 50.85 ? ? ? ? ? ? 55 ALA P CB 1 55
+ATOM 404 N N . PHE A 1 56 ? 12.394 17.736 3.592 1.00 51.48 ? ? ? ? ? ? 56 PHE P N 1 56
+ATOM 405 C CA . PHE A 1 56 ? 12.088 19.151 3.449 1.00 52.22 ? ? ? ? ? ? 56 PHE P CA 1 56
+ATOM 406 C C . PHE A 1 56 ? 13.344 19.973 3.710 1.00 51.54 ? ? ? ? ? ? 56 PHE P C 1 56
+ATOM 407 O O . PHE A 1 56 ? 13.870 19.971 4.825 1.00 53.03 ? ? ? ? ? ? 56 PHE P O 1 56
+ATOM 408 C CB . PHE A 1 56 ? 10.980 19.565 4.424 1.00 53.24 ? ? ? ? ? ? 56 PHE P CB 1 56
+ATOM 409 C CG . PHE A 1 56 ? 9.632 18.989 4.094 1.00 55.48 ? ? ? ? ? ? 56 PHE P CG 1 56
+ATOM 410 C CD1 . PHE A 1 56 ? 9.241 17.754 4.609 1.00 56.61 ? ? ? ? ? ? 56 PHE P CD1 1 56
+ATOM 411 C CD2 . PHE A 1 56 ? 8.748 19.685 3.275 1.00 55.66 ? ? ? ? ? ? 56 PHE P CD2 1 56
+ATOM 412 C CE1 . PHE A 1 56 ? 7.992 17.216 4.304 1.00 56.49 ? ? ? ? ? ? 56 PHE P CE1 1 56
+ATOM 413 C CE2 . PHE A 1 56 ? 7.498 19.158 2.964 1.00 55.83 ? ? ? ? ? ? 56 PHE P CE2 1 56
+ATOM 414 C CZ . PHE A 1 56 ? 7.119 17.920 3.482 1.00 56.89 ? ? ? ? ? ? 56 PHE P CZ 1 56
+ATOM 415 N N . VAL A 1 57 ? 13.829 20.660 2.678 1.00 49.70 ? ? ? ? ? ? 57 VAL P N 1 57
+ATOM 416 C CA . VAL A 1 57 ? 14.964 21.566 2.821 1.00 49.92 ? ? ? ? ? ? 57 VAL P CA 1 57
+ATOM 417 C C . VAL A 1 57 ? 14.473 23.008 2.748 1.00 51.04 ? ? ? ? ? ? 57 VAL P C 1 57
+ATOM 418 O O . VAL A 1 57 ? 14.019 23.462 1.696 1.00 50.95 ? ? ? ? ? ? 57 VAL P O 1 57
+ATOM 419 C CB . VAL A 1 57 ? 16.049 21.320 1.745 1.00 49.85 ? ? ? ? ? ? 57 VAL P CB 1 57
+ATOM 420 C CG1 . VAL A 1 57 ? 17.189 22.317 1.895 1.00 50.58 ? ? ? ? ? ? 57 VAL P CG1 1 57
+ATOM 421 C CG2 . VAL A 1 57 ? 16.586 19.904 1.840 1.00 49.81 ? ? ? ? ? ? 57 VAL P CG2 1 57
+ATOM 422 N N . ILE A 1 58 ? 14.564 23.717 3.871 1.00 51.65 ? ? ? ? ? ? 58 ILE P N 1 58
+ATOM 423 C CA . ILE A 1 58 ? 14.102 25.102 3.954 1.00 52.28 ? ? ? ? ? ? 58 ILE P CA 1 58
+ATOM 424 C C . ILE A 1 58 ? 15.261 26.072 3.744 1.00 53.40 ? ? ? ? ? ? 58 ILE P C 1 58
+ATOM 425 O O . ILE A 1 58 ? 16.260 26.027 4.463 1.00 55.73 ? ? ? ? ? ? 58 ILE P O 1 58
+ATOM 426 C CB . ILE A 1 58 ? 13.404 25.408 5.304 1.00 51.18 ? ? ? ? ? ? 58 ILE P CB 1 58
+ATOM 427 C CG1 . ILE A 1 58 ? 12.446 24.278 5.697 1.00 50.88 ? ? ? ? ? ? 58 ILE P CG1 1 58
+ATOM 428 C CG2 . ILE A 1 58 ? 12.662 26.741 5.230 1.00 52.22 ? ? ? ? ? ? 58 ILE P CG2 1 58
+ATOM 429 C CD1 . ILE A 1 58 ? 11.880 24.403 7.103 1.00 51.34 ? ? ? ? ? ? 58 ILE P CD1 1 58
+ATOM 430 N N . PHE A 1 59 ? 15.116 26.948 2.756 1.00 55.12 ? ? ? ? ? ? 59 PHE P N 1 59
+ATOM 431 C CA . PHE A 1 59 ? 16.137 27.943 2.443 1.00 57.70 ? ? ? ? ? ? 59 PHE P CA 1 59
+ATOM 432 C C . PHE A 1 59 ? 15.776 29.311 3.011 1.00 59.81 ? ? ? ? ? ? 59 PHE P C 1 59
+ATOM 433 O O . PHE A 1 59 ? 14.606 29.583 3.290 1.00 59.92 ? ? ? ? ? ? 59 PHE P O 1 59
+ATOM 434 C CB . PHE A 1 59 ? 16.315 28.059 0.927 1.00 56.34 ? ? ? ? ? ? 59 PHE P CB 1 59
+ATOM 435 C CG . PHE A 1 59 ? 16.958 26.859 0.293 1.00 55.66 ? ? ? ? ? ? 59 PHE P CG 1 59
+ATOM 436 C CD1 . PHE A 1 59 ? 18.343 26.772 0.185 1.00 55.51 ? ? ? ? ? ? 59 PHE P CD1 1 59
+ATOM 437 C CD2 . PHE A 1 59 ? 16.181 25.822 -0.210 1.00 55.01 ? ? ? ? ? ? 59 PHE P CD2 1 59
+ATOM 438 C CE1 . PHE A 1 59 ? 18.945 25.663 -0.408 1.00 55.30 ? ? ? ? ? ? 59 PHE P CE1 1 59
+ATOM 439 C CE2 . PHE A 1 59 ? 16.771 24.712 -0.808 1.00 55.15 ? ? ? ? ? ? 59 PHE P CE2 1 59
+ATOM 440 C CZ . PHE A 1 59 ? 18.157 24.631 -0.905 1.00 54.59 ? ? ? ? ? ? 59 PHE P CZ 1 59
+ATOM 441 N N . LYS A 1 60 ? 16.786 30.166 3.181 1.00 62.92 ? ? ? ? ? ? 60 LYS P N 1 60
+ATOM 442 C CA . LYS A 1 60 ? 16.564 31.576 3.498 1.00 64.82 ? ? ? ? ? ? 60 LYS P CA 1 60
+ATOM 443 C C . LYS A 1 60 ? 15.810 32.248 2.362 1.00 65.30 ? ? ? ? ? ? 60 LYS P C 1 60
+ATOM 444 O O . LYS A 1 60 ? 14.854 32.985 2.593 1.00 65.12 ? ? ? ? ? ? 60 LYS P O 1 60
+ATOM 445 C CB . LYS A 1 60 ? 17.887 32.312 3.729 1.00 67.05 ? ? ? ? ? ? 60 LYS P CB 1 60
+ATOM 446 C CG . LYS A 1 60 ? 18.379 32.322 5.167 1.00 68.90 ? ? ? ? ? ? 60 LYS P CG 1 60
+ATOM 447 C CD . LYS A 1 60 ? 19.448 33.392 5.363 1.00 71.74 ? ? ? ? ? ? 60 LYS P CD 1 60
+ATOM 448 C CE . LYS A 1 60 ? 20.033 33.373 6.776 1.00 73.73 ? ? ? ? ? ? 60 LYS P CE 1 60
+ATOM 449 N NZ . LYS A 1 60 ? 21.063 32.308 6.968 1.00 74.60 ? ? ? ? ? ? 60 LYS P NZ 1 60
+ATOM 450 N N . GLU A 1 61 ? 16.239 31.971 1.134 1.00 66.25 ? ? ? ? ? ? 61 GLU P N 1 61
+ATOM 451 C CA . GLU A 1 61 ? 15.692 32.627 -0.047 1.00 66.70 ? ? ? ? ? ? 61 GLU P CA 1 61
+ATOM 452 C C . GLU A 1 61 ? 15.037 31.640 -1.006 1.00 66.84 ? ? ? ? ? ? 61 GLU P C 1 61
+ATOM 453 O O . GLU A 1 61 ? 15.579 30.564 -1.267 1.00 67.07 ? ? ? ? ? ? 61 GLU P O 1 61
+ATOM 454 C CB . GLU A 1 61 ? 16.794 33.409 -0.758 1.00 67.58 ? ? ? ? ? ? 61 GLU P CB 1 61
+ATOM 455 C CG . GLU A 1 61 ? 17.429 34.489 0.112 1.00 69.78 ? ? ? ? ? ? 61 GLU P CG 1 61
+ATOM 456 C CD . GLU A 1 61 ? 18.677 35.086 -0.502 1.00 70.73 ? ? ? ? ? ? 61 GLU P CD 1 61
+ATOM 457 O OE1 . GLU A 1 61 ? 19.654 35.309 0.246 1.00 71.11 ? ? ? ? ? ? 61 GLU P OE1 1 61
+ATOM 458 O OE2 . GLU A 1 61 ? 18.683 35.328 -1.729 1.00 71.63 ? ? ? ? ? ? 61 GLU P OE2 1 61
+ATOM 459 N N . VAL A 1 62 ? 13.869 32.021 -1.523 1.00 67.50 ? ? ? ? ? ? 62 VAL P N 1 62
+ATOM 460 C CA . VAL A 1 62 ? 13.124 31.217 -2.504 1.00 68.34 ? ? ? ? ? ? 62 VAL P CA 1 62
+ATOM 461 C C . VAL A 1 62 ? 13.938 31.014 -3.785 1.00 69.51 ? ? ? ? ? ? 62 VAL P C 1 62
+ATOM 462 O O . VAL A 1 62 ? 13.882 29.949 -4.401 1.00 69.69 ? ? ? ? ? ? 62 VAL P O 1 62
+ATOM 463 C CB . VAL A 1 62 ? 11.750 31.861 -2.859 1.00 67.33 ? ? ? ? ? ? 62 VAL P CB 1 62
+ATOM 464 C CG1 . VAL A 1 62 ? 10.998 31.023 -3.892 1.00 66.61 ? ? ? ? ? ? 62 VAL P CG1 1 62
+ATOM 465 C CG2 . VAL A 1 62 ? 10.899 32.049 -1.615 1.00 65.99 ? ? ? ? ? ? 62 VAL P CG2 1 62
+ATOM 466 N N . SER A 1 63 ? 14.691 32.040 -4.174 1.00 70.80 ? ? ? ? ? ? 63 SER P N 1 63
+ATOM 467 C CA . SER A 1 63 ? 15.532 31.980 -5.366 1.00 72.94 ? ? ? ? ? ? 63 SER P CA 1 63
+ATOM 468 C C . SER A 1 63 ? 16.560 30.851 -5.278 1.00 73.51 ? ? ? ? ? ? 63 SER P C 1 63
+ATOM 469 O O . SER A 1 63 ? 16.797 30.148 -6.261 1.00 74.86 ? ? ? ? ? ? 63 SER P O 1 63
+ATOM 470 C CB . SER A 1 63 ? 16.226 33.323 -5.601 1.00 73.36 ? ? ? ? ? ? 63 SER P CB 1 63
+ATOM 471 O OG . SER A 1 63 ? 16.988 33.704 -4.470 1.00 75.33 ? ? ? ? ? ? 63 SER P OG 1 63
+ATOM 472 N N . SER A 1 64 ? 17.153 30.678 -4.097 1.00 73.28 ? ? ? ? ? ? 64 SER P N 1 64
+ATOM 473 C CA . SER A 1 64 ? 18.118 29.607 -3.863 1.00 73.78 ? ? ? ? ? ? 64 SER P CA 1 64
+ATOM 474 C C . SER A 1 64 ? 17.442 28.233 -3.872 1.00 74.09 ? ? ? ? ? ? 64 SER P C 1 64
+ATOM 475 O O . SER A 1 64 ? 18.055 27.233 -4.255 1.00 74.55 ? ? ? ? ? ? 64 SER P O 1 64
+ATOM 476 C CB . SER A 1 64 ? 18.878 29.833 -2.553 1.00 74.22 ? ? ? ? ? ? 64 SER P CB 1 64
+ATOM 477 O OG . SER A 1 64 ? 18.035 29.680 -1.428 1.00 76.33 ? ? ? ? ? ? 64 SER P OG 1 64
+ATOM 478 N N . ALA A 1 65 ? 16.179 28.194 -3.450 1.00 73.75 ? ? ? ? ? ? 65 ALA P N 1 65
+ATOM 479 C CA . ALA A 1 65 ? 15.363 26.983 -3.538 1.00 72.77 ? ? ? ? ? ? 65 ALA P CA 1 65
+ATOM 480 C C . ALA A 1 65 ? 15.023 26.666 -4.991 1.00 72.62 ? ? ? ? ? ? 65 ALA P C 1 65
+ATOM 481 O O . ALA A 1 65 ? 14.969 25.499 -5.379 1.00 73.18 ? ? ? ? ? ? 65 ALA P O 1 65
+ATOM 482 C CB . ALA A 1 65 ? 14.090 27.137 -2.721 1.00 71.97 ? ? ? ? ? ? 65 ALA P CB 1 65
+ATOM 483 N N . THR A 1 66 ? 14.800 27.716 -5.780 1.00 72.37 ? ? ? ? ? ? 66 THR P N 1 66
+ATOM 484 C CA . THR A 1 66 ? 14.475 27.594 -7.201 1.00 71.59 ? ? ? ? ? ? 66 THR P CA 1 66
+ATOM 485 C C . THR A 1 66 ? 15.646 27.000 -7.979 1.00 70.84 ? ? ? ? ? ? 66 THR P C 1 66
+ATOM 486 O O . THR A 1 66 ? 15.458 26.130 -8.831 1.00 69.83 ? ? ? ? ? ? 66 THR P O 1 66
+ATOM 487 C CB . THR A 1 66 ? 14.083 28.966 -7.804 1.00 72.05 ? ? ? ? ? ? 66 THR P CB 1 66
+ATOM 488 O OG1 . THR A 1 66 ? 13.075 29.579 -6.991 1.00 72.70 ? ? ? ? ? ? 66 THR P OG1 1 66
+ATOM 489 C CG2 . THR A 1 66 ? 13.555 28.812 -9.229 1.00 71.59 ? ? ? ? ? ? 66 THR P CG2 1 66
+ATOM 490 N N . ASN A 1 67 ? 16.852 27.471 -7.672 1.00 70.47 ? ? ? ? ? ? 67 ASN P N 1 67
+ATOM 491 C CA . ASN A 1 67 ? 18.058 26.971 -8.319 1.00 70.79 ? ? ? ? ? ? 67 ASN P CA 1 67
+ATOM 492 C C . ASN A 1 67 ? 18.331 25.519 -7.955 1.00 69.83 ? ? ? ? ? ? 67 ASN P C 1 67
+ATOM 493 O O . ASN A 1 67 ? 18.590 24.702 -8.834 1.00 70.19 ? ? ? ? ? ? 67 ASN P O 1 67
+ATOM 494 C CB . ASN A 1 67 ? 19.262 27.854 -7.983 1.00 71.93 ? ? ? ? ? ? 67 ASN P CB 1 67
+ATOM 495 C CG . ASN A 1 67 ? 19.121 29.272 -8.523 1.00 73.48 ? ? ? ? ? ? 67 ASN P CG 1 67
+ATOM 496 O OD1 . ASN A 1 67 ? 18.128 29.618 -9.170 1.00 72.43 ? ? ? ? ? ? 67 ASN P OD1 1 67
+ATOM 497 N ND2 . ASN A 1 67 ? 20.123 30.103 -8.253 1.00 75.22 ? ? ? ? ? ? 67 ASN P ND2 1 67
+ATOM 498 N N . ALA A 1 68 ? 18.239 25.207 -6.662 1.00 69.11 ? ? ? ? ? ? 68 ALA P N 1 68
+ATOM 499 C CA . ALA A 1 68 ? 18.466 23.854 -6.140 1.00 68.14 ? ? ? ? ? ? 68 ALA P CA 1 68
+ATOM 500 C C . ALA A 1 68 ? 17.574 22.801 -6.797 1.00 68.29 ? ? ? ? ? ? 68 ALA P C 1 68
+ATOM 501 O O . ALA A 1 68 ? 18.025 21.692 -7.086 1.00 67.81 ? ? ? ? ? ? 68 ALA P O 1 68
+ATOM 502 C CB . ALA A 1 68 ? 18.282 23.836 -4.629 1.00 67.95 ? ? ? ? ? ? 68 ALA P CB 1 68
+ATOM 503 N N . LEU A 1 69 ? 16.312 23.160 -7.026 1.00 69.27 ? ? ? ? ? ? 69 LEU P N 1 69
+ATOM 504 C CA . LEU A 1 69 ? 15.340 22.281 -7.674 1.00 69.95 ? ? ? ? ? ? 69 LEU P CA 1 69
+ATOM 505 C C . LEU A 1 69 ? 15.719 22.050 -9.130 1.00 71.53 ? ? ? ? ? ? 69 LEU P C 1 69
+ATOM 506 O O . LEU A 1 69 ? 15.865 20.909 -9.568 1.00 72.31 ? ? ? ? ? ? 69 LEU P O 1 69
+ATOM 507 C CB . LEU A 1 69 ? 13.930 22.886 -7.578 1.00 68.95 ? ? ? ? ? ? 69 LEU P CB 1 69
+ATOM 508 C CG . LEU A 1 69 ? 12.708 22.127 -8.115 1.00 68.62 ? ? ? ? ? ? 69 LEU P CG 1 69
+ATOM 509 C CD1 . LEU A 1 69 ? 11.455 22.552 -7.366 1.00 68.96 ? ? ? ? ? ? 69 LEU P CD1 1 69
+ATOM 510 C CD2 . LEU A 1 69 ? 12.511 22.311 -9.617 1.00 68.65 ? ? ? ? ? ? 69 LEU P CD2 1 69
+ATOM 511 N N . ARG A 1 70 ? 15.876 23.145 -9.870 1.00 73.08 ? ? ? ? ? ? 70 ARG P N 1 70
+ATOM 512 C CA . ARG A 1 70 ? 16.155 23.088 -11.298 1.00 74.41 ? ? ? ? ? ? 70 ARG P CA 1 70
+ATOM 513 C C . ARG A 1 70 ? 17.530 22.486 -11.599 1.00 75.37 ? ? ? ? ? ? 70 ARG P C 1 70
+ATOM 514 O O . ARG A 1 70 ? 17.700 21.795 -12.607 1.00 75.39 ? ? ? ? ? ? 70 ARG P O 1 70
+ATOM 515 C CB . ARG A 1 70 ? 15.986 24.477 -11.931 1.00 75.27 ? ? ? ? ? ? 70 ARG P CB 1 70
+ATOM 516 C CG . ARG A 1 70 ? 14.540 24.779 -12.343 1.00 76.61 ? ? ? ? ? ? 70 ARG P CG 1 70
+ATOM 517 C CD . ARG A 1 70 ? 14.132 26.241 -12.128 1.00 78.28 ? ? ? ? ? ? 70 ARG P CD 1 70
+ATOM 518 N NE . ARG A 1 70 ? 14.722 27.167 -13.100 1.00 79.62 ? ? ? ? ? ? 70 ARG P NE 1 70
+ATOM 519 C CZ . ARG A 1 70 ? 14.294 28.411 -13.320 1.00 79.79 ? ? ? ? ? ? 70 ARG P CZ 1 70
+ATOM 520 N NH1 . ARG A 1 70 ? 13.256 28.901 -12.652 1.00 80.16 ? ? ? ? ? ? 70 ARG P NH1 1 70
+ATOM 521 N NH2 . ARG A 1 70 ? 14.902 29.170 -14.221 1.00 80.30 ? ? ? ? ? ? 70 ARG P NH2 1 70
+ATOM 522 N N . SER A 1 71 ? 18.491 22.722 -10.705 1.00 75.79 ? ? ? ? ? ? 71 SER P N 1 71
+ATOM 523 C CA . SER A 1 71 ? 19.872 22.276 -10.908 1.00 76.68 ? ? ? ? ? ? 71 SER P CA 1 71
+ATOM 524 C C . SER A 1 71 ? 20.121 20.816 -10.532 1.00 77.22 ? ? ? ? ? ? 71 SER P C 1 71
+ATOM 525 O O . SER A 1 71 ? 21.059 20.199 -11.042 1.00 78.31 ? ? ? ? ? ? 71 SER P O 1 71
+ATOM 526 C CB . SER A 1 71 ? 20.852 23.173 -10.147 1.00 76.18 ? ? ? ? ? ? 71 SER P CB 1 71
+ATOM 527 O OG . SER A 1 71 ? 20.682 24.535 -10.506 1.00 77.09 ? ? ? ? ? ? 71 SER P OG 1 71
+ATOM 528 N N . MET A 1 72 ? 19.292 20.264 -9.649 1.00 77.19 ? ? ? ? ? ? 72 MET P N 1 72
+ATOM 529 C CA . MET A 1 72 ? 19.538 18.914 -9.136 1.00 76.71 ? ? ? ? ? ? 72 MET P CA 1 72
+ATOM 530 C C . MET A 1 72 ? 18.343 17.947 -9.154 1.00 76.58 ? ? ? ? ? ? 72 MET P C 1 72
+ATOM 531 O O . MET A 1 72 ? 18.313 16.933 -8.359 1.00 75.50 ? ? ? ? ? ? 72 MET P O 1 72
+ATOM 532 C CB . MET A 1 72 ? 20.158 18.976 -7.739 1.00 77.03 ? ? ? ? ? ? 72 MET P CB 1 72
+ATOM 533 C CG . MET A 1 72 ? 21.659 19.136 -7.768 1.00 78.13 ? ? ? ? ? ? 72 MET P CG 1 72
+ATOM 534 S SD . MET A 1 72 ? 22.386 18.963 -6.138 1.00 80.36 ? ? ? ? ? ? 72 MET P SD 1 72
+ATOM 535 C CE . MET A 1 72 ? 24.116 18.765 -6.562 1.00 81.61 ? ? ? ? ? ? 72 MET P CE 1 72
+ATOM 536 N N . GLN A 1 73 ? 17.377 18.244 -10.069 1.00 77.39 ? ? ? ? ? ? 73 GLN P N 1 73
+ATOM 537 C CA . GLN A 1 73 ? 16.236 17.333 -10.223 1.00 78.05 ? ? ? ? ? ? 73 GLN P CA 1 73
+ATOM 538 C C . GLN A 1 73 ? 16.685 16.089 -10.985 1.00 78.05 ? ? ? ? ? ? 73 GLN P C 1 73
+ATOM 539 O O . GLN A 1 73 ? 17.300 16.195 -12.048 1.00 77.97 ? ? ? ? ? ? 73 GLN P O 1 73
+ATOM 540 C CB . GLN A 1 73 ? 15.086 18.020 -10.964 1.00 78.23 ? ? ? ? ? ? 73 GLN P CB 1 73
+ATOM 541 C CG . GLN A 1 73 ? 13.720 17.913 -10.273 1.00 79.31 ? ? ? ? ? ? 73 GLN P CG 1 73
+ATOM 542 C CD . GLN A 1 73 ? 13.085 16.525 -10.335 1.00 79.89 ? ? ? ? ? ? 73 GLN P CD 1 73
+ATOM 543 O OE1 . GLN A 1 73 ? 13.680 15.564 -10.825 1.00 80.91 ? ? ? ? ? ? 73 GLN P OE1 1 73
+ATOM 544 N NE2 . GLN A 1 73 ? 11.861 16.424 -9.833 1.00 80.00 ? ? ? ? ? ? 73 GLN P NE2 1 73
+ATOM 545 N N . GLY A 1 74 ? 16.390 14.916 -10.427 1.00 78.16 ? ? ? ? ? ? 74 GLY P N 1 74
+ATOM 546 C CA . GLY A 1 74 ? 16.762 13.639 -11.042 1.00 78.21 ? ? ? ? ? ? 74 GLY P CA 1 74
+ATOM 547 C C . GLY A 1 74 ? 18.062 13.044 -10.523 1.00 77.68 ? ? ? ? ? ? 74 GLY P C 1 74
+ATOM 548 O O . GLY A 1 74 ? 18.272 11.834 -10.615 1.00 78.32 ? ? ? ? ? ? 74 GLY P O 1 74
+ATOM 549 N N . PHE A 1 75 ? 18.925 13.903 -9.980 1.00 76.74 ? ? ? ? ? ? 75 PHE P N 1 75
+ATOM 550 C CA . PHE A 1 75 ? 20.240 13.526 -9.446 1.00 77.20 ? ? ? ? ? ? 75 PHE P CA 1 75
+ATOM 551 C C . PHE A 1 75 ? 20.203 12.243 -8.600 1.00 76.71 ? ? ? ? ? ? 75 PHE P C 1 75
+ATOM 552 O O . PHE A 1 75 ? 19.464 12.170 -7.614 1.00 75.98 ? ? ? ? ? ? 75 PHE P O 1 75
+ATOM 553 C CB . PHE A 1 75 ? 20.806 14.692 -8.622 1.00 77.88 ? ? ? ? ? ? 75 PHE P CB 1 75
+ATOM 554 C CG . PHE A 1 75 ? 22.297 14.643 -8.417 1.00 79.00 ? ? ? ? ? ? 75 PHE P CG 1 75
+ATOM 555 C CD1 . PHE A 1 75 ? 23.151 15.331 -9.276 1.00 79.61 ? ? ? ? ? ? 75 PHE P CD1 1 75
+ATOM 556 C CD2 . PHE A 1 75 ? 22.848 13.938 -7.349 1.00 79.27 ? ? ? ? ? ? 75 PHE P CD2 1 75
+ATOM 557 C CE1 . PHE A 1 75 ? 24.534 15.303 -9.084 1.00 80.20 ? ? ? ? ? ? 75 PHE P CE1 1 75
+ATOM 558 C CE2 . PHE A 1 75 ? 24.229 13.900 -7.150 1.00 79.39 ? ? ? ? ? ? 75 PHE P CE2 1 75
+ATOM 559 C CZ . PHE A 1 75 ? 25.073 14.585 -8.017 1.00 79.98 ? ? ? ? ? ? 75 PHE P CZ 1 75
+ATOM 560 N N . PRO A 1 76 ? 20.990 11.222 -8.999 1.00 76.70 ? ? ? ? ? ? 76 PRO P N 1 76
+ATOM 561 C CA . PRO A 1 76 ? 21.116 9.972 -8.246 1.00 76.59 ? ? ? ? ? ? 76 PRO P CA 1 76
+ATOM 562 C C . PRO A 1 76 ? 21.790 10.183 -6.891 1.00 75.90 ? ? ? ? ? ? 76 PRO P C 1 76
+ATOM 563 O O . PRO A 1 76 ? 22.881 10.757 -6.815 1.00 75.94 ? ? ? ? ? ? 76 PRO P O 1 76
+ATOM 564 C CB . PRO A 1 76 ? 21.990 9.097 -9.153 1.00 76.82 ? ? ? ? ? ? 76 PRO P CB 1 76
+ATOM 565 C CG . PRO A 1 76 ? 21.821 9.672 -10.511 1.00 77.27 ? ? ? ? ? ? 76 PRO P CG 1 76
+ATOM 566 C CD . PRO A 1 76 ? 21.701 11.145 -10.288 1.00 77.15 ? ? ? ? ? ? 76 PRO P CD 1 76
+ATOM 567 N N . PHE A 1 77 ? 21.129 9.700 -5.841 1.00 74.72 ? ? ? ? ? ? 77 PHE P N 1 77
+ATOM 568 C CA . PHE A 1 77 ? 21.515 9.960 -4.458 1.00 72.57 ? ? ? ? ? ? 77 PHE P CA 1 77
+ATOM 569 C C . PHE A 1 77 ? 21.297 8.693 -3.629 1.00 71.11 ? ? ? ? ? ? 77 PHE P C 1 77
+ATOM 570 O O . PHE A 1 77 ? 20.155 8.282 -3.395 1.00 68.54 ? ? ? ? ? ? 77 PHE P O 1 77
+ATOM 571 C CB . PHE A 1 77 ? 20.676 11.120 -3.918 1.00 72.34 ? ? ? ? ? ? 77 PHE P CB 1 77
+ATOM 572 C CG . PHE A 1 77 ? 21.122 11.635 -2.586 1.00 72.37 ? ? ? ? ? ? 77 PHE P CG 1 77
+ATOM 573 C CD1 . PHE A 1 77 ? 22.336 12.300 -2.451 1.00 72.45 ? ? ? ? ? ? 77 PHE P CD1 1 77
+ATOM 574 C CD2 . PHE A 1 77 ? 20.310 11.486 -1.468 1.00 72.33 ? ? ? ? ? ? 77 PHE P CD2 1 77
+ATOM 575 C CE1 . PHE A 1 77 ? 22.745 12.788 -1.217 1.00 73.06 ? ? ? ? ? ? 77 PHE P CE1 1 77
+ATOM 576 C CE2 . PHE A 1 77 ? 20.707 11.975 -0.231 1.00 73.27 ? ? ? ? ? ? 77 PHE P CE2 1 77
+ATOM 577 C CZ . PHE A 1 77 ? 21.929 12.627 -0.105 1.00 73.40 ? ? ? ? ? ? 77 PHE P CZ 1 77
+ATOM 578 N N . TYR A 1 78 ? 22.401 8.088 -3.190 1.00 69.87 ? ? ? ? ? ? 78 TYR P N 1 78
+ATOM 579 C CA . TYR A 1 78 ? 22.399 6.757 -2.575 1.00 69.55 ? ? ? ? ? ? 78 TYR P CA 1 78
+ATOM 580 C C . TYR A 1 78 ? 21.743 5.741 -3.510 1.00 71.10 ? ? ? ? ? ? 78 TYR P C 1 78
+ATOM 581 O O . TYR A 1 78 ? 20.803 5.042 -3.121 1.00 70.76 ? ? ? ? ? ? 78 TYR P O 1 78
+ATOM 582 C CB . TYR A 1 78 ? 21.700 6.758 -1.209 1.00 67.92 ? ? ? ? ? ? 78 TYR P CB 1 78
+ATOM 583 C CG . TYR A 1 78 ? 22.436 7.489 -0.110 1.00 66.15 ? ? ? ? ? ? 78 TYR P CG 1 78
+ATOM 584 C CD1 . TYR A 1 78 ? 23.514 6.900 0.547 1.00 65.85 ? ? ? ? ? ? 78 TYR P CD1 1 78
+ATOM 585 C CD2 . TYR A 1 78 ? 22.039 8.761 0.291 1.00 65.44 ? ? ? ? ? ? 78 TYR P CD2 1 78
+ATOM 586 C CE1 . TYR A 1 78 ? 24.183 7.566 1.568 1.00 65.00 ? ? ? ? ? ? 78 TYR P CE1 1 78
+ATOM 587 C CE2 . TYR A 1 78 ? 22.706 9.436 1.308 1.00 65.15 ? ? ? ? ? ? 78 TYR P CE2 1 78
+ATOM 588 C CZ . TYR A 1 78 ? 23.777 8.832 1.941 1.00 64.50 ? ? ? ? ? ? 78 TYR P CZ 1 78
+ATOM 589 O OH . TYR A 1 78 ? 24.438 9.492 2.950 1.00 63.15 ? ? ? ? ? ? 78 TYR P OH 1 78
+ATOM 590 N N . ASP A 1 79 ? 22.242 5.689 -4.747 1.00 73.33 ? ? ? ? ? ? 79 ASP P N 1 79
+ATOM 591 C CA . ASP A 1 79 ? 21.730 4.804 -5.808 1.00 74.53 ? ? ? ? ? ? 79 ASP P CA 1 79
+ATOM 592 C C . ASP A 1 79 ? 20.236 5.014 -6.150 1.00 73.85 ? ? ? ? ? ? 79 ASP P C 1 79
+ATOM 593 O O . ASP A 1 79 ? 19.592 4.131 -6.724 1.00 73.76 ? ? ? ? ? ? 79 ASP P O 1 79
+ATOM 594 C CB . ASP A 1 79 ? 22.039 3.328 -5.488 1.00 75.93 ? ? ? ? ? ? 79 ASP P CB 1 79
+ATOM 595 C CG . ASP A 1 79 ? 22.074 2.443 -6.732 1.00 77.34 ? ? ? ? ? ? 79 ASP P CG 1 79
+ATOM 596 O OD1 . ASP A 1 79 ? 22.408 2.944 -7.831 1.00 77.86 ? ? ? ? ? ? 79 ASP P OD1 1 79
+ATOM 597 O OD2 . ASP A 1 79 ? 21.771 1.236 -6.605 1.00 77.54 ? ? ? ? ? ? 79 ASP P OD2 1 79
+ATOM 598 N N . LYS A 1 80 ? 19.696 6.182 -5.803 1.00 73.73 ? ? ? ? ? ? 80 LYS P N 1 80
+ATOM 599 C CA . LYS A 1 80 ? 18.301 6.518 -6.110 1.00 73.49 ? ? ? ? ? ? 80 LYS P CA 1 80
+ATOM 600 C C . LYS A 1 80 ? 18.146 7.961 -6.599 1.00 74.26 ? ? ? ? ? ? 80 LYS P C 1 80
+ATOM 601 O O . LYS A 1 80 ? 18.685 8.886 -5.985 1.00 73.92 ? ? ? ? ? ? 80 LYS P O 1 80
+ATOM 602 C CB . LYS A 1 80 ? 17.389 6.271 -4.903 1.00 72.16 ? ? ? ? ? ? 80 LYS P CB 1 80
+ATOM 603 C CG . LYS A 1 80 ? 16.982 4.816 -4.711 1.00 72.11 ? ? ? ? ? ? 80 LYS P CG 1 80
+ATOM 604 C CD . LYS A 1 80 ? 15.839 4.673 -3.718 1.00 71.48 ? ? ? ? ? ? 80 LYS P CD 1 80
+ATOM 605 C CE . LYS A 1 80 ? 14.502 5.031 -4.348 1.00 71.99 ? ? ? ? ? ? 80 LYS P CE 1 80
+ATOM 606 N NZ . LYS A 1 80 ? 13.403 5.043 -3.345 1.00 73.15 ? ? ? ? ? ? 80 LYS P NZ 1 80
+ATOM 607 N N . PRO A 1 81 ? 17.397 8.156 -7.704 1.00 74.32 ? ? ? ? ? ? 81 PRO P N 1 81
+ATOM 608 C CA . PRO A 1 81 ? 17.201 9.495 -8.254 1.00 73.20 ? ? ? ? ? ? 81 PRO P CA 1 81
+ATOM 609 C C . PRO A 1 81 ? 16.276 10.331 -7.376 1.00 72.45 ? ? ? ? ? ? 81 PRO P C 1 81
+ATOM 610 O O . PRO A 1 81 ? 15.177 9.889 -7.029 1.00 71.86 ? ? ? ? ? ? 81 PRO P O 1 81
+ATOM 611 C CB . PRO A 1 81 ? 16.554 9.225 -9.615 1.00 73.27 ? ? ? ? ? ? 81 PRO P CB 1 81
+ATOM 612 C CG . PRO A 1 81 ? 15.848 7.926 -9.447 1.00 73.64 ? ? ? ? ? ? 81 PRO P CG 1 81
+ATOM 613 C CD . PRO A 1 81 ? 16.650 7.130 -8.459 1.00 74.15 ? ? ? ? ? ? 81 PRO P CD 1 81
+ATOM 614 N N . MET A 1 82 ? 16.734 11.523 -7.009 1.00 72.19 ? ? ? ? ? ? 82 MET P N 1 82
+ATOM 615 C CA . MET A 1 82 ? 15.919 12.453 -6.239 1.00 72.11 ? ? ? ? ? ? 82 MET P CA 1 82
+ATOM 616 C C . MET A 1 82 ? 14.759 12.967 -7.083 1.00 72.34 ? ? ? ? ? ? 82 MET P C 1 82
+ATOM 617 O O . MET A 1 82 ? 14.875 13.085 -8.305 1.00 72.60 ? ? ? ? ? ? 82 MET P O 1 82
+ATOM 618 C CB . MET A 1 82 ? 16.769 13.620 -5.733 1.00 71.74 ? ? ? ? ? ? 82 MET P CB 1 82
+ATOM 619 C CG . MET A 1 82 ? 17.663 13.272 -4.551 1.00 71.59 ? ? ? ? ? ? 82 MET P CG 1 82
+ATOM 620 S SD . MET A 1 82 ? 18.623 14.674 -3.937 1.00 71.26 ? ? ? ? ? ? 82 MET P SD 1 82
+ATOM 621 C CE . MET A 1 82 ? 20.010 14.674 -5.066 1.00 71.25 ? ? ? ? ? ? 82 MET P CE 1 82
+ATOM 622 N N . ARG A 1 83 ? 13.635 13.249 -6.430 1.00 72.88 ? ? ? ? ? ? 83 ARG P N 1 83
+ATOM 623 C CA . ARG A 1 83 ? 12.481 13.836 -7.103 1.00 74.28 ? ? ? ? ? ? 83 ARG P CA 1 83
+ATOM 624 C C . ARG A 1 83 ? 12.070 15.115 -6.384 1.00 73.25 ? ? ? ? ? ? 83 ARG P C 1 83
+ATOM 625 O O . ARG A 1 83 ? 11.290 15.089 -5.429 1.00 74.77 ? ? ? ? ? ? 83 ARG P O 1 83
+ATOM 626 C CB . ARG A 1 83 ? 11.314 12.840 -7.184 1.00 77.26 ? ? ? ? ? ? 83 ARG P CB 1 83
+ATOM 627 C CG . ARG A 1 83 ? 11.616 11.564 -7.975 1.00 80.64 ? ? ? ? ? ? 83 ARG P CG 1 83
+ATOM 628 C CD . ARG A 1 83 ? 11.611 11.798 -9.487 1.00 82.60 ? ? ? ? ? ? 83 ARG P CD 1 83
+ATOM 629 N NE . ARG A 1 83 ? 12.506 10.879 -10.193 1.00 84.36 ? ? ? ? ? ? 83 ARG P NE 1 83
+ATOM 630 C CZ . ARG A 1 83 ? 12.192 9.637 -10.559 1.00 85.59 ? ? ? ? ? ? 83 ARG P CZ 1 83
+ATOM 631 N NH1 . ARG A 1 83 ? 10.994 9.129 -10.292 1.00 85.97 ? ? ? ? ? ? 83 ARG P NH1 1 83
+ATOM 632 N NH2 . ARG A 1 83 ? 13.087 8.893 -11.197 1.00 85.96 ? ? ? ? ? ? 83 ARG P NH2 1 83
+ATOM 633 N N . ILE A 1 84 ? 12.614 16.234 -6.848 1.00 70.68 ? ? ? ? ? ? 84 ILE P N 1 84
+ATOM 634 C CA . ILE A 1 84 ? 12.389 17.524 -6.207 1.00 68.59 ? ? ? ? ? ? 84 ILE P CA 1 84
+ATOM 635 C C . ILE A 1 84 ? 11.180 18.243 -6.802 1.00 68.25 ? ? ? ? ? ? 84 ILE P C 1 84
+ATOM 636 O O . ILE A 1 84 ? 11.027 18.329 -8.021 1.00 68.71 ? ? ? ? ? ? 84 ILE P O 1 84
+ATOM 637 C CB . ILE A 1 84 ? 13.643 18.437 -6.297 1.00 68.14 ? ? ? ? ? ? 84 ILE P CB 1 84
+ATOM 638 C CG1 . ILE A 1 84 ? 14.920 17.630 -6.026 1.00 67.86 ? ? ? ? ? ? 84 ILE P CG1 1 84
+ATOM 639 C CG2 . ILE A 1 84 ? 13.520 19.619 -5.329 1.00 68.05 ? ? ? ? ? ? 84 ILE P CG2 1 84
+ATOM 640 C CD1 . ILE A 1 84 ? 16.214 18.332 -6.419 1.00 67.21 ? ? ? ? ? ? 84 ILE P CD1 1 84
+ATOM 641 N N . GLN A 1 85 ? 10.319 18.734 -5.919 1.00 68.10 ? ? ? ? ? ? 85 GLN P N 1 85
+ATOM 642 C CA . GLN A 1 85 ? 9.235 19.639 -6.281 1.00 69.41 ? ? ? ? ? ? 85 GLN P CA 1 85
+ATOM 643 C C . GLN A 1 85 ? 9.021 20.614 -5.123 1.00 70.51 ? ? ? ? ? ? 85 GLN P C 1 85
+ATOM 644 O O . GLN A 1 85 ? 9.499 20.373 -4.015 1.00 71.01 ? ? ? ? ? ? 85 GLN P O 1 85
+ATOM 645 C CB . GLN A 1 85 ? 7.950 18.867 -6.612 1.00 69.26 ? ? ? ? ? ? 85 GLN P CB 1 85
+ATOM 646 C CG . GLN A 1 85 ? 7.436 17.958 -5.495 1.00 69.64 ? ? ? ? ? ? 85 GLN P CG 1 85
+ATOM 647 C CD . GLN A 1 85 ? 6.210 17.141 -5.888 1.00 68.19 ? ? ? ? ? ? 85 GLN P CD 1 85
+ATOM 648 O OE1 . GLN A 1 85 ? 5.755 16.289 -5.123 1.00 66.95 ? ? ? ? ? ? 85 GLN P OE1 1 85
+ATOM 649 N NE2 . GLN A 1 85 ? 5.671 17.398 -7.074 1.00 67.51 ? ? ? ? ? ? 85 GLN P NE2 1 85
+ATOM 650 N N . TYR A 1 86 ? 8.322 21.716 -5.380 1.00 71.54 ? ? ? ? ? ? 86 TYR P N 1 86
+ATOM 651 C CA . TYR A 1 86 ? 8.063 22.717 -4.347 1.00 72.64 ? ? ? ? ? ? 86 TYR P CA 1 86
+ATOM 652 C C . TYR A 1 86 ? 7.132 22.208 -3.252 1.00 73.71 ? ? ? ? ? ? 86 TYR P C 1 86
+ATOM 653 O O . TYR A 1 86 ? 6.305 21.319 -3.484 1.00 73.77 ? ? ? ? ? ? 86 TYR P O 1 86
+ATOM 654 C CB . TYR A 1 86 ? 7.464 23.985 -4.959 1.00 74.07 ? ? ? ? ? ? 86 TYR P CB 1 86
+ATOM 655 C CG . TYR A 1 86 ? 8.466 24.894 -5.629 1.00 74.93 ? ? ? ? ? ? 86 TYR P CG 1 86
+ATOM 656 C CD1 . TYR A 1 86 ? 9.476 25.515 -4.893 1.00 75.09 ? ? ? ? ? ? 86 TYR P CD1 1 86
+ATOM 657 C CD2 . TYR A 1 86 ? 8.393 25.150 -6.997 1.00 75.01 ? ? ? ? ? ? 86 TYR P CD2 1 86
+ATOM 658 C CE1 . TYR A 1 86 ? 10.394 26.355 -5.503 1.00 75.42 ? ? ? ? ? ? 86 TYR P CE1 1 86
+ATOM 659 C CE2 . TYR A 1 86 ? 9.305 25.988 -7.617 1.00 76.04 ? ? ? ? ? ? 86 TYR P CE2 1 86
+ATOM 660 C CZ . TYR A 1 86 ? 10.302 26.587 -6.864 1.00 76.45 ? ? ? ? ? ? 86 TYR P CZ 1 86
+ATOM 661 O OH . TYR A 1 86 ? 11.207 27.420 -7.474 1.00 77.07 ? ? ? ? ? ? 86 TYR P OH 1 86
+ATOM 662 N N . ALA A 1 87 ? 7.278 22.779 -2.059 1.00 73.67 ? ? ? ? ? ? 87 ALA P N 1 87
+ATOM 663 C CA . ALA A 1 87 ? 6.354 22.531 -0.962 1.00 74.48 ? ? ? ? ? ? 87 ALA P CA 1 87
+ATOM 664 C C . ALA A 1 87 ? 5.014 23.200 -1.264 1.00 75.95 ? ? ? ? ? ? 87 ALA P C 1 87
+ATOM 665 O O . ALA A 1 87 ? 4.978 24.268 -1.889 1.00 76.31 ? ? ? ? ? ? 87 ALA P O 1 87
+ATOM 666 C CB . ALA A 1 87 ? 6.931 23.055 0.342 1.00 74.00 ? ? ? ? ? ? 87 ALA P CB 1 87
+ATOM 667 N N . LYS A 1 88 ? 3.919 22.560 -0.828 1.00 78.69 ? ? ? ? ? ? 88 LYS P N 1 88
+ATOM 668 C CA . LYS A 1 88 ? 2.572 23.092 -1.037 1.00 80.61 ? ? ? ? ? ? 88 LYS P CA 1 88
+ATOM 669 C C . LYS A 1 88 ? 2.330 24.286 -0.122 1.00 82.43 ? ? ? ? ? ? 88 LYS P C 1 88
+ATOM 670 O O . LYS A 1 88 ? 1.979 25.389 -0.583 1.00 81.29 ? ? ? ? ? ? 88 LYS P O 1 88
+ATOM 671 C CB . LYS A 1 88 ? 1.525 22.013 -0.748 1.00 81.34 ? ? ? ? ? ? 88 LYS P CB 1 88
+ATOM 672 C CG . LYS A 1 88 ? 1.591 20.802 -1.669 1.00 82.53 ? ? ? ? ? ? 88 LYS P CG 1 88
+ATOM 673 C CD . LYS A 1 88 ? 0.630 19.716 -1.206 1.00 82.77 ? ? ? ? ? ? 88 LYS P CD 1 88
+ATOM 674 C CE . LYS A 1 88 ? 0.687 18.501 -2.122 1.00 83.16 ? ? ? ? ? ? 88 LYS P CE 1 88
+ATOM 675 N NZ . LYS A 1 88 ? -0.109 17.366 -1.577 1.00 83.03 ? ? ? ? ? ? 88 LYS P NZ 1 88
+ATOM 676 N N . THR A 1 89 ? 2.532 24.035 1.184 1.00 86.65 ? ? ? ? ? ? 89 THR P N 1 89
+ATOM 677 C CA . THR A 1 89 ? 2.326 25.040 2.223 1.00 91.29 ? ? ? ? ? ? 89 THR P CA 1 89
+ATOM 678 C C . THR A 1 89 ? 3.624 25.012 3.064 1.00 93.56 ? ? ? ? ? ? 89 THR P C 1 89
+ATOM 679 O O . THR A 1 89 ? 4.263 23.915 3.201 1.00 95.63 ? ? ? ? ? ? 89 THR P O 1 89
+ATOM 680 C CB . THR A 1 89 ? 1.170 24.605 3.188 1.00 91.85 ? ? ? ? ? ? 89 THR P CB 1 89
+ATOM 681 O OG1 . THR A 1 89 ? 1.659 23.561 4.098 1.00 92.96 ? ? ? ? ? ? 89 THR P OG1 1 89
+ATOM 682 C CG2 . THR A 1 89 ? -0.048 24.085 2.409 1.00 91.80 ? ? ? ? ? ? 89 THR P CG2 1 89
+ATOM 683 N N . ASP A 1 90 ? 4.015 26.200 3.638 1.00 94.83 ? ? ? ? ? ? 90 ASP P N 1 90
+ATOM 684 C CA . ASP A 1 90 ? 5.263 26.232 4.415 1.00 96.77 ? ? ? ? ? ? 90 ASP P CA 1 90
+ATOM 685 C C . ASP A 1 90 ? 5.010 26.968 5.761 1.00 96.82 ? ? ? ? ? ? 90 ASP P C 1 90
+ATOM 686 O O . ASP A 1 90 ? 4.706 28.166 5.811 1.00 97.65 ? ? ? ? ? ? 90 ASP P O 1 90
+ATOM 687 C CB . ASP A 1 90 ? 6.318 27.053 3.601 1.00 98.64 ? ? ? ? ? ? 90 ASP P CB 1 90
+ATOM 688 C CG . ASP A 1 90 ? 7.490 27.588 4.452 1.00 100.17 ? ? ? ? ? ? 90 ASP P CG 1 90
+ATOM 689 O OD1 . ASP A 1 90 ? 8.159 26.774 5.157 1.00 100.67 ? ? ? ? ? ? 90 ASP P OD1 1 90
+ATOM 690 O OD2 . ASP A 1 90 ? 7.750 28.827 4.396 1.00 101.43 ? ? ? ? ? ? 90 ASP P OD2 1 90
+ATOM 691 N N . SER A 1 91 ? 5.112 26.167 6.846 1.00 96.55 ? ? ? ? ? ? 91 SER P N 1 91
+ATOM 692 C CA . SER A 1 91 ? 5.073 26.712 8.219 1.00 96.88 ? ? ? ? ? ? 91 SER P CA 1 91
+ATOM 693 C C . SER A 1 91 ? 6.514 27.054 8.624 1.00 96.62 ? ? ? ? ? ? 91 SER P C 1 91
+ATOM 694 O O . SER A 1 91 ? 7.505 26.742 7.859 1.00 96.50 ? ? ? ? ? ? 91 SER P O 1 91
+ATOM 695 C CB . SER A 1 91 ? 4.458 25.701 9.201 1.00 97.01 ? ? ? ? ? ? 91 SER P CB 1 91
+ATOM 696 O OG . SER A 1 91 ? 4.501 26.191 10.550 1.00 96.14 ? ? ? ? ? ? 91 SER P OG 1 91
+ATOM 697 N N . ASP A 1 92 ? 6.617 27.687 9.827 1.00 96.09 ? ? ? ? ? ? 92 ASP P N 1 92
+ATOM 698 C CA . ASP A 1 92 ? 7.916 28.243 10.265 1.00 96.41 ? ? ? ? ? ? 92 ASP P CA 1 92
+ATOM 699 C C . ASP A 1 92 ? 8.195 29.522 9.462 1.00 97.21 ? ? ? ? ? ? 92 ASP P C 1 92
+ATOM 700 O O . ASP A 1 92 ? 7.266 30.141 8.927 1.00 97.34 ? ? ? ? ? ? 92 ASP P O 1 92
+ATOM 701 C CB . ASP A 1 92 ? 9.045 27.210 10.088 1.00 96.12 ? ? ? ? ? ? 92 ASP P CB 1 92
+ATOM 702 C CG . ASP A 1 92 ? 10.218 27.458 11.014 1.00 96.39 ? ? ? ? ? ? 92 ASP P CG 1 92
+ATOM 703 O OD1 . ASP A 1 92 ? 10.147 27.037 12.188 1.00 96.84 ? ? ? ? ? ? 92 ASP P OD1 1 92
+ATOM 704 O OD2 . ASP A 1 92 ? 11.215 28.064 10.564 1.00 96.10 ? ? ? ? ? ? 92 ASP P OD2 1 92
+ATOM 705 N N . ILE A 1 93 ? 9.465 29.912 9.378 1.00 97.36 ? ? ? ? ? ? 93 ILE P N 1 93
+ATOM 706 C CA . ILE A 1 93 ? 9.858 31.124 8.662 1.00 97.66 ? ? ? ? ? ? 93 ILE P CA 1 93
+ATOM 707 C C . ILE A 1 93 ? 10.452 30.788 7.287 1.00 96.98 ? ? ? ? ? ? 93 ILE P C 1 93
+ATOM 708 O O . ILE A 1 93 ? 9.720 30.563 6.320 1.00 94.99 ? ? ? ? ? ? 93 ILE P O 1 93
+ATOM 709 C CB . ILE A 1 93 ? 10.845 31.970 9.507 1.00 98.20 ? ? ? ? ? ? 93 ILE P CB 1 93
+ATOM 710 C CG1 . ILE A 1 93 ? 10.111 32.605 10.695 1.00 98.87 ? ? ? ? ? ? 93 ILE P CG1 1 93
+ATOM 711 C CG2 . ILE A 1 93 ? 11.518 33.037 8.657 1.00 97.94 ? ? ? ? ? ? 93 ILE P CG2 1 93
+ATOM 712 C CD1 . ILE A 1 93 ? 11.016 33.035 11.843 1.00 99.64 ? ? ? ? ? ? 93 ILE P CD1 1 93
+ATOM 713 P PG . GTP B 2 1 ? 0.140 -8.175 68.585 1.00 101.58 ? ? ? ? ? ? 8 GTP R PG 1 1
+ATOM 714 O O1G . GTP B 2 1 ? 0.190 -6.803 67.948 1.00 101.50 ? ? ? ? ? ? 8 GTP R O1G 1 1
+ATOM 715 O O2G . GTP B 2 1 ? 1.348 -8.374 69.479 1.00 101.57 ? ? ? ? ? ? 8 GTP R O2G 1 1
+ATOM 716 O O3G . GTP B 2 1 ? -1.133 -8.320 69.389 1.00 101.02 ? ? ? ? ? ? 8 GTP R O3G 1 1
+ATOM 717 O O3B . GTP B 2 1 ? 0.173 -9.259 67.393 1.00 99.61 ? ? ? ? ? ? 8 GTP R O3B 1 1
+ATOM 718 P PB . GTP B 2 1 ? -0.723 -10.597 67.460 1.00 98.43 ? ? ? ? ? ? 8 GTP R PB 1 1
+ATOM 719 O O1B . GTP B 2 1 ? -2.146 -10.275 67.056 1.00 97.77 ? ? ? ? ? ? 8 GTP R O1B 1 1
+ATOM 720 O O2B . GTP B 2 1 ? -0.672 -11.233 68.832 1.00 98.31 ? ? ? ? ? ? 8 GTP R O2B 1 1
+ATOM 721 O O3A . GTP B 2 1 ? -0.024 -11.546 66.359 1.00 94.67 ? ? ? ? ? ? 8 GTP R O3A 1 1
+ATOM 722 P PA . GTP B 2 1 ? 1.557 -11.859 66.400 1.00 90.76 ? ? ? ? ? ? 8 GTP R PA 1 1
+ATOM 723 O O1A . GTP B 2 1 ? 2.175 -11.300 67.662 1.00 90.52 ? ? ? ? ? ? 8 GTP R O1A 1 1
+ATOM 724 O O2A . GTP B 2 1 ? 2.255 -11.317 65.173 1.00 90.62 ? ? ? ? ? ? 8 GTP R O2A 1 1
+ATOM 725 O "O5'" . GTP B 2 1 ? 1.598 -13.469 66.440 1.00 86.77 ? ? ? ? ? ? 8 GTP R "O5'" 1 1
+ATOM 726 C "C5'" . GTP B 2 1 ? 1.644 -14.206 65.241 1.00 80.20 ? ? ? ? ? ? 8 GTP R "C5'" 1 1
+ATOM 727 C "C4'" . GTP B 2 1 ? 0.775 -15.458 65.309 1.00 75.66 ? ? ? ? ? ? 8 GTP R "C4'" 1 1
+ATOM 728 O "O4'" . GTP B 2 1 ? -0.224 -15.412 66.315 1.00 73.25 ? ? ? ? ? ? 8 GTP R "O4'" 1 1
+ATOM 729 C "C3'" . GTP B 2 1 ? 0.001 -15.623 64.018 1.00 73.91 ? ? ? ? ? ? 8 GTP R "C3'" 1 1
+ATOM 730 O "O3'" . GTP B 2 1 ? 0.769 -16.223 63.006 1.00 72.21 ? ? ? ? ? ? 8 GTP R "O3'" 1 1
+ATOM 731 C "C2'" . GTP B 2 1 ? -1.219 -16.416 64.424 1.00 72.23 ? ? ? ? ? ? 8 GTP R "C2'" 1 1
+ATOM 732 O "O2'" . GTP B 2 1 ? -0.928 -17.795 64.430 1.00 72.32 ? ? ? ? ? ? 8 GTP R "O2'" 1 1
+ATOM 733 C "C1'" . GTP B 2 1 ? -1.470 -15.916 65.840 1.00 69.93 ? ? ? ? ? ? 8 GTP R "C1'" 1 1
+ATOM 734 N N9 . GTP B 2 1 ? -2.500 -14.842 65.861 1.00 65.33 ? ? ? ? ? ? 8 GTP R N9 1 1
+ATOM 735 C C8 . GTP B 2 1 ? -2.371 -13.634 66.502 1.00 64.07 ? ? ? ? ? ? 8 GTP R C8 1 1
+ATOM 736 N N7 . GTP B 2 1 ? -3.492 -12.901 66.320 1.00 60.73 ? ? ? ? ? ? 8 GTP R N7 1 1
+ATOM 737 C C5 . GTP B 2 1 ? -4.351 -13.619 65.569 1.00 59.04 ? ? ? ? ? ? 8 GTP R C5 1 1
+ATOM 738 C C6 . GTP B 2 1 ? -5.628 -13.335 65.099 1.00 56.79 ? ? ? ? ? ? 8 GTP R C6 1 1
+ATOM 739 O O6 . GTP B 2 1 ? -6.156 -12.258 65.364 1.00 55.11 ? ? ? ? ? ? 8 GTP R O6 1 1
+ATOM 740 N N1 . GTP B 2 1 ? -6.300 -14.269 64.337 1.00 55.42 ? ? ? ? ? ? 8 GTP R N1 1 1
+ATOM 741 C C2 . GTP B 2 1 ? -5.696 -15.476 64.046 1.00 56.18 ? ? ? ? ? ? 8 GTP R C2 1 1
+ATOM 742 N N2 . GTP B 2 1 ? -6.339 -16.375 63.311 1.00 54.79 ? ? ? ? ? ? 8 GTP R N2 1 1
+ATOM 743 N N3 . GTP B 2 1 ? -4.423 -15.752 64.517 1.00 58.75 ? ? ? ? ? ? 8 GTP R N3 1 1
+ATOM 744 C C4 . GTP B 2 1 ? -3.751 -14.841 65.272 1.00 61.17 ? ? ? ? ? ? 8 GTP R C4 1 1
+ATOM 745 P P . G B 2 2 ? 1.092 -15.405 61.669 1.00 71.32 ? ? ? ? ? ? 9 G R P 1 2
+ATOM 746 O OP1 . G B 2 2 ? 2.304 -16.004 61.050 1.00 71.77 ? ? ? ? ? ? 9 G R OP1 1 2
+ATOM 747 O OP2 . G B 2 2 ? 1.080 -13.952 62.005 1.00 70.00 ? ? ? ? ? ? 9 G R OP2 1 2
+ATOM 748 O "O5'" . G B 2 2 ? -0.185 -15.699 60.753 1.00 68.84 ? ? ? ? ? ? 9 G R "O5'" 1 2
+ATOM 749 C "C5'" . G B 2 2 ? -0.533 -17.036 60.402 1.00 66.18 ? ? ? ? ? ? 9 G R "C5'" 1 2
+ATOM 750 C "C4'" . G B 2 2 ? -1.948 -17.101 59.859 1.00 63.74 ? ? ? ? ? ? 9 G R "C4'" 1 2
+ATOM 751 O "O4'" . G B 2 2 ? -2.894 -16.771 60.907 1.00 62.47 ? ? ? ? ? ? 9 G R "O4'" 1 2
+ATOM 752 C "C3'" . G B 2 2 ? -2.285 -16.078 58.784 1.00 62.80 ? ? ? ? ? ? 9 G R "C3'" 1 2
+ATOM 753 O "O3'" . G B 2 2 ? -1.756 -16.429 57.509 1.00 61.79 ? ? ? ? ? ? 9 G R "O3'" 1 2
+ATOM 754 C "C2'" . G B 2 2 ? -3.807 -16.126 58.818 1.00 61.27 ? ? ? ? ? ? 9 G R "C2'" 1 2
+ATOM 755 O "O2'" . G B 2 2 ? -4.345 -17.255 58.154 1.00 62.11 ? ? ? ? ? ? 9 G R "O2'" 1 2
+ATOM 756 C "C1'" . G B 2 2 ? -4.058 -16.199 60.324 1.00 59.67 ? ? ? ? ? ? 9 G R "C1'" 1 2
+ATOM 757 N N9 . G B 2 2 ? -4.368 -14.890 60.915 1.00 55.85 ? ? ? ? ? ? 9 G R N9 1 2
+ATOM 758 C C8 . G B 2 2 ? -3.600 -14.131 61.770 1.00 54.67 ? ? ? ? ? ? 9 G R C8 1 2
+ATOM 759 N N7 . G B 2 2 ? -4.161 -13.003 62.124 1.00 52.55 ? ? ? ? ? ? 9 G R N7 1 2
+ATOM 760 C C5 . G B 2 2 ? -5.381 -13.006 61.462 1.00 52.49 ? ? ? ? ? ? 9 G R C5 1 2
+ATOM 761 C C6 . G B 2 2 ? -6.431 -12.048 61.449 1.00 52.41 ? ? ? ? ? ? 9 G R C6 1 2
+ATOM 762 O O6 . G B 2 2 ? -6.502 -10.961 62.040 1.00 52.44 ? ? ? ? ? ? 9 G R O6 1 2
+ATOM 763 N N1 . G B 2 2 ? -7.495 -12.447 60.641 1.00 53.56 ? ? ? ? ? ? 9 G R N1 1 2
+ATOM 764 C C2 . G B 2 2 ? -7.543 -13.626 59.928 1.00 53.90 ? ? ? ? ? ? 9 G R C2 1 2
+ATOM 765 N N2 . G B 2 2 ? -8.649 -13.846 59.200 1.00 54.28 ? ? ? ? ? ? 9 G R N2 1 2
+ATOM 766 N N3 . G B 2 2 ? -6.570 -14.531 59.932 1.00 53.24 ? ? ? ? ? ? 9 G R N3 1 2
+ATOM 767 C C4 . G B 2 2 ? -5.522 -14.160 60.716 1.00 54.04 ? ? ? ? ? ? 9 G R C4 1 2
+ATOM 768 P P . U B 2 3 ? -1.279 -15.272 56.506 1.00 62.06 ? ? ? ? ? ? 10 U R P 1 3
+ATOM 769 O OP1 . U B 2 3 ? -0.780 -15.928 55.276 1.00 62.31 ? ? ? ? ? ? 10 U R OP1 1 3
+ATOM 770 O OP2 . U B 2 3 ? -0.389 -14.352 57.253 1.00 60.55 ? ? ? ? ? ? 10 U R OP2 1 3
+ATOM 771 O "O5'" . U B 2 3 ? -2.635 -14.489 56.154 1.00 59.94 ? ? ? ? ? ? 10 U R "O5'" 1 3
+ATOM 772 C "C5'" . U B 2 3 ? -3.637 -15.118 55.355 1.00 57.27 ? ? ? ? ? ? 10 U R "C5'" 1 3
+ATOM 773 C "C4'" . U B 2 3 ? -4.939 -14.343 55.380 1.00 56.27 ? ? ? ? ? ? 10 U R "C4'" 1 3
+ATOM 774 O "O4'" . U B 2 3 ? -5.333 -14.033 56.736 1.00 55.10 ? ? ? ? ? ? 10 U R "O4'" 1 3
+ATOM 775 C "C3'" . U B 2 3 ? -4.857 -12.979 54.725 1.00 57.13 ? ? ? ? ? ? 10 U R "C3'" 1 3
+ATOM 776 O "O3'" . U B 2 3 ? -4.968 -13.123 53.326 1.00 59.57 ? ? ? ? ? ? 10 U R "O3'" 1 3
+ATOM 777 C "C2'" . U B 2 3 ? -6.042 -12.242 55.344 1.00 55.44 ? ? ? ? ? ? 10 U R "C2'" 1 3
+ATOM 778 O "O2'" . U B 2 3 ? -7.281 -12.463 54.696 1.00 53.73 ? ? ? ? ? ? 10 U R "O2'" 1 3
+ATOM 779 C "C1'" . U B 2 3 ? -6.059 -12.812 56.759 1.00 53.94 ? ? ? ? ? ? 10 U R "C1'" 1 3
+ATOM 780 N N1 . U B 2 3 ? -5.456 -11.869 57.759 1.00 52.28 ? ? ? ? ? ? 10 U R N1 1 3
+ATOM 781 C C2 . U B 2 3 ? -6.149 -10.727 58.134 1.00 52.45 ? ? ? ? ? ? 10 U R C2 1 3
+ATOM 782 O O2 . U B 2 3 ? -7.251 -10.412 57.707 1.00 52.60 ? ? ? ? ? ? 10 U R O2 1 3
+ATOM 783 N N3 . U B 2 3 ? -5.493 -9.942 59.053 1.00 53.37 ? ? ? ? ? ? 10 U R N3 1 3
+ATOM 784 C C4 . U B 2 3 ? -4.249 -10.164 59.625 1.00 52.82 ? ? ? ? ? ? 10 U R C4 1 3
+ATOM 785 O O4 . U B 2 3 ? -3.807 -9.356 60.435 1.00 53.67 ? ? ? ? ? ? 10 U R O4 1 3
+ATOM 786 C C5 . U B 2 3 ? -3.584 -11.365 59.185 1.00 52.33 ? ? ? ? ? ? 10 U R C5 1 3
+ATOM 787 C C6 . U B 2 3 ? -4.203 -12.150 58.290 1.00 52.89 ? ? ? ? ? ? 10 U R C6 1 3
+ATOM 788 P P . C B 2 4 ? -4.133 -12.159 52.363 1.00 60.71 ? ? ? ? ? ? 11 C R P 1 4
+ATOM 789 O OP1 . C B 2 4 ? -4.286 -12.712 50.998 1.00 62.71 ? ? ? ? ? ? 11 C R OP1 1 4
+ATOM 790 O OP2 . C B 2 4 ? -2.776 -11.967 52.927 1.00 60.68 ? ? ? ? ? ? 11 C R OP2 1 4
+ATOM 791 O "O5'" . C B 2 4 ? -4.924 -10.770 52.473 1.00 60.32 ? ? ? ? ? ? 11 C R "O5'" 1 4
+ATOM 792 C "C5'" . C B 2 4 ? -6.256 -10.666 51.967 1.00 61.90 ? ? ? ? ? ? 11 C R "C5'" 1 4
+ATOM 793 C "C4'" . C B 2 4 ? -6.934 -9.390 52.428 1.00 62.56 ? ? ? ? ? ? 11 C R "C4'" 1 4
+ATOM 794 O "O4'" . C B 2 4 ? -7.099 -9.397 53.869 1.00 63.94 ? ? ? ? ? ? 11 C R "O4'" 1 4
+ATOM 795 C "C3'" . C B 2 4 ? -6.141 -8.119 52.178 1.00 63.04 ? ? ? ? ? ? 11 C R "C3'" 1 4
+ATOM 796 O "O3'" . C B 2 4 ? -6.256 -7.704 50.829 1.00 63.93 ? ? ? ? ? ? 11 C R "O3'" 1 4
+ATOM 797 C "C2'" . C B 2 4 ? -6.797 -7.155 53.162 1.00 62.84 ? ? ? ? ? ? 11 C R "C2'" 1 4
+ATOM 798 O "O2'" . C B 2 4 ? -8.042 -6.646 52.723 1.00 63.83 ? ? ? ? ? ? 11 C R "O2'" 1 4
+ATOM 799 C "C1'" . C B 2 4 ? -6.997 -8.068 54.368 1.00 62.60 ? ? ? ? ? ? 11 C R "C1'" 1 4
+ATOM 800 N N1 . C B 2 4 ? -5.895 -7.954 55.398 1.00 60.84 ? ? ? ? ? ? 11 C R N1 1 4
+ATOM 801 C C2 . C B 2 4 ? -5.949 -6.942 56.380 1.00 60.62 ? ? ? ? ? ? 11 C R C2 1 4
+ATOM 802 O O2 . C B 2 4 ? -6.898 -6.143 56.400 1.00 59.51 ? ? ? ? ? ? 11 C R O2 1 4
+ATOM 803 N N3 . C B 2 4 ? -4.944 -6.861 57.296 1.00 59.87 ? ? ? ? ? ? 11 C R N3 1 4
+ATOM 804 C C4 . C B 2 4 ? -3.924 -7.728 57.258 1.00 59.87 ? ? ? ? ? ? 11 C R C4 1 4
+ATOM 805 N N4 . C B 2 4 ? -2.961 -7.608 58.177 1.00 59.50 ? ? ? ? ? ? 11 C R N4 1 4
+ATOM 806 C C5 . C B 2 4 ? -3.846 -8.758 56.273 1.00 60.06 ? ? ? ? ? ? 11 C R C5 1 4
+ATOM 807 C C6 . C B 2 4 ? -4.840 -8.831 55.377 1.00 59.96 ? ? ? ? ? ? 11 C R C6 1 4
+ATOM 808 P P . A B 2 5 ? -5.012 -7.004 50.105 1.00 64.89 ? ? ? ? ? ? 12 A R P 1 5
+ATOM 809 O OP1 . A B 2 5 ? -5.176 -7.271 48.659 1.00 65.68 ? ? ? ? ? ? 12 A R OP1 1 5
+ATOM 810 O OP2 . A B 2 5 ? -3.751 -7.410 50.776 1.00 63.68 ? ? ? ? ? ? 12 A R OP2 1 5
+ATOM 811 O "O5'" . A B 2 5 ? -5.276 -5.446 50.393 1.00 63.76 ? ? ? ? ? ? 12 A R "O5'" 1 5
+ATOM 812 C "C5'" . A B 2 5 ? -4.347 -4.657 51.146 1.00 62.34 ? ? ? ? ? ? 12 A R "C5'" 1 5
+ATOM 813 C "C4'" . A B 2 5 ? -5.064 -3.579 51.943 1.00 61.88 ? ? ? ? ? ? 12 A R "C4'" 1 5
+ATOM 814 O "O4'" . A B 2 5 ? -5.574 -4.128 53.190 1.00 60.71 ? ? ? ? ? ? 12 A R "O4'" 1 5
+ATOM 815 C "C3'" . A B 2 5 ? -4.192 -2.402 52.357 1.00 61.61 ? ? ? ? ? ? 12 A R "C3'" 1 5
+ATOM 816 O "O3'" . A B 2 5 ? -4.270 -1.384 51.377 1.00 63.11 ? ? ? ? ? ? 12 A R "O3'" 1 5
+ATOM 817 C "C2'" . A B 2 5 ? -4.844 -1.962 53.664 1.00 61.04 ? ? ? ? ? ? 12 A R "C2'" 1 5
+ATOM 818 O "O2'" . A B 2 5 ? -6.018 -1.200 53.455 1.00 62.36 ? ? ? ? ? ? 12 A R "O2'" 1 5
+ATOM 819 C "C1'" . A B 2 5 ? -5.202 -3.306 54.285 1.00 58.98 ? ? ? ? ? ? 12 A R "C1'" 1 5
+ATOM 820 N N9 . A B 2 5 ? -4.097 -3.929 55.022 1.00 56.09 ? ? ? ? ? ? 12 A R N9 1 5
+ATOM 821 C C8 . A B 2 5 ? -3.455 -5.097 54.707 1.00 54.04 ? ? ? ? ? ? 12 A R C8 1 5
+ATOM 822 N N7 . A B 2 5 ? -2.496 -5.424 55.538 1.00 53.37 ? ? ? ? ? ? 12 A R N7 1 5
+ATOM 823 C C5 . A B 2 5 ? -2.501 -4.402 56.470 1.00 52.28 ? ? ? ? ? ? 12 A R C5 1 5
+ATOM 824 C C6 . A B 2 5 ? -1.714 -4.160 57.618 1.00 50.30 ? ? ? ? ? ? 12 A R C6 1 5
+ATOM 825 N N6 . A B 2 5 ? -0.736 -4.976 58.021 1.00 49.01 ? ? ? ? ? ? 12 A R N6 1 5
+ATOM 826 N N1 . A B 2 5 ? -1.971 -3.044 58.336 1.00 50.10 ? ? ? ? ? ? 12 A R N1 1 5
+ATOM 827 C C2 . A B 2 5 ? -2.952 -2.224 57.931 1.00 51.14 ? ? ? ? ? ? 12 A R C2 1 5
+ATOM 828 N N3 . A B 2 5 ? -3.758 -2.348 56.870 1.00 53.09 ? ? ? ? ? ? 12 A R N3 1 5
+ATOM 829 C C4 . A B 2 5 ? -3.482 -3.469 56.171 1.00 54.10 ? ? ? ? ? ? 12 A R C4 1 5
+ATOM 830 P P . C B 2 6 ? -2.972 -0.548 50.953 1.00 64.68 ? ? ? ? ? ? 13 C R P 1 6
+ATOM 831 O OP1 . C B 2 6 ? -3.427 0.475 49.985 1.00 65.38 ? ? ? ? ? ? 13 C R OP1 1 6
+ATOM 832 O OP2 . C B 2 6 ? -1.909 -1.502 50.562 1.00 64.52 ? ? ? ? ? ? 13 C R OP2 1 6
+ATOM 833 O "O5'" . C B 2 6 ? -2.505 0.167 52.307 1.00 62.85 ? ? ? ? ? ? 13 C R "O5'" 1 6
+ATOM 834 C "C5'" . C B 2 6 ? -3.252 1.244 52.868 1.00 61.05 ? ? ? ? ? ? 13 C R "C5'" 1 6
+ATOM 835 C "C4'" . C B 2 6 ? -2.678 1.621 54.220 1.00 60.77 ? ? ? ? ? ? 13 C R "C4'" 1 6
+ATOM 836 O "O4'" . C B 2 6 ? -2.723 0.482 55.116 1.00 59.20 ? ? ? ? ? ? 13 C R "O4'" 1 6
+ATOM 837 C "C3'" . C B 2 6 ? -1.206 1.997 54.193 1.00 60.65 ? ? ? ? ? ? 13 C R "C3'" 1 6
+ATOM 838 O "O3'" . C B 2 6 ? -1.059 3.351 53.815 1.00 62.13 ? ? ? ? ? ? 13 C R "O3'" 1 6
+ATOM 839 C "C2'" . C B 2 6 ? -0.783 1.746 55.636 1.00 59.30 ? ? ? ? ? ? 13 C R "C2'" 1 6
+ATOM 840 O "O2'" . C B 2 6 ? -1.145 2.793 56.518 1.00 60.09 ? ? ? ? ? ? 13 C R "O2'" 1 6
+ATOM 841 C "C1'" . C B 2 6 ? -1.582 0.489 55.959 1.00 56.30 ? ? ? ? ? ? 13 C R "C1'" 1 6
+ATOM 842 N N1 . C B 2 6 ? -0.809 -0.774 55.761 1.00 53.47 ? ? ? ? ? ? 13 C R N1 1 6
+ATOM 843 C C2 . C B 2 6 ? 0.156 -1.167 56.708 1.00 52.41 ? ? ? ? ? ? 13 C R C2 1 6
+ATOM 844 O O2 . C B 2 6 ? 0.369 -0.463 57.704 1.00 52.00 ? ? ? ? ? ? 13 C R O2 1 6
+ATOM 845 N N3 . C B 2 6 ? 0.839 -2.327 56.501 1.00 50.59 ? ? ? ? ? ? 13 C R N3 1 6
+ATOM 846 C C4 . C B 2 6 ? 0.591 -3.069 55.414 1.00 49.69 ? ? ? ? ? ? 13 C R C4 1 6
+ATOM 847 N N4 . C B 2 6 ? 1.286 -4.194 55.256 1.00 48.88 ? ? ? ? ? ? 13 C R N4 1 6
+ATOM 848 C C5 . C B 2 6 ? -0.382 -2.695 54.439 1.00 50.63 ? ? ? ? ? ? 13 C R C5 1 6
+ATOM 849 C C6 . C B 2 6 ? -1.048 -1.553 54.655 1.00 53.49 ? ? ? ? ? ? 13 C R C6 1 6
+ATOM 850 P P . G B 2 7 ? 0.258 3.812 53.042 1.00 63.38 ? ? ? ? ? ? 14 G R P 1 7
+ATOM 851 O OP1 . G B 2 7 ? -0.023 5.157 52.492 1.00 64.31 ? ? ? ? ? ? 14 G R OP1 1 7
+ATOM 852 O OP2 . G B 2 7 ? 0.701 2.724 52.141 1.00 63.46 ? ? ? ? ? ? 14 G R OP2 1 7
+ATOM 853 O "O5'" . G B 2 7 ? 1.338 3.926 54.216 1.00 63.49 ? ? ? ? ? ? 14 G R "O5'" 1 7
+ATOM 854 C "C5'" . G B 2 7 ? 1.260 4.992 55.158 1.00 64.52 ? ? ? ? ? ? 14 G R "C5'" 1 7
+ATOM 855 C "C4'" . G B 2 7 ? 2.336 4.838 56.216 1.00 64.74 ? ? ? ? ? ? 14 G R "C4'" 1 7
+ATOM 856 O "O4'" . G B 2 7 ? 2.379 3.456 56.656 1.00 63.78 ? ? ? ? ? ? 14 G R "O4'" 1 7
+ATOM 857 C "C3'" . G B 2 7 ? 3.749 5.197 55.766 1.00 66.62 ? ? ? ? ? ? 14 G R "C3'" 1 7
+ATOM 858 O "O3'" . G B 2 7 ? 4.409 5.948 56.790 1.00 71.46 ? ? ? ? ? ? 14 G R "O3'" 1 7
+ATOM 859 C "C2'" . G B 2 7 ? 4.413 3.839 55.521 1.00 64.82 ? ? ? ? ? ? 14 G R "C2'" 1 7
+ATOM 860 O "O2'" . G B 2 7 ? 5.802 3.826 55.801 1.00 67.05 ? ? ? ? ? ? 14 G R "O2'" 1 7
+ATOM 861 C "C1'" . G B 2 7 ? 3.678 2.922 56.495 1.00 61.77 ? ? ? ? ? ? 14 G R "C1'" 1 7
+ATOM 862 N N9 . G B 2 7 ? 3.560 1.545 56.015 1.00 57.07 ? ? ? ? ? ? 14 G R N9 1 7
+ATOM 863 C C8 . G B 2 7 ? 2.768 1.094 54.984 1.00 55.11 ? ? ? ? ? ? 14 G R C8 1 7
+ATOM 864 N N7 . G B 2 7 ? 2.865 -0.189 54.772 1.00 52.35 ? ? ? ? ? ? 14 G R N7 1 7
+ATOM 865 C C5 . G B 2 7 ? 3.779 -0.619 55.723 1.00 51.71 ? ? ? ? ? ? 14 G R C5 1 7
+ATOM 866 C C6 . G B 2 7 ? 4.283 -1.916 55.982 1.00 50.53 ? ? ? ? ? ? 14 G R C6 1 7
+ATOM 867 O O6 . G B 2 7 ? 4.013 -2.973 55.404 1.00 50.94 ? ? ? ? ? ? 14 G R O6 1 7
+ATOM 868 N N1 . G B 2 7 ? 5.193 -1.930 57.035 1.00 50.87 ? ? ? ? ? ? 14 G R N1 1 7
+ATOM 869 C C2 . G B 2 7 ? 5.571 -0.824 57.756 1.00 51.10 ? ? ? ? ? ? 14 G R C2 1 7
+ATOM 870 N N2 . G B 2 7 ? 6.463 -1.038 58.734 1.00 50.12 ? ? ? ? ? ? 14 G R N2 1 7
+ATOM 871 N N3 . G B 2 7 ? 5.107 0.401 57.523 1.00 52.48 ? ? ? ? ? ? 14 G R N3 1 7
+ATOM 872 C C4 . G B 2 7 ? 4.218 0.433 56.497 1.00 53.49 ? ? ? ? ? ? 14 G R C4 1 7
+ATOM 873 P P . C B 2 8 ? 4.504 7.550 56.750 1.00 74.77 ? ? ? ? ? ? 15 C R P 1 8
+ATOM 874 O OP1 . C B 2 8 ? 3.298 8.092 57.417 1.00 72.78 ? ? ? ? ? ? 15 C R OP1 1 8
+ATOM 875 O OP2 . C B 2 8 ? 4.830 7.991 55.373 1.00 74.51 ? ? ? ? ? ? 15 C R OP2 1 8
+ATOM 876 O "O5'" . C B 2 8 ? 5.802 7.805 57.658 1.00 75.53 ? ? ? ? ? ? 15 C R "O5'" 1 8
+ATOM 877 C "C5'" . C B 2 8 ? 5.926 8.978 58.464 1.00 78.77 ? ? ? ? ? ? 15 C R "C5'" 1 8
+ATOM 878 C "C4'" . C B 2 8 ? 6.004 8.652 59.950 1.00 80.45 ? ? ? ? ? ? 15 C R "C4'" 1 8
+ATOM 879 O "O4'" . C B 2 8 ? 4.666 8.490 60.476 1.00 81.15 ? ? ? ? ? ? 15 C R "O4'" 1 8
+ATOM 880 C "C3'" . C B 2 8 ? 6.740 7.368 60.316 1.00 81.19 ? ? ? ? ? ? 15 C R "C3'" 1 8
+ATOM 881 O "O3'" . C B 2 8 ? 8.103 7.650 60.564 1.00 81.63 ? ? ? ? ? ? 15 C R "O3'" 1 8
+ATOM 882 C "C2'" . C B 2 8 ? 6.059 6.904 61.598 1.00 81.69 ? ? ? ? ? ? 15 C R "C2'" 1 8
+ATOM 883 O "O2'" . C B 2 8 ? 6.754 7.330 62.754 1.00 81.39 ? ? ? ? ? ? 15 C R "O2'" 1 8
+ATOM 884 C "C1'" . C B 2 8 ? 4.671 7.545 61.529 1.00 82.56 ? ? ? ? ? ? 15 C R "C1'" 1 8
+ATOM 885 N N1 . C B 2 8 ? 3.565 6.550 61.303 1.00 84.70 ? ? ? ? ? ? 15 C R N1 1 8
+ATOM 886 C C2 . C B 2 8 ? 2.796 6.086 62.390 1.00 85.70 ? ? ? ? ? ? 15 C R C2 1 8
+ATOM 887 O O2 . C B 2 8 ? 3.027 6.496 63.536 1.00 85.87 ? ? ? ? ? ? 15 C R O2 1 8
+ATOM 888 N N3 . C B 2 8 ? 1.804 5.183 62.153 1.00 85.99 ? ? ? ? ? ? 15 C R N3 1 8
+ATOM 889 C C4 . C B 2 8 ? 1.568 4.750 60.910 1.00 85.66 ? ? ? ? ? ? 15 C R C4 1 8
+ATOM 890 N N4 . C B 2 8 ? 0.586 3.866 60.725 1.00 85.80 ? ? ? ? ? ? 15 C R N4 1 8
+ATOM 891 C C5 . C B 2 8 ? 2.332 5.208 59.795 1.00 85.77 ? ? ? ? ? ? 15 C R C5 1 8
+ATOM 892 C C6 . C B 2 8 ? 3.308 6.094 60.036 1.00 85.16 ? ? ? ? ? ? 15 C R C6 1 8
+ATOM 893 P P . A B 2 9 ? 9.197 7.523 59.408 1.00 81.98 ? ? ? ? ? ? 16 A R P 1 9
+ATOM 894 O OP1 . A B 2 9 ? 9.696 8.891 59.140 1.00 82.37 ? ? ? ? ? ? 16 A R OP1 1 9
+ATOM 895 O OP2 . A B 2 9 ? 8.630 6.726 58.298 1.00 82.89 ? ? ? ? ? ? 16 A R OP2 1 9
+ATOM 896 O "O5'" . A B 2 9 ? 10.350 6.664 60.115 1.00 83.24 ? ? ? ? ? ? 16 A R "O5'" 1 9
+ATOM 897 C "C5'" . A B 2 9 ? 10.122 5.307 60.481 1.00 86.50 ? ? ? ? ? ? 16 A R "C5'" 1 9
+ATOM 898 C "C4'" . A B 2 9 ? 10.025 5.146 61.988 1.00 89.36 ? ? ? ? ? ? 16 A R "C4'" 1 9
+ATOM 899 O "O4'" . A B 2 9 ? 8.672 4.755 62.345 1.00 90.33 ? ? ? ? ? ? 16 A R "O4'" 1 9
+ATOM 900 C "C3'" . A B 2 9 ? 10.926 4.065 62.574 1.00 90.38 ? ? ? ? ? ? 16 A R "C3'" 1 9
+ATOM 901 O "O3'" . A B 2 9 ? 12.203 4.596 62.932 1.00 91.82 ? ? ? ? ? ? 16 A R "O3'" 1 9
+ATOM 902 C "C2'" . A B 2 9 ? 10.139 3.609 63.800 1.00 91.00 ? ? ? ? ? ? 16 A R "C2'" 1 9
+ATOM 903 O "O2'" . A B 2 9 ? 10.348 4.429 64.935 1.00 91.41 ? ? ? ? ? ? 16 A R "O2'" 1 9
+ATOM 904 C "C1'" . A B 2 9 ? 8.696 3.719 63.315 1.00 91.59 ? ? ? ? ? ? 16 A R "C1'" 1 9
+ATOM 905 N N9 . A B 2 9 ? 8.165 2.471 62.747 1.00 92.84 ? ? ? ? ? ? 16 A R N9 1 9
+ATOM 906 C C8 . A B 2 9 ? 7.752 2.263 61.458 1.00 93.05 ? ? ? ? ? ? 16 A R C8 1 9
+ATOM 907 N N7 . A B 2 9 ? 7.322 1.047 61.220 1.00 92.93 ? ? ? ? ? ? 16 A R N7 1 9
+ATOM 908 C C5 . A B 2 9 ? 7.459 0.403 62.436 1.00 93.48 ? ? ? ? ? ? 16 A R C5 1 9
+ATOM 909 C C6 . A B 2 9 ? 7.176 -0.918 62.853 1.00 93.99 ? ? ? ? ? ? 16 A R C6 1 9
+ATOM 910 N N6 . A B 2 9 ? 6.673 -1.849 62.038 1.00 94.91 ? ? ? ? ? ? 16 A R N6 1 9
+ATOM 911 N N1 . A B 2 9 ? 7.429 -1.249 64.140 1.00 94.14 ? ? ? ? ? ? 16 A R N1 1 9
+ATOM 912 C C2 . A B 2 9 ? 7.932 -0.314 64.958 1.00 94.09 ? ? ? ? ? ? 16 A R C2 1 9
+ATOM 913 N N3 . A B 2 9 ? 8.239 0.956 64.679 1.00 94.11 ? ? ? ? ? ? 16 A R N3 1 9
+ATOM 914 C C4 . A B 2 9 ? 7.977 1.262 63.391 1.00 93.52 ? ? ? ? ? ? 16 A R C4 1 9
+ATOM 915 P P . C B 2 10 ? 13.534 3.706 62.814 1.00 93.25 ? ? ? ? ? ? 17 C R P 1 10
+ATOM 916 O OP1 . C B 2 10 ? 14.662 4.503 63.349 1.00 93.31 ? ? ? ? ? ? 17 C R OP1 1 10
+ATOM 917 O OP2 . C B 2 10 ? 13.610 3.188 61.430 1.00 92.50 ? ? ? ? ? ? 17 C R OP2 1 10
+ATOM 918 O "O5'" . C B 2 10 ? 13.259 2.455 63.783 1.00 95.03 ? ? ? ? ? ? 17 C R "O5'" 1 10
+ATOM 919 C "C5'" . C B 2 10 ? 13.312 2.558 65.212 1.00 97.15 ? ? ? ? ? ? 17 C R "C5'" 1 10
+ATOM 920 C "C4'" . C B 2 10 ? 12.938 1.241 65.875 1.00 98.38 ? ? ? ? ? ? 17 C R "C4'" 1 10
+ATOM 921 O "O4'" . C B 2 10 ? 11.607 0.833 65.468 1.00 98.65 ? ? ? ? ? ? 17 C R "O4'" 1 10
+ATOM 922 C "C3'" . C B 2 10 ? 13.838 0.074 65.499 1.00 99.25 ? ? ? ? ? ? 17 C R "C3'" 1 10
+ATOM 923 O "O3'" . C B 2 10 ? 14.931 0.008 66.393 1.00 100.43 ? ? ? ? ? ? 17 C R "O3'" 1 10
+ATOM 924 C "C2'" . C B 2 10 ? 12.934 -1.150 65.613 1.00 99.34 ? ? ? ? ? ? 17 C R "C2'" 1 10
+ATOM 925 O "O2'" . C B 2 10 ? 12.943 -1.730 66.903 1.00 98.94 ? ? ? ? ? ? 17 C R "O2'" 1 10
+ATOM 926 C "C1'" . C B 2 10 ? 11.557 -0.573 65.277 1.00 99.35 ? ? ? ? ? ? 17 C R "C1'" 1 10
+ATOM 927 N N1 . C B 2 10 ? 11.109 -0.885 63.870 1.00 99.84 ? ? ? ? ? ? 17 C R N1 1 10
+ATOM 928 C C2 . C B 2 10 ? 10.585 -2.154 63.548 1.00 99.68 ? ? ? ? ? ? 17 C R C2 1 10
+ATOM 929 O O2 . C B 2 10 ? 10.480 -3.031 64.414 1.00 99.42 ? ? ? ? ? ? 17 C R O2 1 10
+ATOM 930 N N3 . C B 2 10 ? 10.195 -2.398 62.269 1.00 100.14 ? ? ? ? ? ? 17 C R N3 1 10
+ATOM 931 C C4 . C B 2 10 ? 10.309 -1.449 61.335 1.00 100.55 ? ? ? ? ? ? 17 C R C4 1 10
+ATOM 932 N N4 . C B 2 10 ? 9.910 -1.742 60.093 1.00 101.27 ? ? ? ? ? ? 17 C R N4 1 10
+ATOM 933 C C5 . C B 2 10 ? 10.838 -0.158 61.636 1.00 100.21 ? ? ? ? ? ? 17 C R C5 1 10
+ATOM 934 C C6 . C B 2 10 ? 11.220 0.073 62.897 1.00 99.81 ? ? ? ? ? ? 17 C R C6 1 10
+ATOM 935 P P . A B 2 11 ? 16.406 -0.067 65.791 1.00 101.72 ? ? ? ? ? ? 18 A R P 1 11
+ATOM 936 O OP1 . A B 2 11 ? 17.355 0.159 66.908 1.00 101.76 ? ? ? ? ? ? 18 A R OP1 1 11
+ATOM 937 O OP2 . A B 2 11 ? 16.456 0.812 64.600 1.00 101.60 ? ? ? ? ? ? 18 A R OP2 1 11
+ATOM 938 O "O5'" . A B 2 11 ? 16.506 -1.585 65.289 1.00 101.21 ? ? ? ? ? ? 18 A R "O5'" 1 11
+ATOM 939 C "C5'" . A B 2 11 ? 16.893 -2.607 66.200 1.00 101.02 ? ? ? ? ? ? 18 A R "C5'" 1 11
+ATOM 940 C "C4'" . A B 2 11 ? 16.603 -3.987 65.646 1.00 100.63 ? ? ? ? ? ? 18 A R "C4'" 1 11
+ATOM 941 O "O4'" . A B 2 11 ? 15.218 -4.088 65.235 1.00 101.37 ? ? ? ? ? ? 18 A R "O4'" 1 11
+ATOM 942 C "C3'" . A B 2 11 ? 17.367 -4.358 64.387 1.00 100.17 ? ? ? ? ? ? 18 A R "C3'" 1 11
+ATOM 943 O "O3'" . A B 2 11 ? 18.709 -4.721 64.689 1.00 98.50 ? ? ? ? ? ? 18 A R "O3'" 1 11
+ATOM 944 C "C2'" . A B 2 11 ? 16.532 -5.530 63.879 1.00 100.89 ? ? ? ? ? ? 18 A R "C2'" 1 11
+ATOM 945 O "O2'" . A B 2 11 ? 16.819 -6.758 64.523 1.00 99.68 ? ? ? ? ? ? 18 A R "O2'" 1 11
+ATOM 946 C "C1'" . A B 2 11 ? 15.116 -5.056 64.204 1.00 102.34 ? ? ? ? ? ? 18 A R "C1'" 1 11
+ATOM 947 N N9 . A B 2 11 ? 14.471 -4.455 63.038 1.00 104.57 ? ? ? ? ? ? 18 A R N9 1 11
+ATOM 948 C C8 . A B 2 11 ? 14.257 -3.123 62.812 1.00 105.36 ? ? ? ? ? ? 18 A R C8 1 11
+ATOM 949 N N7 . A B 2 11 ? 13.660 -2.866 61.673 1.00 105.81 ? ? ? ? ? ? 18 A R N7 1 11
+ATOM 950 C C5 . A B 2 11 ? 13.475 -4.116 61.108 1.00 105.43 ? ? ? ? ? ? 18 A R C5 1 11
+ATOM 951 C C6 . A B 2 11 ? 12.891 -4.532 59.893 1.00 105.84 ? ? ? ? ? ? 18 A R C6 1 11
+ATOM 952 N N6 . A B 2 11 ? 12.377 -3.674 59.005 1.00 105.59 ? ? ? ? ? ? 18 A R N6 1 11
+ATOM 953 N N1 . A B 2 11 ? 12.864 -5.859 59.623 1.00 106.12 ? ? ? ? ? ? 18 A R N1 1 11
+ATOM 954 C C2 . A B 2 11 ? 13.383 -6.714 60.519 1.00 105.77 ? ? ? ? ? ? 18 A R C2 1 11
+ATOM 955 N N3 . A B 2 11 ? 13.954 -6.438 61.694 1.00 105.31 ? ? ? ? ? ? 18 A R N3 1 11
+ATOM 956 C C4 . A B 2 11 ? 13.970 -5.112 61.933 1.00 105.07 ? ? ? ? ? ? 18 A R C4 1 11
+ATOM 957 P P . G B 2 12 ? 19.864 -4.498 63.600 1.00 96.97 ? ? ? ? ? ? 19 G R P 1 12
+ATOM 958 O OP1 . G B 2 12 ? 21.168 -4.712 64.267 1.00 97.32 ? ? ? ? ? ? 19 G R OP1 1 12
+ATOM 959 O OP2 . G B 2 12 ? 19.602 -3.219 62.899 1.00 97.07 ? ? ? ? ? ? 19 G R OP2 1 12
+ATOM 960 O "O5'" . G B 2 12 ? 19.612 -5.686 62.565 1.00 93.61 ? ? ? ? ? ? 19 G R "O5'" 1 12
+ATOM 961 C "C5'" . G B 2 12 ? 19.789 -7.031 62.976 1.00 91.14 ? ? ? ? ? ? 19 G R "C5'" 1 12
+ATOM 962 C "C4'" . G B 2 12 ? 19.351 -7.959 61.867 1.00 89.62 ? ? ? ? ? ? 19 G R "C4'" 1 12
+ATOM 963 O "O4'" . G B 2 12 ? 17.934 -7.764 61.633 1.00 89.19 ? ? ? ? ? ? 19 G R "O4'" 1 12
+ATOM 964 C "C3'" . G B 2 12 ? 19.970 -7.674 60.506 1.00 89.18 ? ? ? ? ? ? 19 G R "C3'" 1 12
+ATOM 965 O "O3'" . G B 2 12 ? 21.299 -8.187 60.375 1.00 87.87 ? ? ? ? ? ? 19 G R "O3'" 1 12
+ATOM 966 C "C2'" . G B 2 12 ? 18.951 -8.316 59.567 1.00 89.10 ? ? ? ? ? ? 19 G R "C2'" 1 12
+ATOM 967 O "O2'" . G B 2 12 ? 19.051 -9.727 59.492 1.00 89.19 ? ? ? ? ? ? 19 G R "O2'" 1 12
+ATOM 968 C "C1'" . G B 2 12 ? 17.652 -7.886 60.248 1.00 88.55 ? ? ? ? ? ? 19 G R "C1'" 1 12
+ATOM 969 N N9 . G B 2 12 ? 17.128 -6.614 59.739 1.00 87.43 ? ? ? ? ? ? 19 G R N9 1 12
+ATOM 970 C C8 . G B 2 12 ? 17.424 -5.346 60.187 1.00 87.12 ? ? ? ? ? ? 19 G R C8 1 12
+ATOM 971 N N7 . G B 2 12 ? 16.808 -4.400 59.536 1.00 86.74 ? ? ? ? ? ? 19 G R N7 1 12
+ATOM 972 C C5 . G B 2 12 ? 16.050 -5.080 58.591 1.00 86.12 ? ? ? ? ? ? 19 G R C5 1 12
+ATOM 973 C C6 . G B 2 12 ? 15.173 -4.584 57.592 1.00 85.60 ? ? ? ? ? ? 19 G R C6 1 12
+ATOM 974 O O6 . G B 2 12 ? 14.882 -3.405 57.346 1.00 85.10 ? ? ? ? ? ? 19 G R O6 1 12
+ATOM 975 N N1 . G B 2 12 ? 14.600 -5.609 56.838 1.00 85.56 ? ? ? ? ? ? 19 G R N1 1 12
+ATOM 976 C C2 . G B 2 12 ? 14.849 -6.951 57.023 1.00 85.36 ? ? ? ? ? ? 19 G R C2 1 12
+ATOM 977 N N2 . G B 2 12 ? 14.210 -7.797 56.202 1.00 84.65 ? ? ? ? ? ? 19 G R N2 1 12
+ATOM 978 N N3 . G B 2 12 ? 15.671 -7.427 57.953 1.00 85.52 ? ? ? ? ? ? 19 G R N3 1 12
+ATOM 979 C C4 . G B 2 12 ? 16.238 -6.442 58.700 1.00 86.32 ? ? ? ? ? ? 19 G R C4 1 12
+ATOM 980 P P . G B 2 13 ? 22.572 -7.212 60.503 1.00 87.08 ? ? ? ? ? ? 20 G R P 1 13
+ATOM 981 O OP1 . G B 2 13 ? 23.679 -8.042 61.028 1.00 87.37 ? ? ? ? ? ? 20 G R OP1 1 13
+ATOM 982 O OP2 . G B 2 13 ? 22.190 -5.964 61.211 1.00 86.12 ? ? ? ? ? ? 20 G R OP2 1 13
+ATOM 983 O "O5'" . G B 2 13 ? 22.918 -6.816 58.994 1.00 83.80 ? ? ? ? ? ? 20 G R "O5'" 1 13
+ATOM 984 C "C5'" . G B 2 13 ? 22.315 -5.683 58.380 1.00 79.73 ? ? ? ? ? ? 20 G R "C5'" 1 13
+ATOM 985 C "C4'" . G B 2 13 ? 21.161 -6.153 57.518 1.00 76.53 ? ? ? ? ? ? 20 G R "C4'" 1 13
+ATOM 986 O "O4'" . G B 2 13 ? 19.916 -5.538 57.930 1.00 76.27 ? ? ? ? ? ? 20 G R "O4'" 1 13
+ATOM 987 C "C3'" . G B 2 13 ? 21.263 -5.858 56.034 1.00 73.78 ? ? ? ? ? ? 20 G R "C3'" 1 13
+ATOM 988 O "O3'" . G B 2 13 ? 22.152 -6.799 55.427 1.00 69.26 ? ? ? ? ? ? 20 G R "O3'" 1 13
+ATOM 989 C "C2'" . G B 2 13 ? 19.803 -6.053 55.631 1.00 74.20 ? ? ? ? ? ? 20 G R "C2'" 1 13
+ATOM 990 O "O2'" . G B 2 13 ? 19.439 -7.416 55.520 1.00 73.18 ? ? ? ? ? ? 20 G R "O2'" 1 13
+ATOM 991 C "C1'" . G B 2 13 ? 19.071 -5.410 56.803 1.00 75.04 ? ? ? ? ? ? 20 G R "C1'" 1 13
+ATOM 992 N N9 . G B 2 13 ? 18.769 -3.992 56.609 1.00 75.64 ? ? ? ? ? ? 20 G R N9 1 13
+ATOM 993 C C8 . G B 2 13 ? 19.372 -2.929 57.241 1.00 76.41 ? ? ? ? ? ? 20 G R C8 1 13
+ATOM 994 N N7 . G B 2 13 ? 18.903 -1.768 56.879 1.00 76.65 ? ? ? ? ? ? 20 G R N7 1 13
+ATOM 995 C C5 . G B 2 13 ? 17.923 -2.078 55.946 1.00 76.09 ? ? ? ? ? ? 20 G R C5 1 13
+ATOM 996 C C6 . G B 2 13 ? 17.069 -1.220 55.206 1.00 76.26 ? ? ? ? ? ? 20 G R C6 1 13
+ATOM 997 O O6 . G B 2 13 ? 17.019 0.020 55.239 1.00 75.92 ? ? ? ? ? ? 20 G R O6 1 13
+ATOM 998 N N1 . G B 2 13 ? 16.217 -1.939 54.362 1.00 75.80 ? ? ? ? ? ? 20 G R N1 1 13
+ATOM 999 C C2 . G B 2 13 ? 16.196 -3.314 54.251 1.00 74.64 ? ? ? ? ? ? 20 G R C2 1 13
+ATOM 1000 N N2 . G B 2 13 ? 15.308 -3.829 53.391 1.00 74.53 ? ? ? ? ? ? 20 G R N2 1 13
+ATOM 1001 N N3 . G B 2 13 ? 16.990 -4.126 54.939 1.00 74.10 ? ? ? ? ? ? 20 G R N3 1 13
+ATOM 1002 C C4 . G B 2 13 ? 17.827 -3.444 55.765 1.00 75.33 ? ? ? ? ? ? 20 G R C4 1 13
+ATOM 1003 P P . G B 2 14 ? 22.496 -6.740 53.864 1.00 65.21 ? ? ? ? ? ? 21 G R P 1 14
+ATOM 1004 O OP1 . G B 2 14 ? 23.510 -7.779 53.568 1.00 64.77 ? ? ? ? ? ? 21 G R OP1 1 14
+ATOM 1005 O OP2 . G B 2 14 ? 22.744 -5.329 53.482 1.00 65.68 ? ? ? ? ? ? 21 G R OP2 1 14
+ATOM 1006 O "O5'" . G B 2 14 ? 21.095 -7.180 53.240 1.00 61.98 ? ? ? ? ? ? 21 G R "O5'" 1 14
+ATOM 1007 C "C5'" . G B 2 14 ? 21.026 -7.844 52.009 1.00 57.17 ? ? ? ? ? ? 21 G R "C5'" 1 14
+ATOM 1008 C "C4'" . G B 2 14 ? 19.720 -7.523 51.321 1.00 54.12 ? ? ? ? ? ? 21 G R "C4'" 1 14
+ATOM 1009 O "O4'" . G B 2 14 ? 18.891 -6.638 52.109 1.00 53.25 ? ? ? ? ? ? 21 G R "O4'" 1 14
+ATOM 1010 C "C3'" . G B 2 14 ? 19.920 -6.725 50.060 1.00 52.50 ? ? ? ? ? ? 21 G R "C3'" 1 14
+ATOM 1011 O "O3'" . G B 2 14 ? 20.398 -7.592 49.063 1.00 52.31 ? ? ? ? ? ? 21 G R "O3'" 1 14
+ATOM 1012 C "C2'" . G B 2 14 ? 18.517 -6.195 49.809 1.00 51.43 ? ? ? ? ? ? 21 G R "C2'" 1 14
+ATOM 1013 O "O2'" . G B 2 14 ? 17.639 -7.159 49.261 1.00 48.28 ? ? ? ? ? ? 21 G R "O2'" 1 14
+ATOM 1014 C "C1'" . G B 2 14 ? 18.119 -5.825 51.238 1.00 51.47 ? ? ? ? ? ? 21 G R "C1'" 1 14
+ATOM 1015 N N9 . G B 2 14 ? 18.354 -4.423 51.593 1.00 50.42 ? ? ? ? ? ? 21 G R N9 1 14
+ATOM 1016 C C8 . G B 2 14 ? 19.201 -3.963 52.574 1.00 50.69 ? ? ? ? ? ? 21 G R C8 1 14
+ATOM 1017 N N7 . G B 2 14 ? 19.221 -2.665 52.689 1.00 50.57 ? ? ? ? ? ? 21 G R N7 1 14
+ATOM 1018 C C5 . G B 2 14 ? 18.329 -2.225 51.723 1.00 49.87 ? ? ? ? ? ? 21 G R C5 1 14
+ATOM 1019 C C6 . G B 2 14 ? 17.939 -0.902 51.382 1.00 51.06 ? ? ? ? ? ? 21 G R C6 1 14
+ATOM 1020 O O6 . G B 2 14 ? 18.330 0.162 51.897 1.00 50.76 ? ? ? ? ? ? 21 G R O6 1 14
+ATOM 1021 N N1 . G B 2 14 ? 17.007 -0.884 50.334 1.00 49.85 ? ? ? ? ? ? 21 G R N1 1 14
+ATOM 1022 C C2 . G B 2 14 ? 16.516 -2.015 49.706 1.00 48.94 ? ? ? ? ? ? 21 G R C2 1 14
+ATOM 1023 N N2 . G B 2 14 ? 15.625 -1.819 48.723 1.00 47.46 ? ? ? ? ? ? 21 G R N2 1 14
+ATOM 1024 N N3 . G B 2 14 ? 16.875 -3.258 50.023 1.00 47.98 ? ? ? ? ? ? 21 G R N3 1 14
+ATOM 1025 C C4 . G B 2 14 ? 17.783 -3.295 51.036 1.00 49.64 ? ? ? ? ? ? 21 G R C4 1 14
+ATOM 1026 P P . C B 2 15 ? 21.706 -7.130 48.274 1.00 50.29 ? ? ? ? ? ? 22 C R P 1 15
+ATOM 1027 O OP1 . C B 2 15 ? 22.378 -8.329 47.735 1.00 48.95 ? ? ? ? ? ? 22 C R OP1 1 15
+ATOM 1028 O OP2 . C B 2 15 ? 22.458 -6.195 49.141 1.00 51.24 ? ? ? ? ? ? 22 C R OP2 1 15
+ATOM 1029 O "O5'" . C B 2 15 ? 21.047 -6.302 47.076 1.00 50.36 ? ? ? ? ? ? 22 C R "O5'" 1 15
+ATOM 1030 C "C5'" . C B 2 15 ? 19.948 -6.853 46.341 1.00 47.32 ? ? ? ? ? ? 22 C R "C5'" 1 15
+ATOM 1031 C "C4'" . C B 2 15 ? 19.100 -5.745 45.754 1.00 47.19 ? ? ? ? ? ? 22 C R "C4'" 1 15
+ATOM 1032 O "O4'" . C B 2 15 ? 18.560 -4.915 46.812 1.00 47.51 ? ? ? ? ? ? 22 C R "O4'" 1 15
+ATOM 1033 C "C3'" . C B 2 15 ? 19.857 -4.761 44.879 1.00 46.49 ? ? ? ? ? ? 22 C R "C3'" 1 15
+ATOM 1034 O "O3'" . C B 2 15 ? 19.985 -5.287 43.572 1.00 46.54 ? ? ? ? ? ? 22 C R "O3'" 1 15
+ATOM 1035 C "C2'" . C B 2 15 ? 18.934 -3.552 44.912 1.00 46.86 ? ? ? ? ? ? 22 C R "C2'" 1 15
+ATOM 1036 O "O2'" . C B 2 15 ? 17.853 -3.638 44.004 1.00 49.26 ? ? ? ? ? ? 22 C R "O2'" 1 15
+ATOM 1037 C "C1'" . C B 2 15 ? 18.393 -3.590 46.336 1.00 45.86 ? ? ? ? ? ? 22 C R "C1'" 1 15
+ATOM 1038 N N1 . C B 2 15 ? 19.057 -2.602 47.243 1.00 44.65 ? ? ? ? ? ? 22 C R N1 1 15
+ATOM 1039 C C2 . C B 2 15 ? 18.775 -1.230 47.099 1.00 46.56 ? ? ? ? ? ? 22 C R C2 1 15
+ATOM 1040 O O2 . C B 2 15 ? 17.985 -0.849 46.221 1.00 46.87 ? ? ? ? ? ? 22 C R O2 1 15
+ATOM 1041 N N3 . C B 2 15 ? 19.384 -0.343 47.935 1.00 46.85 ? ? ? ? ? ? 22 C R N3 1 15
+ATOM 1042 C C4 . C B 2 15 ? 20.234 -0.778 48.874 1.00 45.89 ? ? ? ? ? ? 22 C R C4 1 15
+ATOM 1043 N N4 . C B 2 15 ? 20.802 0.134 49.669 1.00 45.82 ? ? ? ? ? ? 22 C R N4 1 15
+ATOM 1044 C C5 . C B 2 15 ? 20.534 -2.165 49.038 1.00 44.92 ? ? ? ? ? ? 22 C R C5 1 15
+ATOM 1045 C C6 . C B 2 15 ? 19.929 -3.030 48.210 1.00 44.89 ? ? ? ? ? ? 22 C R C6 1 15
+ATOM 1046 P P . A B 2 16 ? 21.343 -5.149 42.731 1.00 48.48 ? ? ? ? ? ? 23 A R P 1 16
+ATOM 1047 O OP1 . A B 2 16 ? 21.164 -5.965 41.507 1.00 46.89 ? ? ? ? ? ? 23 A R OP1 1 16
+ATOM 1048 O OP2 . A B 2 16 ? 22.500 -5.387 43.633 1.00 44.61 ? ? ? ? ? ? 23 A R OP2 1 16
+ATOM 1049 O "O5'" . A B 2 16 ? 21.373 -3.607 42.310 1.00 46.09 ? ? ? ? ? ? 23 A R "O5'" 1 16
+ATOM 1050 C "C5'" . A B 2 16 ? 20.287 -2.976 41.638 1.00 46.26 ? ? ? ? ? ? 23 A R "C5'" 1 16
+ATOM 1051 C "C4'" . A B 2 16 ? 20.423 -1.469 41.779 1.00 47.11 ? ? ? ? ? ? 23 A R "C4'" 1 16
+ATOM 1052 O "O4'" . A B 2 16 ? 20.405 -1.097 43.184 1.00 46.84 ? ? ? ? ? ? 23 A R "O4'" 1 16
+ATOM 1053 C "C3'" . A B 2 16 ? 21.729 -0.940 41.199 1.00 47.34 ? ? ? ? ? ? 23 A R "C3'" 1 16
+ATOM 1054 O "O3'" . A B 2 16 ? 21.480 0.182 40.378 1.00 47.33 ? ? ? ? ? ? 23 A R "O3'" 1 16
+ATOM 1055 C "C2'" . A B 2 16 ? 22.571 -0.585 42.423 1.00 48.10 ? ? ? ? ? ? 23 A R "C2'" 1 16
+ATOM 1056 O "O2'" . A B 2 16 ? 23.439 0.518 42.227 1.00 49.12 ? ? ? ? ? ? 23 A R "O2'" 1 16
+ATOM 1057 C "C1'" . A B 2 16 ? 21.510 -0.268 43.473 1.00 47.02 ? ? ? ? ? ? 23 A R "C1'" 1 16
+ATOM 1058 N N9 . A B 2 16 ? 22.052 -0.541 44.799 1.00 46.26 ? ? ? ? ? ? 23 A R N9 1 16
+ATOM 1059 C C8 . A B 2 16 ? 22.416 -1.753 45.317 1.00 46.49 ? ? ? ? ? ? 23 A R C8 1 16
+ATOM 1060 N N7 . A B 2 16 ? 22.904 -1.687 46.534 1.00 47.15 ? ? ? ? ? ? 23 A R N7 1 16
+ATOM 1061 C C5 . A B 2 16 ? 22.869 -0.336 46.832 1.00 47.56 ? ? ? ? ? ? 23 A R C5 1 16
+ATOM 1062 C C6 . A B 2 16 ? 23.253 0.406 47.970 1.00 47.67 ? ? ? ? ? ? 23 A R C6 1 16
+ATOM 1063 N N6 . A B 2 16 ? 23.764 -0.152 49.069 1.00 50.08 ? ? ? ? ? ? 23 A R N6 1 16
+ATOM 1064 N N1 . A B 2 16 ? 23.082 1.746 47.950 1.00 47.35 ? ? ? ? ? ? 23 A R N1 1 16
+ATOM 1065 C C2 . A B 2 16 ? 22.571 2.309 46.848 1.00 47.69 ? ? ? ? ? ? 23 A R C2 1 16
+ATOM 1066 N N3 . A B 2 16 ? 22.175 1.719 45.718 1.00 47.86 ? ? ? ? ? ? 23 A R N3 1 16
+ATOM 1067 C C4 . A B 2 16 ? 22.351 0.385 45.771 1.00 47.38 ? ? ? ? ? ? 23 A R C4 1 16
+ATOM 1068 P P . A B 2 17 ? 22.147 0.226 38.926 1.00 48.21 ? ? ? ? ? ? 24 A R P 1 17
+ATOM 1069 O OP1 . A B 2 17 ? 21.428 -0.731 38.055 1.00 47.98 ? ? ? ? ? ? 24 A R OP1 1 17
+ATOM 1070 O OP2 . A B 2 17 ? 23.618 0.143 39.097 1.00 44.91 ? ? ? ? ? ? 24 A R OP2 1 17
+ATOM 1071 O "O5'" . A B 2 17 ? 21.760 1.695 38.436 1.00 47.93 ? ? ? ? ? ? 24 A R "O5'" 1 17
+ATOM 1072 C "C5'" . A B 2 17 ? 20.397 2.030 38.201 1.00 46.67 ? ? ? ? ? ? 24 A R "C5'" 1 17
+ATOM 1073 C "C4'" . A B 2 17 ? 20.193 3.531 38.277 1.00 47.53 ? ? ? ? ? ? 24 A R "C4'" 1 17
+ATOM 1074 O "O4'" . A B 2 17 ? 20.319 3.997 39.645 1.00 47.25 ? ? ? ? ? ? 24 A R "O4'" 1 17
+ATOM 1075 C "C3'" . A B 2 17 ? 21.223 4.368 37.536 1.00 47.99 ? ? ? ? ? ? 24 A R "C3'" 1 17
+ATOM 1076 O "O3'" . A B 2 17 ? 20.939 4.374 36.152 1.00 49.41 ? ? ? ? ? ? 24 A R "O3'" 1 17
+ATOM 1077 C "C2'" . A B 2 17 ? 20.995 5.728 38.183 1.00 47.92 ? ? ? ? ? ? 24 A R "C2'" 1 17
+ATOM 1078 O "O2'" . A B 2 17 ? 19.850 6.397 37.695 1.00 48.99 ? ? ? ? ? ? 24 A R "O2'" 1 17
+ATOM 1079 C "C1'" . A B 2 17 ? 20.795 5.334 39.646 1.00 46.09 ? ? ? ? ? ? 24 A R "C1'" 1 17
+ATOM 1080 N N9 . A B 2 17 ? 22.032 5.417 40.424 1.00 43.36 ? ? ? ? ? ? 24 A R N9 1 17
+ATOM 1081 C C8 . A B 2 17 ? 22.684 4.393 41.055 1.00 43.62 ? ? ? ? ? ? 24 A R C8 1 17
+ATOM 1082 N N7 . A B 2 17 ? 23.781 4.759 41.675 1.00 43.25 ? ? ? ? ? ? 24 A R N7 1 17
+ATOM 1083 C C5 . A B 2 17 ? 23.855 6.119 41.434 1.00 42.22 ? ? ? ? ? ? 24 A R C5 1 17
+ATOM 1084 C C6 . A B 2 17 ? 24.791 7.101 41.818 1.00 43.42 ? ? ? ? ? ? 24 A R C6 1 17
+ATOM 1085 N N6 . A B 2 17 ? 25.871 6.833 42.561 1.00 45.49 ? ? ? ? ? ? 24 A R N6 1 17
+ATOM 1086 N N1 . A B 2 17 ? 24.576 8.375 41.413 1.00 44.01 ? ? ? ? ? ? 24 A R N1 1 17
+ATOM 1087 C C2 . A B 2 17 ? 23.497 8.643 40.664 1.00 42.83 ? ? ? ? ? ? 24 A R C2 1 17
+ATOM 1088 N N3 . A B 2 17 ? 22.552 7.800 40.241 1.00 42.38 ? ? ? ? ? ? 24 A R N3 1 17
+ATOM 1089 C C4 . A B 2 17 ? 22.788 6.544 40.665 1.00 42.02 ? ? ? ? ? ? 24 A R C4 1 17
+ATOM 1090 P P . A B 2 18 ? 22.089 4.110 35.069 1.00 51.29 ? ? ? ? ? ? 25 A R P 1 18
+ATOM 1091 O OP1 . A B 2 18 ? 21.412 4.070 33.752 1.00 51.01 ? ? ? ? ? ? 25 A R OP1 1 18
+ATOM 1092 O OP2 . A B 2 18 ? 22.956 2.990 35.506 1.00 49.03 ? ? ? ? ? ? 25 A R OP2 1 18
+ATOM 1093 O "O5'" . A B 2 18 ? 22.962 5.443 35.158 1.00 50.98 ? ? ? ? ? ? 25 A R "O5'" 1 18
+ATOM 1094 C "C5'" . A B 2 18 ? 22.414 6.692 34.749 1.00 47.94 ? ? ? ? ? ? 25 A R "C5'" 1 18
+ATOM 1095 C "C4'" . A B 2 18 ? 23.255 7.822 35.304 1.00 45.90 ? ? ? ? ? ? 25 A R "C4'" 1 18
+ATOM 1096 O "O4'" . A B 2 18 ? 23.315 7.712 36.744 1.00 43.54 ? ? ? ? ? ? 25 A R "O4'" 1 18
+ATOM 1097 C "C3'" . A B 2 18 ? 24.714 7.797 34.880 1.00 45.50 ? ? ? ? ? ? 25 A R "C3'" 1 18
+ATOM 1098 O "O3'" . A B 2 18 ? 24.878 8.394 33.604 1.00 44.28 ? ? ? ? ? ? 25 A R "O3'" 1 18
+ATOM 1099 C "C2'" . A B 2 18 ? 25.344 8.643 35.974 1.00 45.71 ? ? ? ? ? ? 25 A R "C2'" 1 18
+ATOM 1100 O "O2'" . A B 2 18 ? 25.135 10.027 35.764 1.00 49.08 ? ? ? ? ? ? 25 A R "O2'" 1 18
+ATOM 1101 C "C1'" . A B 2 18 ? 24.571 8.169 37.200 1.00 43.36 ? ? ? ? ? ? 25 A R "C1'" 1 18
+ATOM 1102 N N9 . A B 2 18 ? 25.240 7.106 37.950 1.00 42.28 ? ? ? ? ? ? 25 A R N9 1 18
+ATOM 1103 C C8 . A B 2 18 ? 24.838 5.805 38.108 1.00 41.66 ? ? ? ? ? ? 25 A R C8 1 18
+ATOM 1104 N N7 . A B 2 18 ? 25.647 5.081 38.853 1.00 40.50 ? ? ? ? ? ? 25 A R N7 1 18
+ATOM 1105 C C5 . A B 2 18 ? 26.652 5.967 39.208 1.00 42.42 ? ? ? ? ? ? 25 A R C5 1 18
+ATOM 1106 C C6 . A B 2 18 ? 27.822 5.834 39.995 1.00 43.38 ? ? ? ? ? ? 25 A R C6 1 18
+ATOM 1107 N N6 . A B 2 18 ? 28.192 4.693 40.587 1.00 44.62 ? ? ? ? ? ? 25 A R N6 1 18
+ATOM 1108 N N1 . A B 2 18 ? 28.613 6.919 40.149 1.00 42.85 ? ? ? ? ? ? 25 A R N1 1 18
+ATOM 1109 C C2 . A B 2 18 ? 28.251 8.066 39.560 1.00 42.93 ? ? ? ? ? ? 25 A R C2 1 18
+ATOM 1110 N N3 . A B 2 18 ? 27.178 8.315 38.804 1.00 41.24 ? ? ? ? ? ? 25 A R N3 1 18
+ATOM 1111 C C4 . A B 2 18 ? 26.413 7.219 38.663 1.00 41.86 ? ? ? ? ? ? 25 A R C4 1 18
+ATOM 1112 P P . C B 2 19 ? 25.881 7.756 32.535 1.00 43.87 ? ? ? ? ? ? 26 C R P 1 19
+ATOM 1113 O OP1 . C B 2 19 ? 25.924 8.672 31.372 1.00 45.22 ? ? ? ? ? ? 26 C R OP1 1 19
+ATOM 1114 O OP2 . C B 2 19 ? 25.530 6.337 32.323 1.00 43.11 ? ? ? ? ? ? 26 C R OP2 1 19
+ATOM 1115 O "O5'" . C B 2 19 ? 27.280 7.766 33.302 1.00 42.41 ? ? ? ? ? ? 26 C R "O5'" 1 19
+ATOM 1116 C "C5'" . C B 2 19 ? 28.029 8.954 33.428 1.00 42.47 ? ? ? ? ? ? 26 C R "C5'" 1 19
+ATOM 1117 C "C4'" . C B 2 19 ? 29.199 8.688 34.344 1.00 42.95 ? ? ? ? ? ? 26 C R "C4'" 1 19
+ATOM 1118 O "O4'" . C B 2 19 ? 28.701 8.197 35.611 1.00 44.10 ? ? ? ? ? ? 26 C R "O4'" 1 19
+ATOM 1119 C "C3'" . C B 2 19 ? 30.122 7.583 33.870 1.00 43.32 ? ? ? ? ? ? 26 C R "C3'" 1 19
+ATOM 1120 O "O3'" . C B 2 19 ? 31.055 8.076 32.906 1.00 42.98 ? ? ? ? ? ? 26 C R "O3'" 1 19
+ATOM 1121 C "C2'" . C B 2 19 ? 30.780 7.169 35.180 1.00 44.14 ? ? ? ? ? ? 26 C R "C2'" 1 19
+ATOM 1122 O "O2'" . C B 2 19 ? 31.797 8.067 35.579 1.00 45.74 ? ? ? ? ? ? 26 C R "O2'" 1 19
+ATOM 1123 C "C1'" . C B 2 19 ? 29.596 7.233 36.141 1.00 44.24 ? ? ? ? ? ? 26 C R "C1'" 1 19
+ATOM 1124 N N1 . C B 2 19 ? 28.882 5.914 36.346 1.00 44.11 ? ? ? ? ? ? 26 C R N1 1 19
+ATOM 1125 C C2 . C B 2 19 ? 29.416 4.951 37.225 1.00 44.20 ? ? ? ? ? ? 26 C R C2 1 19
+ATOM 1126 O O2 . C B 2 19 ? 30.471 5.186 37.825 1.00 45.68 ? ? ? ? ? ? 26 C R O2 1 19
+ATOM 1127 N N3 . C B 2 19 ? 28.759 3.771 37.398 1.00 43.48 ? ? ? ? ? ? 26 C R N3 1 19
+ATOM 1128 C C4 . C B 2 19 ? 27.623 3.534 36.735 1.00 43.64 ? ? ? ? ? ? 26 C R C4 1 19
+ATOM 1129 N N4 . C B 2 19 ? 27.013 2.364 36.935 1.00 43.97 ? ? ? ? ? ? 26 C R N4 1 19
+ATOM 1130 C C5 . C B 2 19 ? 27.060 4.491 35.835 1.00 43.52 ? ? ? ? ? ? 26 C R C5 1 19
+ATOM 1131 C C6 . C B 2 19 ? 27.714 5.650 35.678 1.00 43.68 ? ? ? ? ? ? 26 C R C6 1 19
+ATOM 1132 P P . C B 2 20 ? 31.556 7.144 31.693 1.00 39.78 ? ? ? ? ? ? 27 C R P 1 20
+ATOM 1133 O OP1 . C B 2 20 ? 32.323 8.022 30.791 1.00 39.80 ? ? ? ? ? ? 27 C R OP1 1 20
+ATOM 1134 O OP2 . C B 2 20 ? 30.417 6.356 31.160 1.00 36.35 ? ? ? ? ? ? 27 C R OP2 1 20
+ATOM 1135 O "O5'" . C B 2 20 ? 32.572 6.148 32.419 1.00 38.07 ? ? ? ? ? ? 27 C R "O5'" 1 20
+ATOM 1136 C "C5'" . C B 2 20 ? 33.723 6.671 33.085 1.00 39.59 ? ? ? ? ? ? 27 C R "C5'" 1 20
+ATOM 1137 C "C4'" . C B 2 20 ? 34.404 5.601 33.916 1.00 40.17 ? ? ? ? ? ? 27 C R "C4'" 1 20
+ATOM 1138 O "O4'" . C B 2 20 ? 33.530 5.176 34.989 1.00 41.08 ? ? ? ? ? ? 27 C R "O4'" 1 20
+ATOM 1139 C "C3'" . C B 2 20 ? 34.684 4.298 33.189 1.00 41.06 ? ? ? ? ? ? 27 C R "C3'" 1 20
+ATOM 1140 O "O3'" . C B 2 20 ? 35.819 4.403 32.341 1.00 41.21 ? ? ? ? ? ? 27 C R "O3'" 1 20
+ATOM 1141 C "C2'" . C B 2 20 ? 34.907 3.363 34.373 1.00 41.83 ? ? ? ? ? ? 27 C R "C2'" 1 20
+ATOM 1142 O "O2'" . C B 2 20 ? 36.171 3.525 34.987 1.00 44.59 ? ? ? ? ? ? 27 C R "O2'" 1 20
+ATOM 1143 C "C1'" . C B 2 20 ? 33.805 3.823 35.319 1.00 40.05 ? ? ? ? ? ? 27 C R "C1'" 1 20
+ATOM 1144 N N1 . C B 2 20 ? 32.559 2.968 35.259 1.00 38.33 ? ? ? ? ? ? 27 C R N1 1 20
+ATOM 1145 C C2 . C B 2 20 ? 32.548 1.722 35.912 1.00 38.95 ? ? ? ? ? ? 27 C R C2 1 20
+ATOM 1146 O O2 . C B 2 20 ? 33.554 1.340 36.520 1.00 40.74 ? ? ? ? ? ? 27 C R O2 1 20
+ATOM 1147 N N3 . C B 2 20 ? 31.428 0.953 35.864 1.00 38.42 ? ? ? ? ? ? 27 C R N3 1 20
+ATOM 1148 C C4 . C B 2 20 ? 30.351 1.380 35.200 1.00 37.42 ? ? ? ? ? ? 27 C R C4 1 20
+ATOM 1149 N N4 . C B 2 20 ? 29.283 0.579 35.186 1.00 37.14 ? ? ? ? ? ? 27 C R N4 1 20
+ATOM 1150 C C5 . C B 2 20 ? 30.331 2.642 34.527 1.00 36.89 ? ? ? ? ? ? 27 C R C5 1 20
+ATOM 1151 C C6 . C B 2 20 ? 31.443 3.391 34.584 1.00 37.84 ? ? ? ? ? ? 27 C R C6 1 20
+ATOM 1152 P P . A B 2 21 ? 35.931 3.458 31.055 1.00 43.40 ? ? ? ? ? ? 28 A R P 1 21
+ATOM 1153 O OP1 . A B 2 21 ? 37.136 3.860 30.290 1.00 41.89 ? ? ? ? ? ? 28 A R OP1 1 21
+ATOM 1154 O OP2 . A B 2 21 ? 34.605 3.427 30.388 1.00 41.02 ? ? ? ? ? ? 28 A R OP2 1 21
+ATOM 1155 O "O5'" . A B 2 21 ? 36.179 2.017 31.702 1.00 43.30 ? ? ? ? ? ? 28 A R "O5'" 1 21
+ATOM 1156 C "C5'" . A B 2 21 ? 37.436 1.648 32.245 1.00 45.08 ? ? ? ? ? ? 28 A R "C5'" 1 21
+ATOM 1157 C "C4'" . A B 2 21 ? 37.394 0.197 32.687 1.00 47.78 ? ? ? ? ? ? 28 A R "C4'" 1 21
+ATOM 1158 O "O4'" . A B 2 21 ? 36.372 0.060 33.704 1.00 48.75 ? ? ? ? ? ? 28 A R "O4'" 1 21
+ATOM 1159 C "C3'" . A B 2 21 ? 36.970 -0.821 31.636 1.00 49.28 ? ? ? ? ? ? 28 A R "C3'" 1 21
+ATOM 1160 O "O3'" . A B 2 21 ? 38.037 -1.180 30.768 1.00 50.48 ? ? ? ? ? ? 28 A R "O3'" 1 21
+ATOM 1161 C "C2'" . A B 2 21 ? 36.530 -1.977 32.528 1.00 50.10 ? ? ? ? ? ? 28 A R "C2'" 1 21
+ATOM 1162 O "O2'" . A B 2 21 ? 37.603 -2.745 33.037 1.00 51.40 ? ? ? ? ? ? 28 A R "O2'" 1 21
+ATOM 1163 C "C1'" . A B 2 21 ? 35.816 -1.239 33.655 1.00 49.12 ? ? ? ? ? ? 28 A R "C1'" 1 21
+ATOM 1164 N N9 . A B 2 21 ? 34.381 -1.148 33.405 1.00 49.16 ? ? ? ? ? ? 28 A R N9 1 21
+ATOM 1165 C C8 . A B 2 21 ? 33.703 -0.130 32.793 1.00 49.52 ? ? ? ? ? ? 28 A R C8 1 21
+ATOM 1166 N N7 . A B 2 21 ? 32.410 -0.333 32.696 1.00 50.33 ? ? ? ? ? ? 28 A R N7 1 21
+ATOM 1167 C C5 . A B 2 21 ? 32.229 -1.574 33.280 1.00 49.47 ? ? ? ? ? ? 28 A R C5 1 21
+ATOM 1168 C C6 . A B 2 21 ? 31.082 -2.366 33.495 1.00 49.83 ? ? ? ? ? ? 28 A R C6 1 21
+ATOM 1169 N N6 . A B 2 21 ? 29.853 -1.996 33.122 1.00 49.71 ? ? ? ? ? ? 28 A R N6 1 21
+ATOM 1170 N N1 . A B 2 21 ? 31.250 -3.562 34.102 1.00 50.49 ? ? ? ? ? ? 28 A R N1 1 21
+ATOM 1171 C C2 . A B 2 21 ? 32.482 -3.938 34.473 1.00 49.24 ? ? ? ? ? ? 28 A R C2 1 21
+ATOM 1172 N N3 . A B 2 21 ? 33.631 -3.277 34.327 1.00 48.13 ? ? ? ? ? ? 28 A R N3 1 21
+ATOM 1173 C C4 . A B 2 21 ? 33.434 -2.095 33.718 1.00 49.09 ? ? ? ? ? ? 28 A R C4 1 21
+ATOM 1174 P P . U B 2 22 ? 37.749 -1.562 29.235 1.00 51.88 ? ? ? ? ? ? 29 U R P 1 22
+ATOM 1175 O OP1 . U B 2 22 ? 39.065 -1.714 28.578 1.00 52.03 ? ? ? ? ? ? 29 U R OP1 1 22
+ATOM 1176 O OP2 . U B 2 22 ? 36.747 -0.632 28.667 1.00 50.95 ? ? ? ? ? ? 29 U R OP2 1 22
+ATOM 1177 O "O5'" . U B 2 22 ? 37.032 -2.985 29.327 1.00 52.23 ? ? ? ? ? ? 29 U R "O5'" 1 22
+ATOM 1178 C "C5'" . U B 2 22 ? 37.724 -4.155 29.742 1.00 51.27 ? ? ? ? ? ? 29 U R "C5'" 1 22
+ATOM 1179 C "C4'" . U B 2 22 ? 36.710 -5.241 30.046 1.00 51.64 ? ? ? ? ? ? 29 U R "C4'" 1 22
+ATOM 1180 O "O4'" . U B 2 22 ? 35.768 -4.729 31.021 1.00 51.20 ? ? ? ? ? ? 29 U R "O4'" 1 22
+ATOM 1181 C "C3'" . U B 2 22 ? 35.803 -5.623 28.888 1.00 51.62 ? ? ? ? ? ? 29 U R "C3'" 1 22
+ATOM 1182 O "O3'" . U B 2 22 ? 36.436 -6.515 27.977 1.00 53.54 ? ? ? ? ? ? 29 U R "O3'" 1 22
+ATOM 1183 C "C2'" . U B 2 22 ? 34.636 -6.260 29.639 1.00 50.64 ? ? ? ? ? ? 29 U R "C2'" 1 22
+ATOM 1184 O "O2'" . U B 2 22 ? 34.909 -7.570 30.098 1.00 48.36 ? ? ? ? ? ? 29 U R "O2'" 1 22
+ATOM 1185 C "C1'" . U B 2 22 ? 34.487 -5.298 30.814 1.00 49.41 ? ? ? ? ? ? 29 U R "C1'" 1 22
+ATOM 1186 N N1 . U B 2 22 ? 33.449 -4.230 30.577 1.00 49.14 ? ? ? ? ? ? 29 U R N1 1 22
+ATOM 1187 C C2 . U B 2 22 ? 32.119 -4.509 30.860 1.00 48.59 ? ? ? ? ? ? 29 U R C2 1 22
+ATOM 1188 O O2 . U B 2 22 ? 31.733 -5.578 31.298 1.00 47.71 ? ? ? ? ? ? 29 U R O2 1 22
+ATOM 1189 N N3 . U B 2 22 ? 31.237 -3.482 30.606 1.00 47.53 ? ? ? ? ? ? 29 U R N3 1 22
+ATOM 1190 C C4 . U B 2 22 ? 31.542 -2.224 30.111 1.00 48.35 ? ? ? ? ? ? 29 U R C4 1 22
+ATOM 1191 O O4 . U B 2 22 ? 30.646 -1.401 29.941 1.00 49.31 ? ? ? ? ? ? 29 U R O4 1 22
+ATOM 1192 C C5 . U B 2 22 ? 32.942 -2.002 29.841 1.00 48.45 ? ? ? ? ? ? 29 U R C5 1 22
+ATOM 1193 C C6 . U B 2 22 ? 33.819 -2.989 30.078 1.00 48.88 ? ? ? ? ? ? 29 U R C6 1 22
+ATOM 1194 P P . U B 2 23 ? 35.891 -6.612 26.473 1.00 55.92 ? ? ? ? ? ? 30 U R P 1 23
+ATOM 1195 O OP1 . U B 2 23 ? 36.885 -7.370 25.685 1.00 56.79 ? ? ? ? ? ? 30 U R OP1 1 23
+ATOM 1196 O OP2 . U B 2 23 ? 35.472 -5.266 26.026 1.00 56.02 ? ? ? ? ? ? 30 U R OP2 1 23
+ATOM 1197 O "O5'" . U B 2 23 ? 34.562 -7.489 26.615 1.00 55.88 ? ? ? ? ? ? 30 U R "O5'" 1 23
+ATOM 1198 C "C5'" . U B 2 23 ? 34.646 -8.880 26.907 1.00 54.03 ? ? ? ? ? ? 30 U R "C5'" 1 23
+ATOM 1199 C "C4'" . U B 2 23 ? 33.261 -9.453 27.111 1.00 52.65 ? ? ? ? ? ? 30 U R "C4'" 1 23
+ATOM 1200 O "O4'" . U B 2 23 ? 32.604 -8.723 28.174 1.00 53.98 ? ? ? ? ? ? 30 U R "O4'" 1 23
+ATOM 1201 C "C3'" . U B 2 23 ? 32.326 -9.267 25.931 1.00 52.84 ? ? ? ? ? ? 30 U R "C3'" 1 23
+ATOM 1202 O "O3'" . U B 2 23 ? 32.533 -10.276 24.969 1.00 53.35 ? ? ? ? ? ? 30 U R "O3'" 1 23
+ATOM 1203 C "C2'" . U B 2 23 ? 30.964 -9.386 26.601 1.00 53.57 ? ? ? ? ? ? 30 U R "C2'" 1 23
+ATOM 1204 O "O2'" . U B 2 23 ? 30.578 -10.727 26.842 1.00 53.89 ? ? ? ? ? ? 30 U R "O2'" 1 23
+ATOM 1205 C "C1'" . U B 2 23 ? 31.212 -8.649 27.915 1.00 53.68 ? ? ? ? ? ? 30 U R "C1'" 1 23
+ATOM 1206 N N1 . U B 2 23 ? 30.749 -7.219 27.876 1.00 53.17 ? ? ? ? ? ? 30 U R N1 1 23
+ATOM 1207 C C2 . U B 2 23 ? 29.401 -6.947 28.060 1.00 53.95 ? ? ? ? ? ? 30 U R C2 1 23
+ATOM 1208 O O2 . U B 2 23 ? 28.556 -7.801 28.260 1.00 53.72 ? ? ? ? ? ? 30 U R O2 1 23
+ATOM 1209 N N3 . U B 2 23 ? 29.064 -5.616 28.007 1.00 55.46 ? ? ? ? ? ? 30 U R N3 1 23
+ATOM 1210 C C4 . U B 2 23 ? 29.917 -4.547 27.788 1.00 55.95 ? ? ? ? ? ? 30 U R C4 1 23
+ATOM 1211 O O4 . U B 2 23 ? 29.461 -3.405 27.769 1.00 57.24 ? ? ? ? ? ? 30 U R O4 1 23
+ATOM 1212 C C5 . U B 2 23 ? 31.304 -4.906 27.600 1.00 54.11 ? ? ? ? ? ? 30 U R C5 1 23
+ATOM 1213 C C6 . U B 2 23 ? 31.658 -6.198 27.651 1.00 52.33 ? ? ? ? ? ? 30 U R C6 1 23
+ATOM 1214 P P . C B 2 24 ? 32.283 -9.967 23.422 1.00 52.17 ? ? ? ? ? ? 31 C R P 1 24
+ATOM 1215 O OP1 . C B 2 24 ? 32.848 -11.102 22.662 1.00 53.59 ? ? ? ? ? ? 31 C R OP1 1 24
+ATOM 1216 O OP2 . C B 2 24 ? 32.747 -8.594 23.131 1.00 54.12 ? ? ? ? ? ? 31 C R OP2 1 24
+ATOM 1217 O "O5'" . C B 2 24 ? 30.687 -9.957 23.300 1.00 52.70 ? ? ? ? ? ? 31 C R "O5'" 1 24
+ATOM 1218 C "C5'" . C B 2 24 ? 29.932 -11.153 23.477 1.00 53.71 ? ? ? ? ? ? 31 C R "C5'" 1 24
+ATOM 1219 C "C4'" . C B 2 24 ? 28.450 -10.857 23.618 1.00 53.63 ? ? ? ? ? ? 31 C R "C4'" 1 24
+ATOM 1220 O "O4'" . C B 2 24 ? 28.230 -9.974 24.745 1.00 54.03 ? ? ? ? ? ? 31 C R "O4'" 1 24
+ATOM 1221 C "C3'" . C B 2 24 ? 27.817 -10.070 22.484 1.00 54.65 ? ? ? ? ? ? 31 C R "C3'" 1 24
+ATOM 1222 O "O3'" . C B 2 24 ? 27.605 -10.864 21.320 1.00 56.43 ? ? ? ? ? ? 31 C R "O3'" 1 24
+ATOM 1223 C "C2'" . C B 2 24 ? 26.527 -9.592 23.151 1.00 54.06 ? ? ? ? ? ? 31 C R "C2'" 1 24
+ATOM 1224 O "O2'" . C B 2 24 ? 25.530 -10.586 23.275 1.00 53.49 ? ? ? ? ? ? 31 C R "O2'" 1 24
+ATOM 1225 C "C1'" . C B 2 24 ? 27.053 -9.208 24.529 1.00 53.46 ? ? ? ? ? ? 31 C R "C1'" 1 24
+ATOM 1226 N N1 . C B 2 24 ? 27.340 -7.732 24.675 1.00 53.11 ? ? ? ? ? ? 31 C R N1 1 24
+ATOM 1227 C C2 . C B 2 24 ? 26.282 -6.835 24.929 1.00 53.12 ? ? ? ? ? ? 31 C R C2 1 24
+ATOM 1228 O O2 . C B 2 24 ? 25.121 -7.255 25.028 1.00 52.24 ? ? ? ? ? ? 31 C R O2 1 24
+ATOM 1229 N N3 . C B 2 24 ? 26.559 -5.511 25.059 1.00 53.11 ? ? ? ? ? ? 31 C R N3 1 24
+ATOM 1230 C C4 . C B 2 24 ? 27.817 -5.073 24.947 1.00 53.09 ? ? ? ? ? ? 31 C R C4 1 24
+ATOM 1231 N N4 . C B 2 24 ? 28.030 -3.762 25.087 1.00 53.24 ? ? ? ? ? ? 31 C R N4 1 24
+ATOM 1232 C C5 . C B 2 24 ? 28.908 -5.959 24.691 1.00 52.72 ? ? ? ? ? ? 31 C R C5 1 24
+ATOM 1233 C C6 . C B 2 24 ? 28.625 -7.264 24.566 1.00 52.42 ? ? ? ? ? ? 31 C R C6 1 24
+ATOM 1234 P P . G B 2 25 ? 27.805 -10.204 19.869 1.00 57.68 ? ? ? ? ? ? 32 G R P 1 25
+ATOM 1235 O OP1 . G B 2 25 ? 27.654 -11.275 18.856 1.00 57.60 ? ? ? ? ? ? 32 G R OP1 1 25
+ATOM 1236 O OP2 . G B 2 25 ? 29.032 -9.374 19.887 1.00 55.05 ? ? ? ? ? ? 32 G R OP2 1 25
+ATOM 1237 O "O5'" . G B 2 25 ? 26.552 -9.219 19.755 1.00 56.53 ? ? ? ? ? ? 32 G R "O5'" 1 25
+ATOM 1238 C "C5'" . G B 2 25 ? 25.214 -9.713 19.775 1.00 56.44 ? ? ? ? ? ? 32 G R "C5'" 1 25
+ATOM 1239 C "C4'" . G B 2 25 ? 24.243 -8.552 19.860 1.00 57.18 ? ? ? ? ? ? 32 G R "C4'" 1 25
+ATOM 1240 O "O4'" . G B 2 25 ? 24.377 -7.870 21.133 1.00 57.36 ? ? ? ? ? ? 32 G R "O4'" 1 25
+ATOM 1241 C "C3'" . G B 2 25 ? 24.526 -7.412 18.899 1.00 58.50 ? ? ? ? ? ? 32 G R "C3'" 1 25
+ATOM 1242 O "O3'" . G B 2 25 ? 24.232 -7.740 17.545 1.00 60.15 ? ? ? ? ? ? 32 G R "O3'" 1 25
+ATOM 1243 C "C2'" . G B 2 25 ? 23.668 -6.311 19.510 1.00 57.04 ? ? ? ? ? ? 32 G R "C2'" 1 25
+ATOM 1244 O "O2'" . G B 2 25 ? 22.280 -6.522 19.345 1.00 59.42 ? ? ? ? ? ? 32 G R "O2'" 1 25
+ATOM 1245 C "C1'" . G B 2 25 ? 24.075 -6.490 20.971 1.00 55.51 ? ? ? ? ? ? 32 G R "C1'" 1 25
+ATOM 1246 N N9 . G B 2 25 ? 25.235 -5.664 21.304 1.00 53.55 ? ? ? ? ? ? 32 G R N9 1 25
+ATOM 1247 C C8 . G B 2 25 ? 26.554 -6.052 21.347 1.00 53.69 ? ? ? ? ? ? 32 G R C8 1 25
+ATOM 1248 N N7 . G B 2 25 ? 27.377 -5.089 21.658 1.00 53.73 ? ? ? ? ? ? 32 G R N7 1 25
+ATOM 1249 C C5 . G B 2 25 ? 26.554 -3.985 21.829 1.00 53.84 ? ? ? ? ? ? 32 G R C5 1 25
+ATOM 1250 C C6 . G B 2 25 ? 26.881 -2.650 22.174 1.00 54.54 ? ? ? ? ? ? 32 G R C6 1 25
+ATOM 1251 O O6 . G B 2 25 ? 28.007 -2.181 22.400 1.00 56.21 ? ? ? ? ? ? 32 G R O6 1 25
+ATOM 1252 N N1 . G B 2 25 ? 25.752 -1.829 22.248 1.00 52.91 ? ? ? ? ? ? 32 G R N1 1 25
+ATOM 1253 C C2 . G B 2 25 ? 24.465 -2.258 22.013 1.00 52.70 ? ? ? ? ? ? 32 G R C2 1 25
+ATOM 1254 N N2 . G B 2 25 ? 23.496 -1.339 22.126 1.00 53.64 ? ? ? ? ? ? 32 G R N2 1 25
+ATOM 1255 N N3 . G B 2 25 ? 24.147 -3.507 21.689 1.00 52.97 ? ? ? ? ? ? 32 G R N3 1 25
+ATOM 1256 C C4 . G B 2 25 ? 25.234 -4.319 21.614 1.00 53.66 ? ? ? ? ? ? 32 G R C4 1 25
+ATOM 1257 P P . A B 2 26 ? 25.364 -7.422 16.452 1.00 61.56 ? ? ? ? ? ? 33 A R P 1 26
+ATOM 1258 O OP1 . A B 2 26 ? 25.209 -8.395 15.347 1.00 60.83 ? ? ? ? ? ? 33 A R OP1 1 26
+ATOM 1259 O OP2 . A B 2 26 ? 26.673 -7.287 17.141 1.00 59.56 ? ? ? ? ? ? 33 A R OP2 1 26
+ATOM 1260 O "O5'" . A B 2 26 ? 24.923 -5.972 15.940 1.00 59.89 ? ? ? ? ? ? 33 A R "O5'" 1 26
+ATOM 1261 C "C5'" . A B 2 26 ? 25.897 -5.006 15.557 1.00 58.91 ? ? ? ? ? ? 33 A R "C5'" 1 26
+ATOM 1262 C "C4'" . A B 2 26 ? 25.212 -3.749 15.057 1.00 57.67 ? ? ? ? ? ? 33 A R "C4'" 1 26
+ATOM 1263 O "O4'" . A B 2 26 ? 24.090 -4.120 14.217 1.00 57.15 ? ? ? ? ? ? 33 A R "O4'" 1 26
+ATOM 1264 C "C3'" . A B 2 26 ? 24.622 -2.871 16.147 1.00 56.29 ? ? ? ? ? ? 33 A R "C3'" 1 26
+ATOM 1265 O "O3'" . A B 2 26 ? 25.604 -1.932 16.570 1.00 56.61 ? ? ? ? ? ? 33 A R "O3'" 1 26
+ATOM 1266 C "C2'" . A B 2 26 ? 23.457 -2.197 15.434 1.00 55.61 ? ? ? ? ? ? 33 A R "C2'" 1 26
+ATOM 1267 O "O2'" . A B 2 26 ? 23.855 -1.055 14.695 1.00 55.44 ? ? ? ? ? ? 33 A R "O2'" 1 26
+ATOM 1268 C "C1'" . A B 2 26 ? 22.981 -3.284 14.474 1.00 55.30 ? ? ? ? ? ? 33 A R "C1'" 1 26
+ATOM 1269 N N9 . A B 2 26 ? 21.864 -4.121 14.930 1.00 55.07 ? ? ? ? ? ? 33 A R N9 1 26
+ATOM 1270 C C8 . A B 2 26 ? 21.863 -5.482 15.079 1.00 54.80 ? ? ? ? ? ? 33 A R C8 1 26
+ATOM 1271 N N7 . A B 2 26 ? 20.720 -5.978 15.491 1.00 54.47 ? ? ? ? ? ? 33 A R N7 1 26
+ATOM 1272 C C5 . A B 2 26 ? 19.907 -4.868 15.616 1.00 54.13 ? ? ? ? ? ? 33 A R C5 1 26
+ATOM 1273 C C6 . A B 2 26 ? 18.564 -4.713 16.014 1.00 54.74 ? ? ? ? ? ? 33 A R C6 1 26
+ATOM 1274 N N6 . A B 2 26 ? 17.779 -5.732 16.372 1.00 55.74 ? ? ? ? ? ? 33 A R N6 1 26
+ATOM 1275 N N1 . A B 2 26 ? 18.047 -3.466 16.028 1.00 55.08 ? ? ? ? ? ? 33 A R N1 1 26
+ATOM 1276 C C2 . A B 2 26 ? 18.830 -2.439 15.671 1.00 55.44 ? ? ? ? ? ? 33 A R C2 1 26
+ATOM 1277 N N3 . A B 2 26 ? 20.104 -2.458 15.280 1.00 55.35 ? ? ? ? ? ? 33 A R N3 1 26
+ATOM 1278 C C4 . A B 2 26 ? 20.592 -3.714 15.273 1.00 54.75 ? ? ? ? ? ? 33 A R C4 1 26
+ATOM 1279 P P . A B 2 27 ? 25.899 -1.729 18.128 1.00 55.74 ? ? ? ? ? ? 34 A R P 1 27
+ATOM 1280 O OP1 . A B 2 27 ? 27.156 -0.961 18.279 1.00 54.88 ? ? ? ? ? ? 34 A R OP1 1 27
+ATOM 1281 O OP2 . A B 2 27 ? 25.781 -3.059 18.763 1.00 57.39 ? ? ? ? ? ? 34 A R OP2 1 27
+ATOM 1282 O "O5'" . A B 2 27 ? 24.665 -0.832 18.614 1.00 54.02 ? ? ? ? ? ? 34 A R "O5'" 1 27
+ATOM 1283 C "C5'" . A B 2 27 ? 24.456 0.481 18.090 1.00 52.80 ? ? ? ? ? ? 34 A R "C5'" 1 27
+ATOM 1284 C "C4'" . A B 2 27 ? 22.992 0.875 18.185 1.00 52.89 ? ? ? ? ? ? 34 A R "C4'" 1 27
+ATOM 1285 O "O4'" . A B 2 27 ? 22.172 -0.161 17.588 1.00 52.10 ? ? ? ? ? ? 34 A R "O4'" 1 27
+ATOM 1286 C "C3'" . A B 2 27 ? 22.445 1.015 19.600 1.00 53.41 ? ? ? ? ? ? 34 A R "C3'" 1 27
+ATOM 1287 O "O3'" . A B 2 27 ? 22.684 2.325 20.108 1.00 53.18 ? ? ? ? ? ? 34 A R "O3'" 1 27
+ATOM 1288 C "C2'" . A B 2 27 ? 20.954 0.743 19.413 1.00 53.05 ? ? ? ? ? ? 34 A R "C2'" 1 27
+ATOM 1289 O "O2'" . A B 2 27 ? 20.243 1.896 19.006 1.00 54.41 ? ? ? ? ? ? 34 A R "O2'" 1 27
+ATOM 1290 C "C1'" . A B 2 27 ? 20.940 -0.277 18.282 1.00 51.91 ? ? ? ? ? ? 34 A R "C1'" 1 27
+ATOM 1291 N N9 . A B 2 27 ? 20.731 -1.672 18.685 1.00 50.62 ? ? ? ? ? ? 34 A R N9 1 27
+ATOM 1292 C C8 . A B 2 27 ? 21.693 -2.623 18.898 1.00 51.25 ? ? ? ? ? ? 34 A R C8 1 27
+ATOM 1293 N N7 . A B 2 27 ? 21.222 -3.801 19.236 1.00 49.82 ? ? ? ? ? ? 34 A R N7 1 27
+ATOM 1294 C C5 . A B 2 27 ? 19.852 -3.617 19.243 1.00 49.76 ? ? ? ? ? ? 34 A R C5 1 27
+ATOM 1295 C C6 . A B 2 27 ? 18.774 -4.490 19.521 1.00 49.94 ? ? ? ? ? ? 34 A R C6 1 27
+ATOM 1296 N N6 . A B 2 27 ? 18.940 -5.773 19.859 1.00 49.41 ? ? ? ? ? ? 34 A R N6 1 27
+ATOM 1297 N N1 . A B 2 27 ? 17.515 -3.998 19.441 1.00 49.13 ? ? ? ? ? ? 34 A R N1 1 27
+ATOM 1298 C C2 . A B 2 27 ? 17.354 -2.711 19.106 1.00 49.13 ? ? ? ? ? ? 34 A R C2 1 27
+ATOM 1299 N N3 . A B 2 27 ? 18.290 -1.800 18.822 1.00 49.72 ? ? ? ? ? ? 34 A R N3 1 27
+ATOM 1300 C C4 . A B 2 27 ? 19.531 -2.314 18.908 1.00 49.62 ? ? ? ? ? ? 34 A R C4 1 27
+ATOM 1301 P P . A B 2 28 ? 22.801 2.583 21.687 1.00 53.86 ? ? ? ? ? ? 35 A R P 1 28
+ATOM 1302 O OP1 . A B 2 28 ? 23.178 4.002 21.865 1.00 53.79 ? ? ? ? ? ? 35 A R OP1 1 28
+ATOM 1303 O OP2 . A B 2 28 ? 23.645 1.520 22.280 1.00 53.01 ? ? ? ? ? ? 35 A R OP2 1 28
+ATOM 1304 O "O5'" . A B 2 28 ? 21.308 2.352 22.218 1.00 53.14 ? ? ? ? ? ? 35 A R "O5'" 1 28
+ATOM 1305 C "C5'" . A B 2 28 ? 20.402 3.437 22.382 1.00 52.47 ? ? ? ? ? ? 35 A R "C5'" 1 28
+ATOM 1306 C "C4'" . A B 2 28 ? 18.998 2.929 22.666 1.00 52.85 ? ? ? ? ? ? 35 A R "C4'" 1 28
+ATOM 1307 O "O4'" . A B 2 28 ? 18.675 1.828 21.776 1.00 51.59 ? ? ? ? ? ? 35 A R "O4'" 1 28
+ATOM 1308 C "C3'" . A B 2 28 ? 18.780 2.345 24.053 1.00 53.08 ? ? ? ? ? ? 35 A R "C3'" 1 28
+ATOM 1309 O "O3'" . A B 2 28 ? 18.546 3.363 25.014 1.00 55.52 ? ? ? ? ? ? 35 A R "O3'" 1 28
+ATOM 1310 C "C2'" . A B 2 28 ? 17.554 1.462 23.825 1.00 51.88 ? ? ? ? ? ? 35 A R "C2'" 1 28
+ATOM 1311 O "O2'" . A B 2 28 ? 16.329 2.169 23.769 1.00 50.77 ? ? ? ? ? ? 35 A R "O2'" 1 28
+ATOM 1312 C "C1'" . A B 2 28 ? 17.890 0.869 22.461 1.00 50.48 ? ? ? ? ? ? 35 A R "C1'" 1 28
+ATOM 1313 N N9 . A B 2 28 ? 18.635 -0.384 22.559 1.00 48.64 ? ? ? ? ? ? 35 A R N9 1 28
+ATOM 1314 C C8 . A B 2 28 ? 19.995 -0.546 22.610 1.00 49.70 ? ? ? ? ? ? 35 A R C8 1 28
+ATOM 1315 N N7 . A B 2 28 ? 20.384 -1.798 22.699 1.00 48.97 ? ? ? ? ? ? 35 A R N7 1 28
+ATOM 1316 C C5 . A B 2 28 ? 19.192 -2.508 22.711 1.00 46.90 ? ? ? ? ? ? 35 A R C5 1 28
+ATOM 1317 C C6 . A B 2 28 ? 18.911 -3.888 22.795 1.00 46.04 ? ? ? ? ? ? 35 A R C6 1 28
+ATOM 1318 N N6 . A B 2 28 ? 19.859 -4.832 22.882 1.00 46.58 ? ? ? ? ? ? 35 A R N6 1 28
+ATOM 1319 N N1 . A B 2 28 ? 17.612 -4.262 22.779 1.00 45.17 ? ? ? ? ? ? 35 A R N1 1 28
+ATOM 1320 C C2 . A B 2 28 ? 16.664 -3.315 22.691 1.00 45.35 ? ? ? ? ? ? 35 A R C2 1 28
+ATOM 1321 N N3 . A B 2 28 ? 16.805 -1.992 22.613 1.00 45.86 ? ? ? ? ? ? 35 A R N3 1 28
+ATOM 1322 C C4 . A B 2 28 ? 18.105 -1.650 22.628 1.00 46.96 ? ? ? ? ? ? 35 A R C4 1 28
+ATOM 1323 P P . G B 2 29 ? 19.511 3.530 26.284 1.00 58.20 ? ? ? ? ? ? 36 G R P 1 29
+ATOM 1324 O OP1 . G B 2 29 ? 18.775 4.376 27.253 1.00 57.99 ? ? ? ? ? ? 36 G R OP1 1 29
+ATOM 1325 O OP2 . G B 2 29 ? 20.855 3.939 25.807 1.00 55.69 ? ? ? ? ? ? 36 G R OP2 1 29
+ATOM 1326 O "O5'" . G B 2 29 ? 19.655 2.050 26.878 1.00 57.97 ? ? ? ? ? ? 36 G R "O5'" 1 29
+ATOM 1327 C "C5'" . G B 2 29 ? 18.560 1.412 27.534 1.00 57.83 ? ? ? ? ? ? 36 G R "C5'" 1 29
+ATOM 1328 C "C4'" . G B 2 29 ? 18.527 -0.076 27.225 1.00 57.14 ? ? ? ? ? ? 36 G R "C4'" 1 29
+ATOM 1329 O "O4'" . G B 2 29 ? 19.195 -0.379 25.969 1.00 56.01 ? ? ? ? ? ? 36 G R "O4'" 1 29
+ATOM 1330 C "C3'" . G B 2 29 ? 19.252 -0.970 28.216 1.00 56.29 ? ? ? ? ? ? 36 G R "C3'" 1 29
+ATOM 1331 O "O3'" . G B 2 29 ? 18.497 -1.147 29.413 1.00 54.08 ? ? ? ? ? ? 36 G R "O3'" 1 29
+ATOM 1332 C "C2'" . G B 2 29 ? 19.365 -2.246 27.386 1.00 56.82 ? ? ? ? ? ? 36 G R "C2'" 1 29
+ATOM 1333 O "O2'" . G B 2 29 ? 18.134 -2.940 27.256 1.00 58.92 ? ? ? ? ? ? 36 G R "O2'" 1 29
+ATOM 1334 C "C1'" . G B 2 29 ? 19.789 -1.662 26.038 1.00 53.98 ? ? ? ? ? ? 36 G R "C1'" 1 29
+ATOM 1335 N N9 . G B 2 29 ? 21.240 -1.527 25.870 1.00 51.24 ? ? ? ? ? ? 36 G R N9 1 29
+ATOM 1336 C C8 . G B 2 29 ? 21.969 -0.360 25.841 1.00 50.73 ? ? ? ? ? ? 36 G R C8 1 29
+ATOM 1337 N N7 . G B 2 29 ? 23.253 -0.536 25.681 1.00 48.03 ? ? ? ? ? ? 36 G R N7 1 29
+ATOM 1338 C C5 . G B 2 29 ? 23.393 -1.914 25.600 1.00 47.67 ? ? ? ? ? ? 36 G R C5 1 29
+ATOM 1339 C C6 . G B 2 29 ? 24.558 -2.703 25.430 1.00 46.74 ? ? ? ? ? ? 36 G R C6 1 29
+ATOM 1340 O O6 . G B 2 29 ? 25.729 -2.322 25.314 1.00 45.80 ? ? ? ? ? ? 36 G R O6 1 29
+ATOM 1341 N N1 . G B 2 29 ? 24.269 -4.067 25.399 1.00 46.80 ? ? ? ? ? ? 36 G R N1 1 29
+ATOM 1342 C C2 . G B 2 29 ? 23.003 -4.598 25.520 1.00 48.59 ? ? ? ? ? ? 36 G R C2 1 29
+ATOM 1343 N N2 . G B 2 29 ? 22.910 -5.934 25.471 1.00 48.06 ? ? ? ? ? ? 36 G R N2 1 29
+ATOM 1344 N N3 . G B 2 29 ? 21.900 -3.870 25.682 1.00 48.76 ? ? ? ? ? ? 36 G R N3 1 29
+ATOM 1345 C C4 . G B 2 29 ? 22.165 -2.538 25.714 1.00 49.31 ? ? ? ? ? ? 36 G R C4 1 29
+ATOM 1346 P P . A B 2 30 ? 19.268 -1.223 30.816 1.00 52.19 ? ? ? ? ? ? 37 A R P 1 30
+ATOM 1347 O OP1 . A B 2 30 ? 18.287 -1.000 31.901 1.00 52.56 ? ? ? ? ? ? 37 A R OP1 1 30
+ATOM 1348 O OP2 . A B 2 30 ? 20.468 -0.356 30.739 1.00 53.44 ? ? ? ? ? ? 37 A R OP2 1 30
+ATOM 1349 O "O5'" . A B 2 30 ? 19.758 -2.747 30.849 1.00 50.68 ? ? ? ? ? ? 37 A R "O5'" 1 30
+ATOM 1350 C "C5'" . A B 2 30 ? 18.810 -3.814 30.923 1.00 47.96 ? ? ? ? ? ? 37 A R "C5'" 1 30
+ATOM 1351 C "C4'" . A B 2 30 ? 19.407 -5.142 30.487 1.00 45.30 ? ? ? ? ? ? 37 A R "C4'" 1 30
+ATOM 1352 O "O4'" . A B 2 30 ? 20.061 -5.001 29.198 1.00 43.97 ? ? ? ? ? ? 37 A R "O4'" 1 30
+ATOM 1353 C "C3'" . A B 2 30 ? 20.502 -5.691 31.389 1.00 43.93 ? ? ? ? ? ? 37 A R "C3'" 1 30
+ATOM 1354 O "O3'" . A B 2 30 ? 19.963 -6.389 32.497 1.00 43.64 ? ? ? ? ? ? 37 A R "O3'" 1 30
+ATOM 1355 C "C2'" . A B 2 30 ? 21.231 -6.628 30.436 1.00 43.05 ? ? ? ? ? ? 37 A R "C2'" 1 30
+ATOM 1356 O "O2'" . A B 2 30 ? 20.541 -7.846 30.248 1.00 44.55 ? ? ? ? ? ? 37 A R "O2'" 1 30
+ATOM 1357 C "C1'" . A B 2 30 ? 21.228 -5.807 29.152 1.00 42.24 ? ? ? ? ? ? 37 A R "C1'" 1 30
+ATOM 1358 N N9 . A B 2 30 ? 22.415 -4.959 28.993 1.00 41.12 ? ? ? ? ? ? 37 A R N9 1 30
+ATOM 1359 C C8 . A B 2 30 ? 22.462 -3.591 29.039 1.00 41.53 ? ? ? ? ? ? 37 A R C8 1 30
+ATOM 1360 N N7 . A B 2 30 ? 23.662 -3.085 28.864 1.00 40.53 ? ? ? ? ? ? 37 A R N7 1 30
+ATOM 1361 C C5 . A B 2 30 ? 24.463 -4.195 28.689 1.00 39.80 ? ? ? ? ? ? 37 A R C5 1 30
+ATOM 1362 C C6 . A B 2 30 ? 25.847 -4.333 28.455 1.00 40.58 ? ? ? ? ? ? 37 A R C6 1 30
+ATOM 1363 N N6 . A B 2 30 ? 26.675 -3.287 28.360 1.00 39.26 ? ? ? ? ? ? 37 A R N6 1 30
+ATOM 1364 N N1 . A B 2 30 ? 26.346 -5.585 28.321 1.00 39.87 ? ? ? ? ? ? 37 A R N1 1 30
+ATOM 1365 C C2 . A B 2 30 ? 25.502 -6.622 28.415 1.00 41.00 ? ? ? ? ? ? 37 A R C2 1 30
+ATOM 1366 N N3 . A B 2 30 ? 24.183 -6.615 28.634 1.00 40.26 ? ? ? ? ? ? 37 A R N3 1 30
+ATOM 1367 C C4 . A B 2 30 ? 23.716 -5.360 28.764 1.00 40.22 ? ? ? ? ? ? 37 A R C4 1 30
+ATOM 1368 P P . G B 2 31 ? 20.801 -6.465 33.861 1.00 44.19 ? ? ? ? ? ? 38 G R P 1 31
+ATOM 1369 O OP1 . G B 2 31 ? 19.904 -7.043 34.886 1.00 44.89 ? ? ? ? ? ? 38 G R OP1 1 31
+ATOM 1370 O OP2 . G B 2 31 ? 21.425 -5.149 34.106 1.00 43.62 ? ? ? ? ? ? 38 G R OP2 1 31
+ATOM 1371 O "O5'" . G B 2 31 ? 21.993 -7.478 33.532 1.00 42.81 ? ? ? ? ? ? 38 G R "O5'" 1 31
+ATOM 1372 C "C5'" . G B 2 31 ? 21.780 -8.880 33.459 1.00 41.49 ? ? ? ? ? ? 38 G R "C5'" 1 31
+ATOM 1373 C "C4'" . G B 2 31 ? 23.070 -9.592 33.091 1.00 43.18 ? ? ? ? ? ? 38 G R "C4'" 1 31
+ATOM 1374 O "O4'" . G B 2 31 ? 23.612 -9.055 31.860 1.00 42.94 ? ? ? ? ? ? 38 G R "O4'" 1 31
+ATOM 1375 C "C3'" . G B 2 31 ? 24.221 -9.425 34.071 1.00 43.20 ? ? ? ? ? ? 38 G R "C3'" 1 31
+ATOM 1376 O "O3'" . G B 2 31 ? 24.055 -10.299 35.164 1.00 43.73 ? ? ? ? ? ? 38 G R "O3'" 1 31
+ATOM 1377 C "C2'" . G B 2 31 ? 25.407 -9.815 33.205 1.00 41.94 ? ? ? ? ? ? 38 G R "C2'" 1 31
+ATOM 1378 O "O2'" . G B 2 31 ? 25.520 -11.212 33.024 1.00 41.94 ? ? ? ? ? ? 38 G R "O2'" 1 31
+ATOM 1379 C "C1'" . G B 2 31 ? 25.026 -9.143 31.889 1.00 43.10 ? ? ? ? ? ? 38 G R "C1'" 1 31
+ATOM 1380 N N9 . G B 2 31 ? 25.602 -7.807 31.746 1.00 44.86 ? ? ? ? ? ? 38 G R N9 1 31
+ATOM 1381 C C8 . G B 2 31 ? 24.936 -6.604 31.741 1.00 45.13 ? ? ? ? ? ? 38 G R C8 1 31
+ATOM 1382 N N7 . G B 2 31 ? 25.720 -5.571 31.599 1.00 44.89 ? ? ? ? ? ? 38 G R N7 1 31
+ATOM 1383 C C5 . G B 2 31 ? 26.988 -6.123 31.511 1.00 45.32 ? ? ? ? ? ? 38 G R C5 1 31
+ATOM 1384 C C6 . G B 2 31 ? 28.243 -5.495 31.349 1.00 46.89 ? ? ? ? ? ? 38 G R C6 1 31
+ATOM 1385 O O6 . G B 2 31 ? 28.487 -4.287 31.253 1.00 50.65 ? ? ? ? ? ? 38 G R O6 1 31
+ATOM 1386 N N1 . G B 2 31 ? 29.288 -6.412 31.307 1.00 47.83 ? ? ? ? ? ? 38 G R N1 1 31
+ATOM 1387 C C2 . G B 2 31 ? 29.143 -7.776 31.406 1.00 47.49 ? ? ? ? ? ? 38 G R C2 1 31
+ATOM 1388 N N2 . G B 2 31 ? 30.275 -8.493 31.341 1.00 47.67 ? ? ? ? ? ? 38 G R N2 1 31
+ATOM 1389 N N3 . G B 2 31 ? 27.970 -8.384 31.552 1.00 45.77 ? ? ? ? ? ? 38 G R N3 1 31
+ATOM 1390 C C4 . G B 2 31 ? 26.938 -7.498 31.599 1.00 45.82 ? ? ? ? ? ? 38 G R C4 1 31
+ATOM 1391 P P . U B 2 32 ? 24.162 -9.740 36.657 1.00 44.51 ? ? ? ? ? ? 39 U R P 1 32
+ATOM 1392 O OP1 . U B 2 32 ? 23.503 -10.743 37.528 1.00 43.82 ? ? ? ? ? ? 39 U R OP1 1 32
+ATOM 1393 O OP2 . U B 2 32 ? 23.692 -8.336 36.680 1.00 44.11 ? ? ? ? ? ? 39 U R OP2 1 32
+ATOM 1394 O "O5'" . U B 2 32 ? 25.740 -9.730 36.933 1.00 42.60 ? ? ? ? ? ? 39 U R "O5'" 1 32
+ATOM 1395 C "C5'" . U B 2 32 ? 26.491 -10.927 36.778 1.00 43.07 ? ? ? ? ? ? 39 U R "C5'" 1 32
+ATOM 1396 C "C4'" . U B 2 32 ? 27.958 -10.640 36.533 1.00 44.22 ? ? ? ? ? ? 39 U R "C4'" 1 32
+ATOM 1397 O "O4'" . U B 2 32 ? 28.141 -9.947 35.275 1.00 43.57 ? ? ? ? ? ? 39 U R "O4'" 1 32
+ATOM 1398 C "C3'" . U B 2 32 ? 28.603 -9.687 37.523 1.00 46.48 ? ? ? ? ? ? 39 U R "C3'" 1 32
+ATOM 1399 O "O3'" . U B 2 32 ? 28.866 -10.319 38.765 1.00 46.94 ? ? ? ? ? ? 39 U R "O3'" 1 32
+ATOM 1400 C "C2'" . U B 2 32 ? 29.858 -9.288 36.758 1.00 45.68 ? ? ? ? ? ? 39 U R "C2'" 1 32
+ATOM 1401 O "O2'" . U B 2 32 ? 30.836 -10.311 36.728 1.00 46.72 ? ? ? ? ? ? 39 U R "O2'" 1 32
+ATOM 1402 C "C1'" . U B 2 32 ? 29.259 -9.079 35.370 1.00 44.61 ? ? ? ? ? ? 39 U R "C1'" 1 32
+ATOM 1403 N N1 . U B 2 32 ? 28.846 -7.656 35.102 1.00 45.89 ? ? ? ? ? ? 39 U R N1 1 32
+ATOM 1404 C C2 . U B 2 32 ? 29.813 -6.712 34.788 1.00 47.86 ? ? ? ? ? ? 39 U R C2 1 32
+ATOM 1405 O O2 . U B 2 32 ? 31.004 -6.959 34.716 1.00 48.89 ? ? ? ? ? ? 39 U R O2 1 32
+ATOM 1406 N N3 . U B 2 32 ? 29.338 -5.439 34.562 1.00 48.50 ? ? ? ? ? ? 39 U R N3 1 32
+ATOM 1407 C C4 . U B 2 32 ? 28.021 -5.019 34.612 1.00 48.94 ? ? ? ? ? ? 39 U R C4 1 32
+ATOM 1408 O O4 . U B 2 32 ? 27.750 -3.845 34.385 1.00 50.10 ? ? ? ? ? ? 39 U R O4 1 32
+ATOM 1409 C C5 . U B 2 32 ? 27.069 -6.052 34.940 1.00 48.62 ? ? ? ? ? ? 39 U R C5 1 32
+ATOM 1410 C C6 . U B 2 32 ? 27.508 -7.299 35.166 1.00 47.17 ? ? ? ? ? ? 39 U R C6 1 32
+ATOM 1411 P P . G B 2 33 ? 28.661 -9.463 40.100 1.00 46.70 ? ? ? ? ? ? 40 G R P 1 33
+ATOM 1412 O OP1 . G B 2 33 ? 28.707 -10.400 41.245 1.00 48.42 ? ? ? ? ? ? 40 G R OP1 1 33
+ATOM 1413 O OP2 . G B 2 33 ? 27.484 -8.579 39.938 1.00 45.90 ? ? ? ? ? ? 40 G R OP2 1 33
+ATOM 1414 O "O5'" . G B 2 33 ? 29.970 -8.542 40.100 1.00 48.32 ? ? ? ? ? ? 40 G R "O5'" 1 33
+ATOM 1415 C "C5'" . G B 2 33 ? 31.266 -9.105 40.315 1.00 48.50 ? ? ? ? ? ? 40 G R "C5'" 1 33
+ATOM 1416 C "C4'" . G B 2 33 ? 32.356 -8.056 40.164 1.00 49.16 ? ? ? ? ? ? 40 G R "C4'" 1 33
+ATOM 1417 O "O4'" . G B 2 33 ? 32.432 -7.604 38.786 1.00 49.52 ? ? ? ? ? ? 40 G R "O4'" 1 33
+ATOM 1418 C "C3'" . G B 2 33 ? 32.154 -6.765 40.944 1.00 48.95 ? ? ? ? ? ? 40 G R "C3'" 1 33
+ATOM 1419 O "O3'" . G B 2 33 ? 32.509 -6.919 42.303 1.00 50.51 ? ? ? ? ? ? 40 G R "O3'" 1 33
+ATOM 1420 C "C2'" . G B 2 33 ? 33.104 -5.839 40.195 1.00 48.68 ? ? ? ? ? ? 40 G R "C2'" 1 33
+ATOM 1421 O "O2'" . G B 2 33 ? 34.470 -6.059 40.491 1.00 48.19 ? ? ? ? ? ? 40 G R "O2'" 1 33
+ATOM 1422 C "C1'" . G B 2 33 ? 32.784 -6.231 38.758 1.00 48.39 ? ? ? ? ? ? 40 G R "C1'" 1 33
+ATOM 1423 N N9 . G B 2 33 ? 31.682 -5.434 38.216 1.00 48.51 ? ? ? ? ? ? 40 G R N9 1 33
+ATOM 1424 C C8 . G B 2 33 ? 30.376 -5.822 38.028 1.00 47.85 ? ? ? ? ? ? 40 G R C8 1 33
+ATOM 1425 N N7 . G B 2 33 ? 29.621 -4.883 37.528 1.00 48.63 ? ? ? ? ? ? 40 G R N7 1 33
+ATOM 1426 C C5 . G B 2 33 ? 30.475 -3.797 37.376 1.00 48.23 ? ? ? ? ? ? 40 G R C5 1 33
+ATOM 1427 C C6 . G B 2 33 ? 30.225 -2.489 36.882 1.00 48.37 ? ? ? ? ? ? 40 G R C6 1 33
+ATOM 1428 O O6 . G B 2 33 ? 29.156 -2.019 36.462 1.00 48.86 ? ? ? ? ? ? 40 G R O6 1 33
+ATOM 1429 N N1 . G B 2 33 ? 31.373 -1.694 36.900 1.00 47.02 ? ? ? ? ? ? 40 G R N1 1 33
+ATOM 1430 C C2 . G B 2 33 ? 32.606 -2.111 37.342 1.00 46.42 ? ? ? ? ? ? 40 G R C2 1 33
+ATOM 1431 N N2 . G B 2 33 ? 33.599 -1.216 37.286 1.00 46.60 ? ? ? ? ? ? 40 G R N2 1 33
+ATOM 1432 N N3 . G B 2 33 ? 32.852 -3.328 37.807 1.00 46.58 ? ? ? ? ? ? 40 G R N3 1 33
+ATOM 1433 C C4 . G B 2 33 ? 31.747 -4.119 37.800 1.00 48.20 ? ? ? ? ? ? 40 G R C4 1 33
+ATOM 1434 P P . G B 2 34 ? 31.803 -6.020 43.428 1.00 51.79 ? ? ? ? ? ? 41 G R P 1 34
+ATOM 1435 O OP1 . G B 2 34 ? 32.238 -6.556 44.736 1.00 50.89 ? ? ? ? ? ? 41 G R OP1 1 34
+ATOM 1436 O OP2 . G B 2 34 ? 30.356 -5.903 43.125 1.00 49.31 ? ? ? ? ? ? 41 G R OP2 1 34
+ATOM 1437 O "O5'" . G B 2 34 ? 32.464 -4.579 43.213 1.00 50.20 ? ? ? ? ? ? 41 G R "O5'" 1 34
+ATOM 1438 C "C5'" . G B 2 34 ? 33.840 -4.359 43.502 1.00 50.09 ? ? ? ? ? ? 41 G R "C5'" 1 34
+ATOM 1439 C "C4'" . G B 2 34 ? 34.306 -3.012 42.972 1.00 49.58 ? ? ? ? ? ? 41 G R "C4'" 1 34
+ATOM 1440 O "O4'" . G B 2 34 ? 34.019 -2.884 41.553 1.00 49.09 ? ? ? ? ? ? 41 G R "O4'" 1 34
+ATOM 1441 C "C3'" . G B 2 34 ? 33.620 -1.787 43.554 1.00 49.25 ? ? ? ? ? ? 41 G R "C3'" 1 34
+ATOM 1442 O "O3'" . G B 2 34 ? 34.098 -1.482 44.854 1.00 49.30 ? ? ? ? ? ? 41 G R "O3'" 1 34
+ATOM 1443 C "C2'" . G B 2 34 ? 34.043 -0.744 42.525 1.00 48.28 ? ? ? ? ? ? 41 G R "C2'" 1 34
+ATOM 1444 O "O2'" . G B 2 34 ? 35.415 -0.410 42.617 1.00 48.44 ? ? ? ? ? ? 41 G R "O2'" 1 34
+ATOM 1445 C "C1'" . G B 2 34 ? 33.779 -1.519 41.242 1.00 46.85 ? ? ? ? ? ? 41 G R "C1'" 1 34
+ATOM 1446 N N9 . G B 2 34 ? 32.419 -1.360 40.725 1.00 45.11 ? ? ? ? ? ? 41 G R N9 1 34
+ATOM 1447 C C8 . G B 2 34 ? 31.414 -2.297 40.746 1.00 44.97 ? ? ? ? ? ? 41 G R C8 1 34
+ATOM 1448 N N7 . G B 2 34 ? 30.299 -1.887 40.208 1.00 45.13 ? ? ? ? ? ? 41 G R N7 1 34
+ATOM 1449 C C5 . G B 2 34 ? 30.577 -0.591 39.798 1.00 44.76 ? ? ? ? ? ? 41 G R C5 1 34
+ATOM 1450 C C6 . G B 2 34 ? 29.745 0.356 39.145 1.00 45.41 ? ? ? ? ? ? 41 G R C6 1 34
+ATOM 1451 O O6 . G B 2 34 ? 28.562 0.230 38.792 1.00 45.47 ? ? ? ? ? ? 41 G R O6 1 34
+ATOM 1452 N N1 . G B 2 34 ? 30.412 1.556 38.903 1.00 44.98 ? ? ? ? ? ? 41 G R N1 1 34
+ATOM 1453 C C2 . G B 2 34 ? 31.720 1.805 39.249 1.00 44.31 ? ? ? ? ? ? 41 G R C2 1 34
+ATOM 1454 N N2 . G B 2 34 ? 32.189 3.020 38.933 1.00 44.23 ? ? ? ? ? ? 41 G R N2 1 34
+ATOM 1455 N N3 . G B 2 34 ? 32.511 0.925 39.859 1.00 43.72 ? ? ? ? ? ? 41 G R N3 1 34
+ATOM 1456 C C4 . G B 2 34 ? 31.878 -0.250 40.107 1.00 44.73 ? ? ? ? ? ? 41 G R C4 1 34
+ATOM 1457 P P . G B 2 35 ? 33.143 -0.770 45.924 1.00 51.11 ? ? ? ? ? ? 42 G R P 1 35
+ATOM 1458 O OP1 . G B 2 35 ? 34.010 -0.259 47.009 1.00 51.05 ? ? ? ? ? ? 42 G R OP1 1 35
+ATOM 1459 O OP2 . G B 2 35 ? 32.031 -1.698 46.228 1.00 51.32 ? ? ? ? ? ? 42 G R OP2 1 35
+ATOM 1460 O "O5'" . G B 2 35 ? 32.483 0.459 45.142 1.00 50.76 ? ? ? ? ? ? 42 G R "O5'" 1 35
+ATOM 1461 C "C5'" . G B 2 35 ? 33.118 1.726 45.039 1.00 50.33 ? ? ? ? ? ? 42 G R "C5'" 1 35
+ATOM 1462 C "C4'" . G B 2 35 ? 32.195 2.676 44.298 1.00 50.72 ? ? ? ? ? ? 42 G R "C4'" 1 35
+ATOM 1463 O "O4'" . G B 2 35 ? 31.640 2.016 43.131 1.00 48.78 ? ? ? ? ? ? 42 G R "O4'" 1 35
+ATOM 1464 C "C3'" . G B 2 35 ? 30.989 3.122 45.107 1.00 50.26 ? ? ? ? ? ? 42 G R "C3'" 1 35
+ATOM 1465 O "O3'" . G B 2 35 ? 31.354 4.266 45.871 1.00 51.31 ? ? ? ? ? ? 42 G R "O3'" 1 35
+ATOM 1466 C "C2'" . G B 2 35 ? 29.963 3.436 44.019 1.00 49.86 ? ? ? ? ? ? 42 G R "C2'" 1 35
+ATOM 1467 O "O2'" . G B 2 35 ? 30.077 4.753 43.515 1.00 51.59 ? ? ? ? ? ? 42 G R "O2'" 1 35
+ATOM 1468 C "C1'" . G B 2 35 ? 30.307 2.435 42.919 1.00 47.89 ? ? ? ? ? ? 42 G R "C1'" 1 35
+ATOM 1469 N N9 . G B 2 35 ? 29.436 1.259 42.894 1.00 45.85 ? ? ? ? ? ? 42 G R N9 1 35
+ATOM 1470 C C8 . G B 2 35 ? 29.644 0.068 43.546 1.00 45.91 ? ? ? ? ? ? 42 G R C8 1 35
+ATOM 1471 N N7 . G B 2 35 ? 28.701 -0.809 43.340 1.00 45.51 ? ? ? ? ? ? 42 G R N7 1 35
+ATOM 1472 C C5 . G B 2 35 ? 27.806 -0.163 42.499 1.00 43.67 ? ? ? ? ? ? 42 G R C5 1 35
+ATOM 1473 C C6 . G B 2 35 ? 26.584 -0.620 41.937 1.00 44.02 ? ? ? ? ? ? 42 G R C6 1 35
+ATOM 1474 O O6 . G B 2 35 ? 26.033 -1.723 42.075 1.00 43.11 ? ? ? ? ? ? 42 G R O6 1 35
+ATOM 1475 N N1 . G B 2 35 ? 25.986 0.349 41.135 1.00 43.67 ? ? ? ? ? ? 42 G R N1 1 35
+ATOM 1476 C C2 . G B 2 35 ? 26.507 1.603 40.910 1.00 43.58 ? ? ? ? ? ? 42 G R C2 1 35
+ATOM 1477 N N2 . G B 2 35 ? 25.791 2.408 40.110 1.00 44.89 ? ? ? ? ? ? 42 G R N2 1 35
+ATOM 1478 N N3 . G B 2 35 ? 27.647 2.038 41.433 1.00 41.86 ? ? ? ? ? ? 42 G R N3 1 35
+ATOM 1479 C C4 . G B 2 35 ? 28.245 1.111 42.216 1.00 42.98 ? ? ? ? ? ? 42 G R C4 1 35
+ATOM 1480 P P . A B 2 36 ? 30.465 4.786 47.100 1.00 52.33 ? ? ? ? ? ? 43 A R P 1 36
+ATOM 1481 O OP1 . A B 2 36 ? 31.357 5.592 47.961 1.00 53.58 ? ? ? ? ? ? 43 A R OP1 1 36
+ATOM 1482 O OP2 . A B 2 36 ? 29.712 3.644 47.664 1.00 52.58 ? ? ? ? ? ? 43 A R OP2 1 36
+ATOM 1483 O "O5'" . A B 2 36 ? 29.419 5.771 46.416 1.00 51.77 ? ? ? ? ? ? 43 A R "O5'" 1 36
+ATOM 1484 C "C5'" . A B 2 36 ? 28.291 6.189 47.152 1.00 52.46 ? ? ? ? ? ? 43 A R "C5'" 1 36
+ATOM 1485 C "C4'" . A B 2 36 ? 27.107 6.418 46.229 1.00 52.39 ? ? ? ? ? ? 43 A R "C4'" 1 36
+ATOM 1486 O "O4'" . A B 2 36 ? 26.932 5.274 45.353 1.00 50.60 ? ? ? ? ? ? 43 A R "O4'" 1 36
+ATOM 1487 C "C3'" . A B 2 36 ? 25.786 6.619 46.960 1.00 52.71 ? ? ? ? ? ? 43 A R "C3'" 1 36
+ATOM 1488 O "O3'" . A B 2 36 ? 25.046 7.652 46.335 1.00 55.18 ? ? ? ? ? ? 43 A R "O3'" 1 36
+ATOM 1489 C "C2'" . A B 2 36 ? 25.077 5.277 46.795 1.00 53.30 ? ? ? ? ? ? 43 A R "C2'" 1 36
+ATOM 1490 O "O2'" . A B 2 36 ? 23.668 5.412 46.769 1.00 54.56 ? ? ? ? ? ? 43 A R "O2'" 1 36
+ATOM 1491 C "C1'" . A B 2 36 ? 25.595 4.819 45.434 1.00 51.94 ? ? ? ? ? ? 43 A R "C1'" 1 36
+ATOM 1492 N N9 . A B 2 36 ? 25.561 3.371 45.210 1.00 50.70 ? ? ? ? ? ? 43 A R N9 1 36
+ATOM 1493 C C8 . A B 2 36 ? 24.875 2.734 44.212 1.00 50.32 ? ? ? ? ? ? 43 A R C8 1 36
+ATOM 1494 N N7 . A B 2 36 ? 25.004 1.430 44.217 1.00 49.68 ? ? ? ? ? ? 43 A R N7 1 36
+ATOM 1495 C C5 . A B 2 36 ? 25.836 1.189 45.295 1.00 50.21 ? ? ? ? ? ? 43 A R C5 1 36
+ATOM 1496 C C6 . A B 2 36 ? 26.363 -0.004 45.837 1.00 50.79 ? ? ? ? ? ? 43 A R C6 1 36
+ATOM 1497 N N6 . A B 2 36 ? 26.095 -1.208 45.326 1.00 49.84 ? ? ? ? ? ? 43 A R N6 1 36
+ATOM 1498 N N1 . A B 2 36 ? 27.174 0.088 46.920 1.00 52.32 ? ? ? ? ? ? 43 A R N1 1 36
+ATOM 1499 C C2 . A B 2 36 ? 27.437 1.304 47.428 1.00 51.59 ? ? ? ? ? ? 43 A R C2 1 36
+ATOM 1500 N N3 . A B 2 36 ? 26.996 2.494 47.001 1.00 51.17 ? ? ? ? ? ? 43 A R N3 1 36
+ATOM 1501 C C4 . A B 2 36 ? 26.194 2.372 45.922 1.00 50.16 ? ? ? ? ? ? 43 A R C4 1 36
+ATOM 1502 P P . C B 2 37 ? 25.237 9.201 46.692 1.00 57.03 ? ? ? ? ? ? 44 C R P 1 37
+ATOM 1503 O OP1 . C B 2 37 ? 26.222 9.752 45.727 1.00 56.12 ? ? ? ? ? ? 44 C R OP1 1 37
+ATOM 1504 O OP2 . C B 2 37 ? 25.474 9.358 48.148 1.00 56.22 ? ? ? ? ? ? 44 C R OP2 1 37
+ATOM 1505 O "O5'" . C B 2 37 ? 23.757 9.735 46.387 1.00 52.44 ? ? ? ? ? ? 44 C R "O5'" 1 37
+ATOM 1506 C "C5'" . C B 2 37 ? 23.516 10.797 45.483 1.00 48.40 ? ? ? ? ? ? 44 C R "C5'" 1 37
+ATOM 1507 C "C4'" . C B 2 37 ? 22.333 10.492 44.584 1.00 44.93 ? ? ? ? ? ? 44 C R "C4'" 1 37
+ATOM 1508 O "O4'" . C B 2 37 ? 22.527 9.245 43.881 1.00 44.65 ? ? ? ? ? ? 44 C R "O4'" 1 37
+ATOM 1509 C "C3'" . C B 2 37 ? 21.002 10.214 45.256 1.00 44.11 ? ? ? ? ? ? 44 C R "C3'" 1 37
+ATOM 1510 O "O3'" . C B 2 37 ? 20.425 11.371 45.832 1.00 44.49 ? ? ? ? ? ? 44 C R "O3'" 1 37
+ATOM 1511 C "C2'" . C B 2 37 ? 20.219 9.714 44.049 1.00 44.48 ? ? ? ? ? ? 44 C R "C2'" 1 37
+ATOM 1512 O "O2'" . C B 2 37 ? 19.804 10.730 43.161 1.00 45.65 ? ? ? ? ? ? 44 C R "O2'" 1 37
+ATOM 1513 C "C1'" . C B 2 37 ? 21.265 8.852 43.354 1.00 44.25 ? ? ? ? ? ? 44 C R "C1'" 1 37
+ATOM 1514 N N1 . C B 2 37 ? 21.016 7.375 43.529 1.00 43.78 ? ? ? ? ? ? 44 C R N1 1 37
+ATOM 1515 C C2 . C B 2 37 ? 19.950 6.749 42.847 1.00 42.83 ? ? ? ? ? ? 44 C R C2 1 37
+ATOM 1516 O O2 . C B 2 37 ? 19.214 7.405 42.099 1.00 41.60 ? ? ? ? ? ? 44 C R O2 1 37
+ATOM 1517 N N3 . C B 2 37 ? 19.746 5.418 43.026 1.00 42.89 ? ? ? ? ? ? 44 C R N3 1 37
+ATOM 1518 C C4 . C B 2 37 ? 20.551 4.718 43.833 1.00 43.67 ? ? ? ? ? ? 44 C R C4 1 37
+ATOM 1519 N N4 . C B 2 37 ? 20.313 3.410 43.972 1.00 44.22 ? ? ? ? ? ? 44 C R N4 1 37
+ATOM 1520 C C5 . C B 2 37 ? 21.637 5.328 44.536 1.00 43.51 ? ? ? ? ? ? 44 C R C5 1 37
+ATOM 1521 C C6 . C B 2 37 ? 21.829 6.642 44.358 1.00 43.72 ? ? ? ? ? ? 44 C R C6 1 37
+ATOM 1522 P P . G B 2 38 ? 19.380 11.223 47.042 1.00 45.07 ? ? ? ? ? ? 45 G R P 1 38
+ATOM 1523 O OP1 . G B 2 38 ? 19.337 12.529 47.735 1.00 41.50 ? ? ? ? ? ? 45 G R OP1 1 38
+ATOM 1524 O OP2 . G B 2 38 ? 19.689 9.972 47.783 1.00 43.11 ? ? ? ? ? ? 45 G R OP2 1 38
+ATOM 1525 O "O5'" . G B 2 38 ? 17.977 11.024 46.304 1.00 43.44 ? ? ? ? ? ? 45 G R "O5'" 1 38
+ATOM 1526 C "C5'" . G B 2 38 ? 16.994 10.169 46.858 1.00 43.41 ? ? ? ? ? ? 45 G R "C5'" 1 38
+ATOM 1527 C "C4'" . G B 2 38 ? 16.637 9.089 45.854 1.00 44.48 ? ? ? ? ? ? 45 G R "C4'" 1 38
+ATOM 1528 O "O4'" . G B 2 38 ? 17.831 8.359 45.475 1.00 44.34 ? ? ? ? ? ? 45 G R "O4'" 1 38
+ATOM 1529 C "C3'" . G B 2 38 ? 15.686 8.032 46.387 1.00 43.37 ? ? ? ? ? ? 45 G R "C3'" 1 38
+ATOM 1530 O "O3'" . G B 2 38 ? 14.328 8.451 46.218 1.00 42.53 ? ? ? ? ? ? 45 G R "O3'" 1 38
+ATOM 1531 C "C2'" . G B 2 38 ? 16.048 6.823 45.535 1.00 42.65 ? ? ? ? ? ? 45 G R "C2'" 1 38
+ATOM 1532 O "O2'" . G B 2 38 ? 15.456 6.887 44.256 1.00 42.86 ? ? ? ? ? ? 45 G R "O2'" 1 38
+ATOM 1533 C "C1'" . G B 2 38 ? 17.561 6.970 45.399 1.00 43.55 ? ? ? ? ? ? 45 G R "C1'" 1 38
+ATOM 1534 N N9 . G B 2 38 ? 18.374 6.268 46.403 1.00 44.12 ? ? ? ? ? ? 45 G R N9 1 38
+ATOM 1535 C C8 . G B 2 38 ? 19.247 6.824 47.314 1.00 43.89 ? ? ? ? ? ? 45 G R C8 1 38
+ATOM 1536 N N7 . G B 2 38 ? 19.846 5.956 48.083 1.00 42.13 ? ? ? ? ? ? 45 G R N7 1 38
+ATOM 1537 C C5 . G B 2 38 ? 19.341 4.740 47.653 1.00 42.81 ? ? ? ? ? ? 45 G R C5 1 38
+ATOM 1538 C C6 . G B 2 38 ? 19.618 3.431 48.112 1.00 44.14 ? ? ? ? ? ? 45 G R C6 1 38
+ATOM 1539 O O6 . G B 2 38 ? 20.391 3.095 49.024 1.00 45.94 ? ? ? ? ? ? 45 G R O6 1 38
+ATOM 1540 N N1 . G B 2 38 ? 18.898 2.464 47.403 1.00 44.37 ? ? ? ? ? ? 45 G R N1 1 38
+ATOM 1541 C C2 . G B 2 38 ? 18.012 2.738 46.383 1.00 44.72 ? ? ? ? ? ? 45 G R C2 1 38
+ATOM 1542 N N2 . G B 2 38 ? 17.398 1.695 45.808 1.00 44.15 ? ? ? ? ? ? 45 G R N2 1 38
+ATOM 1543 N N3 . G B 2 38 ? 17.745 3.963 45.948 1.00 44.64 ? ? ? ? ? ? 45 G R N3 1 38
+ATOM 1544 C C4 . G B 2 38 ? 18.442 4.911 46.622 1.00 43.43 ? ? ? ? ? ? 45 G R C4 1 38
+ATOM 1545 P P . C B 2 39 ? 13.264 8.018 47.333 1.00 42.35 ? ? ? ? ? ? 46 C R P 1 39
+ATOM 1546 O OP1 . C B 2 39 ? 11.995 8.754 47.122 1.00 38.48 ? ? ? ? ? ? 46 C R OP1 1 39
+ATOM 1547 O OP2 . C B 2 39 ? 13.968 8.074 48.638 1.00 42.04 ? ? ? ? ? ? 46 C R OP2 1 39
+ATOM 1548 O "O5'" . C B 2 39 ? 13.038 6.474 46.998 1.00 42.35 ? ? ? ? ? ? 46 C R "O5'" 1 39
+ATOM 1549 C "C5'" . C B 2 39 ? 12.257 6.057 45.884 1.00 42.72 ? ? ? ? ? ? 46 C R "C5'" 1 39
+ATOM 1550 C "C4'" . C B 2 39 ? 12.267 4.541 45.826 1.00 43.56 ? ? ? ? ? ? 46 C R "C4'" 1 39
+ATOM 1551 O "O4'" . C B 2 39 ? 13.642 4.107 45.882 1.00 43.58 ? ? ? ? ? ? 46 C R "O4'" 1 39
+ATOM 1552 C "C3'" . C B 2 39 ? 11.637 3.825 47.011 1.00 43.82 ? ? ? ? ? ? 46 C R "C3'" 1 39
+ATOM 1553 O "O3'" . C B 2 39 ? 10.237 3.694 46.849 1.00 44.65 ? ? ? ? ? ? 46 C R "O3'" 1 39
+ATOM 1554 C "C2'" . C B 2 39 ? 12.327 2.470 46.977 1.00 43.64 ? ? ? ? ? ? 46 C R "C2'" 1 39
+ATOM 1555 O "O2'" . C B 2 39 ? 11.742 1.570 46.058 1.00 46.61 ? ? ? ? ? ? 46 C R "O2'" 1 39
+ATOM 1556 C "C1'" . C B 2 39 ? 13.730 2.844 46.514 1.00 43.43 ? ? ? ? ? ? 46 C R "C1'" 1 39
+ATOM 1557 N N1 . C B 2 39 ? 14.734 2.898 47.622 1.00 41.58 ? ? ? ? ? ? 46 C R N1 1 39
+ATOM 1558 C C2 . C B 2 39 ? 15.249 1.701 48.143 1.00 42.96 ? ? ? ? ? ? 46 C R C2 1 39
+ATOM 1559 O O2 . C B 2 39 ? 14.870 0.617 47.677 1.00 43.48 ? ? ? ? ? ? 46 C R O2 1 39
+ATOM 1560 N N3 . C B 2 39 ? 16.159 1.760 49.152 1.00 43.65 ? ? ? ? ? ? 46 C R N3 1 39
+ATOM 1561 C C4 . C B 2 39 ? 16.546 2.943 49.633 1.00 43.09 ? ? ? ? ? ? 46 C R C4 1 39
+ATOM 1562 N N4 . C B 2 39 ? 17.441 2.953 50.626 1.00 43.69 ? ? ? ? ? ? 46 C R N4 1 39
+ATOM 1563 C C5 . C B 2 39 ? 16.030 4.170 49.113 1.00 43.36 ? ? ? ? ? ? 46 C R C5 1 39
+ATOM 1564 C C6 . C B 2 39 ? 15.136 4.101 48.121 1.00 41.05 ? ? ? ? ? ? 46 C R C6 1 39
+ATOM 1565 P P . A B 2 40 ? 9.259 4.280 47.969 1.00 44.44 ? ? ? ? ? ? 47 A R P 1 40
+ATOM 1566 O OP1 . A B 2 40 ? 8.289 5.159 47.280 1.00 43.91 ? ? ? ? ? ? 47 A R OP1 1 40
+ATOM 1567 O OP2 . A B 2 40 ? 10.102 4.809 49.066 1.00 43.82 ? ? ? ? ? ? 47 A R OP2 1 40
+ATOM 1568 O "O5'" . A B 2 40 ? 8.477 2.990 48.507 1.00 45.10 ? ? ? ? ? ? 47 A R "O5'" 1 40
+ATOM 1569 C "C5'" . A B 2 40 ? 9.176 1.947 49.190 1.00 46.36 ? ? ? ? ? ? 47 A R "C5'" 1 40
+ATOM 1570 C "C4'" . A B 2 40 ? 8.270 0.766 49.515 1.00 47.32 ? ? ? ? ? ? 47 A R "C4'" 1 40
+ATOM 1571 O "O4'" . A B 2 40 ? 8.989 -0.183 50.342 1.00 47.90 ? ? ? ? ? ? 47 A R "O4'" 1 40
+ATOM 1572 C "C3'" . A B 2 40 ? 7.010 1.057 50.317 1.00 47.66 ? ? ? ? ? ? 47 A R "C3'" 1 40
+ATOM 1573 O "O3'" . A B 2 40 ? 6.108 -0.014 50.173 1.00 48.86 ? ? ? ? ? ? 47 A R "O3'" 1 40
+ATOM 1574 C "C2'" . A B 2 40 ? 7.550 1.018 51.735 1.00 47.93 ? ? ? ? ? ? 47 A R "C2'" 1 40
+ATOM 1575 O "O2'" . A B 2 40 ? 6.521 0.826 52.682 1.00 49.51 ? ? ? ? ? ? 47 A R "O2'" 1 40
+ATOM 1576 C "C1'" . A B 2 40 ? 8.435 -0.222 51.646 1.00 47.50 ? ? ? ? ? ? 47 A R "C1'" 1 40
+ATOM 1577 N N9 . A B 2 40 ? 9.542 -0.298 52.602 1.00 47.73 ? ? ? ? ? ? 47 A R N9 1 40
+ATOM 1578 C C8 . A B 2 40 ? 10.145 0.737 53.264 1.00 47.31 ? ? ? ? ? ? 47 A R C8 1 40
+ATOM 1579 N N7 . A B 2 40 ? 11.122 0.359 54.054 1.00 48.47 ? ? ? ? ? ? 47 A R N7 1 40
+ATOM 1580 C C5 . A B 2 40 ? 11.166 -1.014 53.906 1.00 45.96 ? ? ? ? ? ? 47 A R C5 1 40
+ATOM 1581 C C6 . A B 2 40 ? 11.986 -2.006 54.482 1.00 46.35 ? ? ? ? ? ? 47 A R C6 1 40
+ATOM 1582 N N6 . A B 2 40 ? 12.957 -1.735 55.360 1.00 46.71 ? ? ? ? ? ? 47 A R N6 1 40
+ATOM 1583 N N1 . A B 2 40 ? 11.772 -3.292 54.123 1.00 47.25 ? ? ? ? ? ? 47 A R N1 1 40
+ATOM 1584 C C2 . A B 2 40 ? 10.796 -3.560 53.242 1.00 47.77 ? ? ? ? ? ? 47 A R C2 1 40
+ATOM 1585 N N3 . A B 2 40 ? 9.962 -2.710 52.636 1.00 47.19 ? ? ? ? ? ? 47 A R N3 1 40
+ATOM 1586 C C4 . A B 2 40 ? 10.202 -1.439 53.012 1.00 46.72 ? ? ? ? ? ? 47 A R C4 1 40
+ATOM 1587 P P . A B 2 41 ? 4.955 -0.091 49.076 1.00 51.51 ? ? ? ? ? ? 48 A R P 1 41
+ATOM 1588 O OP1 . A B 2 41 ? 5.265 0.820 47.948 1.00 51.90 ? ? ? ? ? ? 48 A R OP1 1 41
+ATOM 1589 O OP2 . A B 2 41 ? 3.646 0.007 49.757 1.00 52.49 ? ? ? ? ? ? 48 A R OP2 1 41
+ATOM 1590 O "O5'" . A B 2 41 ? 5.117 -1.628 48.662 1.00 51.05 ? ? ? ? ? ? 48 A R "O5'" 1 41
+ATOM 1591 C "C5'" . A B 2 41 ? 5.581 -2.012 47.387 1.00 48.96 ? ? ? ? ? ? 48 A R "C5'" 1 41
+ATOM 1592 C "C4'" . A B 2 41 ? 7.076 -2.256 47.406 1.00 47.63 ? ? ? ? ? ? 48 A R "C4'" 1 41
+ATOM 1593 O "O4'" . A B 2 41 ? 7.366 -3.557 47.994 1.00 47.54 ? ? ? ? ? ? 48 A R "O4'" 1 41
+ATOM 1594 C "C3'" . A B 2 41 ? 7.670 -2.294 46.000 1.00 48.38 ? ? ? ? ? ? 48 A R "C3'" 1 41
+ATOM 1595 O "O3'" . A B 2 41 ? 8.953 -1.683 45.942 1.00 47.50 ? ? ? ? ? ? 48 A R "O3'" 1 41
+ATOM 1596 C "C2'" . A B 2 41 ? 7.764 -3.785 45.722 1.00 47.48 ? ? ? ? ? ? 48 A R "C2'" 1 41
+ATOM 1597 O "O2'" . A B 2 41 ? 8.712 -4.111 44.727 1.00 47.73 ? ? ? ? ? ? 48 A R "O2'" 1 41
+ATOM 1598 C "C1'" . A B 2 41 ? 8.217 -4.251 47.099 1.00 46.30 ? ? ? ? ? ? 48 A R "C1'" 1 41
+ATOM 1599 N N9 . A B 2 41 ? 8.131 -5.703 47.214 1.00 44.07 ? ? ? ? ? ? 48 A R N9 1 41
+ATOM 1600 C C8 . A B 2 41 ? 7.038 -6.496 46.986 1.00 43.97 ? ? ? ? ? ? 48 A R C8 1 41
+ATOM 1601 N N7 . A B 2 41 ? 7.279 -7.776 47.136 1.00 43.91 ? ? ? ? ? ? 48 A R N7 1 41
+ATOM 1602 C C5 . A B 2 41 ? 8.622 -7.823 47.479 1.00 41.25 ? ? ? ? ? ? 48 A R C5 1 41
+ATOM 1603 C C6 . A B 2 41 ? 9.493 -8.888 47.778 1.00 40.57 ? ? ? ? ? ? 48 A R C6 1 41
+ATOM 1604 N N6 . A B 2 41 ? 9.103 -10.165 47.777 1.00 41.36 ? ? ? ? ? ? 48 A R N6 1 41
+ATOM 1605 N N1 . A B 2 41 ? 10.780 -8.596 48.082 1.00 41.01 ? ? ? ? ? ? 48 A R N1 1 41
+ATOM 1606 C C2 . A B 2 41 ? 11.169 -7.314 48.087 1.00 40.88 ? ? ? ? ? ? 48 A R C2 1 41
+ATOM 1607 N N3 . A B 2 41 ? 10.439 -6.228 47.823 1.00 41.29 ? ? ? ? ? ? 48 A R N3 1 41
+ATOM 1608 C C4 . A B 2 41 ? 9.166 -6.554 47.527 1.00 41.82 ? ? ? ? ? ? 48 A R C4 1 41
+ATOM 1609 P P . A B 2 42 ? 9.244 -0.667 44.749 1.00 47.34 ? ? ? ? ? ? 49 A R P 1 42
+ATOM 1610 O OP1 . A B 2 42 ? 9.187 0.705 45.299 1.00 47.04 ? ? ? ? ? ? 49 A R OP1 1 42
+ATOM 1611 O OP2 . A B 2 42 ? 8.388 -1.041 43.595 1.00 47.35 ? ? ? ? ? ? 49 A R OP2 1 42
+ATOM 1612 O "O5'" . A B 2 42 ? 10.757 -1.007 44.375 1.00 47.41 ? ? ? ? ? ? 49 A R "O5'" 1 42
+ATOM 1613 C "C5'" . A B 2 42 ? 11.069 -2.228 43.707 1.00 46.93 ? ? ? ? ? ? 49 A R "C5'" 1 42
+ATOM 1614 C "C4'" . A B 2 42 ? 12.558 -2.330 43.426 1.00 45.41 ? ? ? ? ? ? 49 A R "C4'" 1 42
+ATOM 1615 O "O4'" . A B 2 42 ? 12.939 -1.251 42.542 1.00 45.25 ? ? ? ? ? ? 49 A R "O4'" 1 42
+ATOM 1616 C "C3'" . A B 2 42 ? 13.487 -2.228 44.632 1.00 45.51 ? ? ? ? ? ? 49 A R "C3'" 1 42
+ATOM 1617 O "O3'" . A B 2 42 ? 14.614 -3.079 44.421 1.00 46.52 ? ? ? ? ? ? 49 A R "O3'" 1 42
+ATOM 1618 C "C2'" . A B 2 42 ? 13.887 -0.751 44.666 1.00 44.48 ? ? ? ? ? ? 49 A R "C2'" 1 42
+ATOM 1619 O "O2'" . A B 2 42 ? 15.206 -0.573 45.143 1.00 44.52 ? ? ? ? ? ? 49 A R "O2'" 1 42
+ATOM 1620 C "C1'" . A B 2 42 ? 13.820 -0.356 43.193 1.00 43.80 ? ? ? ? ? ? 49 A R "C1'" 1 42
+ATOM 1621 N N9 . A B 2 42 ? 13.351 0.999 42.903 1.00 42.51 ? ? ? ? ? ? 49 A R N9 1 42
+ATOM 1622 C C8 . A B 2 42 ? 12.136 1.356 42.382 1.00 42.71 ? ? ? ? ? ? 49 A R C8 1 42
+ATOM 1623 N N7 . A B 2 42 ? 11.991 2.649 42.202 1.00 41.67 ? ? ? ? ? ? 49 A R N7 1 42
+ATOM 1624 C C5 . A B 2 42 ? 13.195 3.175 42.631 1.00 40.69 ? ? ? ? ? ? 49 A R C5 1 42
+ATOM 1625 C C6 . A B 2 42 ? 13.685 4.495 42.700 1.00 40.78 ? ? ? ? ? ? 49 A R C6 1 42
+ATOM 1626 N N6 . A B 2 42 ? 12.985 5.567 42.328 1.00 41.62 ? ? ? ? ? ? 49 A R N6 1 42
+ATOM 1627 N N1 . A B 2 42 ? 14.931 4.682 43.177 1.00 41.13 ? ? ? ? ? ? 49 A R N1 1 42
+ATOM 1628 C C2 . A B 2 42 ? 15.643 3.613 43.564 1.00 42.39 ? ? ? ? ? ? 49 A R C2 1 42
+ATOM 1629 N N3 . A B 2 42 ? 15.294 2.325 43.544 1.00 41.56 ? ? ? ? ? ? 49 A R N3 1 42
+ATOM 1630 C C4 . A B 2 42 ? 14.047 2.172 43.061 1.00 41.16 ? ? ? ? ? ? 49 A R C4 1 42
+ATOM 1631 P P . G B 2 43 ? 14.830 -4.432 45.254 1.00 46.95 ? ? ? ? ? ? 50 G R P 1 43
+ATOM 1632 O OP1 . G B 2 43 ? 14.915 -4.082 46.690 1.00 47.70 ? ? ? ? ? ? 50 G R OP1 1 43
+ATOM 1633 O OP2 . G B 2 43 ? 15.952 -5.166 44.622 1.00 45.67 ? ? ? ? ? ? 50 G R OP2 1 43
+ATOM 1634 O "O5'" . G B 2 43 ? 13.472 -5.244 44.996 1.00 44.47 ? ? ? ? ? ? 50 G R "O5'" 1 43
+ATOM 1635 C "C5'" . G B 2 43 ? 13.208 -5.853 43.740 1.00 43.48 ? ? ? ? ? ? 50 G R "C5'" 1 43
+ATOM 1636 C "C4'" . G B 2 43 ? 13.210 -7.362 43.866 1.00 43.27 ? ? ? ? ? ? 50 G R "C4'" 1 43
+ATOM 1637 O "O4'" . G B 2 43 ? 12.263 -7.755 44.893 1.00 42.53 ? ? ? ? ? ? 50 G R "O4'" 1 43
+ATOM 1638 C "C3'" . G B 2 43 ? 12.767 -8.102 42.612 1.00 43.46 ? ? ? ? ? ? 50 G R "C3'" 1 43
+ATOM 1639 O "O3'" . G B 2 43 ? 13.883 -8.375 41.771 1.00 44.99 ? ? ? ? ? ? 50 G R "O3'" 1 43
+ATOM 1640 C "C2'" . G B 2 43 ? 12.169 -9.379 43.192 1.00 42.91 ? ? ? ? ? ? 50 G R "C2'" 1 43
+ATOM 1641 O "O2'" . G B 2 43 ? 13.156 -10.333 43.534 1.00 44.03 ? ? ? ? ? ? 50 G R "O2'" 1 43
+ATOM 1642 C "C1'" . G B 2 43 ? 11.483 -8.853 44.452 1.00 41.18 ? ? ? ? ? ? 50 G R "C1'" 1 43
+ATOM 1643 N N9 . G B 2 43 ? 10.107 -8.406 44.233 1.00 38.70 ? ? ? ? ? ? 50 G R N9 1 43
+ATOM 1644 C C8 . G B 2 43 ? 9.642 -7.114 44.307 1.00 37.65 ? ? ? ? ? ? 50 G R C8 1 43
+ATOM 1645 N N7 . G B 2 43 ? 8.365 -7.003 44.066 1.00 37.68 ? ? ? ? ? ? 50 G R N7 1 43
+ATOM 1646 C C5 . G B 2 43 ? 7.953 -8.303 43.810 1.00 36.40 ? ? ? ? ? ? 50 G R C5 1 43
+ATOM 1647 C C6 . G B 2 43 ? 6.671 -8.804 43.477 1.00 37.05 ? ? ? ? ? ? 50 G R C6 1 43
+ATOM 1648 O O6 . G B 2 43 ? 5.614 -8.173 43.342 1.00 37.59 ? ? ? ? ? ? 50 G R O6 1 43
+ATOM 1649 N N1 . G B 2 43 ? 6.674 -10.185 43.290 1.00 37.48 ? ? ? ? ? ? 50 G R N1 1 43
+ATOM 1650 C C2 . G B 2 43 ? 7.787 -10.980 43.413 1.00 38.03 ? ? ? ? ? ? 50 G R C2 1 43
+ATOM 1651 N N2 . G B 2 43 ? 7.598 -12.288 43.199 1.00 40.53 ? ? ? ? ? ? 50 G R N2 1 43
+ATOM 1652 N N3 . G B 2 43 ? 8.997 -10.524 43.721 1.00 37.80 ? ? ? ? ? ? 50 G R N3 1 43
+ATOM 1653 C C4 . G B 2 43 ? 9.012 -9.179 43.906 1.00 37.29 ? ? ? ? ? ? 50 G R C4 1 43
+ATOM 1654 P P . C B 2 44 ? 13.818 -8.093 40.194 1.00 45.41 ? ? ? ? ? ? 51 C R P 1 44
+ATOM 1655 O OP1 . C B 2 44 ? 15.136 -8.458 39.632 1.00 45.51 ? ? ? ? ? ? 51 C R OP1 1 44
+ATOM 1656 O OP2 . C B 2 44 ? 13.300 -6.720 40.000 1.00 47.90 ? ? ? ? ? ? 51 C R OP2 1 44
+ATOM 1657 O "O5'" . C B 2 44 ? 12.698 -9.100 39.649 1.00 44.83 ? ? ? ? ? ? 51 C R "O5'" 1 44
+ATOM 1658 C "C5'" . C B 2 44 ? 12.918 -10.507 39.627 1.00 45.29 ? ? ? ? ? ? 51 C R "C5'" 1 44
+ATOM 1659 C "C4'" . C B 2 44 ? 11.613 -11.268 39.472 1.00 45.75 ? ? ? ? ? ? 51 C R "C4'" 1 44
+ATOM 1660 O "O4'" . C B 2 44 ? 10.687 -10.934 40.536 1.00 46.23 ? ? ? ? ? ? 51 C R "O4'" 1 44
+ATOM 1661 C "C3'" . C B 2 44 ? 10.806 -10.940 38.227 1.00 46.47 ? ? ? ? ? ? 51 C R "C3'" 1 44
+ATOM 1662 O "O3'" . C B 2 44 ? 11.348 -11.575 37.091 1.00 46.60 ? ? ? ? ? ? 51 C R "O3'" 1 44
+ATOM 1663 C "C2'" . C B 2 44 ? 9.444 -11.508 38.603 1.00 46.63 ? ? ? ? ? ? 51 C R "C2'" 1 44
+ATOM 1664 O "O2'" . C B 2 44 ? 9.388 -12.921 38.525 1.00 49.14 ? ? ? ? ? ? 51 C R "O2'" 1 44
+ATOM 1665 C "C1'" . C B 2 44 ? 9.353 -11.058 40.056 1.00 45.84 ? ? ? ? ? ? 51 C R "C1'" 1 44
+ATOM 1666 N N1 . C B 2 44 ? 8.611 -9.763 40.221 1.00 45.10 ? ? ? ? ? ? 51 C R N1 1 44
+ATOM 1667 C C2 . C B 2 44 ? 7.210 -9.732 40.100 1.00 45.06 ? ? ? ? ? ? 51 C R C2 1 44
+ATOM 1668 O O2 . C B 2 44 ? 6.581 -10.768 39.859 1.00 43.14 ? ? ? ? ? ? 51 C R O2 1 44
+ATOM 1669 N N3 . C B 2 44 ? 6.567 -8.545 40.255 1.00 45.68 ? ? ? ? ? ? 51 C R N3 1 44
+ATOM 1670 C C4 . C B 2 44 ? 7.255 -7.430 40.520 1.00 44.03 ? ? ? ? ? ? 51 C R C4 1 44
+ATOM 1671 N N4 . C B 2 44 ? 6.568 -6.295 40.666 1.00 44.60 ? ? ? ? ? ? 51 C R N4 1 44
+ATOM 1672 C C5 . C B 2 44 ? 8.674 -7.434 40.648 1.00 43.53 ? ? ? ? ? ? 51 C R C5 1 44
+ATOM 1673 C C6 . C B 2 44 ? 9.299 -8.608 40.492 1.00 44.83 ? ? ? ? ? ? 51 C R C6 1 44
+ATOM 1674 P P . C B 2 45 ? 11.224 -10.860 35.670 1.00 47.31 ? ? ? ? ? ? 52 C R P 1 45
+ATOM 1675 O OP1 . C B 2 45 ? 12.072 -11.630 34.730 1.00 46.90 ? ? ? ? ? ? 52 C R OP1 1 45
+ATOM 1676 O OP2 . C B 2 45 ? 11.449 -9.404 35.844 1.00 45.44 ? ? ? ? ? ? 52 C R OP2 1 45
+ATOM 1677 O "O5'" . C B 2 45 ? 9.679 -11.078 35.300 1.00 46.82 ? ? ? ? ? ? 52 C R "O5'" 1 45
+ATOM 1678 C "C5'" . C B 2 45 ? 9.287 -12.186 34.497 1.00 46.25 ? ? ? ? ? ? 52 C R "C5'" 1 45
+ATOM 1679 C "C4'" . C B 2 45 ? 7.780 -12.268 34.376 1.00 45.47 ? ? ? ? ? ? 52 C R "C4'" 1 45
+ATOM 1680 O "O4'" . C B 2 45 ? 7.159 -11.805 35.606 1.00 43.62 ? ? ? ? ? ? 52 C R "O4'" 1 45
+ATOM 1681 C "C3'" . C B 2 45 ? 7.188 -11.377 33.298 1.00 46.15 ? ? ? ? ? ? 52 C R "C3'" 1 45
+ATOM 1682 O "O3'" . C B 2 45 ? 7.304 -11.973 32.000 1.00 47.35 ? ? ? ? ? ? 52 C R "O3'" 1 45
+ATOM 1683 C "C2'" . C B 2 45 ? 5.746 -11.267 33.781 1.00 44.90 ? ? ? ? ? ? 52 C R "C2'" 1 45
+ATOM 1684 O "O2'" . C B 2 45 ? 4.977 -12.401 33.430 1.00 43.53 ? ? ? ? ? ? 52 C R "O2'" 1 45
+ATOM 1685 C "C1'" . C B 2 45 ? 5.929 -11.169 35.302 1.00 43.74 ? ? ? ? ? ? 52 C R "C1'" 1 45
+ATOM 1686 N N1 . C B 2 45 ? 5.951 -9.755 35.839 1.00 42.95 ? ? ? ? ? ? 52 C R N1 1 45
+ATOM 1687 C C2 . C B 2 45 ? 4.769 -8.993 35.949 1.00 43.00 ? ? ? ? ? ? 52 C R C2 1 45
+ATOM 1688 O O2 . C B 2 45 ? 3.681 -9.470 35.612 1.00 44.02 ? ? ? ? ? ? 52 C R O2 1 45
+ATOM 1689 N N3 . C B 2 45 ? 4.840 -7.724 36.433 1.00 42.38 ? ? ? ? ? ? 52 C R N3 1 45
+ATOM 1690 C C4 . C B 2 45 ? 6.014 -7.206 36.804 1.00 42.74 ? ? ? ? ? ? 52 C R C4 1 45
+ATOM 1691 N N4 . C B 2 45 ? 6.030 -5.955 37.278 1.00 43.12 ? ? ? ? ? ? 52 C R N4 1 45
+ATOM 1692 C C5 . C B 2 45 ? 7.225 -7.954 36.708 1.00 42.43 ? ? ? ? ? ? 52 C R C5 1 45
+ATOM 1693 C C6 . C B 2 45 ? 7.144 -9.202 36.226 1.00 43.56 ? ? ? ? ? ? 52 C R C6 1 45
+ATOM 1694 P P . U B 2 46 ? 8.138 -11.249 30.828 1.00 48.68 ? ? ? ? ? ? 53 U R P 1 46
+ATOM 1695 O OP1 . U B 2 46 ? 8.489 -12.289 29.839 1.00 47.12 ? ? ? ? ? ? 53 U R OP1 1 46
+ATOM 1696 O OP2 . U B 2 46 ? 9.230 -10.441 31.421 1.00 48.44 ? ? ? ? ? ? 53 U R OP2 1 46
+ATOM 1697 O "O5'" . U B 2 46 ? 7.083 -10.220 30.199 1.00 49.66 ? ? ? ? ? ? 53 U R "O5'" 1 46
+ATOM 1698 C "C5'" . U B 2 46 ? 5.921 -10.671 29.502 1.00 54.40 ? ? ? ? ? ? 53 U R "C5'" 1 46
+ATOM 1699 C "C4'" . U B 2 46 ? 4.963 -9.523 29.198 1.00 57.53 ? ? ? ? ? ? 53 U R "C4'" 1 46
+ATOM 1700 O "O4'" . U B 2 46 ? 5.287 -8.340 29.980 1.00 58.88 ? ? ? ? ? ? 53 U R "O4'" 1 46
+ATOM 1701 C "C3'" . U B 2 46 ? 4.914 -9.062 27.740 1.00 59.19 ? ? ? ? ? ? 53 U R "C3'" 1 46
+ATOM 1702 O "O3'" . U B 2 46 ? 3.560 -8.799 27.368 1.00 61.47 ? ? ? ? ? ? 53 U R "O3'" 1 46
+ATOM 1703 C "C2'" . U B 2 46 ? 5.745 -7.780 27.752 1.00 59.32 ? ? ? ? ? ? 53 U R "C2'" 1 46
+ATOM 1704 O "O2'" . U B 2 46 ? 5.377 -6.857 26.745 1.00 57.74 ? ? ? ? ? ? 53 U R "O2'" 1 46
+ATOM 1705 C "C1'" . U B 2 46 ? 5.371 -7.220 29.121 1.00 59.06 ? ? ? ? ? ? 53 U R "C1'" 1 46
+ATOM 1706 N N1 . U B 2 46 ? 6.340 -6.249 29.712 1.00 58.09 ? ? ? ? ? ? 53 U R N1 1 46
+ATOM 1707 C C2 . U B 2 46 ? 5.859 -5.056 30.218 1.00 58.80 ? ? ? ? ? ? 53 U R C2 1 46
+ATOM 1708 O O2 . U B 2 46 ? 4.677 -4.755 30.201 1.00 58.05 ? ? ? ? ? ? 53 U R O2 1 46
+ATOM 1709 N N3 . U B 2 46 ? 6.820 -4.221 30.752 1.00 59.01 ? ? ? ? ? ? 53 U R N3 1 46
+ATOM 1710 C C4 . U B 2 46 ? 8.187 -4.464 30.825 1.00 60.61 ? ? ? ? ? ? 53 U R C4 1 46
+ATOM 1711 O O4 . U B 2 46 ? 8.943 -3.633 31.329 1.00 61.27 ? ? ? ? ? ? 53 U R O4 1 46
+ATOM 1712 C C5 . U B 2 46 ? 8.606 -5.731 30.274 1.00 60.10 ? ? ? ? ? ? 53 U R C5 1 46
+ATOM 1713 C C6 . U B 2 46 ? 7.688 -6.556 29.750 1.00 58.38 ? ? ? ? ? ? 53 U R C6 1 46
+ATOM 1714 P P . C B 2 47 ? 2.584 -9.951 26.828 1.00 64.91 ? ? ? ? ? ? 54 C R P 1 47
+ATOM 1715 O OP1 . C B 2 47 ? 2.979 -11.258 27.407 1.00 63.17 ? ? ? ? ? ? 54 C R OP1 1 47
+ATOM 1716 O OP2 . C B 2 47 ? 2.483 -9.798 25.359 1.00 65.09 ? ? ? ? ? ? 54 C R OP2 1 47
+ATOM 1717 O "O5'" . C B 2 47 ? 1.185 -9.501 27.460 1.00 65.30 ? ? ? ? ? ? 54 C R "O5'" 1 47
+ATOM 1718 C "C5'" . C B 2 47 ? 0.024 -10.322 27.343 1.00 66.07 ? ? ? ? ? ? 54 C R "C5'" 1 47
+ATOM 1719 C "C4'" . C B 2 47 ? -1.185 -9.644 27.967 1.00 66.39 ? ? ? ? ? ? 54 C R "C4'" 1 47
+ATOM 1720 O "O4'" . C B 2 47 ? -1.087 -9.717 29.411 1.00 65.78 ? ? ? ? ? ? 54 C R "O4'" 1 47
+ATOM 1721 C "C3'" . C B 2 47 ? -1.312 -8.159 27.662 1.00 66.72 ? ? ? ? ? ? 54 C R "C3'" 1 47
+ATOM 1722 O "O3'" . C B 2 47 ? -2.036 -7.964 26.455 1.00 67.66 ? ? ? ? ? ? 54 C R "O3'" 1 47
+ATOM 1723 C "C2'" . C B 2 47 ? -2.044 -7.617 28.886 1.00 66.13 ? ? ? ? ? ? 54 C R "C2'" 1 47
+ATOM 1724 O "O2'" . C B 2 47 ? -3.449 -7.770 28.809 1.00 66.82 ? ? ? ? ? ? 54 C R "O2'" 1 47
+ATOM 1725 C "C1'" . C B 2 47 ? -1.474 -8.487 30.002 1.00 65.57 ? ? ? ? ? ? 54 C R "C1'" 1 47
+ATOM 1726 N N1 . C B 2 47 ? -0.310 -7.864 30.746 1.00 65.06 ? ? ? ? ? ? 54 C R N1 1 47
+ATOM 1727 C C2 . C B 2 47 ? -0.545 -6.896 31.745 1.00 64.59 ? ? ? ? ? ? 54 C R C2 1 47
+ATOM 1728 O O2 . C B 2 47 ? -1.699 -6.547 32.019 1.00 64.26 ? ? ? ? ? ? 54 C R O2 1 47
+ATOM 1729 N N3 . C B 2 47 ? 0.512 -6.352 32.401 1.00 64.26 ? ? ? ? ? ? 54 C R N3 1 47
+ATOM 1730 C C4 . C B 2 47 ? 1.757 -6.733 32.100 1.00 64.92 ? ? ? ? ? ? 54 C R C4 1 47
+ATOM 1731 N N4 . C B 2 47 ? 2.760 -6.164 32.775 1.00 64.83 ? ? ? ? ? ? 54 C R N4 1 47
+ATOM 1732 C C5 . C B 2 47 ? 2.024 -7.713 31.093 1.00 64.53 ? ? ? ? ? ? 54 C R C5 1 47
+ATOM 1733 C C6 . C B 2 47 ? 0.975 -8.243 30.454 1.00 63.98 ? ? ? ? ? ? 54 C R C6 1 47
+ATOM 1734 P P . C B 2 48 ? -1.674 -6.723 25.517 1.00 68.81 ? ? ? ? ? ? 55 C R P 1 48
+ATOM 1735 O OP1 . C B 2 48 ? -2.447 -6.864 24.261 1.00 69.41 ? ? ? ? ? ? 55 C R OP1 1 48
+ATOM 1736 O OP2 . C B 2 48 ? -0.200 -6.603 25.448 1.00 67.86 ? ? ? ? ? ? 55 C R OP2 1 48
+ATOM 1737 O "O5'" . C B 2 48 ? -2.242 -5.482 26.358 1.00 69.07 ? ? ? ? ? ? 55 C R "O5'" 1 48
+ATOM 1738 C "C5'" . C B 2 48 ? -3.646 -5.221 26.427 1.00 69.11 ? ? ? ? ? ? 55 C R "C5'" 1 48
+ATOM 1739 C "C4'" . C B 2 48 ? -3.923 -3.891 27.104 1.00 69.61 ? ? ? ? ? ? 55 C R "C4'" 1 48
+ATOM 1740 O "O4'" . C B 2 48 ? -3.596 -3.997 28.516 1.00 69.65 ? ? ? ? ? ? 55 C R "O4'" 1 48
+ATOM 1741 C "C3'" . C B 2 48 ? -3.074 -2.716 26.634 1.00 70.13 ? ? ? ? ? ? 55 C R "C3'" 1 48
+ATOM 1742 O "O3'" . C B 2 48 ? -3.542 -2.139 25.412 1.00 71.13 ? ? ? ? ? ? 55 C R "O3'" 1 48
+ATOM 1743 C "C2'" . C B 2 48 ? -3.199 -1.771 27.825 1.00 69.72 ? ? ? ? ? ? 55 C R "C2'" 1 48
+ATOM 1744 O "O2'" . C B 2 48 ? -4.425 -1.063 27.857 1.00 70.48 ? ? ? ? ? ? 55 C R "O2'" 1 48
+ATOM 1745 C "C1'" . C B 2 48 ? -3.094 -2.756 28.991 1.00 68.89 ? ? ? ? ? ? 55 C R "C1'" 1 48
+ATOM 1746 N N1 . C B 2 48 ? -1.672 -2.897 29.486 1.00 67.73 ? ? ? ? ? ? 55 C R N1 1 48
+ATOM 1747 C C2 . C B 2 48 ? -1.115 -1.908 30.324 1.00 66.72 ? ? ? ? ? ? 55 C R C2 1 48
+ATOM 1748 O O2 . C B 2 48 ? -1.786 -0.928 30.673 1.00 66.06 ? ? ? ? ? ? 55 C R O2 1 48
+ATOM 1749 N N3 . C B 2 48 ? 0.167 -2.051 30.746 1.00 65.96 ? ? ? ? ? ? 55 C R N3 1 48
+ATOM 1750 C C4 . C B 2 48 ? 0.889 -3.110 30.372 1.00 66.12 ? ? ? ? ? ? 55 C R C4 1 48
+ATOM 1751 N N4 . C B 2 48 ? 2.144 -3.192 30.825 1.00 65.85 ? ? ? ? ? ? 55 C R N4 1 48
+ATOM 1752 C C5 . C B 2 48 ? 0.355 -4.127 29.520 1.00 66.17 ? ? ? ? ? ? 55 C R C5 1 48
+ATOM 1753 C C6 . C B 2 48 ? -0.912 -3.978 29.109 1.00 67.27 ? ? ? ? ? ? 55 C R C6 1 48
+ATOM 1754 P P . G B 2 49 ? -2.484 -1.496 24.388 1.00 71.07 ? ? ? ? ? ? 56 G R P 1 49
+ATOM 1755 O OP1 . G B 2 49 ? -3.206 -1.125 23.152 1.00 69.59 ? ? ? ? ? ? 56 G R OP1 1 49
+ATOM 1756 O OP2 . G B 2 49 ? -1.316 -2.403 24.306 1.00 72.26 ? ? ? ? ? ? 56 G R OP2 1 49
+ATOM 1757 O "O5'" . G B 2 49 ? -1.997 -0.169 25.135 1.00 70.09 ? ? ? ? ? ? 56 G R "O5'" 1 49
+ATOM 1758 C "C5'" . G B 2 49 ? -2.853 0.960 25.173 1.00 70.52 ? ? ? ? ? ? 56 G R "C5'" 1 49
+ATOM 1759 C "C4'" . G B 2 49 ? -2.377 1.985 26.182 1.00 70.37 ? ? ? ? ? ? 56 G R "C4'" 1 49
+ATOM 1760 O "O4'" . G B 2 49 ? -2.024 1.355 27.441 1.00 69.03 ? ? ? ? ? ? 56 G R "O4'" 1 49
+ATOM 1761 C "C3'" . G B 2 49 ? -1.099 2.727 25.832 1.00 71.29 ? ? ? ? ? ? 56 G R "C3'" 1 49
+ATOM 1762 O "O3'" . G B 2 49 ? -1.282 3.677 24.778 1.00 73.32 ? ? ? ? ? ? 56 G R "O3'" 1 49
+ATOM 1763 C "C2'" . G B 2 49 ? -0.848 3.381 27.187 1.00 70.15 ? ? ? ? ? ? 56 G R "C2'" 1 49
+ATOM 1764 O "O2'" . G B 2 49 ? -1.722 4.456 27.464 1.00 71.67 ? ? ? ? ? ? 56 G R "O2'" 1 49
+ATOM 1765 C "C1'" . G B 2 49 ? -1.125 2.211 28.132 1.00 68.21 ? ? ? ? ? ? 56 G R "C1'" 1 49
+ATOM 1766 N N9 . G B 2 49 ? 0.118 1.509 28.466 1.00 66.22 ? ? ? ? ? ? 56 G R N9 1 49
+ATOM 1767 C C8 . G B 2 49 ? 0.498 0.241 28.086 1.00 65.38 ? ? ? ? ? ? 56 G R C8 1 49
+ATOM 1768 N N7 . G B 2 49 ? 1.676 -0.105 28.526 1.00 63.88 ? ? ? ? ? ? 56 G R N7 1 49
+ATOM 1769 C C5 . G B 2 49 ? 2.112 1.006 29.239 1.00 63.04 ? ? ? ? ? ? 56 G R C5 1 49
+ATOM 1770 C C6 . G B 2 49 ? 3.322 1.229 29.944 1.00 62.11 ? ? ? ? ? ? 56 G R C6 1 49
+ATOM 1771 O O6 . G B 2 49 ? 4.279 0.457 30.079 1.00 60.80 ? ? ? ? ? ? 56 G R O6 1 49
+ATOM 1772 N N1 . G B 2 49 ? 3.373 2.494 30.533 1.00 61.90 ? ? ? ? ? ? 56 G R N1 1 49
+ATOM 1773 C C2 . G B 2 49 ? 2.370 3.432 30.446 1.00 62.39 ? ? ? ? ? ? 56 G R C2 1 49
+ATOM 1774 N N2 . G B 2 49 ? 2.583 4.598 31.071 1.00 62.64 ? ? ? ? ? ? 56 G R N2 1 49
+ATOM 1775 N N3 . G B 2 49 ? 1.233 3.238 29.788 1.00 62.60 ? ? ? ? ? ? 56 G R N3 1 49
+ATOM 1776 C C4 . G B 2 49 ? 1.168 2.009 29.209 1.00 63.77 ? ? ? ? ? ? 56 G R C4 1 49
+ATOM 1777 P P . G B 2 50 ? -0.085 4.016 23.757 1.00 75.33 ? ? ? ? ? ? 57 G R P 1 50
+ATOM 1778 O OP1 . G B 2 50 ? -0.597 5.022 22.796 1.00 74.12 ? ? ? ? ? ? 57 G R OP1 1 50
+ATOM 1779 O OP2 . G B 2 50 ? 0.475 2.738 23.256 1.00 74.57 ? ? ? ? ? ? 57 G R OP2 1 50
+ATOM 1780 O "O5'" . G B 2 50 ? 1.039 4.692 24.679 1.00 72.62 ? ? ? ? ? ? 57 G R "O5'" 1 50
+ATOM 1781 C "C5'" . G B 2 50 ? 0.908 6.045 25.089 1.00 70.25 ? ? ? ? ? ? 57 G R "C5'" 1 50
+ATOM 1782 C "C4'" . G B 2 50 ? 1.990 6.442 26.077 1.00 68.44 ? ? ? ? ? ? 57 G R "C4'" 1 50
+ATOM 1783 O "O4'" . G B 2 50 ? 2.130 5.455 27.130 1.00 67.93 ? ? ? ? ? ? 57 G R "O4'" 1 50
+ATOM 1784 C "C3'" . G B 2 50 ? 3.389 6.533 25.501 1.00 67.83 ? ? ? ? ? ? 57 G R "C3'" 1 50
+ATOM 1785 O "O3'" . G B 2 50 ? 3.544 7.750 24.788 1.00 67.62 ? ? ? ? ? ? 57 G R "O3'" 1 50
+ATOM 1786 C "C2'" . G B 2 50 ? 4.228 6.480 26.775 1.00 67.28 ? ? ? ? ? ? 57 G R "C2'" 1 50
+ATOM 1787 O "O2'" . G B 2 50 ? 4.245 7.701 27.493 1.00 67.41 ? ? ? ? ? ? 57 G R "O2'" 1 50
+ATOM 1788 C "C1'" . G B 2 50 ? 3.480 5.411 27.565 1.00 65.42 ? ? ? ? ? ? 57 G R "C1'" 1 50
+ATOM 1789 N N9 . G B 2 50 ? 3.992 4.050 27.384 1.00 62.94 ? ? ? ? ? ? 57 G R N9 1 50
+ATOM 1790 C C8 . G B 2 50 ? 3.357 3.008 26.749 1.00 61.94 ? ? ? ? ? ? 57 G R C8 1 50
+ATOM 1791 N N7 . G B 2 50 ? 4.045 1.901 26.738 1.00 61.98 ? ? ? ? ? ? 57 G R N7 1 50
+ATOM 1792 C C5 . G B 2 50 ? 5.214 2.221 27.415 1.00 62.24 ? ? ? ? ? ? 57 G R C5 1 50
+ATOM 1793 C C6 . G B 2 50 ? 6.345 1.415 27.723 1.00 62.49 ? ? ? ? ? ? 57 G R C6 1 50
+ATOM 1794 O O6 . G B 2 50 ? 6.537 0.220 27.442 1.00 63.27 ? ? ? ? ? ? 57 G R O6 1 50
+ATOM 1795 N N1 . G B 2 50 ? 7.322 2.129 28.421 1.00 61.21 ? ? ? ? ? ? 57 G R N1 1 50
+ATOM 1796 C C2 . G B 2 50 ? 7.215 3.454 28.781 1.00 61.37 ? ? ? ? ? ? 57 G R C2 1 50
+ATOM 1797 N N2 . G B 2 50 ? 8.253 3.973 29.450 1.00 60.62 ? ? ? ? ? ? 57 G R N2 1 50
+ATOM 1798 N N3 . G B 2 50 ? 6.161 4.217 28.502 1.00 61.88 ? ? ? ? ? ? 57 G R N3 1 50
+ATOM 1799 C C4 . G B 2 50 ? 5.198 3.542 27.820 1.00 62.34 ? ? ? ? ? ? 57 G R C4 1 50
+ATOM 1800 P P . C B 2 51 ? 4.331 7.764 23.394 1.00 66.82 ? ? ? ? ? ? 58 C R P 1 51
+ATOM 1801 O OP1 . C B 2 51 ? 4.146 9.102 22.794 1.00 64.78 ? ? ? ? ? ? 58 C R OP1 1 51
+ATOM 1802 O OP2 . C B 2 51 ? 3.955 6.551 22.628 1.00 65.42 ? ? ? ? ? ? 58 C R OP2 1 51
+ATOM 1803 O "O5'" . C B 2 51 ? 5.853 7.597 23.862 1.00 65.33 ? ? ? ? ? ? 58 C R "O5'" 1 51
+ATOM 1804 C "C5'" . C B 2 51 ? 6.470 8.558 24.720 1.00 63.15 ? ? ? ? ? ? 58 C R "C5'" 1 51
+ATOM 1805 C "C4'" . C B 2 51 ? 7.754 8.014 25.325 1.00 61.23 ? ? ? ? ? ? 58 C R "C4'" 1 51
+ATOM 1806 O "O4'" . C B 2 51 ? 7.477 6.872 26.179 1.00 60.71 ? ? ? ? ? ? 58 C R "O4'" 1 51
+ATOM 1807 C "C3'" . C B 2 51 ? 8.746 7.463 24.317 1.00 60.20 ? ? ? ? ? ? 58 C R "C3'" 1 51
+ATOM 1808 O "O3'" . C B 2 51 ? 9.461 8.522 23.692 1.00 59.53 ? ? ? ? ? ? 58 C R "O3'" 1 51
+ATOM 1809 C "C2'" . C B 2 51 ? 9.603 6.564 25.208 1.00 60.13 ? ? ? ? ? ? 58 C R "C2'" 1 51
+ATOM 1810 O "O2'" . C B 2 51 ? 10.540 7.271 26.001 1.00 59.39 ? ? ? ? ? ? 58 C R "O2'" 1 51
+ATOM 1811 C "C1'" . C B 2 51 ? 8.528 5.923 26.083 1.00 58.53 ? ? ? ? ? ? 58 C R "C1'" 1 51
+ATOM 1812 N N1 . C B 2 51 ? 7.995 4.611 25.552 1.00 57.48 ? ? ? ? ? ? 58 C R N1 1 51
+ATOM 1813 C C2 . C B 2 51 ? 8.740 3.421 25.706 1.00 57.42 ? ? ? ? ? ? 58 C R C2 1 51
+ATOM 1814 O O2 . C B 2 51 ? 9.839 3.447 26.275 1.00 58.14 ? ? ? ? ? ? 58 C R O2 1 51
+ATOM 1815 N N3 . C B 2 51 ? 8.236 2.254 25.218 1.00 56.01 ? ? ? ? ? ? 58 C R N3 1 51
+ATOM 1816 C C4 . C B 2 51 ? 7.048 2.239 24.601 1.00 56.24 ? ? ? ? ? ? 58 C R C4 1 51
+ATOM 1817 N N4 . C B 2 51 ? 6.590 1.069 24.143 1.00 55.00 ? ? ? ? ? ? 58 C R N4 1 51
+ATOM 1818 C C5 . C B 2 51 ? 6.273 3.430 24.436 1.00 56.57 ? ? ? ? ? ? 58 C R C5 1 51
+ATOM 1819 C C6 . C B 2 51 ? 6.779 4.573 24.918 1.00 56.66 ? ? ? ? ? ? 58 C R C6 1 51
+ATOM 1820 P P . C B 2 52 ? 9.970 8.372 22.178 1.00 58.04 ? ? ? ? ? ? 59 C R P 1 52
+ATOM 1821 O OP1 . C B 2 52 ? 10.457 9.700 21.742 1.00 56.37 ? ? ? ? ? ? 59 C R OP1 1 52
+ATOM 1822 O OP2 . C B 2 52 ? 8.936 7.670 21.381 1.00 56.88 ? ? ? ? ? ? 59 C R OP2 1 52
+ATOM 1823 O "O5'" . C B 2 52 ? 11.218 7.381 22.342 1.00 56.91 ? ? ? ? ? ? 59 C R "O5'" 1 52
+ATOM 1824 C "C5'" . C B 2 52 ? 12.373 7.793 23.078 1.00 54.79 ? ? ? ? ? ? 59 C R "C5'" 1 52
+ATOM 1825 C "C4'" . C B 2 52 ? 13.325 6.634 23.316 1.00 53.17 ? ? ? ? ? ? 59 C R "C4'" 1 52
+ATOM 1826 O "O4'" . C B 2 52 ? 12.666 5.587 24.069 1.00 51.92 ? ? ? ? ? ? 59 C R "O4'" 1 52
+ATOM 1827 C "C3'" . C B 2 52 ? 13.788 5.902 22.066 1.00 52.19 ? ? ? ? ? ? 59 C R "C3'" 1 52
+ATOM 1828 O "O3'" . C B 2 52 ? 14.813 6.614 21.401 1.00 52.04 ? ? ? ? ? ? 59 C R "O3'" 1 52
+ATOM 1829 C "C2'" . C B 2 52 ? 14.293 4.599 22.662 1.00 50.91 ? ? ? ? ? ? 59 C R "C2'" 1 52
+ATOM 1830 O "O2'" . C B 2 52 ? 15.539 4.726 23.317 1.00 52.45 ? ? ? ? ? ? 59 C R "O2'" 1 52
+ATOM 1831 C "C1'" . C B 2 52 ? 13.203 4.330 23.688 1.00 50.14 ? ? ? ? ? ? 59 C R "C1'" 1 52
+ATOM 1832 N N1 . C B 2 52 ? 12.117 3.425 23.184 1.00 47.53 ? ? ? ? ? ? 59 C R N1 1 52
+ATOM 1833 C C2 . C B 2 52 ? 12.376 2.054 23.009 1.00 47.46 ? ? ? ? ? ? 59 C R C2 1 52
+ATOM 1834 O O2 . C B 2 52 ? 13.499 1.589 23.268 1.00 46.61 ? ? ? ? ? ? 59 C R O2 1 52
+ATOM 1835 N N3 . C B 2 52 ? 11.370 1.256 22.561 1.00 47.15 ? ? ? ? ? ? 59 C R N3 1 52
+ATOM 1836 C C4 . C B 2 52 ? 10.166 1.769 22.294 1.00 46.45 ? ? ? ? ? ? 59 C R C4 1 52
+ATOM 1837 N N4 . C B 2 52 ? 9.216 0.940 21.853 1.00 47.76 ? ? ? ? ? ? 59 C R N4 1 52
+ATOM 1838 C C5 . C B 2 52 ? 9.887 3.157 22.462 1.00 46.52 ? ? ? ? ? ? 59 C R C5 1 52
+ATOM 1839 C C6 . C B 2 52 ? 10.880 3.936 22.905 1.00 46.27 ? ? ? ? ? ? 59 C R C6 1 52
+ATOM 1840 P P . U B 2 53 ? 14.852 6.617 19.804 1.00 51.39 ? ? ? ? ? ? 60 U R P 1 53
+ATOM 1841 O OP1 . U B 2 53 ? 15.893 7.589 19.399 1.00 49.66 ? ? ? ? ? ? 60 U R OP1 1 53
+ATOM 1842 O OP2 . U B 2 53 ? 13.469 6.751 19.281 1.00 49.84 ? ? ? ? ? ? 60 U R OP2 1 53
+ATOM 1843 O "O5'" . U B 2 53 ? 15.358 5.134 19.492 1.00 49.51 ? ? ? ? ? ? 60 U R "O5'" 1 53
+ATOM 1844 C "C5'" . U B 2 53 ? 16.729 4.827 19.687 1.00 49.76 ? ? ? ? ? ? 60 U R "C5'" 1 53
+ATOM 1845 C "C4'" . U B 2 53 ? 16.990 3.360 19.429 1.00 49.17 ? ? ? ? ? ? 60 U R "C4'" 1 53
+ATOM 1846 O "O4'" . U B 2 53 ? 15.995 2.556 20.099 1.00 48.61 ? ? ? ? ? ? 60 U R "O4'" 1 53
+ATOM 1847 C "C3'" . U B 2 53 ? 16.868 2.953 17.977 1.00 50.30 ? ? ? ? ? ? 60 U R "C3'" 1 53
+ATOM 1848 O "O3'" . U B 2 53 ? 18.092 3.224 17.328 1.00 53.67 ? ? ? ? ? ? 60 U R "O3'" 1 53
+ATOM 1849 C "C2'" . U B 2 53 ? 16.607 1.458 18.086 1.00 48.65 ? ? ? ? ? ? 60 U R "C2'" 1 53
+ATOM 1850 O "O2'" . U B 2 53 ? 17.800 0.717 18.227 1.00 47.72 ? ? ? ? ? ? 60 U R "O2'" 1 53
+ATOM 1851 C "C1'" . U B 2 53 ? 15.795 1.360 19.372 1.00 47.50 ? ? ? ? ? ? 60 U R "C1'" 1 53
+ATOM 1852 N N1 . U B 2 53 ? 14.331 1.139 19.159 1.00 46.04 ? ? ? ? ? ? 60 U R N1 1 53
+ATOM 1853 C C2 . U B 2 53 ? 13.900 -0.110 18.747 1.00 46.05 ? ? ? ? ? ? 60 U R C2 1 53
+ATOM 1854 O O2 . U B 2 53 ? 14.652 -1.046 18.538 1.00 46.35 ? ? ? ? ? ? 60 U R O2 1 53
+ATOM 1855 N N3 . U B 2 53 ? 12.539 -0.229 18.583 1.00 45.25 ? ? ? ? ? ? 60 U R N3 1 53
+ATOM 1856 C C4 . U B 2 53 ? 11.588 0.752 18.788 1.00 45.23 ? ? ? ? ? ? 60 U R C4 1 53
+ATOM 1857 O O4 . U B 2 53 ? 10.404 0.491 18.600 1.00 46.01 ? ? ? ? ? ? 60 U R O4 1 53
+ATOM 1858 C C5 . U B 2 53 ? 12.112 2.027 19.216 1.00 44.64 ? ? ? ? ? ? 60 U R C5 1 53
+ATOM 1859 C C6 . U B 2 53 ? 13.435 2.170 19.383 1.00 44.49 ? ? ? ? ? ? 60 U R C6 1 53
+ATOM 1860 P P . A B 2 54 ? 18.095 3.811 15.843 1.00 55.88 ? ? ? ? ? ? 61 A R P 1 54
+ATOM 1861 O OP1 . A B 2 54 ? 19.511 4.030 15.463 1.00 55.87 ? ? ? ? ? ? 61 A R OP1 1 54
+ATOM 1862 O OP2 . A B 2 54 ? 17.121 4.925 15.779 1.00 55.17 ? ? ? ? ? ? 61 A R OP2 1 54
+ATOM 1863 O "O5'" . A B 2 54 ? 17.499 2.607 14.985 1.00 56.08 ? ? ? ? ? ? 61 A R "O5'" 1 54
+ATOM 1864 C "C5'" . A B 2 54 ? 18.247 1.418 14.804 1.00 60.18 ? ? ? ? ? ? 61 A R "C5'" 1 54
+ATOM 1865 C "C4'" . A B 2 54 ? 17.368 0.397 14.120 1.00 63.58 ? ? ? ? ? ? 61 A R "C4'" 1 54
+ATOM 1866 O "O4'" . A B 2 54 ? 16.139 0.242 14.864 1.00 65.68 ? ? ? ? ? ? 61 A R "O4'" 1 54
+ATOM 1867 C "C3'" . A B 2 54 ? 16.953 0.786 12.708 1.00 65.51 ? ? ? ? ? ? 61 A R "C3'" 1 54
+ATOM 1868 O "O3'" . A B 2 54 ? 17.601 -0.087 11.816 1.00 67.99 ? ? ? ? ? ? 61 A R "O3'" 1 54
+ATOM 1869 C "C2'" . A B 2 54 ? 15.435 0.617 12.666 1.00 66.06 ? ? ? ? ? ? 61 A R "C2'" 1 54
+ATOM 1870 O "O2'" . A B 2 54 ? 14.996 -0.118 11.540 1.00 67.03 ? ? ? ? ? ? 61 A R "O2'" 1 54
+ATOM 1871 C "C1'" . A B 2 54 ? 15.150 -0.159 13.947 1.00 66.09 ? ? ? ? ? ? 61 A R "C1'" 1 54
+ATOM 1872 N N9 . A B 2 54 ? 13.830 0.121 14.502 1.00 66.27 ? ? ? ? ? ? 61 A R N9 1 54
+ATOM 1873 C C8 . A B 2 54 ? 13.390 1.277 15.092 1.00 67.06 ? ? ? ? ? ? 61 A R C8 1 54
+ATOM 1874 N N7 . A B 2 54 ? 12.139 1.229 15.490 1.00 66.93 ? ? ? ? ? ? 61 A R N7 1 54
+ATOM 1875 C C5 . A B 2 54 ? 11.735 -0.048 15.134 1.00 66.40 ? ? ? ? ? ? 61 A R C5 1 54
+ATOM 1876 C C6 . A B 2 54 ? 10.512 -0.736 15.276 1.00 66.60 ? ? ? ? ? ? 61 A R C6 1 54
+ATOM 1877 N N6 . A B 2 54 ? 9.431 -0.193 15.845 1.00 66.56 ? ? ? ? ? ? 61 A R N6 1 54
+ATOM 1878 N N1 . A B 2 54 ? 10.447 -2.007 14.807 1.00 66.86 ? ? ? ? ? ? 61 A R N1 1 54
+ATOM 1879 C C2 . A B 2 54 ? 11.529 -2.556 14.234 1.00 66.21 ? ? ? ? ? ? 61 A R C2 1 54
+ATOM 1880 N N3 . A B 2 54 ? 12.730 -2.006 14.047 1.00 66.53 ? ? ? ? ? ? 61 A R N3 1 54
+ATOM 1881 C C4 . A B 2 54 ? 12.765 -0.745 14.523 1.00 66.31 ? ? ? ? ? ? 61 A R C4 1 54
+ATOM 1882 P P . A B 2 55 ? 18.808 0.448 10.921 1.00 70.61 ? ? ? ? ? ? 62 A R P 1 55
+ATOM 1883 O OP1 . A B 2 55 ? 19.846 1.046 11.801 1.00 70.09 ? ? ? ? ? ? 62 A R OP1 1 55
+ATOM 1884 O OP2 . A B 2 55 ? 18.189 1.269 9.850 1.00 69.57 ? ? ? ? ? ? 62 A R OP2 1 55
+ATOM 1885 O "O5'" . A B 2 55 ? 19.363 -0.920 10.281 1.00 70.02 ? ? ? ? ? ? 62 A R "O5'" 1 55
+ATOM 1886 C "C5'" . A B 2 55 ? 20.685 -1.405 10.548 1.00 68.98 ? ? ? ? ? ? 62 A R "C5'" 1 55
+ATOM 1887 C "C4'" . A B 2 55 ? 20.806 -2.926 10.497 1.00 68.42 ? ? ? ? ? ? 62 A R "C4'" 1 55
+ATOM 1888 O "O4'" . A B 2 55 ? 20.652 -3.464 11.837 1.00 67.73 ? ? ? ? ? ? 62 A R "O4'" 1 55
+ATOM 1889 C "C3'" . A B 2 55 ? 19.780 -3.698 9.671 1.00 67.81 ? ? ? ? ? ? 62 A R "C3'" 1 55
+ATOM 1890 O "O3'" . A B 2 55 ? 20.150 -3.767 8.301 1.00 67.43 ? ? ? ? ? ? 62 A R "O3'" 1 55
+ATOM 1891 C "C2'" . A B 2 55 ? 19.794 -5.065 10.356 1.00 67.15 ? ? ? ? ? ? 62 A R "C2'" 1 55
+ATOM 1892 O "O2'" . A B 2 55 ? 20.926 -5.855 10.048 1.00 66.64 ? ? ? ? ? ? 62 A R "O2'" 1 55
+ATOM 1893 C "C1'" . A B 2 55 ? 19.851 -4.633 11.811 1.00 66.76 ? ? ? ? ? ? 62 A R "C1'" 1 55
+ATOM 1894 N N9 . A B 2 55 ? 18.531 -4.335 12.368 1.00 66.14 ? ? ? ? ? ? 62 A R N9 1 55
+ATOM 1895 C C8 . A B 2 55 ? 17.961 -3.103 12.531 1.00 65.50 ? ? ? ? ? ? 62 A R C8 1 55
+ATOM 1896 N N7 . A B 2 55 ? 16.762 -3.134 13.055 1.00 66.50 ? ? ? ? ? ? 62 A R N7 1 55
+ATOM 1897 C C5 . A B 2 55 ? 16.524 -4.481 13.248 1.00 65.38 ? ? ? ? ? ? 62 A R C5 1 55
+ATOM 1898 C C6 . A B 2 55 ? 15.419 -5.178 13.774 1.00 65.32 ? ? ? ? ? ? 62 A R C6 1 55
+ATOM 1899 N N6 . A B 2 55 ? 14.316 -4.565 14.213 1.00 65.36 ? ? ? ? ? ? 62 A R N6 1 55
+ATOM 1900 N N1 . A B 2 55 ? 15.494 -6.528 13.829 1.00 65.84 ? ? ? ? ? ? 62 A R N1 1 55
+ATOM 1901 C C2 . A B 2 55 ? 16.606 -7.135 13.385 1.00 65.92 ? ? ? ? ? ? 62 A R C2 1 55
+ATOM 1902 N N3 . A B 2 55 ? 17.708 -6.582 12.869 1.00 65.79 ? ? ? ? ? ? 62 A R N3 1 55
+ATOM 1903 C C4 . A B 2 55 ? 17.602 -5.240 12.828 1.00 65.71 ? ? ? ? ? ? 62 A R C4 1 55
+ATOM 1904 P P . A B 2 56 ? 19.022 -3.797 7.162 1.00 67.83 ? ? ? ? ? ? 63 A R P 1 56
+ATOM 1905 O OP1 . A B 2 56 ? 19.713 -3.744 5.853 1.00 68.70 ? ? ? ? ? ? 63 A R OP1 1 56
+ATOM 1906 O OP2 . A B 2 56 ? 18.003 -2.770 7.474 1.00 66.63 ? ? ? ? ? ? 63 A R OP2 1 56
+ATOM 1907 O "O5'" . A B 2 56 ? 18.365 -5.245 7.349 1.00 65.68 ? ? ? ? ? ? 63 A R "O5'" 1 56
+ATOM 1908 C "C5'" . A B 2 56 ? 19.118 -6.412 7.029 1.00 65.79 ? ? ? ? ? ? 63 A R "C5'" 1 56
+ATOM 1909 C "C4'" . A B 2 56 ? 18.365 -7.669 7.413 1.00 65.99 ? ? ? ? ? ? 63 A R "C4'" 1 56
+ATOM 1910 O "O4'" . A B 2 56 ? 18.059 -7.655 8.831 1.00 66.84 ? ? ? ? ? ? 63 A R "O4'" 1 56
+ATOM 1911 C "C3'" . A B 2 56 ? 17.002 -7.824 6.758 1.00 66.13 ? ? ? ? ? ? 63 A R "C3'" 1 56
+ATOM 1912 O "O3'" . A B 2 56 ? 17.132 -8.296 5.419 1.00 65.53 ? ? ? ? ? ? 63 A R "O3'" 1 56
+ATOM 1913 C "C2'" . A B 2 56 ? 16.341 -8.827 7.702 1.00 66.33 ? ? ? ? ? ? 63 A R "C2'" 1 56
+ATOM 1914 O "O2'" . A B 2 56 ? 16.763 -10.162 7.497 1.00 67.01 ? ? ? ? ? ? 63 A R "O2'" 1 56
+ATOM 1915 C "C1'" . A B 2 56 ? 16.823 -8.316 9.060 1.00 65.48 ? ? ? ? ? ? 63 A R "C1'" 1 56
+ATOM 1916 N N9 . A B 2 56 ? 15.866 -7.394 9.678 1.00 64.09 ? ? ? ? ? ? 63 A R N9 1 56
+ATOM 1917 C C8 . A B 2 56 ? 15.881 -6.026 9.629 1.00 64.16 ? ? ? ? ? ? 63 A R C8 1 56
+ATOM 1918 N N7 . A B 2 56 ? 14.890 -5.454 10.271 1.00 63.71 ? ? ? ? ? ? 63 A R N7 1 56
+ATOM 1919 C C5 . A B 2 56 ? 14.171 -6.521 10.773 1.00 62.63 ? ? ? ? ? ? 63 A R C5 1 56
+ATOM 1920 C C6 . A B 2 56 ? 12.999 -6.589 11.549 1.00 62.92 ? ? ? ? ? ? 63 A R C6 1 56
+ATOM 1921 N N6 . A B 2 56 ? 12.331 -5.507 11.959 1.00 63.55 ? ? ? ? ? ? 63 A R N6 1 56
+ATOM 1922 N N1 . A B 2 56 ? 12.535 -7.811 11.889 1.00 64.68 ? ? ? ? ? ? 63 A R N1 1 56
+ATOM 1923 C C2 . A B 2 56 ? 13.205 -8.897 11.477 1.00 65.12 ? ? ? ? ? ? 63 A R C2 1 56
+ATOM 1924 N N3 . A B 2 56 ? 14.318 -8.955 10.742 1.00 64.84 ? ? ? ? ? ? 63 A R N3 1 56
+ATOM 1925 C C4 . A B 2 56 ? 14.754 -7.723 10.418 1.00 63.46 ? ? ? ? ? ? 63 A R C4 1 56
+ATOM 1926 P P . C B 2 57 ? 16.202 -7.701 4.256 1.00 64.35 ? ? ? ? ? ? 64 C R P 1 57
+ATOM 1927 O OP1 . C B 2 57 ? 16.630 -8.322 2.979 1.00 64.74 ? ? ? ? ? ? 64 C R OP1 1 57
+ATOM 1928 O OP2 . C B 2 57 ? 16.158 -6.226 4.374 1.00 64.06 ? ? ? ? ? ? 64 C R OP2 1 57
+ATOM 1929 O "O5'" . C B 2 57 ? 14.762 -8.261 4.660 1.00 63.87 ? ? ? ? ? ? 64 C R "O5'" 1 57
+ATOM 1930 C "C5'" . C B 2 57 ? 14.475 -9.632 4.450 1.00 64.11 ? ? ? ? ? ? 64 C R "C5'" 1 57
+ATOM 1931 C "C4'" . C B 2 57 ? 13.188 -10.026 5.137 1.00 64.62 ? ? ? ? ? ? 64 C R "C4'" 1 57
+ATOM 1932 O "O4'" . C B 2 57 ? 13.264 -9.676 6.539 1.00 64.41 ? ? ? ? ? ? 64 C R "O4'" 1 57
+ATOM 1933 C "C3'" . C B 2 57 ? 11.952 -9.289 4.653 1.00 65.26 ? ? ? ? ? ? 64 C R "C3'" 1 57
+ATOM 1934 O "O3'" . C B 2 57 ? 11.474 -9.832 3.432 1.00 66.02 ? ? ? ? ? ? 64 C R "O3'" 1 57
+ATOM 1935 C "C2'" . C B 2 57 ? 11.004 -9.512 5.827 1.00 65.59 ? ? ? ? ? ? 64 C R "C2'" 1 57
+ATOM 1936 O "O2'" . C B 2 57 ? 10.404 -10.796 5.841 1.00 65.45 ? ? ? ? ? ? 64 C R "O2'" 1 57
+ATOM 1937 C "C1'" . C B 2 57 ? 11.971 -9.331 7.001 1.00 65.21 ? ? ? ? ? ? 64 C R "C1'" 1 57
+ATOM 1938 N N1 . C B 2 57 ? 11.972 -7.932 7.538 1.00 65.99 ? ? ? ? ? ? 64 C R N1 1 57
+ATOM 1939 C C2 . C B 2 57 ? 10.991 -7.563 8.469 1.00 65.89 ? ? ? ? ? ? 64 C R C2 1 57
+ATOM 1940 O O2 . C B 2 57 ? 10.156 -8.399 8.839 1.00 65.59 ? ? ? ? ? ? 64 C R O2 1 57
+ATOM 1941 N N3 . C B 2 57 ? 10.992 -6.288 8.943 1.00 66.88 ? ? ? ? ? ? 64 C R N3 1 57
+ATOM 1942 C C4 . C B 2 57 ? 11.912 -5.407 8.529 1.00 66.35 ? ? ? ? ? ? 64 C R C4 1 57
+ATOM 1943 N N4 . C B 2 57 ? 11.866 -4.171 9.035 1.00 66.67 ? ? ? ? ? ? 64 C R N4 1 57
+ATOM 1944 C C5 . C B 2 57 ? 12.920 -5.759 7.581 1.00 65.89 ? ? ? ? ? ? 64 C R C5 1 57
+ATOM 1945 C C6 . C B 2 57 ? 12.908 -7.017 7.120 1.00 66.49 ? ? ? ? ? ? 64 C R C6 1 57
+ATOM 1946 P P . C B 2 58 ? 10.835 -8.852 2.340 1.00 66.38 ? ? ? ? ? ? 65 C R P 1 58
+ATOM 1947 O OP1 . C B 2 58 ? 10.679 -9.605 1.076 1.00 65.39 ? ? ? ? ? ? 65 C R OP1 1 58
+ATOM 1948 O OP2 . C B 2 58 ? 11.591 -7.578 2.342 1.00 66.10 ? ? ? ? ? ? 65 C R OP2 1 58
+ATOM 1949 O "O5'" . C B 2 58 ? 9.402 -8.544 2.968 1.00 66.36 ? ? ? ? ? ? 65 C R "O5'" 1 58
+ATOM 1950 C "C5'" . C B 2 58 ? 8.415 -9.549 3.103 1.00 67.74 ? ? ? ? ? ? 65 C R "C5'" 1 58
+ATOM 1951 C "C4'" . C B 2 58 ? 7.214 -8.955 3.805 1.00 70.39 ? ? ? ? ? ? 65 C R "C4'" 1 58
+ATOM 1952 O "O4'" . C B 2 58 ? 7.605 -8.542 5.140 1.00 71.34 ? ? ? ? ? ? 65 C R "O4'" 1 58
+ATOM 1953 C "C3'" . C B 2 58 ? 6.693 -7.661 3.196 1.00 71.53 ? ? ? ? ? ? 65 C R "C3'" 1 58
+ATOM 1954 O "O3'" . C B 2 58 ? 5.913 -7.861 2.023 1.00 72.00 ? ? ? ? ? ? 65 C R "O3'" 1 58
+ATOM 1955 C "C2'" . C B 2 58 ? 5.917 -7.071 4.369 1.00 72.12 ? ? ? ? ? ? 65 C R "C2'" 1 58
+ATOM 1956 O "O2'" . C B 2 58 ? 4.665 -7.687 4.621 1.00 71.68 ? ? ? ? ? ? 65 C R "O2'" 1 58
+ATOM 1957 C "C1'" . C B 2 58 ? 6.905 -7.356 5.499 1.00 71.91 ? ? ? ? ? ? 65 C R "C1'" 1 58
+ATOM 1958 N N1 . C B 2 58 ? 7.867 -6.218 5.736 1.00 71.73 ? ? ? ? ? ? 65 C R N1 1 58
+ATOM 1959 C C2 . C B 2 58 ? 7.417 -5.018 6.319 1.00 72.06 ? ? ? ? ? ? 65 C R C2 1 58
+ATOM 1960 O O2 . C B 2 58 ? 6.235 -4.893 6.648 1.00 72.91 ? ? ? ? ? ? 65 C R O2 1 58
+ATOM 1961 N N3 . C B 2 58 ? 8.297 -4.006 6.525 1.00 72.19 ? ? ? ? ? ? 65 C R N3 1 58
+ATOM 1962 C C4 . C B 2 58 ? 9.573 -4.153 6.169 1.00 72.47 ? ? ? ? ? ? 65 C R C4 1 58
+ATOM 1963 N N4 . C B 2 58 ? 10.400 -3.130 6.389 1.00 73.39 ? ? ? ? ? ? 65 C R N4 1 58
+ATOM 1964 C C5 . C B 2 58 ? 10.058 -5.355 5.571 1.00 72.68 ? ? ? ? ? ? 65 C R C5 1 58
+ATOM 1965 C C6 . C B 2 58 ? 9.181 -6.348 5.378 1.00 72.24 ? ? ? ? ? ? 65 C R C6 1 58
+ATOM 1966 P P . A B 2 59 ? 6.157 -6.872 0.783 1.00 73.36 ? ? ? ? ? ? 660 A R P 1 59
+ATOM 1967 O OP1 . A B 2 59 ? 5.571 -7.487 -0.427 1.00 73.30 ? ? ? ? ? ? 660 A R OP1 1 59
+ATOM 1968 O OP2 . A B 2 59 ? 7.582 -6.473 0.770 1.00 73.48 ? ? ? ? ? ? 660 A R OP2 1 59
+ATOM 1969 O "O5'" . A B 2 59 ? 5.314 -5.575 1.184 1.00 72.74 ? ? ? ? ? ? 660 A R "O5'" 1 59
+ATOM 1970 C "C5'" . A B 2 59 ? 3.924 -5.665 1.449 1.00 72.25 ? ? ? ? ? ? 660 A R "C5'" 1 59
+ATOM 1971 C "C4'" . A B 2 59 ? 3.469 -4.486 2.286 1.00 72.01 ? ? ? ? ? ? 660 A R "C4'" 1 59
+ATOM 1972 O "O4'" . A B 2 59 ? 4.206 -4.450 3.534 1.00 72.01 ? ? ? ? ? ? 660 A R "O4'" 1 59
+ATOM 1973 C "C3'" . A B 2 59 ? 3.731 -3.125 1.668 1.00 71.66 ? ? ? ? ? ? 660 A R "C3'" 1 59
+ATOM 1974 O "O3'" . A B 2 59 ? 2.728 -2.794 0.719 1.00 71.28 ? ? ? ? ? ? 660 A R "O3'" 1 59
+ATOM 1975 C "C2'" . A B 2 59 ? 3.696 -2.244 2.911 1.00 72.75 ? ? ? ? ? ? 660 A R "C2'" 1 59
+ATOM 1976 O "O2'" . A B 2 59 ? 2.391 -2.003 3.403 1.00 73.27 ? ? ? ? ? ? 660 A R "O2'" 1 59
+ATOM 1977 C "C1'" . A B 2 59 ? 4.488 -3.108 3.886 1.00 73.07 ? ? ? ? ? ? 660 A R "C1'" 1 59
+ATOM 1978 N N9 . A B 2 59 ? 5.932 -2.849 3.820 1.00 74.15 ? ? ? ? ? ? 660 A R N9 1 59
+ATOM 1979 C C8 . A B 2 59 ? 6.898 -3.631 3.242 1.00 74.58 ? ? ? ? ? ? 660 A R C8 1 59
+ATOM 1980 N N7 . A B 2 59 ? 8.111 -3.139 3.332 1.00 74.48 ? ? ? ? ? ? 660 A R N7 1 59
+ATOM 1981 C C5 . A B 2 59 ? 7.937 -1.946 4.014 1.00 73.91 ? ? ? ? ? ? 660 A R C5 1 59
+ATOM 1982 C C6 . A B 2 59 ? 8.841 -0.942 4.432 1.00 73.43 ? ? ? ? ? ? 660 A R C6 1 59
+ATOM 1983 N N6 . A B 2 59 ? 10.158 -0.990 4.203 1.00 73.85 ? ? ? ? ? ? 660 A R N6 1 59
+ATOM 1984 N N1 . A B 2 59 ? 8.339 0.125 5.093 1.00 72.70 ? ? ? ? ? ? 660 A R N1 1 59
+ATOM 1985 C C2 . A B 2 59 ? 7.020 0.182 5.323 1.00 72.56 ? ? ? ? ? ? 660 A R C2 1 59
+ATOM 1986 N N3 . A B 2 59 ? 6.076 -0.697 4.981 1.00 73.34 ? ? ? ? ? ? 660 A R N3 1 59
+ATOM 1987 C C4 . A B 2 59 ? 6.600 -1.749 4.322 1.00 73.85 ? ? ? ? ? ? 660 A R C4 1 59
+ATOM 1988 P P . U B 2 60 ? 3.116 -2.005 -0.622 1.00 71.84 ? ? ? ? ? ? 661 U R P 1 60
+ATOM 1989 O OP1 . U B 2 60 ? 1.940 -2.052 -1.522 1.00 72.64 ? ? ? ? ? ? 661 U R OP1 1 60
+ATOM 1990 O OP2 . U B 2 60 ? 4.423 -2.496 -1.116 1.00 71.22 ? ? ? ? ? ? 661 U R OP2 1 60
+ATOM 1991 O "O5'" . U B 2 60 ? 3.316 -0.505 -0.100 1.00 70.01 ? ? ? ? ? ? 661 U R "O5'" 1 60
+ATOM 1992 C "C5'" . U B 2 60 ? 2.241 0.173 0.553 1.00 69.47 ? ? ? ? ? ? 661 U R "C5'" 1 60
+ATOM 1993 C "C4'" . U B 2 60 ? 2.741 1.356 1.359 1.00 68.25 ? ? ? ? ? ? 661 U R "C4'" 1 60
+ATOM 1994 O "O4'" . U B 2 60 ? 3.717 0.928 2.345 1.00 67.65 ? ? ? ? ? ? 661 U R "O4'" 1 60
+ATOM 1995 C "C3'" . U B 2 60 ? 3.497 2.388 0.545 1.00 67.97 ? ? ? ? ? ? 661 U R "C3'" 1 60
+ATOM 1996 O "O3'" . U B 2 60 ? 2.603 3.226 -0.163 1.00 67.88 ? ? ? ? ? ? 661 U R "O3'" 1 60
+ATOM 1997 C "C2'" . U B 2 60 ? 4.277 3.110 1.636 1.00 67.61 ? ? ? ? ? ? 661 U R "C2'" 1 60
+ATOM 1998 O "O2'" . U B 2 60 ? 3.480 4.008 2.389 1.00 68.00 ? ? ? ? ? ? 661 U R "O2'" 1 60
+ATOM 1999 C "C1'" . U B 2 60 ? 4.726 1.919 2.488 1.00 66.13 ? ? ? ? ? ? 661 U R "C1'" 1 60
+ATOM 2000 N N1 . U B 2 60 ? 6.093 1.375 2.098 1.00 63.66 ? ? ? ? ? ? 661 U R N1 1 60
+ATOM 2001 C C2 . U B 2 60 ? 7.240 2.057 2.492 1.00 62.13 ? ? ? ? ? ? 661 U R C2 1 60
+ATOM 2002 O O2 . U B 2 60 ? 7.224 3.083 3.152 1.00 61.93 ? ? ? ? ? ? 661 U R O2 1 60
+ATOM 2003 N N3 . U B 2 60 ? 8.430 1.491 2.089 1.00 59.95 ? ? ? ? ? ? 661 U R N3 1 60
+ATOM 2004 C C4 . U B 2 60 ? 8.596 0.338 1.343 1.00 59.19 ? ? ? ? ? ? 661 U R C4 1 60
+ATOM 2005 O O4 . U B 2 60 ? 9.725 -0.046 1.055 1.00 56.54 ? ? ? ? ? ? 661 U R O4 1 60
+ATOM 2006 C C5 . U B 2 60 ? 7.366 -0.317 0.968 1.00 60.54 ? ? ? ? ? ? 661 U R C5 1 60
+ATOM 2007 C C6 . U B 2 60 ? 6.194 0.212 1.350 1.00 61.70 ? ? ? ? ? ? 661 U R C6 1 60
+ATOM 2008 P P . U B 2 61 ? 2.902 3.522 -1.708 1.00 68.53 ? ? ? ? ? ? 662 U R P 1 61
+ATOM 2009 O OP1 . U B 2 61 ? 1.692 4.153 -2.287 1.00 68.43 ? ? ? ? ? ? 662 U R OP1 1 61
+ATOM 2010 O OP2 . U B 2 61 ? 3.464 2.303 -2.334 1.00 65.79 ? ? ? ? ? ? 662 U R OP2 1 61
+ATOM 2011 O "O5'" . U B 2 61 ? 4.059 4.620 -1.611 1.00 68.79 ? ? ? ? ? ? 662 U R "O5'" 1 61
+ATOM 2012 C "C5'" . U B 2 61 ? 3.740 5.916 -1.115 1.00 69.67 ? ? ? ? ? ? 662 U R "C5'" 1 61
+ATOM 2013 C "C4'" . U B 2 61 ? 4.317 6.999 -2.007 1.00 70.36 ? ? ? ? ? ? 662 U R "C4'" 1 61
+ATOM 2014 O "O4'" . U B 2 61 ? 5.749 6.834 -2.074 1.00 70.13 ? ? ? ? ? ? 662 U R "O4'" 1 61
+ATOM 2015 C "C3'" . U B 2 61 ? 3.808 7.049 -3.448 1.00 70.69 ? ? ? ? ? ? 662 U R "C3'" 1 61
+ATOM 2016 O "O3'" . U B 2 61 ? 3.355 8.374 -3.746 1.00 70.70 ? ? ? ? ? ? 662 U R "O3'" 1 61
+ATOM 2017 C "C2'" . U B 2 61 ? 5.016 6.625 -4.288 1.00 71.10 ? ? ? ? ? ? 662 U R "C2'" 1 61
+ATOM 2018 O "O2'" . U B 2 61 ? 5.059 7.286 -5.538 1.00 70.55 ? ? ? ? ? ? 662 U R "O2'" 1 61
+ATOM 2019 C "C1'" . U B 2 61 ? 6.192 7.029 -3.396 1.00 71.40 ? ? ? ? ? ? 662 U R "C1'" 1 61
+ATOM 2020 N N1 . U B 2 61 ? 7.458 6.232 -3.525 1.00 72.53 ? ? ? ? ? ? 662 U R N1 1 61
+ATOM 2021 C C2 . U B 2 61 ? 8.528 6.733 -4.252 1.00 73.18 ? ? ? ? ? ? 662 U R C2 1 61
+ATOM 2022 O O2 . U B 2 61 ? 8.520 7.804 -4.834 1.00 74.02 ? ? ? ? ? ? 662 U R O2 1 61
+ATOM 2023 N N3 . U B 2 61 ? 9.633 5.917 -4.283 1.00 72.80 ? ? ? ? ? ? 662 U R N3 1 61
+ATOM 2024 C C4 . U B 2 61 ? 9.783 4.683 -3.672 1.00 73.39 ? ? ? ? ? ? 662 U R C4 1 61
+ATOM 2025 O O4 . U B 2 61 ? 10.839 4.072 -3.794 1.00 74.02 ? ? ? ? ? ? 662 U R O4 1 61
+ATOM 2026 C C5 . U B 2 61 ? 8.638 4.230 -2.925 1.00 73.15 ? ? ? ? ? ? 662 U R C5 1 61
+ATOM 2027 C C6 . U B 2 61 ? 7.547 5.008 -2.880 1.00 72.98 ? ? ? ? ? ? 662 U R C6 1 61
+ATOM 2028 P P . G B 2 62 ? 1.990 8.935 -3.111 1.00 73.05 ? ? ? ? ? ? 663 G R P 1 62
+ATOM 2029 O OP1 . G B 2 62 ? 1.118 7.788 -2.774 1.00 73.27 ? ? ? ? ? ? 663 G R OP1 1 62
+ATOM 2030 O OP2 . G B 2 62 ? 1.486 10.008 -3.997 1.00 73.40 ? ? ? ? ? ? 663 G R OP2 1 62
+ATOM 2031 O "O5'" . G B 2 62 ? 2.431 9.638 -1.754 1.00 71.69 ? ? ? ? ? ? 663 G R "O5'" 1 62
+ATOM 2032 C "C5'" . G B 2 62 ? 1.438 9.866 -0.773 1.00 72.31 ? ? ? ? ? ? 663 G R "C5'" 1 62
+ATOM 2033 C "C4'" . G B 2 62 ? 2.016 9.625 0.603 1.00 72.96 ? ? ? ? ? ? 663 G R "C4'" 1 62
+ATOM 2034 O "O4'" . G B 2 62 ? 3.078 8.642 0.522 1.00 72.80 ? ? ? ? ? ? 663 G R "O4'" 1 62
+ATOM 2035 C "C3'" . G B 2 62 ? 2.679 10.849 1.201 1.00 73.11 ? ? ? ? ? ? 663 G R "C3'" 1 62
+ATOM 2036 O "O3'" . G B 2 62 ? 1.703 11.632 1.857 1.00 74.84 ? ? ? ? ? ? 663 G R "O3'" 1 62
+ATOM 2037 C "C2'" . G B 2 62 ? 3.680 10.224 2.163 1.00 72.69 ? ? ? ? ? ? 663 G R "C2'" 1 62
+ATOM 2038 O "O2'" . G B 2 62 ? 3.085 9.811 3.379 1.00 73.60 ? ? ? ? ? ? 663 G R "O2'" 1 62
+ATOM 2039 C "C1'" . G B 2 62 ? 4.147 9.001 1.374 1.00 71.67 ? ? ? ? ? ? 663 G R "C1'" 1 62
+ATOM 2040 N N9 . G B 2 62 ? 5.344 9.197 0.550 1.00 70.19 ? ? ? ? ? ? 663 G R N9 1 62
+ATOM 2041 C C8 . G B 2 62 ? 5.646 10.283 -0.241 1.00 69.50 ? ? ? ? ? ? 663 G R C8 1 62
+ATOM 2042 N N7 . G B 2 62 ? 6.783 10.180 -0.865 1.00 68.29 ? ? ? ? ? ? 663 G R N7 1 62
+ATOM 2043 C C5 . G B 2 62 ? 7.277 8.949 -0.468 1.00 67.98 ? ? ? ? ? ? 663 G R C5 1 62
+ATOM 2044 C C6 . G B 2 62 ? 8.481 8.295 -0.825 1.00 66.62 ? ? ? ? ? ? 663 G R C6 1 62
+ATOM 2045 O O6 . G B 2 62 ? 9.366 8.702 -1.585 1.00 64.99 ? ? ? ? ? ? 663 G R O6 1 62
+ATOM 2046 N N1 . G B 2 62 ? 8.610 7.051 -0.208 1.00 66.74 ? ? ? ? ? ? 663 G R N1 1 62
+ATOM 2047 C C2 . G B 2 62 ? 7.680 6.509 0.652 1.00 66.89 ? ? ? ? ? ? 663 G R C2 1 62
+ATOM 2048 N N2 . G B 2 62 ? 7.968 5.301 1.152 1.00 67.29 ? ? ? ? ? ? 663 G R N2 1 62
+ATOM 2049 N N3 . G B 2 62 ? 6.545 7.111 0.997 1.00 67.70 ? ? ? ? ? ? 663 G R N3 1 62
+ATOM 2050 C C4 . G B 2 62 ? 6.405 8.327 0.404 1.00 68.85 ? ? ? ? ? ? 663 G R C4 1 62
+ATOM 2051 P P . C B 2 63 ? 1.388 13.121 1.352 1.00 77.36 ? ? ? ? ? ? 664 C R P 1 63
+ATOM 2052 O OP1 . C B 2 63 ? 0.247 13.614 2.163 1.00 77.15 ? ? ? ? ? ? 664 C R OP1 1 63
+ATOM 2053 O OP2 . C B 2 63 ? 1.291 13.114 -0.128 1.00 75.72 ? ? ? ? ? ? 664 C R OP2 1 63
+ATOM 2054 O "O5'" . C B 2 63 ? 2.703 13.937 1.767 1.00 74.70 ? ? ? ? ? ? 664 C R "O5'" 1 63
+ATOM 2055 C "C5'" . C B 2 63 ? 3.071 14.011 3.145 1.00 71.98 ? ? ? ? ? ? 664 C R "C5'" 1 63
+ATOM 2056 C "C4'" . C B 2 63 ? 3.257 15.447 3.605 1.00 68.89 ? ? ? ? ? ? 664 C R "C4'" 1 63
+ATOM 2057 O "O4'" . C B 2 63 ? 4.112 16.148 2.668 1.00 66.34 ? ? ? ? ? ? 664 C R "O4'" 1 63
+ATOM 2058 C "C3'" . C B 2 63 ? 1.995 16.288 3.758 1.00 67.15 ? ? ? ? ? ? 664 C R "C3'" 1 63
+ATOM 2059 O "O3'" . C B 2 63 ? 2.144 17.037 4.962 1.00 69.06 ? ? ? ? ? ? 664 C R "O3'" 1 63
+ATOM 2060 C "C2'" . C B 2 63 ? 1.993 17.177 2.510 1.00 66.25 ? ? ? ? ? ? 664 C R "C2'" 1 63
+ATOM 2061 O "O2'" . C B 2 63 ? 1.416 18.448 2.746 1.00 65.72 ? ? ? ? ? ? 664 C R "O2'" 1 63
+ATOM 2062 C "C1'" . C B 2 63 ? 3.485 17.326 2.207 1.00 64.00 ? ? ? ? ? ? 664 C R "C1'" 1 63
+ATOM 2063 N N1 . C B 2 63 ? 3.886 17.517 0.762 1.00 60.59 ? ? ? ? ? ? 664 C R N1 1 63
+ATOM 2064 C C2 . C B 2 63 ? 4.339 18.773 0.315 1.00 58.54 ? ? ? ? ? ? 664 C R C2 1 63
+ATOM 2065 O O2 . C B 2 63 ? 4.388 19.729 1.098 1.00 57.97 ? ? ? ? ? ? 664 C R O2 1 63
+ATOM 2066 N N3 . C B 2 63 ? 4.710 18.917 -0.985 1.00 56.69 ? ? ? ? ? ? 664 C R N3 1 63
+ATOM 2067 C C4 . C B 2 63 ? 4.651 17.880 -1.824 1.00 55.57 ? ? ? ? ? ? 664 C R C4 1 63
+ATOM 2068 N N4 . C B 2 63 ? 5.027 18.086 -3.087 1.00 54.13 ? ? ? ? ? ? 664 C R N4 1 63
+ATOM 2069 C C5 . C B 2 63 ? 4.203 16.593 -1.398 1.00 56.43 ? ? ? ? ? ? 664 C R C5 1 63
+ATOM 2070 C C6 . C B 2 63 ? 3.839 16.460 -0.113 1.00 59.25 ? ? ? ? ? ? 664 C R C6 1 63
+ATOM 2071 P P . A B 2 64 ? 0.950 17.272 6.000 1.00 70.69 ? ? ? ? ? ? 665 A R P 1 64
+ATOM 2072 O OP1 . A B 2 64 ? -0.050 16.201 5.791 1.00 72.42 ? ? ? ? ? ? 665 A R OP1 1 64
+ATOM 2073 O OP2 . A B 2 64 ? 0.559 18.696 5.896 1.00 70.42 ? ? ? ? ? ? 665 A R OP2 1 64
+ATOM 2074 O "O5'" . A B 2 64 ? 1.610 17.095 7.448 1.00 71.51 ? ? ? ? ? ? 665 A R "O5'" 1 64
+ATOM 2075 C "C5'" . A B 2 64 ? 2.194 15.864 7.861 1.00 72.59 ? ? ? ? ? ? 665 A R "C5'" 1 64
+ATOM 2076 C "C4'" . A B 2 64 ? 3.682 16.048 8.091 1.00 73.87 ? ? ? ? ? ? 665 A R "C4'" 1 64
+ATOM 2077 O "O4'" . A B 2 64 ? 4.315 16.485 6.863 1.00 73.15 ? ? ? ? ? ? 665 A R "O4'" 1 64
+ATOM 2078 C "C3'" . A B 2 64 ? 4.043 17.130 9.096 1.00 75.09 ? ? ? ? ? ? 665 A R "C3'" 1 64
+ATOM 2079 O "O3'" . A B 2 64 ? 4.004 16.605 10.413 1.00 78.27 ? ? ? ? ? ? 665 A R "O3'" 1 64
+ATOM 2080 C "C2'" . A B 2 64 ? 5.457 17.517 8.677 1.00 73.86 ? ? ? ? ? ? 665 A R "C2'" 1 64
+ATOM 2081 O "O2'" . A B 2 64 ? 6.453 16.708 9.269 1.00 73.63 ? ? ? ? ? ? 665 A R "O2'" 1 64
+ATOM 2082 C "C1'" . A B 2 64 ? 5.430 17.308 7.161 1.00 72.50 ? ? ? ? ? ? 665 A R "C1'" 1 64
+ATOM 2083 N N9 . A B 2 64 ? 5.355 18.543 6.375 1.00 71.09 ? ? ? ? ? ? 665 A R N9 1 64
+ATOM 2084 C C8 . A B 2 64 ? 4.413 18.864 5.436 1.00 70.77 ? ? ? ? ? ? 665 A R C8 1 64
+ATOM 2085 N N7 . A B 2 64 ? 4.587 20.037 4.874 1.00 70.25 ? ? ? ? ? ? 665 A R N7 1 64
+ATOM 2086 C C5 . A B 2 64 ? 5.728 20.530 5.483 1.00 69.46 ? ? ? ? ? ? 665 A R C5 1 64
+ATOM 2087 C C6 . A B 2 64 ? 6.450 21.738 5.332 1.00 68.69 ? ? ? ? ? ? 665 A R C6 1 64
+ATOM 2088 N N6 . A B 2 64 ? 6.105 22.708 4.480 1.00 68.87 ? ? ? ? ? ? 665 A R N6 1 64
+ATOM 2089 N N1 . A B 2 64 ? 7.550 21.922 6.092 1.00 67.79 ? ? ? ? ? ? 665 A R N1 1 64
+ATOM 2090 C C2 . A B 2 64 ? 7.908 20.953 6.946 1.00 69.36 ? ? ? ? ? ? 665 A R C2 1 64
+ATOM 2091 N N3 . A B 2 64 ? 7.312 19.780 7.178 1.00 69.82 ? ? ? ? ? ? 665 A R N3 1 64
+ATOM 2092 C C4 . A B 2 64 ? 6.218 19.622 6.409 1.00 70.21 ? ? ? ? ? ? 665 A R C4 1 64
+ATOM 2093 P P . C B 2 65 ? 3.137 17.338 11.542 1.00 81.19 ? ? ? ? ? ? 666 C R P 1 65
+ATOM 2094 O OP1 . C B 2 65 ? 3.058 16.420 12.706 1.00 81.02 ? ? ? ? ? ? 666 C R OP1 1 65
+ATOM 2095 O OP2 . C B 2 65 ? 1.890 17.840 10.913 1.00 80.71 ? ? ? ? ? ? 666 C R OP2 1 65
+ATOM 2096 O "O5'" . C B 2 65 ? 4.051 18.591 11.938 1.00 80.24 ? ? ? ? ? ? 666 C R "O5'" 1 65
+ATOM 2097 C "C5'" . C B 2 65 ? 5.146 18.403 12.830 1.00 80.72 ? ? ? ? ? ? 666 C R "C5'" 1 65
+ATOM 2098 C "C4'" . C B 2 65 ? 6.048 19.620 12.884 1.00 80.88 ? ? ? ? ? ? 666 C R "C4'" 1 65
+ATOM 2099 O "O4'" . C B 2 65 ? 6.613 19.850 11.570 1.00 80.29 ? ? ? ? ? ? 666 C R "O4'" 1 65
+ATOM 2100 C "C3'" . C B 2 65 ? 5.350 20.931 13.222 1.00 81.64 ? ? ? ? ? ? 666 C R "C3'" 1 65
+ATOM 2101 O "O3'" . C B 2 65 ? 5.171 21.071 14.627 1.00 83.95 ? ? ? ? ? ? 666 C R "O3'" 1 65
+ATOM 2102 C "C2'" . C B 2 65 ? 6.297 21.962 12.615 1.00 80.07 ? ? ? ? ? ? 666 C R "C2'" 1 65
+ATOM 2103 O "O2'" . C B 2 65 ? 7.430 22.230 13.423 1.00 78.39 ? ? ? ? ? ? 666 C R "O2'" 1 65
+ATOM 2104 C "C1'" . C B 2 65 ? 6.691 21.244 11.321 1.00 78.65 ? ? ? ? ? ? 666 C R "C1'" 1 65
+ATOM 2105 N N1 . C B 2 65 ? 5.832 21.602 10.132 1.00 75.84 ? ? ? ? ? ? 666 C R N1 1 65
+ATOM 2106 C C2 . C B 2 65 ? 6.202 22.682 9.312 1.00 75.18 ? ? ? ? ? ? 666 C R C2 1 65
+ATOM 2107 O O2 . C B 2 65 ? 7.228 23.331 9.564 1.00 74.05 ? ? ? ? ? ? 666 C R O2 1 65
+ATOM 2108 N N3 . C B 2 65 ? 5.417 22.991 8.243 1.00 74.35 ? ? ? ? ? ? 666 C R N3 1 65
+ATOM 2109 C C4 . C B 2 65 ? 4.311 22.286 7.985 1.00 73.74 ? ? ? ? ? ? 666 C R C4 1 65
+ATOM 2110 N N4 . C B 2 65 ? 3.581 22.638 6.925 1.00 72.83 ? ? ? ? ? ? 666 C R N4 1 65
+ATOM 2111 C C5 . C B 2 65 ? 3.913 21.185 8.802 1.00 74.51 ? ? ? ? ? ? 666 C R C5 1 65
+ATOM 2112 C C6 . C B 2 65 ? 4.695 20.888 9.848 1.00 75.15 ? ? ? ? ? ? 666 C R C6 1 65
+ATOM 2113 P P . U B 2 66 ? 3.681 21.126 15.214 1.00 85.44 ? ? ? ? ? ? 667 U R P 1 66
+ATOM 2114 O OP1 . U B 2 66 ? 2.761 20.443 14.269 1.00 84.32 ? ? ? ? ? ? 667 U R OP1 1 66
+ATOM 2115 O OP2 . U B 2 66 ? 3.423 22.533 15.602 1.00 85.16 ? ? ? ? ? ? 667 U R OP2 1 66
+ATOM 2116 O "O5'" . U B 2 66 ? 3.803 20.244 16.545 1.00 83.25 ? ? ? ? ? ? 667 U R "O5'" 1 66
+ATOM 2117 C "C5'" . U B 2 66 ? 3.811 18.830 16.438 1.00 80.35 ? ? ? ? ? ? 667 U R "C5'" 1 66
+ATOM 2118 C "C4'" . U B 2 66 ? 3.961 18.177 17.795 1.00 78.41 ? ? ? ? ? ? 667 U R "C4'" 1 66
+ATOM 2119 O "O4'" . U B 2 66 ? 2.679 18.168 18.471 1.00 77.53 ? ? ? ? ? ? 667 U R "O4'" 1 66
+ATOM 2120 C "C3'" . U B 2 66 ? 4.400 16.726 17.709 1.00 78.17 ? ? ? ? ? ? 667 U R "C3'" 1 66
+ATOM 2121 O "O3'" . U B 2 66 ? 5.812 16.660 17.870 1.00 78.19 ? ? ? ? ? ? 667 U R "O3'" 1 66
+ATOM 2122 C "C2'" . U B 2 66 ? 3.652 16.047 18.853 1.00 77.56 ? ? ? ? ? ? 667 U R "C2'" 1 66
+ATOM 2123 O "O2'" . U B 2 66 ? 4.355 16.085 20.081 1.00 78.60 ? ? ? ? ? ? 667 U R "O2'" 1 66
+ATOM 2124 C "C1'" . U B 2 66 ? 2.374 16.873 18.964 1.00 75.82 ? ? ? ? ? ? 667 U R "C1'" 1 66
+ATOM 2125 N N1 . U B 2 66 ? 1.158 16.315 18.251 1.00 73.30 ? ? ? ? ? ? 667 U R N1 1 66
+ATOM 2126 C C2 . U B 2 66 ? 0.611 15.087 18.615 1.00 72.31 ? ? ? ? ? ? 667 U R C2 1 66
+ATOM 2127 O O2 . U B 2 66 ? 1.049 14.369 19.498 1.00 71.97 ? ? ? ? ? ? 667 U R O2 1 66
+ATOM 2128 N N3 . U B 2 66 ? -0.501 14.707 17.894 1.00 70.90 ? ? ? ? ? ? 667 U R N3 1 66
+ATOM 2129 C C4 . U B 2 66 ? -1.116 15.411 16.869 1.00 70.84 ? ? ? ? ? ? 667 U R C4 1 66
+ATOM 2130 O O4 . U B 2 66 ? -2.106 14.946 16.309 1.00 70.32 ? ? ? ? ? ? 667 U R O4 1 66
+ATOM 2131 C C5 . U B 2 66 ? -0.496 16.672 16.546 1.00 70.74 ? ? ? ? ? ? 667 U R C5 1 66
+ATOM 2132 C C6 . U B 2 66 ? 0.583 17.065 17.235 1.00 72.25 ? ? ? ? ? ? 667 U R C6 1 66
+ATOM 2133 P P . C B 2 67 ? 6.763 16.185 16.670 1.00 78.26 ? ? ? ? ? ? 668 C R P 1 67
+ATOM 2134 O OP1 . C B 2 67 ? 8.146 16.577 17.031 1.00 76.72 ? ? ? ? ? ? 668 C R OP1 1 67
+ATOM 2135 O OP2 . C B 2 67 ? 6.180 16.623 15.380 1.00 77.82 ? ? ? ? ? ? 668 C R OP2 1 67
+ATOM 2136 O "O5'" . C B 2 67 ? 6.628 14.595 16.719 1.00 74.82 ? ? ? ? ? ? 668 C R "O5'" 1 67
+ATOM 2137 C "C5'" . C B 2 67 ? 7.138 13.875 17.825 1.00 71.24 ? ? ? ? ? ? 668 C R "C5'" 1 67
+ATOM 2138 C "C4'" . C B 2 67 ? 6.244 12.691 18.113 1.00 69.21 ? ? ? ? ? ? 668 C R "C4'" 1 67
+ATOM 2139 O "O4'" . C B 2 67 ? 4.898 13.168 18.353 1.00 67.80 ? ? ? ? ? ? 668 C R "O4'" 1 67
+ATOM 2140 C "C3'" . C B 2 67 ? 6.038 11.725 16.960 1.00 68.63 ? ? ? ? ? ? 668 C R "C3'" 1 67
+ATOM 2141 O "O3'" . C B 2 67 ? 7.160 10.872 16.746 1.00 68.74 ? ? ? ? ? ? 668 C R "O3'" 1 67
+ATOM 2142 C "C2'" . C B 2 67 ? 4.806 10.982 17.464 1.00 68.15 ? ? ? ? ? ? 668 C R "C2'" 1 67
+ATOM 2143 O "O2'" . C B 2 67 ? 5.090 10.060 18.501 1.00 69.50 ? ? ? ? ? ? 668 C R "O2'" 1 67
+ATOM 2144 C "C1'" . C B 2 67 ? 3.978 12.151 17.996 1.00 66.35 ? ? ? ? ? ? 668 C R "C1'" 1 67
+ATOM 2145 N N1 . C B 2 67 ? 2.969 12.650 16.994 1.00 63.67 ? ? ? ? ? ? 668 C R N1 1 67
+ATOM 2146 C C2 . C B 2 67 ? 1.701 12.042 16.943 1.00 63.26 ? ? ? ? ? ? 668 C R C2 1 67
+ATOM 2147 O O2 . C B 2 67 ? 1.429 11.120 17.722 1.00 62.50 ? ? ? ? ? ? 668 C R O2 1 67
+ATOM 2148 N N3 . C B 2 67 ? 0.791 12.485 16.034 1.00 62.12 ? ? ? ? ? ? 668 C R N3 1 67
+ATOM 2149 C C4 . C B 2 67 ? 1.107 13.479 15.202 1.00 62.02 ? ? ? ? ? ? 668 C R C4 1 67
+ATOM 2150 N N4 . C B 2 67 ? 0.172 13.870 14.334 1.00 62.50 ? ? ? ? ? ? 668 C R N4 1 67
+ATOM 2151 C C5 . C B 2 67 ? 2.388 14.112 15.228 1.00 62.03 ? ? ? ? ? ? 668 C R C5 1 67
+ATOM 2152 C C6 . C B 2 67 ? 3.275 13.667 16.128 1.00 63.06 ? ? ? ? ? ? 668 C R C6 1 67
+ATOM 2153 P P . C B 2 68 ? 7.486 10.354 15.260 1.00 69.21 ? ? ? ? ? ? 669 C R P 1 68
+ATOM 2154 O OP1 . C B 2 68 ? 8.826 9.722 15.288 1.00 68.32 ? ? ? ? ? ? 669 C R OP1 1 68
+ATOM 2155 O OP2 . C B 2 68 ? 7.223 11.455 14.306 1.00 69.12 ? ? ? ? ? ? 669 C R OP2 1 68
+ATOM 2156 O "O5'" . C B 2 68 ? 6.369 9.235 15.009 1.00 66.96 ? ? ? ? ? ? 669 C R "O5'" 1 68
+ATOM 2157 C "C5'" . C B 2 68 ? 6.613 7.904 15.433 1.00 64.72 ? ? ? ? ? ? 669 C R "C5'" 1 68
+ATOM 2158 C "C4'" . C B 2 68 ? 5.330 7.149 15.717 1.00 63.48 ? ? ? ? ? ? 669 C R "C4'" 1 68
+ATOM 2159 O "O4'" . C B 2 68 ? 4.246 8.043 16.088 1.00 60.36 ? ? ? ? ? ? 669 C R "O4'" 1 68
+ATOM 2160 C "C3'" . C B 2 68 ? 4.746 6.406 14.528 1.00 63.85 ? ? ? ? ? ? 669 C R "C3'" 1 68
+ATOM 2161 O "O3'" . C B 2 68 ? 5.491 5.232 14.211 1.00 67.88 ? ? ? ? ? ? 669 C R "O3'" 1 68
+ATOM 2162 C "C2'" . C B 2 68 ? 3.356 6.105 15.079 1.00 60.09 ? ? ? ? ? ? 669 C R "C2'" 1 68
+ATOM 2163 O "O2'" . C B 2 68 ? 3.341 5.084 16.057 1.00 58.08 ? ? ? ? ? ? 669 C R "O2'" 1 68
+ATOM 2164 C "C1'" . C B 2 68 ? 3.010 7.453 15.707 1.00 57.11 ? ? ? ? ? ? 669 C R "C1'" 1 68
+ATOM 2165 N N1 . C B 2 68 ? 2.258 8.377 14.780 1.00 52.27 ? ? ? ? ? ? 669 C R N1 1 68
+ATOM 2166 C C2 . C B 2 68 ? 0.984 8.026 14.278 1.00 49.00 ? ? ? ? ? ? 669 C R C2 1 68
+ATOM 2167 O O2 . C B 2 68 ? 0.453 6.951 14.589 1.00 45.59 ? ? ? ? ? ? 669 C R O2 1 68
+ATOM 2168 N N3 . C B 2 68 ? 0.346 8.892 13.450 1.00 47.56 ? ? ? ? ? ? 669 C R N3 1 68
+ATOM 2169 C C4 . C B 2 68 ? 0.919 10.053 13.114 1.00 48.78 ? ? ? ? ? ? 669 C R C4 1 68
+ATOM 2170 N N4 . C B 2 68 ? 0.250 10.868 12.293 1.00 47.03 ? ? ? ? ? ? 669 C R N4 1 68
+ATOM 2171 C C5 . C B 2 68 ? 2.208 10.431 13.607 1.00 49.92 ? ? ? ? ? ? 669 C R C5 1 68
+ATOM 2172 C C6 . C B 2 68 ? 2.830 9.572 14.427 1.00 51.00 ? ? ? ? ? ? 669 C R C6 1 68
+ATOM 2173 P P . G B 2 69 ? 5.428 4.614 12.732 1.00 71.37 ? ? ? ? ? ? 75 G R P 1 69
+ATOM 2174 O OP1 . G B 2 69 ? 6.788 4.138 12.394 1.00 72.21 ? ? ? ? ? ? 75 G R OP1 1 69
+ATOM 2175 O OP2 . G B 2 69 ? 4.747 5.579 11.833 1.00 71.60 ? ? ? ? ? ? 75 G R OP2 1 69
+ATOM 2176 O "O5'" . G B 2 69 ? 4.492 3.328 12.921 1.00 71.76 ? ? ? ? ? ? 75 G R "O5'" 1 69
+ATOM 2177 C "C5'" . G B 2 69 ? 3.070 3.402 12.818 1.00 72.39 ? ? ? ? ? ? 75 G R "C5'" 1 69
+ATOM 2178 C "C4'" . G B 2 69 ? 2.505 2.198 12.085 1.00 72.32 ? ? ? ? ? ? 75 G R "C4'" 1 69
+ATOM 2179 O "O4'" . G B 2 69 ? 2.928 2.238 10.698 1.00 71.55 ? ? ? ? ? ? 75 G R "O4'" 1 69
+ATOM 2180 C "C3'" . G B 2 69 ? 2.982 0.829 12.554 1.00 72.22 ? ? ? ? ? ? 75 G R "C3'" 1 69
+ATOM 2181 O "O3'" . G B 2 69 ? 2.330 0.386 13.738 1.00 72.50 ? ? ? ? ? ? 75 G R "O3'" 1 69
+ATOM 2182 C "C2'" . G B 2 69 ? 2.611 -0.005 11.334 1.00 72.20 ? ? ? ? ? ? 75 G R "C2'" 1 69
+ATOM 2183 O "O2'" . G B 2 69 ? 1.225 -0.263 11.227 1.00 72.60 ? ? ? ? ? ? 75 G R "O2'" 1 69
+ATOM 2184 C "C1'" . G B 2 69 ? 3.106 0.916 10.224 1.00 71.83 ? ? ? ? ? ? 75 G R "C1'" 1 69
+ATOM 2185 N N9 . G B 2 69 ? 4.518 0.655 9.939 1.00 72.58 ? ? ? ? ? ? 75 G R N9 1 69
+ATOM 2186 C C8 . G B 2 69 ? 5.625 1.352 10.376 1.00 72.56 ? ? ? ? ? ? 75 G R C8 1 69
+ATOM 2187 N N7 . G B 2 69 ? 6.757 0.851 9.962 1.00 71.87 ? ? ? ? ? ? 75 G R N7 1 69
+ATOM 2188 C C5 . G B 2 69 ? 6.383 -0.253 9.205 1.00 72.03 ? ? ? ? ? ? 75 G R C5 1 69
+ATOM 2189 C C6 . G B 2 69 ? 7.173 -1.195 8.496 1.00 71.88 ? ? ? ? ? ? 75 G R C6 1 69
+ATOM 2190 O O6 . G B 2 69 ? 8.407 -1.233 8.396 1.00 71.72 ? ? ? ? ? ? 75 G R O6 1 69
+ATOM 2191 N N1 . G B 2 69 ? 6.391 -2.165 7.858 1.00 71.90 ? ? ? ? ? ? 75 G R N1 1 69
+ATOM 2192 C C2 . G B 2 69 ? 5.013 -2.213 7.903 1.00 71.17 ? ? ? ? ? ? 75 G R C2 1 69
+ATOM 2193 N N2 . G B 2 69 ? 4.417 -3.209 7.237 1.00 70.27 ? ? ? ? ? ? 75 G R N2 1 69
+ATOM 2194 N N3 . G B 2 69 ? 4.263 -1.338 8.562 1.00 71.45 ? ? ? ? ? ? 75 G R N3 1 69
+ATOM 2195 C C4 . G B 2 69 ? 5.009 -0.388 9.186 1.00 72.30 ? ? ? ? ? ? 75 G R C4 1 69
+ATOM 2196 P P . G B 2 70 ? 3.082 -0.613 14.742 1.00 72.31 ? ? ? ? ? ? 76 G R P 1 70
+ATOM 2197 O OP1 . G B 2 70 ? 2.235 -0.759 15.946 1.00 73.30 ? ? ? ? ? ? 76 G R OP1 1 70
+ATOM 2198 O OP2 . G B 2 70 ? 4.484 -0.167 14.903 1.00 72.40 ? ? ? ? ? ? 76 G R OP2 1 70
+ATOM 2199 O "O5'" . G B 2 70 ? 3.086 -1.999 13.940 1.00 72.44 ? ? ? ? ? ? 76 G R "O5'" 1 70
+ATOM 2200 C "C5'" . G B 2 70 ? 1.869 -2.705 13.702 1.00 72.32 ? ? ? ? ? ? 76 G R "C5'" 1 70
+ATOM 2201 C "C4'" . G B 2 70 ? 2.065 -3.816 12.686 1.00 72.84 ? ? ? ? ? ? 76 G R "C4'" 1 70
+ATOM 2202 O "O4'" . G B 2 70 ? 2.761 -3.308 11.519 1.00 73.09 ? ? ? ? ? ? 76 G R "O4'" 1 70
+ATOM 2203 C "C3'" . G B 2 70 ? 2.928 -4.972 13.162 1.00 73.20 ? ? ? ? ? ? 76 G R "C3'" 1 70
+ATOM 2204 O "O3'" . G B 2 70 ? 2.147 -5.923 13.861 1.00 73.40 ? ? ? ? ? ? 76 G R "O3'" 1 70
+ATOM 2205 C "C2'" . G B 2 70 ? 3.451 -5.545 11.852 1.00 73.38 ? ? ? ? ? ? 76 G R "C2'" 1 70
+ATOM 2206 O "O2'" . G B 2 70 ? 2.519 -6.398 11.214 1.00 75.40 ? ? ? ? ? ? 76 G R "O2'" 1 70
+ATOM 2207 C "C1'" . G B 2 70 ? 3.679 -4.275 11.037 1.00 72.95 ? ? ? ? ? ? 76 G R "C1'" 1 70
+ATOM 2208 N N9 . G B 2 70 ? 5.049 -3.756 11.134 1.00 71.95 ? ? ? ? ? ? 76 G R N9 1 70
+ATOM 2209 C C8 . G B 2 70 ? 5.462 -2.595 11.746 1.00 71.23 ? ? ? ? ? ? 76 G R C8 1 70
+ATOM 2210 N N7 . G B 2 70 ? 6.748 -2.390 11.673 1.00 70.22 ? ? ? ? ? ? 76 G R N7 1 70
+ATOM 2211 C C5 . G B 2 70 ? 7.225 -3.485 10.968 1.00 70.28 ? ? ? ? ? ? 76 G R C5 1 70
+ATOM 2212 C C6 . G B 2 70 ? 8.546 -3.814 10.576 1.00 70.42 ? ? ? ? ? ? 76 G R C6 1 70
+ATOM 2213 O O6 . G B 2 70 ? 9.585 -3.174 10.791 1.00 70.51 ? ? ? ? ? ? 76 G R O6 1 70
+ATOM 2214 N N1 . G B 2 70 ? 8.602 -5.016 9.868 1.00 70.17 ? ? ? ? ? ? 76 G R N1 1 70
+ATOM 2215 C C2 . G B 2 70 ? 7.511 -5.803 9.576 1.00 70.03 ? ? ? ? ? ? 76 G R C2 1 70
+ATOM 2216 N N2 . G B 2 70 ? 7.746 -6.927 8.885 1.00 69.97 ? ? ? ? ? ? 76 G R N2 1 70
+ATOM 2217 N N3 . G B 2 70 ? 6.268 -5.503 9.934 1.00 70.63 ? ? ? ? ? ? 76 G R N3 1 70
+ATOM 2218 C C4 . G B 2 70 ? 6.194 -4.335 10.626 1.00 71.07 ? ? ? ? ? ? 76 G R C4 1 70
+ATOM 2219 P P . U B 2 71 ? 2.713 -6.599 15.196 1.00 74.13 ? ? ? ? ? ? 77 U R P 1 71
+ATOM 2220 O OP1 . U B 2 71 ? 1.720 -7.616 15.612 1.00 74.26 ? ? ? ? ? ? 77 U R OP1 1 71
+ATOM 2221 O OP2 . U B 2 71 ? 3.118 -5.526 16.135 1.00 72.60 ? ? ? ? ? ? 77 U R OP2 1 71
+ATOM 2222 O "O5'" . U B 2 71 ? 4.050 -7.336 14.719 1.00 73.80 ? ? ? ? ? ? 77 U R "O5'" 1 71
+ATOM 2223 C "C5'" . U B 2 71 ? 4.029 -8.495 13.889 1.00 74.24 ? ? ? ? ? ? 77 U R "C5'" 1 71
+ATOM 2224 C "C4'" . U B 2 71 ? 5.443 -8.860 13.476 1.00 74.39 ? ? ? ? ? ? 77 U R "C4'" 1 71
+ATOM 2225 O "O4'" . U B 2 71 ? 5.985 -7.832 12.601 1.00 74.84 ? ? ? ? ? ? 77 U R "O4'" 1 71
+ATOM 2226 C "C3'" . U B 2 71 ? 6.454 -8.899 14.615 1.00 73.90 ? ? ? ? ? ? 77 U R "C3'" 1 71
+ATOM 2227 O "O3'" . U B 2 71 ? 6.376 -10.083 15.398 1.00 71.11 ? ? ? ? ? ? 77 U R "O3'" 1 71
+ATOM 2228 C "C2'" . U B 2 71 ? 7.757 -8.737 13.847 1.00 74.30 ? ? ? ? ? ? 77 U R "C2'" 1 71
+ATOM 2229 O "O2'" . U B 2 71 ? 8.099 -9.890 13.101 1.00 75.85 ? ? ? ? ? ? 77 U R "O2'" 1 71
+ATOM 2230 C "C1'" . U B 2 71 ? 7.346 -7.585 12.932 1.00 74.63 ? ? ? ? ? ? 77 U R "C1'" 1 71
+ATOM 2231 N N1 . U B 2 71 ? 7.492 -6.216 13.569 1.00 74.85 ? ? ? ? ? ? 77 U R N1 1 71
+ATOM 2232 C C2 . U B 2 71 ? 8.744 -5.634 13.714 1.00 75.56 ? ? ? ? ? ? 77 U R C2 1 71
+ATOM 2233 O O2 . U B 2 71 ? 9.786 -6.155 13.350 1.00 76.56 ? ? ? ? ? ? 77 U R O2 1 71
+ATOM 2234 N N3 . U B 2 71 ? 8.741 -4.392 14.310 1.00 75.42 ? ? ? ? ? ? 77 U R N3 1 71
+ATOM 2235 C C4 . U B 2 71 ? 7.641 -3.683 14.767 1.00 75.70 ? ? ? ? ? ? 77 U R C4 1 71
+ATOM 2236 O O4 . U B 2 71 ? 7.785 -2.579 15.280 1.00 76.39 ? ? ? ? ? ? 77 U R O4 1 71
+ATOM 2237 C C5 . U B 2 71 ? 6.377 -4.345 14.587 1.00 75.87 ? ? ? ? ? ? 77 U R C5 1 71
+ATOM 2238 C C6 . U B 2 71 ? 6.362 -5.550 14.008 1.00 75.21 ? ? ? ? ? ? 77 U R C6 1 71
+ATOM 2239 P P . A B 2 72 ? 6.322 -9.915 16.991 1.00 69.61 ? ? ? ? ? ? 78 A R P 1 72
+ATOM 2240 O OP1 . A B 2 72 ? 5.846 -11.191 17.566 1.00 69.08 ? ? ? ? ? ? 78 A R OP1 1 72
+ATOM 2241 O OP2 . A B 2 72 ? 5.613 -8.654 17.309 1.00 69.17 ? ? ? ? ? ? 78 A R OP2 1 72
+ATOM 2242 O "O5'" . A B 2 72 ? 7.855 -9.693 17.386 1.00 68.19 ? ? ? ? ? ? 78 A R "O5'" 1 72
+ATOM 2243 C "C5'" . A B 2 72 ? 8.850 -10.615 16.967 1.00 66.24 ? ? ? ? ? ? 78 A R "C5'" 1 72
+ATOM 2244 C "C4'" . A B 2 72 ? 10.207 -9.942 16.934 1.00 65.11 ? ? ? ? ? ? 78 A R "C4'" 1 72
+ATOM 2245 O "O4'" . A B 2 72 ? 10.159 -8.722 16.153 1.00 64.17 ? ? ? ? ? ? 78 A R "O4'" 1 72
+ATOM 2246 C "C3'" . A B 2 72 ? 10.704 -9.449 18.280 1.00 64.46 ? ? ? ? ? ? 78 A R "C3'" 1 72
+ATOM 2247 O "O3'" . A B 2 72 ? 11.184 -10.521 19.070 1.00 64.45 ? ? ? ? ? ? 78 A R "O3'" 1 72
+ATOM 2248 C "C2'" . A B 2 72 ? 11.810 -8.498 17.843 1.00 63.71 ? ? ? ? ? ? 78 A R "C2'" 1 72
+ATOM 2249 O "O2'" . A B 2 72 ? 12.999 -9.159 17.453 1.00 63.20 ? ? ? ? ? ? 78 A R "O2'" 1 72
+ATOM 2250 C "C1'" . A B 2 72 ? 11.138 -7.822 16.649 1.00 62.80 ? ? ? ? ? ? 78 A R "C1'" 1 72
+ATOM 2251 N N9 . A B 2 72 ? 10.505 -6.551 17.007 1.00 60.44 ? ? ? ? ? ? 78 A R N9 1 72
+ATOM 2252 C C8 . A B 2 72 ? 9.168 -6.291 17.131 1.00 59.67 ? ? ? ? ? ? 78 A R C8 1 72
+ATOM 2253 N N7 . A B 2 72 ? 8.897 -5.051 17.467 1.00 59.06 ? ? ? ? ? ? 78 A R N7 1 72
+ATOM 2254 C C5 . A B 2 72 ? 10.143 -4.454 17.575 1.00 58.42 ? ? ? ? ? ? 78 A R C5 1 72
+ATOM 2255 C C6 . A B 2 72 ? 10.556 -3.141 17.903 1.00 58.02 ? ? ? ? ? ? 78 A R C6 1 72
+ATOM 2256 N N6 . A B 2 72 ? 9.707 -2.150 18.199 1.00 56.38 ? ? ? ? ? ? 78 A R N6 1 72
+ATOM 2257 N N1 . A B 2 72 ? 11.886 -2.880 17.918 1.00 57.36 ? ? ? ? ? ? 78 A R N1 1 72
+ATOM 2258 C C2 . A B 2 72 ? 12.747 -3.865 17.624 1.00 57.20 ? ? ? ? ? ? 78 A R C2 1 72
+ATOM 2259 N N3 . A B 2 72 ? 12.476 -5.133 17.303 1.00 58.27 ? ? ? ? ? ? 78 A R N3 1 72
+ATOM 2260 C C4 . A B 2 72 ? 11.148 -5.366 17.296 1.00 58.98 ? ? ? ? ? ? 78 A R C4 1 72
+ATOM 2261 P P . G B 2 73 ? 10.928 -10.493 20.649 1.00 65.14 ? ? ? ? ? ? 79 G R P 1 73
+ATOM 2262 O OP1 . G B 2 73 ? 11.299 -11.829 21.174 1.00 63.61 ? ? ? ? ? ? 79 G R OP1 1 73
+ATOM 2263 O OP2 . G B 2 73 ? 9.574 -9.943 20.912 1.00 63.23 ? ? ? ? ? ? 79 G R OP2 1 73
+ATOM 2264 O "O5'" . G B 2 73 ? 11.984 -9.399 21.147 1.00 61.88 ? ? ? ? ? ? 79 G R "O5'" 1 73
+ATOM 2265 C "C5'" . G B 2 73 ? 13.378 -9.639 21.031 1.00 59.30 ? ? ? ? ? ? 79 G R "C5'" 1 73
+ATOM 2266 C "C4'" . G B 2 73 ? 14.145 -8.353 21.257 1.00 58.01 ? ? ? ? ? ? 79 G R "C4'" 1 73
+ATOM 2267 O "O4'" . G B 2 73 ? 13.671 -7.323 20.355 1.00 57.31 ? ? ? ? ? ? 79 G R "O4'" 1 73
+ATOM 2268 C "C3'" . G B 2 73 ? 13.951 -7.693 22.613 1.00 57.77 ? ? ? ? ? ? 79 G R "C3'" 1 73
+ATOM 2269 O "O3'" . G B 2 73 ? 14.661 -8.372 23.647 1.00 57.89 ? ? ? ? ? ? 79 G R "O3'" 1 73
+ATOM 2270 C "C2'" . G B 2 73 ? 14.536 -6.321 22.310 1.00 56.72 ? ? ? ? ? ? 79 G R "C2'" 1 73
+ATOM 2271 O "O2'" . G B 2 73 ? 15.951 -6.333 22.264 1.00 57.00 ? ? ? ? ? ? 79 G R "O2'" 1 73
+ATOM 2272 C "C1'" . G B 2 73 ? 13.938 -6.053 20.929 1.00 54.88 ? ? ? ? ? ? 79 G R "C1'" 1 73
+ATOM 2273 N N9 . G B 2 73 ? 12.706 -5.265 20.993 1.00 51.28 ? ? ? ? ? ? 79 G R N9 1 73
+ATOM 2274 C C8 . G B 2 73 ? 11.420 -5.707 20.779 1.00 50.97 ? ? ? ? ? ? 79 G R C8 1 73
+ATOM 2275 N N7 . G B 2 73 ? 10.516 -4.773 20.915 1.00 49.98 ? ? ? ? ? ? 79 G R N7 1 73
+ATOM 2276 C C5 . G B 2 73 ? 11.247 -3.637 21.242 1.00 50.08 ? ? ? ? ? ? 79 G R C5 1 73
+ATOM 2277 C C6 . G B 2 73 ? 10.812 -2.310 21.505 1.00 50.67 ? ? ? ? ? ? 79 G R C6 1 73
+ATOM 2278 O O6 . G B 2 73 ? 9.651 -1.872 21.503 1.00 52.38 ? ? ? ? ? ? 79 G R O6 1 73
+ATOM 2279 N N1 . G B 2 73 ? 11.877 -1.454 21.798 1.00 49.44 ? ? ? ? ? ? 79 G R N1 1 73
+ATOM 2280 C C2 . G B 2 73 ? 13.203 -1.836 21.830 1.00 50.00 ? ? ? ? ? ? 79 G R C2 1 73
+ATOM 2281 N N2 . G B 2 73 ? 14.100 -0.881 22.130 1.00 49.13 ? ? ? ? ? ? 79 G R N2 1 73
+ATOM 2282 N N3 . G B 2 73 ? 13.620 -3.077 21.581 1.00 49.07 ? ? ? ? ? ? 79 G R N3 1 73
+ATOM 2283 C C4 . G B 2 73 ? 12.596 -3.924 21.295 1.00 49.80 ? ? ? ? ? ? 79 G R C4 1 73
+ATOM 2284 P P . G B 2 74 ? 14.122 -8.350 25.160 1.00 57.66 ? ? ? ? ? ? 80 G R P 1 74
+ATOM 2285 O OP1 . G B 2 74 ? 15.098 -9.124 25.964 1.00 57.33 ? ? ? ? ? ? 80 G R OP1 1 74
+ATOM 2286 O OP2 . G B 2 74 ? 12.693 -8.743 25.173 1.00 55.14 ? ? ? ? ? ? 80 G R OP2 1 74
+ATOM 2287 O "O5'" . G B 2 74 ? 14.209 -6.800 25.553 1.00 53.80 ? ? ? ? ? ? 80 G R "O5'" 1 74
+ATOM 2288 C "C5'" . G B 2 74 ? 15.475 -6.243 25.869 1.00 52.46 ? ? ? ? ? ? 80 G R "C5'" 1 74
+ATOM 2289 C "C4'" . G B 2 74 ? 15.433 -4.729 25.957 1.00 51.00 ? ? ? ? ? ? 80 G R "C4'" 1 74
+ATOM 2290 O "O4'" . G B 2 74 ? 14.604 -4.164 24.918 1.00 49.65 ? ? ? ? ? ? 80 G R "O4'" 1 74
+ATOM 2291 C "C3'" . G B 2 74 ? 14.770 -4.162 27.194 1.00 51.14 ? ? ? ? ? ? 80 G R "C3'" 1 74
+ATOM 2292 O "O3'" . G B 2 74 ? 15.575 -4.364 28.347 1.00 52.84 ? ? ? ? ? ? 80 G R "O3'" 1 74
+ATOM 2293 C "C2'" . G B 2 74 ? 14.648 -2.702 26.774 1.00 49.46 ? ? ? ? ? ? 80 G R "C2'" 1 74
+ATOM 2294 O "O2'" . G B 2 74 ? 15.872 -1.998 26.843 1.00 48.81 ? ? ? ? ? ? 80 G R "O2'" 1 74
+ATOM 2295 C "C1'" . G B 2 74 ? 14.205 -2.866 25.319 1.00 47.58 ? ? ? ? ? ? 80 G R "C1'" 1 74
+ATOM 2296 N N9 . G B 2 74 ? 12.761 -2.739 25.118 1.00 45.43 ? ? ? ? ? ? 80 G R N9 1 74
+ATOM 2297 C C8 . G B 2 74 ? 11.886 -3.721 24.714 1.00 43.16 ? ? ? ? ? ? 80 G R C8 1 74
+ATOM 2298 N N7 . G B 2 74 ? 10.650 -3.313 24.622 1.00 43.61 ? ? ? ? ? ? 80 G R N7 1 74
+ATOM 2299 C C5 . G B 2 74 ? 10.705 -1.975 24.988 1.00 42.89 ? ? ? ? ? ? 80 G R C5 1 74
+ATOM 2300 C C6 . G B 2 74 ? 9.674 -1.014 25.075 1.00 42.76 ? ? ? ? ? ? 80 G R C6 1 74
+ATOM 2301 O O6 . G B 2 74 ? 8.469 -1.184 24.835 1.00 45.44 ? ? ? ? ? ? 80 G R O6 1 74
+ATOM 2302 N N1 . G B 2 74 ? 10.150 0.236 25.489 1.00 41.49 ? ? ? ? ? ? 80 G R N1 1 74
+ATOM 2303 C C2 . G B 2 74 ? 11.471 0.513 25.778 1.00 41.84 ? ? ? ? ? ? 80 G R C2 1 74
+ATOM 2304 N N2 . G B 2 74 ? 11.772 1.764 26.155 1.00 39.89 ? ? ? ? ? ? 80 G R N2 1 74
+ATOM 2305 N N3 . G B 2 74 ? 12.447 -0.381 25.694 1.00 43.10 ? ? ? ? ? ? 80 G R N3 1 74
+ATOM 2306 C C4 . G B 2 74 ? 11.996 -1.602 25.296 1.00 44.40 ? ? ? ? ? ? 80 G R C4 1 74
+ATOM 2307 P P . U B 2 75 ? 14.858 -4.790 29.716 1.00 52.40 ? ? ? ? ? ? 81 U R P 1 75
+ATOM 2308 O OP1 . U B 2 75 ? 15.889 -5.311 30.644 1.00 51.65 ? ? ? ? ? ? 81 U R OP1 1 75
+ATOM 2309 O OP2 . U B 2 75 ? 13.689 -5.635 29.391 1.00 50.77 ? ? ? ? ? ? 81 U R OP2 1 75
+ATOM 2310 O "O5'" . U B 2 75 ? 14.320 -3.375 30.238 1.00 51.33 ? ? ? ? ? ? 81 U R "O5'" 1 75
+ATOM 2311 C "C5'" . U B 2 75 ? 15.231 -2.303 30.495 1.00 50.78 ? ? ? ? ? ? 81 U R "C5'" 1 75
+ATOM 2312 C "C4'" . U B 2 75 ? 14.473 -1.002 30.666 1.00 49.83 ? ? ? ? ? ? 81 U R "C4'" 1 75
+ATOM 2313 O "O4'" . U B 2 75 ? 13.684 -0.746 29.482 1.00 50.87 ? ? ? ? ? ? 81 U R "O4'" 1 75
+ATOM 2314 C "C3'" . U B 2 75 ? 13.426 -1.036 31.764 1.00 50.10 ? ? ? ? ? ? 81 U R "C3'" 1 75
+ATOM 2315 O "O3'" . U B 2 75 ? 14.033 -0.837 33.036 1.00 49.50 ? ? ? ? ? ? 81 U R "O3'" 1 75
+ATOM 2316 C "C2'" . U B 2 75 ? 12.480 0.091 31.351 1.00 49.41 ? ? ? ? ? ? 81 U R "C2'" 1 75
+ATOM 2317 O "O2'" . U B 2 75 ? 12.910 1.380 31.745 1.00 50.56 ? ? ? ? ? ? 81 U R "O2'" 1 75
+ATOM 2318 C "C1'" . U B 2 75 ? 12.508 -0.031 29.829 1.00 48.83 ? ? ? ? ? ? 81 U R "C1'" 1 75
+ATOM 2319 N N1 . U B 2 75 ? 11.300 -0.724 29.270 1.00 47.38 ? ? ? ? ? ? 81 U R N1 1 75
+ATOM 2320 C C2 . U B 2 75 ? 10.152 0.012 29.036 1.00 46.82 ? ? ? ? ? ? 81 U R C2 1 75
+ATOM 2321 O O2 . U B 2 75 ? 10.065 1.211 29.258 1.00 47.68 ? ? ? ? ? ? 81 U R O2 1 75
+ATOM 2322 N N3 . U B 2 75 ? 9.097 -0.711 28.527 1.00 44.94 ? ? ? ? ? ? 81 U R N3 1 75
+ATOM 2323 C C4 . U B 2 75 ? 9.079 -2.065 28.232 1.00 46.49 ? ? ? ? ? ? 81 U R C4 1 75
+ATOM 2324 O O4 . U B 2 75 ? 8.064 -2.577 27.774 1.00 48.37 ? ? ? ? ? ? 81 U R O4 1 75
+ATOM 2325 C C5 . U B 2 75 ? 10.309 -2.767 28.497 1.00 46.21 ? ? ? ? ? ? 81 U R C5 1 75
+ATOM 2326 C C6 . U B 2 75 ? 11.346 -2.082 28.998 1.00 47.52 ? ? ? ? ? ? 81 U R C6 1 75
+ATOM 2327 P P . A B 2 76 ? 13.798 -1.911 34.202 1.00 48.15 ? ? ? ? ? ? 82 A R P 1 76
+ATOM 2328 O OP1 . A B 2 76 ? 14.290 -1.283 35.451 1.00 46.89 ? ? ? ? ? ? 82 A R OP1 1 76
+ATOM 2329 O OP2 . A B 2 76 ? 14.356 -3.215 33.771 1.00 46.66 ? ? ? ? ? ? 82 A R OP2 1 76
+ATOM 2330 O "O5'" . A B 2 76 ? 12.207 -2.069 34.249 1.00 44.82 ? ? ? ? ? ? 82 A R "O5'" 1 76
+ATOM 2331 C "C5'" . A B 2 76 ? 11.417 -1.053 34.843 1.00 45.70 ? ? ? ? ? ? 82 A R "C5'" 1 76
+ATOM 2332 C "C4'" . A B 2 76 ? 10.370 -1.627 35.781 1.00 45.95 ? ? ? ? ? ? 82 A R "C4'" 1 76
+ATOM 2333 O "O4'" . A B 2 76 ? 9.539 -2.570 35.053 1.00 45.43 ? ? ? ? ? ? 82 A R "O4'" 1 76
+ATOM 2334 C "C3'" . A B 2 76 ? 10.920 -2.369 36.999 1.00 45.36 ? ? ? ? ? ? 82 A R "C3'" 1 76
+ATOM 2335 O "O3'" . A B 2 76 ? 10.210 -1.979 38.189 1.00 45.87 ? ? ? ? ? ? 82 A R "O3'" 1 76
+ATOM 2336 C "C2'" . A B 2 76 ? 10.697 -3.831 36.622 1.00 45.35 ? ? ? ? ? ? 82 A R "C2'" 1 76
+ATOM 2337 O "O2'" . A B 2 76 ? 10.535 -4.688 37.734 1.00 47.91 ? ? ? ? ? ? 82 A R "O2'" 1 76
+ATOM 2338 C "C1'" . A B 2 76 ? 9.389 -3.719 35.851 1.00 44.92 ? ? ? ? ? ? 82 A R "C1'" 1 76
+ATOM 2339 N N9 . A B 2 76 ? 9.070 -4.873 35.015 1.00 44.59 ? ? ? ? ? ? 82 A R N9 1 76
+ATOM 2340 C C8 . A B 2 76 ? 9.914 -5.869 34.606 1.00 45.57 ? ? ? ? ? ? 82 A R C8 1 76
+ATOM 2341 N N7 . A B 2 76 ? 9.336 -6.785 33.866 1.00 45.95 ? ? ? ? ? ? 82 A R N7 1 76
+ATOM 2342 C C5 . A B 2 76 ? 8.023 -6.360 33.781 1.00 44.58 ? ? ? ? ? ? 82 A R C5 1 76
+ATOM 2343 C C6 . A B 2 76 ? 6.889 -6.894 33.136 1.00 45.34 ? ? ? ? ? ? 82 A R C6 1 76
+ATOM 2344 N N6 . A B 2 76 ? 6.917 -8.024 32.422 1.00 47.42 ? ? ? ? ? ? 82 A R N6 1 76
+ATOM 2345 N N1 . A B 2 76 ? 5.720 -6.226 33.250 1.00 45.56 ? ? ? ? ? ? 82 A R N1 1 76
+ATOM 2346 C C2 . A B 2 76 ? 5.693 -5.094 33.966 1.00 45.89 ? ? ? ? ? ? 82 A R C2 1 76
+ATOM 2347 N N3 . A B 2 76 ? 6.694 -4.495 34.617 1.00 45.59 ? ? ? ? ? ? 82 A R N3 1 76
+ATOM 2348 C C4 . A B 2 76 ? 7.841 -5.185 34.486 1.00 44.73 ? ? ? ? ? ? 82 A R C4 1 76
+ATOM 2349 P P . G B 2 77 ? 11.017 -1.506 39.497 1.00 47.83 ? ? ? ? ? ? 83 G R P 1 77
+ATOM 2350 O OP1 . G B 2 77 ? 12.163 -2.423 39.702 1.00 45.31 ? ? ? ? ? ? 83 G R OP1 1 77
+ATOM 2351 O OP2 . G B 2 77 ? 10.038 -1.282 40.585 1.00 49.31 ? ? ? ? ? ? 83 G R OP2 1 77
+ATOM 2352 O "O5'" . G B 2 77 ? 11.600 -0.072 39.095 1.00 47.50 ? ? ? ? ? ? 83 G R "O5'" 1 77
+ATOM 2353 C "C5'" . G B 2 77 ? 10.743 1.025 38.770 1.00 45.06 ? ? ? ? ? ? 83 G R "C5'" 1 77
+ATOM 2354 C "C4'" . G B 2 77 ? 11.569 2.199 38.272 1.00 43.12 ? ? ? ? ? ? 83 G R "C4'" 1 77
+ATOM 2355 O "O4'" . G B 2 77 ? 12.687 2.441 39.163 1.00 41.40 ? ? ? ? ? ? 83 G R "O4'" 1 77
+ATOM 2356 C "C3'" . G B 2 77 ? 12.210 2.012 36.903 1.00 43.72 ? ? ? ? ? ? 83 G R "C3'" 1 77
+ATOM 2357 O "O3'" . G B 2 77 ? 12.215 3.265 36.248 1.00 47.09 ? ? ? ? ? ? 83 G R "O3'" 1 77
+ATOM 2358 C "C2'" . G B 2 77 ? 13.628 1.572 37.237 1.00 39.54 ? ? ? ? ? ? 83 G R "C2'" 1 77
+ATOM 2359 O "O2'" . G B 2 77 ? 14.543 1.853 36.205 1.00 40.86 ? ? ? ? ? ? 83 G R "O2'" 1 77
+ATOM 2360 C "C1'" . G B 2 77 ? 13.876 2.504 38.408 1.00 38.06 ? ? ? ? ? ? 83 G R "C1'" 1 77
+ATOM 2361 N N9 . G B 2 77 ? 14.986 2.146 39.276 1.00 34.85 ? ? ? ? ? ? 83 G R N9 1 77
+ATOM 2362 C C8 . G B 2 77 ? 15.352 0.889 39.689 1.00 34.47 ? ? ? ? ? ? 83 G R C8 1 77
+ATOM 2363 N N7 . G B 2 77 ? 16.395 0.886 40.469 1.00 33.72 ? ? ? ? ? ? 83 G R N7 1 77
+ATOM 2364 C C5 . G B 2 77 ? 16.739 2.227 40.581 1.00 32.97 ? ? ? ? ? ? 83 G R C5 1 77
+ATOM 2365 C C6 . G B 2 77 ? 17.790 2.841 41.305 1.00 32.85 ? ? ? ? ? ? 83 G R C6 1 77
+ATOM 2366 O O6 . G B 2 77 ? 18.644 2.303 42.017 1.00 36.28 ? ? ? ? ? ? 83 G R O6 1 77
+ATOM 2367 N N1 . G B 2 77 ? 17.800 4.226 41.161 1.00 32.89 ? ? ? ? ? ? 83 G R N1 1 77
+ATOM 2368 C C2 . G B 2 77 ? 16.893 4.933 40.407 1.00 34.15 ? ? ? ? ? ? 83 G R C2 1 77
+ATOM 2369 N N2 . G B 2 77 ? 17.070 6.262 40.398 1.00 34.45 ? ? ? ? ? ? 83 G R N2 1 77
+ATOM 2370 N N3 . G B 2 77 ? 15.895 4.374 39.719 1.00 32.54 ? ? ? ? ? ? 83 G R N3 1 77
+ATOM 2371 C C4 . G B 2 77 ? 15.879 3.019 39.853 1.00 33.39 ? ? ? ? ? ? 83 G R C4 1 77
+ATOM 2372 P P . C B 2 78 ? 11.886 3.373 34.693 1.00 49.46 ? ? ? ? ? ? 84 C R P 1 78
+ATOM 2373 O OP1 . C B 2 78 ? 11.613 2.030 34.141 1.00 48.44 ? ? ? ? ? ? 84 C R OP1 1 78
+ATOM 2374 O OP2 . C B 2 78 ? 12.962 4.192 34.093 1.00 51.80 ? ? ? ? ? ? 84 C R OP2 1 78
+ATOM 2375 O "O5'" . C B 2 78 ? 10.514 4.194 34.693 1.00 51.45 ? ? ? ? ? ? 84 C R "O5'" 1 78
+ATOM 2376 C "C5'" . C B 2 78 ? 10.439 5.554 35.117 1.00 54.65 ? ? ? ? ? ? 84 C R "C5'" 1 78
+ATOM 2377 C "C4'" . C B 2 78 ? 9.043 6.096 34.857 1.00 57.66 ? ? ? ? ? ? 84 C R "C4'" 1 78
+ATOM 2378 O "O4'" . C B 2 78 ? 8.734 5.975 33.441 1.00 58.13 ? ? ? ? ? ? 84 C R "O4'" 1 78
+ATOM 2379 C "C3'" . C B 2 78 ? 7.903 5.325 35.513 1.00 60.05 ? ? ? ? ? ? 84 C R "C3'" 1 78
+ATOM 2380 O "O3'" . C B 2 78 ? 7.710 5.639 36.892 1.00 61.35 ? ? ? ? ? ? 84 C R "O3'" 1 78
+ATOM 2381 C "C2'" . C B 2 78 ? 6.724 5.727 34.625 1.00 60.61 ? ? ? ? ? ? 84 C R "C2'" 1 78
+ATOM 2382 O "O2'" . C B 2 78 ? 6.274 7.057 34.824 1.00 62.79 ? ? ? ? ? ? 84 C R "O2'" 1 78
+ATOM 2383 C "C1'" . C B 2 78 ? 7.382 5.575 33.257 1.00 58.08 ? ? ? ? ? ? 84 C R "C1'" 1 78
+ATOM 2384 N N1 . C B 2 78 ? 7.283 4.163 32.714 1.00 57.22 ? ? ? ? ? ? 84 C R N1 1 78
+ATOM 2385 C C2 . C B 2 78 ? 6.070 3.701 32.163 1.00 57.45 ? ? ? ? ? ? 84 C R C2 1 78
+ATOM 2386 O O2 . C B 2 78 ? 5.082 4.446 32.114 1.00 59.29 ? ? ? ? ? ? 84 C R O2 1 78
+ATOM 2387 N N3 . C B 2 78 ? 6.002 2.429 31.686 1.00 55.60 ? ? ? ? ? ? 84 C R N3 1 78
+ATOM 2388 C C4 . C B 2 78 ? 7.070 1.629 31.743 1.00 55.19 ? ? ? ? ? ? 84 C R C4 1 78
+ATOM 2389 N N4 . C B 2 78 ? 6.947 0.390 31.264 1.00 54.87 ? ? ? ? ? ? 84 C R N4 1 78
+ATOM 2390 C C5 . C B 2 78 ? 8.312 2.066 32.297 1.00 55.31 ? ? ? ? ? ? 84 C R C5 1 78
+ATOM 2391 C C6 . C B 2 78 ? 8.367 3.321 32.761 1.00 56.34 ? ? ? ? ? ? 84 C R C6 1 78
+ATOM 2392 P P . G B 2 79 ? 6.866 4.631 37.815 1.00 63.25 ? ? ? ? ? ? 85 G R P 1 79
+ATOM 2393 O OP1 . G B 2 79 ? 7.429 4.689 39.182 1.00 63.12 ? ? ? ? ? ? 85 G R OP1 1 79
+ATOM 2394 O OP2 . G B 2 79 ? 6.750 3.317 37.143 1.00 62.60 ? ? ? ? ? ? 85 G R OP2 1 79
+ATOM 2395 O "O5'" . G B 2 79 ? 5.422 5.312 37.804 1.00 60.33 ? ? ? ? ? ? 85 G R "O5'" 1 79
+ATOM 2396 C "C5'" . G B 2 79 ? 4.291 4.526 38.093 1.00 59.21 ? ? ? ? ? ? 85 G R "C5'" 1 79
+ATOM 2397 C "C4'" . G B 2 79 ? 3.159 4.854 37.141 1.00 59.01 ? ? ? ? ? ? 85 G R "C4'" 1 79
+ATOM 2398 O "O4'" . G B 2 79 ? 3.589 4.833 35.754 1.00 58.55 ? ? ? ? ? ? 85 G R "O4'" 1 79
+ATOM 2399 C "C3'" . G B 2 79 ? 2.047 3.828 37.153 1.00 59.27 ? ? ? ? ? ? 85 G R "C3'" 1 79
+ATOM 2400 O "O3'" . G B 2 79 ? 1.275 3.953 38.327 1.00 60.57 ? ? ? ? ? ? 85 G R "O3'" 1 79
+ATOM 2401 C "C2'" . G B 2 79 ? 1.325 4.175 35.858 1.00 57.90 ? ? ? ? ? ? 85 G R "C2'" 1 79
+ATOM 2402 O "O2'" . G B 2 79 ? 0.601 5.387 35.895 1.00 58.82 ? ? ? ? ? ? 85 G R "O2'" 1 79
+ATOM 2403 C "C1'" . G B 2 79 ? 2.548 4.294 34.949 1.00 56.89 ? ? ? ? ? ? 85 G R "C1'" 1 79
+ATOM 2404 N N9 . G B 2 79 ? 2.969 2.989 34.430 1.00 54.26 ? ? ? ? ? ? 85 G R N9 1 79
+ATOM 2405 C C8 . G B 2 79 ? 4.195 2.392 34.598 1.00 52.40 ? ? ? ? ? ? 85 G R C8 1 79
+ATOM 2406 N N7 . G B 2 79 ? 4.286 1.222 34.034 1.00 52.13 ? ? ? ? ? ? 85 G R N7 1 79
+ATOM 2407 C C5 . G B 2 79 ? 3.041 1.022 33.456 1.00 51.80 ? ? ? ? ? ? 85 G R C5 1 79
+ATOM 2408 C C6 . G B 2 79 ? 2.545 -0.075 32.708 1.00 51.73 ? ? ? ? ? ? 85 G R C6 1 79
+ATOM 2409 O O6 . G B 2 79 ? 3.131 -1.120 32.395 1.00 51.53 ? ? ? ? ? ? 85 G R O6 1 79
+ATOM 2410 N N1 . G B 2 79 ? 1.227 0.118 32.302 1.00 51.72 ? ? ? ? ? ? 85 G R N1 1 79
+ATOM 2411 C C2 . G B 2 79 ? 0.478 1.234 32.585 1.00 51.74 ? ? ? ? ? ? 85 G R C2 1 79
+ATOM 2412 N N2 . G B 2 79 ? -0.777 1.244 32.113 1.00 52.75 ? ? ? ? ? ? 85 G R N2 1 79
+ATOM 2413 N N3 . G B 2 79 ? 0.930 2.266 33.285 1.00 51.77 ? ? ? ? ? ? 85 G R N3 1 79
+ATOM 2414 C C4 . G B 2 79 ? 2.216 2.099 33.689 1.00 52.38 ? ? ? ? ? ? 85 G R C4 1 79
+ATOM 2415 P P . G B 2 80 ? 1.228 2.708 39.335 1.00 62.35 ? ? ? ? ? ? 86 G R P 1 80
+ATOM 2416 O OP1 . G B 2 80 ? 1.013 3.258 40.692 1.00 62.27 ? ? ? ? ? ? 86 G R OP1 1 80
+ATOM 2417 O OP2 . G B 2 80 ? 2.383 1.811 39.084 1.00 59.97 ? ? ? ? ? ? 86 G R OP2 1 80
+ATOM 2418 O "O5'" . G B 2 80 ? -0.087 1.934 38.852 1.00 61.06 ? ? ? ? ? ? 86 G R "O5'" 1 80
+ATOM 2419 C "C5'" . G B 2 80 ? -1.254 2.660 38.457 1.00 60.52 ? ? ? ? ? ? 86 G R "C5'" 1 80
+ATOM 2420 C "C4'" . G B 2 80 ? -2.023 1.921 37.377 1.00 58.96 ? ? ? ? ? ? 86 G R "C4'" 1 80
+ATOM 2421 O "O4'" . G B 2 80 ? -1.228 1.792 36.170 1.00 60.02 ? ? ? ? ? ? 86 G R "O4'" 1 80
+ATOM 2422 C "C3'" . G B 2 80 ? -2.355 0.482 37.713 1.00 58.00 ? ? ? ? ? ? 86 G R "C3'" 1 80
+ATOM 2423 O "O3'" . G B 2 80 ? -3.443 0.418 38.619 1.00 57.37 ? ? ? ? ? ? 86 G R "O3'" 1 80
+ATOM 2424 C "C2'" . G B 2 80 ? -2.676 -0.070 36.330 1.00 58.05 ? ? ? ? ? ? 86 G R "C2'" 1 80
+ATOM 2425 O "O2'" . G B 2 80 ? -3.948 0.292 35.837 1.00 58.90 ? ? ? ? ? ? 86 G R "O2'" 1 80
+ATOM 2426 C "C1'" . G B 2 80 ? -1.568 0.583 35.507 1.00 58.67 ? ? ? ? ? ? 86 G R "C1'" 1 80
+ATOM 2427 N N9 . G B 2 80 ? -0.399 -0.296 35.406 1.00 58.68 ? ? ? ? ? ? 86 G R N9 1 80
+ATOM 2428 C C8 . G B 2 80 ? 0.857 -0.098 35.933 1.00 57.81 ? ? ? ? ? ? 86 G R C8 1 80
+ATOM 2429 N N7 . G B 2 80 ? 1.687 -1.073 35.683 1.00 57.19 ? ? ? ? ? ? 86 G R N7 1 80
+ATOM 2430 C C5 . G B 2 80 ? 0.936 -1.981 34.947 1.00 57.25 ? ? ? ? ? ? 86 G R C5 1 80
+ATOM 2431 C C6 . G B 2 80 ? 1.295 -3.236 34.393 1.00 57.26 ? ? ? ? ? ? 86 G R C6 1 80
+ATOM 2432 O O6 . G B 2 80 ? 2.390 -3.808 34.454 1.00 58.09 ? ? ? ? ? ? 86 G R O6 1 80
+ATOM 2433 N N1 . G B 2 80 ? 0.232 -3.843 33.722 1.00 57.48 ? ? ? ? ? ? 86 G R N1 1 80
+ATOM 2434 C C2 . G B 2 80 ? -1.026 -3.296 33.595 1.00 58.19 ? ? ? ? ? ? 86 G R C2 1 80
+ATOM 2435 N N2 . G B 2 80 ? -1.938 -4.007 32.914 1.00 58.42 ? ? ? ? ? ? 86 G R N2 1 80
+ATOM 2436 N N3 . G B 2 80 ? -1.373 -2.125 34.112 1.00 57.80 ? ? ? ? ? ? 86 G R N3 1 80
+ATOM 2437 C C4 . G B 2 80 ? -0.349 -1.521 34.770 1.00 57.74 ? ? ? ? ? ? 86 G R C4 1 80
+ATOM 2438 P P . G B 2 81 ? -3.358 -0.547 39.893 1.00 55.75 ? ? ? ? ? ? 87 G R P 1 81
+ATOM 2439 O OP1 . G B 2 81 ? -4.558 -0.317 40.729 1.00 56.05 ? ? ? ? ? ? 87 G R OP1 1 81
+ATOM 2440 O OP2 . G B 2 81 ? -2.015 -0.385 40.504 1.00 54.68 ? ? ? ? ? ? 87 G R OP2 1 81
+ATOM 2441 O "O5'" . G B 2 81 ? -3.461 -2.002 39.228 1.00 53.17 ? ? ? ? ? ? 87 G R "O5'" 1 81
+ATOM 2442 C "C5'" . G B 2 81 ? -4.602 -2.390 38.472 1.00 51.62 ? ? ? ? ? ? 87 G R "C5'" 1 81
+ATOM 2443 C "C4'" . G B 2 81 ? -4.289 -3.619 37.640 1.00 52.46 ? ? ? ? ? ? 87 G R "C4'" 1 81
+ATOM 2444 O "O4'" . G B 2 81 ? -3.197 -3.333 36.730 1.00 52.03 ? ? ? ? ? ? 87 G R "O4'" 1 81
+ATOM 2445 C "C3'" . G B 2 81 ? -3.765 -4.810 38.420 1.00 52.68 ? ? ? ? ? ? 87 G R "C3'" 1 81
+ATOM 2446 O "O3'" . G B 2 81 ? -4.805 -5.524 39.083 1.00 54.90 ? ? ? ? ? ? 87 G R "O3'" 1 81
+ATOM 2447 C "C2'" . G B 2 81 ? -3.090 -5.615 37.312 1.00 51.73 ? ? ? ? ? ? 87 G R "C2'" 1 81
+ATOM 2448 O "O2'" . G B 2 81 ? -3.989 -6.319 36.476 1.00 52.38 ? ? ? ? ? ? 87 G R "O2'" 1 81
+ATOM 2449 C "C1'" . G B 2 81 ? -2.405 -4.494 36.542 1.00 50.01 ? ? ? ? ? ? 87 G R "C1'" 1 81
+ATOM 2450 N N9 . G B 2 81 ? -1.035 -4.247 37.004 1.00 49.04 ? ? ? ? ? ? 87 G R N9 1 81
+ATOM 2451 C C8 . G B 2 81 ? -0.571 -3.162 37.715 1.00 48.04 ? ? ? ? ? ? 87 G R C8 1 81
+ATOM 2452 N N7 . G B 2 81 ? 0.703 -3.218 37.993 1.00 46.91 ? ? ? ? ? ? 87 G R N7 1 81
+ATOM 2453 C C5 . G B 2 81 ? 1.118 -4.423 37.435 1.00 46.63 ? ? ? ? ? ? 87 G R C5 1 81
+ATOM 2454 C C6 . G B 2 81 ? 2.399 -5.032 37.410 1.00 45.57 ? ? ? ? ? ? 87 G R C6 1 81
+ATOM 2455 O O6 . G B 2 81 ? 3.458 -4.617 37.890 1.00 45.95 ? ? ? ? ? ? 87 G R O6 1 81
+ATOM 2456 N N1 . G B 2 81 ? 2.393 -6.253 36.745 1.00 46.37 ? ? ? ? ? ? 87 G R N1 1 81
+ATOM 2457 C C2 . G B 2 81 ? 1.282 -6.820 36.166 1.00 47.68 ? ? ? ? ? ? 87 G R C2 1 81
+ATOM 2458 N N2 . G B 2 81 ? 1.468 -8.004 35.565 1.00 47.34 ? ? ? ? ? ? 87 G R N2 1 81
+ATOM 2459 N N3 . G B 2 81 ? 0.075 -6.262 36.176 1.00 47.12 ? ? ? ? ? ? 87 G R N3 1 81
+ATOM 2460 C C4 . G B 2 81 ? 0.062 -5.068 36.824 1.00 47.59 ? ? ? ? ? ? 87 G R C4 1 81
+ATOM 2461 P P . G B 2 82 ? -4.452 -6.318 40.437 1.00 57.33 ? ? ? ? ? ? 88 G R P 1 82
+ATOM 2462 O OP1 . G B 2 82 ? -5.721 -6.800 41.027 1.00 56.38 ? ? ? ? ? ? 88 G R OP1 1 82
+ATOM 2463 O OP2 . G B 2 82 ? -3.524 -5.481 41.237 1.00 55.25 ? ? ? ? ? ? 88 G R OP2 1 82
+ATOM 2464 O "O5'" . G B 2 82 ? -3.626 -7.587 39.914 1.00 56.94 ? ? ? ? ? ? 88 G R "O5'" 1 82
+ATOM 2465 C "C5'" . G B 2 82 ? -4.248 -8.549 39.058 1.00 56.89 ? ? ? ? ? ? 88 G R "C5'" 1 82
+ATOM 2466 C "C4'" . G B 2 82 ? -3.237 -9.570 38.575 1.00 55.72 ? ? ? ? ? ? 88 G R "C4'" 1 82
+ATOM 2467 O "O4'" . G B 2 82 ? -2.168 -8.913 37.850 1.00 55.49 ? ? ? ? ? ? 88 G R "O4'" 1 82
+ATOM 2468 C "C3'" . G B 2 82 ? -2.501 -10.306 39.680 1.00 55.58 ? ? ? ? ? ? 88 G R "C3'" 1 82
+ATOM 2469 O "O3'" . G B 2 82 ? -3.314 -11.336 40.231 1.00 55.95 ? ? ? ? ? ? 88 G R "O3'" 1 82
+ATOM 2470 C "C2'" . G B 2 82 ? -1.291 -10.825 38.913 1.00 54.34 ? ? ? ? ? ? 88 G R "C2'" 1 82
+ATOM 2471 O "O2'" . G B 2 82 ? -1.605 -11.912 38.070 1.00 54.19 ? ? ? ? ? ? 88 G R "O2'" 1 82
+ATOM 2472 C "C1'" . G B 2 82 ? -0.949 -9.601 38.069 1.00 53.58 ? ? ? ? ? ? 88 G R "C1'" 1 82
+ATOM 2473 N N9 . G B 2 82 ? -0.002 -8.686 38.711 1.00 52.96 ? ? ? ? ? ? 88 G R N9 1 82
+ATOM 2474 C C8 . G B 2 82 ? -0.277 -7.436 39.218 1.00 53.54 ? ? ? ? ? ? 88 G R C8 1 82
+ATOM 2475 N N7 . G B 2 82 ? 0.758 -6.834 39.739 1.00 52.35 ? ? ? ? ? ? 88 G R N7 1 82
+ATOM 2476 C C5 . G B 2 82 ? 1.789 -7.746 39.569 1.00 51.27 ? ? ? ? ? ? 88 G R C5 1 82
+ATOM 2477 C C6 . G B 2 82 ? 3.152 -7.648 39.933 1.00 50.82 ? ? ? ? ? ? 88 G R C6 1 82
+ATOM 2478 O O6 . G B 2 82 ? 3.722 -6.708 40.501 1.00 51.78 ? ? ? ? ? ? 88 G R O6 1 82
+ATOM 2479 N N1 . G B 2 82 ? 3.875 -8.788 39.587 1.00 50.54 ? ? ? ? ? ? 88 G R N1 1 82
+ATOM 2480 C C2 . G B 2 82 ? 3.341 -9.889 38.958 1.00 50.86 ? ? ? ? ? ? 88 G R C2 1 82
+ATOM 2481 N N2 . G B 2 82 ? 4.192 -10.891 38.700 1.00 49.84 ? ? ? ? ? ? 88 G R N2 1 82
+ATOM 2482 N N3 . G B 2 82 ? 2.062 -9.993 38.606 1.00 50.71 ? ? ? ? ? ? 88 G R N3 1 82
+ATOM 2483 C C4 . G B 2 82 ? 1.343 -8.890 38.940 1.00 51.31 ? ? ? ? ? ? 88 G R C4 1 82
+ATOM 2484 P P . U B 2 83 ? -3.334 -11.564 41.818 1.00 56.48 ? ? ? ? ? ? 89 U R P 1 83
+ATOM 2485 O OP1 . U B 2 83 ? -4.350 -12.600 42.112 1.00 56.34 ? ? ? ? ? ? 89 U R OP1 1 83
+ATOM 2486 O OP2 . U B 2 83 ? -3.425 -10.244 42.482 1.00 54.55 ? ? ? ? ? ? 89 U R OP2 1 83
+ATOM 2487 O "O5'" . U B 2 83 ? -1.879 -12.165 42.103 1.00 54.15 ? ? ? ? ? ? 89 U R "O5'" 1 83
+ATOM 2488 C "C5'" . U B 2 83 ? -1.553 -13.490 41.679 1.00 53.12 ? ? ? ? ? ? 89 U R "C5'" 1 83
+ATOM 2489 C "C4'" . U B 2 83 ? -0.059 -13.733 41.777 1.00 51.71 ? ? ? ? ? ? 89 U R "C4'" 1 83
+ATOM 2490 O "O4'" . U B 2 83 ? 0.647 -12.686 41.068 1.00 51.86 ? ? ? ? ? ? 89 U R "O4'" 1 83
+ATOM 2491 C "C3'" . U B 2 83 ? 0.517 -13.633 43.181 1.00 51.13 ? ? ? ? ? ? 89 U R "C3'" 1 83
+ATOM 2492 O "O3'" . U B 2 83 ? 0.299 -14.812 43.934 1.00 48.90 ? ? ? ? ? ? 89 U R "O3'" 1 83
+ATOM 2493 C "C2'" . U B 2 83 ? 1.989 -13.390 42.882 1.00 50.59 ? ? ? ? ? ? 89 U R "C2'" 1 83
+ATOM 2494 O "O2'" . U B 2 83 ? 2.651 -14.558 42.455 1.00 52.53 ? ? ? ? ? ? 89 U R "O2'" 1 83
+ATOM 2495 C "C1'" . U B 2 83 ? 1.876 -12.408 41.724 1.00 51.16 ? ? ? ? ? ? 89 U R "C1'" 1 83
+ATOM 2496 N N1 . U B 2 83 ? 1.939 -10.973 42.165 1.00 52.58 ? ? ? ? ? ? 89 U R N1 1 83
+ATOM 2497 C C2 . U B 2 83 ? 3.180 -10.398 42.367 1.00 53.85 ? ? ? ? ? ? 89 U R C2 1 83
+ATOM 2498 O O2 . U B 2 83 ? 4.232 -10.983 42.204 1.00 56.49 ? ? ? ? ? ? 89 U R O2 1 83
+ATOM 2499 N N3 . U B 2 83 ? 3.157 -9.088 42.774 1.00 55.13 ? ? ? ? ? ? 89 U R N3 1 83
+ATOM 2500 C C4 . U B 2 83 ? 2.040 -8.301 42.996 1.00 56.18 ? ? ? ? ? ? 89 U R C4 1 83
+ATOM 2501 O O4 . U B 2 83 ? 2.195 -7.136 43.355 1.00 58.79 ? ? ? ? ? ? 89 U R O4 1 83
+ATOM 2502 C C5 . U B 2 83 ? 0.775 -8.959 42.768 1.00 54.63 ? ? ? ? ? ? 89 U R C5 1 83
+ATOM 2503 C C6 . U B 2 83 ? 0.776 -10.241 42.373 1.00 54.47 ? ? ? ? ? ? 89 U R C6 1 83
+ATOM 2504 P P . U B 2 84 ? 0.075 -14.665 45.511 1.00 48.67 ? ? ? ? ? ? 90 U R P 1 84
+ATOM 2505 O OP1 . U B 2 84 ? -0.506 -15.933 46.007 1.00 47.76 ? ? ? ? ? ? 90 U R OP1 1 84
+ATOM 2506 O OP2 . U B 2 84 ? -0.603 -13.374 45.774 1.00 46.97 ? ? ? ? ? ? 90 U R OP2 1 84
+ATOM 2507 O "O5'" . U B 2 84 ? 1.566 -14.536 46.062 1.00 46.20 ? ? ? ? ? ? 90 U R "O5'" 1 84
+ATOM 2508 C "C5'" . U B 2 84 ? 2.420 -15.654 45.969 1.00 44.74 ? ? ? ? ? ? 90 U R "C5'" 1 84
+ATOM 2509 C "C4'" . U B 2 84 ? 3.838 -15.242 46.274 1.00 43.30 ? ? ? ? ? ? 90 U R "C4'" 1 84
+ATOM 2510 O "O4'" . U B 2 84 ? 4.267 -14.197 45.366 1.00 42.68 ? ? ? ? ? ? 90 U R "O4'" 1 84
+ATOM 2511 C "C3'" . U B 2 84 ? 4.019 -14.594 47.631 1.00 42.37 ? ? ? ? ? ? 90 U R "C3'" 1 84
+ATOM 2512 O "O3'" . U B 2 84 ? 4.017 -15.566 48.651 1.00 44.11 ? ? ? ? ? ? 90 U R "O3'" 1 84
+ATOM 2513 C "C2'" . U B 2 84 ? 5.393 -13.977 47.427 1.00 41.27 ? ? ? ? ? ? 90 U R "C2'" 1 84
+ATOM 2514 O "O2'" . U B 2 84 ? 6.438 -14.925 47.499 1.00 38.75 ? ? ? ? ? ? 90 U R "O2'" 1 84
+ATOM 2515 C "C1'" . U B 2 84 ? 5.238 -13.396 46.022 1.00 41.69 ? ? ? ? ? ? 90 U R "C1'" 1 84
+ATOM 2516 N N1 . U B 2 84 ? 4.800 -11.952 46.073 1.00 41.46 ? ? ? ? ? ? 90 U R N1 1 84
+ATOM 2517 C C2 . U B 2 84 ? 5.723 -10.971 46.409 1.00 40.57 ? ? ? ? ? ? 90 U R C2 1 84
+ATOM 2518 O O2 . U B 2 84 ? 6.893 -11.198 46.655 1.00 39.08 ? ? ? ? ? ? 90 U R O2 1 84
+ATOM 2519 N N3 . U B 2 84 ? 5.225 -9.689 46.447 1.00 40.46 ? ? ? ? ? ? 90 U R N3 1 84
+ATOM 2520 C C4 . U B 2 84 ? 3.922 -9.295 46.186 1.00 42.05 ? ? ? ? ? ? 90 U R C4 1 84
+ATOM 2521 O O4 . U B 2 84 ? 3.621 -8.106 46.254 1.00 45.54 ? ? ? ? ? ? 90 U R O4 1 84
+ATOM 2522 C C5 . U B 2 84 ? 3.015 -10.365 45.851 1.00 40.72 ? ? ? ? ? ? 90 U R C5 1 84
+ATOM 2523 C C6 . U B 2 84 ? 3.478 -11.621 45.811 1.00 40.94 ? ? ? ? ? ? 90 U R C6 1 84
+ATOM 2524 P P . A B 2 85 ? 3.462 -15.202 50.108 1.00 44.99 ? ? ? ? ? ? 91 A R P 1 85
+ATOM 2525 O OP1 . A B 2 85 ? 3.420 -16.465 50.879 1.00 45.40 ? ? ? ? ? ? 91 A R OP1 1 85
+ATOM 2526 O OP2 . A B 2 85 ? 2.227 -14.392 49.957 1.00 42.04 ? ? ? ? ? ? 91 A R OP2 1 85
+ATOM 2527 O "O5'" . A B 2 85 ? 4.617 -14.274 50.722 1.00 44.06 ? ? ? ? ? ? 91 A R "O5'" 1 85
+ATOM 2528 C "C5'" . A B 2 85 ? 5.928 -14.786 50.971 1.00 43.66 ? ? ? ? ? ? 91 A R "C5'" 1 85
+ATOM 2529 C "C4'" . A B 2 85 ? 6.948 -13.660 51.058 1.00 44.12 ? ? ? ? ? ? 91 A R "C4'" 1 85
+ATOM 2530 O "O4'" . A B 2 85 ? 6.797 -12.722 49.964 1.00 44.00 ? ? ? ? ? ? 91 A R "O4'" 1 85
+ATOM 2531 C "C3'" . A B 2 85 ? 6.797 -12.761 52.266 1.00 45.38 ? ? ? ? ? ? 91 A R "C3'" 1 85
+ATOM 2532 O "O3'" . A B 2 85 ? 7.362 -13.380 53.398 1.00 46.03 ? ? ? ? ? ? 91 A R "O3'" 1 85
+ATOM 2533 C "C2'" . A B 2 85 ? 7.574 -11.521 51.838 1.00 44.50 ? ? ? ? ? ? 91 A R "C2'" 1 85
+ATOM 2534 O "O2'" . A B 2 85 ? 8.978 -11.680 51.941 1.00 44.63 ? ? ? ? ? ? 91 A R "O2'" 1 85
+ATOM 2535 C "C1'" . A B 2 85 ? 7.169 -11.417 50.372 1.00 41.87 ? ? ? ? ? ? 91 A R "C1'" 1 85
+ATOM 2536 N N9 . A B 2 85 ? 6.071 -10.481 50.111 1.00 39.40 ? ? ? ? ? ? 91 A R N9 1 85
+ATOM 2537 C C8 . A B 2 85 ? 4.790 -10.788 49.731 1.00 38.55 ? ? ? ? ? ? 91 A R C8 1 85
+ATOM 2538 N N7 . A B 2 85 ? 4.010 -9.742 49.557 1.00 36.24 ? ? ? ? ? ? 91 A R N7 1 85
+ATOM 2539 C C5 . A B 2 85 ? 4.835 -8.670 49.840 1.00 35.05 ? ? ? ? ? ? 91 A R C5 1 85
+ATOM 2540 C C6 . A B 2 85 ? 4.612 -7.278 49.845 1.00 34.55 ? ? ? ? ? ? 91 A R C6 1 85
+ATOM 2541 N N6 . A B 2 85 ? 3.435 -6.728 49.538 1.00 33.41 ? ? ? ? ? ? 91 A R N6 1 85
+ATOM 2542 N N1 . A B 2 85 ? 5.644 -6.470 50.178 1.00 35.06 ? ? ? ? ? ? 91 A R N1 1 85
+ATOM 2543 C C2 . A B 2 85 ? 6.827 -7.024 50.485 1.00 35.95 ? ? ? ? ? ? 91 A R C2 1 85
+ATOM 2544 N N3 . A B 2 85 ? 7.157 -8.319 50.516 1.00 36.05 ? ? ? ? ? ? 91 A R N3 1 85
+ATOM 2545 C C4 . A B 2 85 ? 6.109 -9.101 50.181 1.00 37.46 ? ? ? ? ? ? 91 A R C4 1 85
+ATOM 2546 P P . C B 2 86 ? 6.789 -13.028 54.847 1.00 48.12 ? ? ? ? ? ? 92 C R P 1 86
+ATOM 2547 O OP1 . C B 2 86 ? 6.771 -14.310 55.590 1.00 48.81 ? ? ? ? ? ? 92 C R OP1 1 86
+ATOM 2548 O OP2 . C B 2 86 ? 5.542 -12.228 54.736 1.00 44.57 ? ? ? ? ? ? 92 C R OP2 1 86
+ATOM 2549 O "O5'" . C B 2 86 ? 7.933 -12.066 55.427 1.00 48.26 ? ? ? ? ? ? 92 C R "O5'" 1 86
+ATOM 2550 C "C5'" . C B 2 86 ? 9.231 -12.573 55.725 1.00 49.47 ? ? ? ? ? ? 92 C R "C5'" 1 86
+ATOM 2551 C "C4'" . C B 2 86 ? 10.101 -11.516 56.382 1.00 52.54 ? ? ? ? ? ? 92 C R "C4'" 1 86
+ATOM 2552 O "O4'" . C B 2 86 ? 10.443 -10.494 55.409 1.00 52.45 ? ? ? ? ? ? 92 C R "O4'" 1 86
+ATOM 2553 C "C3'" . C B 2 86 ? 9.467 -10.732 57.525 1.00 54.93 ? ? ? ? ? ? 92 C R "C3'" 1 86
+ATOM 2554 O "O3'" . C B 2 86 ? 9.573 -11.442 58.753 1.00 59.24 ? ? ? ? ? ? 92 C R "O3'" 1 86
+ATOM 2555 C "C2'" . C B 2 86 ? 10.325 -9.471 57.529 1.00 53.80 ? ? ? ? ? ? 92 C R "C2'" 1 86
+ATOM 2556 O "O2'" . C B 2 86 ? 11.572 -9.651 58.178 1.00 56.21 ? ? ? ? ? ? 92 C R "O2'" 1 86
+ATOM 2557 C "C1'" . C B 2 86 ? 10.521 -9.225 56.037 1.00 51.06 ? ? ? ? ? ? 92 C R "C1'" 1 86
+ATOM 2558 N N1 . C B 2 86 ? 9.491 -8.287 55.465 1.00 48.29 ? ? ? ? ? ? 92 C R N1 1 86
+ATOM 2559 C C2 . C B 2 86 ? 9.610 -6.899 55.667 1.00 47.94 ? ? ? ? ? ? 92 C R C2 1 86
+ATOM 2560 O O2 . C B 2 86 ? 10.568 -6.447 56.314 1.00 49.20 ? ? ? ? ? ? 92 C R O2 1 86
+ATOM 2561 N N3 . C B 2 86 ? 8.660 -6.075 55.142 1.00 45.47 ? ? ? ? ? ? 92 C R N3 1 86
+ATOM 2562 C C4 . C B 2 86 ? 7.636 -6.584 54.448 1.00 45.47 ? ? ? ? ? ? 92 C R C4 1 86
+ATOM 2563 N N4 . C B 2 86 ? 6.725 -5.741 53.948 1.00 46.21 ? ? ? ? ? ? 92 C R N4 1 86
+ATOM 2564 C C5 . C B 2 86 ? 7.497 -7.987 54.232 1.00 45.83 ? ? ? ? ? ? 92 C R C5 1 86
+ATOM 2565 C C6 . C B 2 86 ? 8.434 -8.787 54.751 1.00 47.06 ? ? ? ? ? ? 92 C R C6 1 86
+ATOM 2566 P P . C B 2 87 ? 8.530 -11.192 59.941 1.00 62.53 ? ? ? ? ? ? 93 C R P 1 87
+ATOM 2567 O OP1 . C B 2 87 ? 8.886 -12.134 61.027 1.00 61.81 ? ? ? ? ? ? 93 C R OP1 1 87
+ATOM 2568 O OP2 . C B 2 87 ? 7.161 -11.180 59.374 1.00 62.77 ? ? ? ? ? ? 93 C R OP2 1 87
+ATOM 2569 O "O5'" . C B 2 87 ? 8.842 -9.697 60.413 1.00 62.73 ? ? ? ? ? ? 93 C R "O5'" 1 87
+ATOM 2570 C "C5'" . C B 2 87 ? 10.038 -9.370 61.116 1.00 63.71 ? ? ? ? ? ? 93 C R "C5'" 1 87
+ATOM 2571 C "C4'" . C B 2 87 ? 10.062 -7.877 61.377 1.00 64.24 ? ? ? ? ? ? 93 C R "C4'" 1 87
+ATOM 2572 O "O4'" . C B 2 87 ? 9.922 -7.159 60.127 1.00 62.97 ? ? ? ? ? ? 93 C R "O4'" 1 87
+ATOM 2573 C "C3'" . C B 2 87 ? 8.895 -7.386 62.212 1.00 65.58 ? ? ? ? ? ? 93 C R "C3'" 1 87
+ATOM 2574 O "O3'" . C B 2 87 ? 9.208 -7.548 63.587 1.00 69.98 ? ? ? ? ? ? 93 C R "O3'" 1 87
+ATOM 2575 C "C2'" . C B 2 87 ? 8.757 -5.924 61.792 1.00 63.66 ? ? ? ? ? ? 93 C R "C2'" 1 87
+ATOM 2576 O "O2'" . C B 2 87 ? 9.588 -5.036 62.514 1.00 65.57 ? ? ? ? ? ? 93 C R "O2'" 1 87
+ATOM 2577 C "C1'" . C B 2 87 ? 9.186 -5.964 60.329 1.00 60.61 ? ? ? ? ? ? 93 C R "C1'" 1 87
+ATOM 2578 N N1 . C B 2 87 ? 8.031 -5.894 59.374 1.00 57.06 ? ? ? ? ? ? 93 C R N1 1 87
+ATOM 2579 C C2 . C B 2 87 ? 7.417 -4.656 59.104 1.00 57.01 ? ? ? ? ? ? 93 C R C2 1 87
+ATOM 2580 O O2 . C B 2 87 ? 7.826 -3.622 59.652 1.00 58.45 ? ? ? ? ? ? 93 C R O2 1 87
+ATOM 2581 N N3 . C B 2 87 ? 6.374 -4.615 58.237 1.00 54.97 ? ? ? ? ? ? 93 C R N3 1 87
+ATOM 2582 C C4 . C B 2 87 ? 5.945 -5.733 57.653 1.00 53.89 ? ? ? ? ? ? 93 C R C4 1 87
+ATOM 2583 N N4 . C B 2 87 ? 4.919 -5.630 56.806 1.00 53.67 ? ? ? ? ? ? 93 C R N4 1 87
+ATOM 2584 C C5 . C B 2 87 ? 6.548 -7.001 57.910 1.00 54.10 ? ? ? ? ? ? 93 C R C5 1 87
+ATOM 2585 C C6 . C B 2 87 ? 7.576 -7.033 58.767 1.00 55.05 ? ? ? ? ? ? 93 C R C6 1 87
+ATOM 2586 P P . G B 2 88 ? 8.200 -8.323 64.560 1.00 72.12 ? ? ? ? ? ? 94 G R P 1 88
+ATOM 2587 O OP1 . G B 2 88 ? 8.924 -8.527 65.835 1.00 72.35 ? ? ? ? ? ? 94 G R OP1 1 88
+ATOM 2588 O OP2 . G B 2 88 ? 7.638 -9.492 63.844 1.00 71.76 ? ? ? ? ? ? 94 G R OP2 1 88
+ATOM 2589 O "O5'" . G B 2 88 ? 7.017 -7.265 64.766 1.00 72.76 ? ? ? ? ? ? 94 G R "O5'" 1 88
+ATOM 2590 C "C5'" . G B 2 88 ? 7.316 -5.954 65.232 1.00 75.85 ? ? ? ? ? ? 94 G R "C5'" 1 88
+ATOM 2591 C "C4'" . G B 2 88 ? 6.274 -4.962 64.751 1.00 78.99 ? ? ? ? ? ? 94 G R "C4'" 1 88
+ATOM 2592 O "O4'" . G B 2 88 ? 6.011 -5.149 63.333 1.00 78.53 ? ? ? ? ? ? 94 G R "O4'" 1 88
+ATOM 2593 C "C3'" . G B 2 88 ? 4.927 -5.073 65.462 1.00 81.20 ? ? ? ? ? ? 94 G R "C3'" 1 88
+ATOM 2594 O "O3'" . G B 2 88 ? 4.539 -3.799 65.972 1.00 87.68 ? ? ? ? ? ? 94 G R "O3'" 1 88
+ATOM 2595 C "C2'" . G B 2 88 ? 3.990 -5.521 64.346 1.00 79.31 ? ? ? ? ? ? 94 G R "C2'" 1 88
+ATOM 2596 O "O2'" . G B 2 88 ? 2.671 -5.047 64.513 1.00 79.21 ? ? ? ? ? ? 94 G R "O2'" 1 88
+ATOM 2597 C "C1'" . G B 2 88 ? 4.645 -4.868 63.134 1.00 77.81 ? ? ? ? ? ? 94 G R "C1'" 1 88
+ATOM 2598 N N9 . G B 2 88 ? 4.148 -5.408 61.869 1.00 75.37 ? ? ? ? ? ? 94 G R N9 1 88
+ATOM 2599 C C8 . G B 2 88 ? 4.129 -6.733 61.501 1.00 74.93 ? ? ? ? ? ? 94 G R C8 1 88
+ATOM 2600 N N7 . G B 2 88 ? 3.609 -6.945 60.327 1.00 73.75 ? ? ? ? ? ? 94 G R N7 1 88
+ATOM 2601 C C5 . G B 2 88 ? 3.254 -5.680 59.882 1.00 72.45 ? ? ? ? ? ? 94 G R C5 1 88
+ATOM 2602 C C6 . G B 2 88 ? 2.640 -5.288 58.666 1.00 70.81 ? ? ? ? ? ? 94 G R C6 1 88
+ATOM 2603 O O6 . G B 2 88 ? 2.292 -6.010 57.724 1.00 69.88 ? ? ? ? ? ? 94 G R O6 1 88
+ATOM 2604 N N1 . G B 2 88 ? 2.446 -3.911 58.586 1.00 70.40 ? ? ? ? ? ? 94 G R N1 1 88
+ATOM 2605 C C2 . G B 2 88 ? 2.800 -3.019 59.572 1.00 71.08 ? ? ? ? ? ? 94 G R C2 1 88
+ATOM 2606 N N2 . G B 2 88 ? 2.528 -1.731 59.314 1.00 68.72 ? ? ? ? ? ? 94 G R N2 1 88
+ATOM 2607 N N3 . G B 2 88 ? 3.374 -3.374 60.725 1.00 72.04 ? ? ? ? ? ? 94 G R N3 1 88
+ATOM 2608 C C4 . G B 2 88 ? 3.574 -4.718 60.818 1.00 73.22 ? ? ? ? ? ? 94 G R C4 1 88
+ATOM 2609 P P . A B 2 89 ? 4.584 -3.446 67.537 1.00 92.04 ? ? ? ? ? ? 95 A R P 1 89
+ATOM 2610 O OP1 . A B 2 89 ? 5.975 -3.080 67.889 1.00 91.19 ? ? ? ? ? ? 95 A R OP1 1 89
+ATOM 2611 O OP2 . A B 2 89 ? 3.890 -4.527 68.276 1.00 92.46 ? ? ? ? ? ? 95 A R OP2 1 89
+ATOM 2612 O "O5'" . A B 2 89 ? 3.680 -2.127 67.620 1.00 93.23 ? ? ? ? ? ? 95 A R "O5'" 1 89
+ATOM 2613 C "C5'" . A B 2 89 ? 3.859 -1.104 66.652 1.00 97.33 ? ? ? ? ? ? 95 A R "C5'" 1 89
+ATOM 2614 C "C4'" . A B 2 89 ? 4.415 0.161 67.278 1.00 100.21 ? ? ? ? ? ? 95 A R "C4'" 1 89
+ATOM 2615 O "O4'" . A B 2 89 ? 5.166 0.911 66.286 1.00 101.29 ? ? ? ? ? ? 95 A R "O4'" 1 89
+ATOM 2616 C "C3'" . A B 2 89 ? 3.365 1.124 67.816 1.00 102.08 ? ? ? ? ? ? 95 A R "C3'" 1 89
+ATOM 2617 O "O3'" . A B 2 89 ? 3.881 1.747 68.988 1.00 105.23 ? ? ? ? ? ? 95 A R "O3'" 1 89
+ATOM 2618 C "C2'" . A B 2 89 ? 3.173 2.098 66.652 1.00 102.18 ? ? ? ? ? ? 95 A R "C2'" 1 89
+ATOM 2619 O "O2'" . A B 2 89 ? 2.683 3.363 67.050 1.00 101.40 ? ? ? ? ? ? 95 A R "O2'" 1 89
+ATOM 2620 C "C1'" . A B 2 89 ? 4.599 2.198 66.117 1.00 102.63 ? ? ? ? ? ? 95 A R "C1'" 1 89
+ATOM 2621 N N9 . A B 2 89 ? 4.703 2.597 64.710 1.00 103.68 ? ? ? ? ? ? 95 A R N9 1 89
+ATOM 2622 C C8 . A B 2 89 ? 5.176 3.793 64.247 1.00 104.22 ? ? ? ? ? ? 95 A R C8 1 89
+ATOM 2623 N N7 . A B 2 89 ? 5.169 3.904 62.940 1.00 104.41 ? ? ? ? ? ? 95 A R N7 1 89
+ATOM 2624 C C5 . A B 2 89 ? 4.651 2.697 62.509 1.00 104.59 ? ? ? ? ? ? 95 A R C5 1 89
+ATOM 2625 C C6 . A B 2 89 ? 4.384 2.185 61.220 1.00 104.89 ? ? ? ? ? ? 95 A R C6 1 89
+ATOM 2626 N N6 . A B 2 89 ? 4.622 2.867 60.095 1.00 105.17 ? ? ? ? ? ? 95 A R N6 1 89
+ATOM 2627 N N1 . A B 2 89 ? 3.870 0.938 61.130 1.00 105.05 ? ? ? ? ? ? 95 A R N1 1 89
+ATOM 2628 C C2 . A B 2 89 ? 3.635 0.253 62.259 1.00 104.88 ? ? ? ? ? ? 95 A R C2 1 89
+ATOM 2629 N N3 . A B 2 89 ? 3.844 0.631 63.523 1.00 104.66 ? ? ? ? ? ? 95 A R N3 1 89
+ATOM 2630 C C4 . A B 2 89 ? 4.359 1.874 63.585 1.00 104.33 ? ? ? ? ? ? 95 A R C4 1 89
+ATOM 2631 P P . U B 2 90 ? 3.059 1.780 70.362 1.00 107.65 ? ? ? ? ? ? 96 U R P 1 90
+ATOM 2632 O OP1 . U B 2 90 ? 2.059 2.865 70.231 1.00 107.76 ? ? ? ? ? ? 96 U R OP1 1 90
+ATOM 2633 O OP2 . U B 2 90 ? 4.049 1.829 71.465 1.00 107.27 ? ? ? ? ? ? 96 U R OP2 1 90
+ATOM 2634 O "O5'" . U B 2 90 ? 2.286 0.372 70.414 1.00 108.85 ? ? ? ? ? ? 96 U R "O5'" 1 90
+ATOM 2635 C "C5'" . U B 2 90 ? 2.763 -0.727 71.197 1.00 110.91 ? ? ? ? ? ? 96 U R "C5'" 1 90
+ATOM 2636 C "C4'" . U B 2 90 ? 1.848 -1.029 72.374 1.00 112.56 ? ? ? ? ? ? 96 U R "C4'" 1 90
+ATOM 2637 O "O4'" . U B 2 90 ? 1.519 0.189 73.104 1.00 114.42 ? ? ? ? ? ? 96 U R "O4'" 1 90
+ATOM 2638 C "C3'" . U B 2 90 ? 0.461 -1.556 72.036 1.00 112.56 ? ? ? ? ? ? 96 U R "C3'" 1 90
+ATOM 2639 O "O3'" . U B 2 90 ? 0.450 -2.900 71.570 1.00 110.11 ? ? ? ? ? ? 96 U R "O3'" 1 90
+ATOM 2640 C "C2'" . U B 2 90 ? -0.227 -1.363 73.386 1.00 114.12 ? ? ? ? ? ? 96 U R "C2'" 1 90
+ATOM 2641 O "O2'" . U B 2 90 ? 0.231 -2.231 74.407 1.00 114.58 ? ? ? ? ? ? 96 U R "O2'" 1 90
+ATOM 2642 C "C1'" . U B 2 90 ? 0.209 0.076 73.652 1.00 115.24 ? ? ? ? ? ? 96 U R "C1'" 1 90
+ATOM 2643 N N1 . U B 2 90 ? -0.758 1.066 73.034 1.00 117.03 ? ? ? ? ? ? 96 U R N1 1 90
+ATOM 2644 C C2 . U B 2 90 ? -1.907 1.419 73.730 1.00 117.89 ? ? ? ? ? ? 96 U R C2 1 90
+ATOM 2645 O O2 . U B 2 90 ? -2.191 0.994 74.839 1.00 117.99 ? ? ? ? ? ? 96 U R O2 1 90
+ATOM 2646 N N3 . U B 2 90 ? -2.726 2.313 73.074 1.00 118.50 ? ? ? ? ? ? 96 U R N3 1 90
+ATOM 2647 C C4 . U B 2 90 ? -2.529 2.874 71.821 1.00 118.71 ? ? ? ? ? ? 96 U R C4 1 90
+ATOM 2648 O O4 . U B 2 90 ? -3.353 3.660 71.365 1.00 119.12 ? ? ? ? ? ? 96 U R O4 1 90
+ATOM 2649 C C5 . U B 2 90 ? -1.321 2.459 71.153 1.00 118.47 ? ? ? ? ? ? 96 U R C5 1 90
+ATOM 2650 C C6 . U B 2 90 ? -0.509 1.591 71.771 1.00 117.95 ? ? ? ? ? ? 96 U R C6 1 90
+ATOM 2651 P P . G B 2 91 ? -0.719 -3.356 70.570 1.00 108.46 ? ? ? ? ? ? 97 G R P 1 91
+ATOM 2652 O OP1 . G B 2 91 ? -1.958 -3.506 71.369 1.00 108.16 ? ? ? ? ? ? 97 G R OP1 1 91
+ATOM 2653 O OP2 . G B 2 91 ? -0.210 -4.515 69.800 1.00 108.55 ? ? ? ? ? ? 97 G R OP2 1 91
+ATOM 2654 O "O5'" . G B 2 91 ? -0.898 -2.100 69.579 1.00 105.18 ? ? ? ? ? ? 97 G R "O5'" 1 91
+ATOM 2655 C "C5'" . G B 2 91 ? -0.395 -2.109 68.239 1.00 99.41 ? ? ? ? ? ? 97 G R "C5'" 1 91
+ATOM 2656 C "C4'" . G B 2 91 ? -0.451 -0.724 67.616 1.00 95.40 ? ? ? ? ? ? 97 G R "C4'" 1 91
+ATOM 2657 O "O4'" . G B 2 91 ? 0.728 -0.514 66.795 1.00 94.32 ? ? ? ? ? ? 97 G R "O4'" 1 91
+ATOM 2658 C "C3'" . G B 2 91 ? -1.604 -0.489 66.649 1.00 93.30 ? ? ? ? ? ? 97 G R "C3'" 1 91
+ATOM 2659 O "O3'" . G B 2 91 ? -2.770 -0.024 67.304 1.00 90.11 ? ? ? ? ? ? 97 G R "O3'" 1 91
+ATOM 2660 C "C2'" . G B 2 91 ? -1.025 0.546 65.690 1.00 93.38 ? ? ? ? ? ? 97 G R "C2'" 1 91
+ATOM 2661 O "O2'" . G B 2 91 ? -0.936 1.847 66.240 1.00 93.04 ? ? ? ? ? ? 97 G R "O2'" 1 91
+ATOM 2662 C "C1'" . G B 2 91 ? 0.361 -0.058 65.500 1.00 93.71 ? ? ? ? ? ? 97 G R "C1'" 1 91
+ATOM 2663 N N9 . G B 2 91 ? 0.412 -1.178 64.544 1.00 93.22 ? ? ? ? ? ? 97 G R N9 1 91
+ATOM 2664 C C8 . G B 2 91 ? 0.908 -2.437 64.796 1.00 93.14 ? ? ? ? ? ? 97 G R C8 1 91
+ATOM 2665 N N7 . G B 2 91 ? 0.835 -3.251 63.781 1.00 92.68 ? ? ? ? ? ? 97 G R N7 1 91
+ATOM 2666 C C5 . G B 2 91 ? 0.253 -2.491 62.777 1.00 92.07 ? ? ? ? ? ? 97 G R C5 1 91
+ATOM 2667 C C6 . G B 2 91 ? -0.075 -2.847 61.442 1.00 91.04 ? ? ? ? ? ? 97 G R C6 1 91
+ATOM 2668 O O6 . G B 2 91 ? 0.092 -3.936 60.879 1.00 90.22 ? ? ? ? ? ? 97 G R O6 1 91
+ATOM 2669 N N1 . G B 2 91 ? -0.654 -1.789 60.741 1.00 90.64 ? ? ? ? ? ? 97 G R N1 1 91
+ATOM 2670 C C2 . G B 2 91 ? -0.886 -0.539 61.268 1.00 91.15 ? ? ? ? ? ? 97 G R C2 1 91
+ATOM 2671 N N2 . G B 2 91 ? -1.455 0.354 60.444 1.00 91.28 ? ? ? ? ? ? 97 G R N2 1 91
+ATOM 2672 N N3 . G B 2 91 ? -0.583 -0.193 62.518 1.00 91.92 ? ? ? ? ? ? 97 G R N3 1 91
+ATOM 2673 C C4 . G B 2 91 ? -0.016 -1.211 63.224 1.00 92.35 ? ? ? ? ? ? 97 G R C4 1 91
+ATOM 2674 P P . G B 2 92 ? -4.177 -0.680 66.913 1.00 88.15 ? ? ? ? ? ? 98 G R P 1 92
+ATOM 2675 O OP1 . G B 2 92 ? -5.196 -0.117 67.829 1.00 89.11 ? ? ? ? ? ? 98 G R OP1 1 92
+ATOM 2676 O OP2 . G B 2 92 ? -3.996 -2.152 66.851 1.00 86.93 ? ? ? ? ? ? 98 G R OP2 1 92
+ATOM 2677 O "O5'" . G B 2 92 ? -4.441 -0.139 65.423 1.00 85.99 ? ? ? ? ? ? 98 G R "O5'" 1 92
+ATOM 2678 C "C5'" . G B 2 92 ? -4.702 1.244 65.157 1.00 81.47 ? ? ? ? ? ? 98 G R "C5'" 1 92
+ATOM 2679 C "C4'" . G B 2 92 ? -5.089 1.476 63.702 1.00 78.96 ? ? ? ? ? ? 98 G R "C4'" 1 92
+ATOM 2680 O "O4'" . G B 2 92 ? -4.249 0.680 62.827 1.00 77.34 ? ? ? ? ? ? 98 G R "O4'" 1 92
+ATOM 2681 C "C3'" . G B 2 92 ? -6.541 1.153 63.356 1.00 77.72 ? ? ? ? ? ? 98 G R "C3'" 1 92
+ATOM 2682 O "O3'" . G B 2 92 ? -7.170 2.313 62.821 1.00 77.97 ? ? ? ? ? ? 98 G R "O3'" 1 92
+ATOM 2683 C "C2'" . G B 2 92 ? -6.489 0.018 62.330 1.00 76.50 ? ? ? ? ? ? 98 G R "C2'" 1 92
+ATOM 2684 O "O2'" . G B 2 92 ? -7.292 0.281 61.193 1.00 75.80 ? ? ? ? ? ? 98 G R "O2'" 1 92
+ATOM 2685 C "C1'" . G B 2 92 ? -5.022 -0.068 61.904 1.00 75.46 ? ? ? ? ? ? 98 G R "C1'" 1 92
+ATOM 2686 N N9 . G B 2 92 ? -4.487 -1.439 61.826 1.00 72.64 ? ? ? ? ? ? 98 G R N9 1 92
+ATOM 2687 C C8 . G B 2 92 ? -3.547 -2.008 62.659 1.00 70.33 ? ? ? ? ? ? 98 G R C8 1 92
+ATOM 2688 N N7 . G B 2 92 ? -3.247 -3.242 62.364 1.00 68.22 ? ? ? ? ? ? 98 G R N7 1 92
+ATOM 2689 C C5 . G B 2 92 ? -4.037 -3.523 61.258 1.00 68.81 ? ? ? ? ? ? 98 G R C5 1 92
+ATOM 2690 C C6 . G B 2 92 ? -4.141 -4.716 60.497 1.00 68.33 ? ? ? ? ? ? 98 G R C6 1 92
+ATOM 2691 O O6 . G B 2 92 ? -3.532 -5.783 60.665 1.00 67.91 ? ? ? ? ? ? 98 G R O6 1 92
+ATOM 2692 N N1 . G B 2 92 ? -5.060 -4.595 59.450 1.00 68.01 ? ? ? ? ? ? 98 G R N1 1 92
+ATOM 2693 C C2 . G B 2 92 ? -5.792 -3.458 59.179 1.00 68.56 ? ? ? ? ? ? 98 G R C2 1 92
+ATOM 2694 N N2 . G B 2 92 ? -6.626 -3.531 58.132 1.00 68.46 ? ? ? ? ? ? 98 G R N2 1 92
+ATOM 2695 N N3 . G B 2 92 ? -5.704 -2.330 59.884 1.00 69.01 ? ? ? ? ? ? 98 G R N3 1 92
+ATOM 2696 C C4 . G B 2 92 ? -4.809 -2.427 60.910 1.00 70.46 ? ? ? ? ? ? 98 G R C4 1 92
+ATOM 2697 O OP3 . G C 3 1 ? 16.680 4.894 56.478 1.00 67.77 ? ? ? ? ? ? 1 G A OP3 1 1
+ATOM 2698 P P . G C 3 1 ? 16.591 4.857 55.001 1.00 67.32 ? ? ? ? ? ? 1 G A P 1 1
+ATOM 2699 O OP1 . G C 3 1 ? 17.559 5.658 54.215 1.00 66.30 ? ? ? ? ? ? 1 G A OP1 1 1
+ATOM 2700 O OP2 . G C 3 1 ? 16.756 3.435 54.599 1.00 65.81 ? ? ? ? ? ? 1 G A OP2 1 1
+ATOM 2701 O "O5'" . G C 3 1 ? 15.116 5.343 54.600 1.00 62.36 ? ? ? ? ? ? 1 G A "O5'" 1 1
+ATOM 2702 C "C5'" . G C 3 1 ? 14.036 4.409 54.495 1.00 57.38 ? ? ? ? ? ? 1 G A "C5'" 1 1
+ATOM 2703 C "C4'" . G C 3 1 ? 13.513 4.307 53.072 1.00 53.29 ? ? ? ? ? ? 1 G A "C4'" 1 1
+ATOM 2704 O "O4'" . G C 3 1 ? 14.344 3.389 52.324 1.00 49.91 ? ? ? ? ? ? 1 G A "O4'" 1 1
+ATOM 2705 C "C3'" . G C 3 1 ? 12.097 3.762 52.926 1.00 51.90 ? ? ? ? ? ? 1 G A "C3'" 1 1
+ATOM 2706 O "O3'" . G C 3 1 ? 11.148 4.823 53.089 1.00 53.15 ? ? ? ? ? ? 1 G A "O3'" 1 1
+ATOM 2707 C "C2'" . G C 3 1 ? 12.128 3.210 51.500 1.00 50.86 ? ? ? ? ? ? 1 G A "C2'" 1 1
+ATOM 2708 O "O2'" . G C 3 1 ? 11.883 4.186 50.503 1.00 48.54 ? ? ? ? ? ? 1 G A "O2'" 1 1
+ATOM 2709 C "C1'" . G C 3 1 ? 13.561 2.695 51.372 1.00 49.44 ? ? ? ? ? ? 1 G A "C1'" 1 1
+ATOM 2710 N N9 . G C 3 1 ? 13.715 1.254 51.582 1.00 47.96 ? ? ? ? ? ? 1 G A N9 1 1
+ATOM 2711 C C8 . G C 3 1 ? 14.475 0.634 52.548 1.00 47.85 ? ? ? ? ? ? 1 G A C8 1 1
+ATOM 2712 N N7 . G C 3 1 ? 14.436 -0.669 52.503 1.00 46.32 ? ? ? ? ? ? 1 G A N7 1 1
+ATOM 2713 C C5 . G C 3 1 ? 13.596 -0.940 51.434 1.00 47.44 ? ? ? ? ? ? 1 G A C5 1 1
+ATOM 2714 C C6 . G C 3 1 ? 13.172 -2.184 50.900 1.00 47.47 ? ? ? ? ? ? 1 G A C6 1 1
+ATOM 2715 O O6 . G C 3 1 ? 13.471 -3.324 51.289 1.00 47.88 ? ? ? ? ? ? 1 G A O6 1 1
+ATOM 2716 N N1 . G C 3 1 ? 12.316 -2.023 49.807 1.00 46.02 ? ? ? ? ? ? 1 G A N1 1 1
+ATOM 2717 C C2 . G C 3 1 ? 11.924 -0.805 49.299 1.00 46.75 ? ? ? ? ? ? 1 G A C2 1 1
+ATOM 2718 N N2 . G C 3 1 ? 11.095 -0.837 48.246 1.00 48.57 ? ? ? ? ? ? 1 G A N2 1 1
+ATOM 2719 N N3 . G C 3 1 ? 12.313 0.367 49.789 1.00 46.88 ? ? ? ? ? ? 1 G A N3 1 1
+ATOM 2720 C C4 . G C 3 1 ? 13.145 0.231 50.853 1.00 47.68 ? ? ? ? ? ? 1 G A C4 1 1
+ATOM 2721 P P . G C 3 2 ? 9.589 4.583 53.396 1.00 55.92 ? ? ? ? ? ? 2 G A P 1 2
+ATOM 2722 O OP1 . G C 3 2 ? 9.032 3.714 52.336 1.00 54.98 ? ? ? ? ? ? 2 G A OP1 1 2
+ATOM 2723 O OP2 . G C 3 2 ? 8.950 5.903 53.629 1.00 54.37 ? ? ? ? ? ? 2 G A OP2 1 2
+ATOM 2724 O "O5'" . G C 3 2 ? 9.627 3.783 54.787 1.00 56.00 ? ? ? ? ? ? 2 G A "O5'" 1 2
+ATOM 2725 C "C5'" . G C 3 2 ? 9.986 4.464 55.993 1.00 54.43 ? ? ? ? ? ? 2 G A "C5'" 1 2
+ATOM 2726 C "C4'" . G C 3 2 ? 10.428 3.527 57.108 1.00 53.48 ? ? ? ? ? ? 2 G A "C4'" 1 2
+ATOM 2727 O "O4'" . G C 3 2 ? 9.273 2.816 57.623 1.00 52.76 ? ? ? ? ? ? 2 G A "O4'" 1 2
+ATOM 2728 C "C3'" . G C 3 2 ? 11.449 2.454 56.739 1.00 53.00 ? ? ? ? ? ? 2 G A "C3'" 1 2
+ATOM 2729 O "O3'" . G C 3 2 ? 12.776 2.918 56.975 1.00 51.51 ? ? ? ? ? ? 2 G A "O3'" 1 2
+ATOM 2730 C "C2'" . G C 3 2 ? 11.077 1.300 57.671 1.00 52.24 ? ? ? ? ? ? 2 G A "C2'" 1 2
+ATOM 2731 O "O2'" . G C 3 2 ? 11.644 1.426 58.960 1.00 51.75 ? ? ? ? ? ? 2 G A "O2'" 1 2
+ATOM 2732 C "C1'" . G C 3 2 ? 9.562 1.439 57.773 1.00 51.55 ? ? ? ? ? ? 2 G A "C1'" 1 2
+ATOM 2733 N N9 . G C 3 2 ? 8.790 0.705 56.769 1.00 51.63 ? ? ? ? ? ? 2 G A N9 1 2
+ATOM 2734 C C8 . G C 3 2 ? 7.883 1.261 55.897 1.00 52.21 ? ? ? ? ? ? 2 G A C8 1 2
+ATOM 2735 N N7 . G C 3 2 ? 7.318 0.397 55.104 1.00 52.19 ? ? ? ? ? ? 2 G A N7 1 2
+ATOM 2736 C C5 . G C 3 2 ? 7.884 -0.817 55.466 1.00 51.22 ? ? ? ? ? ? 2 G A C5 1 2
+ATOM 2737 C C6 . G C 3 2 ? 7.647 -2.110 54.945 1.00 50.57 ? ? ? ? ? ? 2 G A C6 1 2
+ATOM 2738 O O6 . G C 3 2 ? 6.872 -2.425 54.031 1.00 51.81 ? ? ? ? ? ? 2 G A O6 1 2
+ATOM 2739 N N1 . G C 3 2 ? 8.417 -3.084 55.582 1.00 48.53 ? ? ? ? ? ? 2 G A N1 1 2
+ATOM 2740 C C2 . G C 3 2 ? 9.303 -2.830 56.603 1.00 48.48 ? ? ? ? ? ? 2 G A C2 1 2
+ATOM 2741 N N2 . G C 3 2 ? 9.957 -3.891 57.096 1.00 46.83 ? ? ? ? ? ? 2 G A N2 1 2
+ATOM 2742 N N3 . G C 3 2 ? 9.531 -1.617 57.104 1.00 49.72 ? ? ? ? ? ? 2 G A N3 1 2
+ATOM 2743 C C4 . G C 3 2 ? 8.791 -0.653 56.494 1.00 51.27 ? ? ? ? ? ? 2 G A C4 1 2
+HETATM 2744 MG MG . MG D 4 . ? 4.000 -2.776 51.209 1.00 66.65 ? ? ? ? ? ? 1 MG R MG 1 1
+HETATM 2745 O O . HOH E 5 . ? 4.376 31.687 10.017 1.00 29.48 ? ? ? ? ? ? 99 HOH P O 1 99
+HETATM 2746 O O . HOH E 5 . ? 8.620 24.826 6.657 1.00 42.09 ? ? ? ? ? ? 100 HOH P O 1 100
+HETATM 2747 O O . HOH E 5 . ? 4.700 30.085 8.176 1.00 44.90 ? ? ? ? ? ? 101 HOH P O 1 101
+HETATM 2748 O O . HOH F 5 . ? 3.779 13.244 -1.019 1.00 39.86 ? ? ? ? ? ? 3 HOH R O 1 3
+HETATM 2749 O O . HOH F 5 . ? 26.468 -4.600 41.966 1.00 27.27 ? ? ? ? ? ? 4 HOH R O 1 4
+HETATM 2750 O O . HOH F 5 . ? 12.478 -8.451 31.611 1.00 33.82 ? ? ? ? ? ? 5 HOH R O 1 5
+HETATM 2751 O O . HOH F 5 . ? 29.314 -2.272 18.976 1.00 48.37 ? ? ? ? ? ? 670 HOH R O 1 670
+HETATM 2752 O O . HOH F 5 . ? 9.514 -9.005 51.220 1.00 55.48 ? ? ? ? ? ? 671 HOH R O 1 671
+HETATM 2753 O O . HOH F 5 . ? 11.169 6.329 -1.078 1.00 59.28 ? ? ? ? ? ? 672 HOH R O 1 672
+HETATM 2754 O O . HOH F 5 . ? 2.744 -4.232 50.183 1.00 67.60 ? ? ? ? ? ? 673 HOH R O 1 673
+HETATM 2755 O O . HOH F 5 . ? 5.774 -3.685 50.326 1.00 67.45 ? ? ? ? ? ? 674 HOH R O 1 674
+HETATM 2756 O O . HOH F 5 . ? 2.234 -1.949 52.189 1.00 67.27 ? ? ? ? ? ? 675 HOH R O 1 675
+HETATM 2757 O O . HOH F 5 . ? 4.177 -4.197 52.851 1.00 67.86 ? ? ? ? ? ? 676 HOH R O 1 676
+HETATM 2758 O O . HOH G 5 . ? 5.266 -1.415 52.341 1.00 67.29 ? ? ? ? ? ? 3 HOH A O 1 3
+#
+loop_
+_pdbx_poly_seq_scheme.asym_id             
+_pdbx_poly_seq_scheme.entity_id           
+_pdbx_poly_seq_scheme.seq_id              
+_pdbx_poly_seq_scheme.mon_id              
+_pdbx_poly_seq_scheme.ndb_seq_num         
+_pdbx_poly_seq_scheme.pdb_seq_num         
+_pdbx_poly_seq_scheme.auth_seq_num        
+_pdbx_poly_seq_scheme.pdb_mon_id          
+_pdbx_poly_seq_scheme.auth_mon_id         
+_pdbx_poly_seq_scheme.pdb_strand_id       
+_pdbx_poly_seq_scheme.pdb_ins_code        
+_pdbx_poly_seq_scheme.hetero              
+A 1 1 MET 1 1 ? ? ? P . n
+A 1 2 ALA 2 2 ? ? ? P . n
+A 1 3 VAL 3 3 ? ? ? P . n
+A 1 4 PRO 4 4 ? ? ? P . n
+A 1 5 GLU 5 5 ? ? ? P . n
+A 1 6 THR 6 6 ? ? ? P . n
+A 1 7 ARG 7 7 7 ARG ARG P . n
+A 1 8 PRO 8 8 8 PRO PRO P . n
+A 1 9 ASN 9 9 9 ASN ASN P . n
+A 1 10 HIS 10 10 10 HIS HIS P . n
+A 1 11 THR 11 11 11 THR THR P . n
+A 1 12 ILE 12 12 12 ILE ILE P . n
+A 1 13 TYR 13 13 13 TYR TYR P . n
+A 1 14 ILE 14 14 14 ILE ILE P . n
+A 1 15 ASN 15 15 15 ASN ASN P . n
+A 1 16 ASN 16 16 16 ASN ASN P . n
+A 1 17 LEU 17 17 17 LEU LEU P . n
+A 1 18 ASN 18 18 18 ASN ASN P . n
+A 1 19 GLU 19 19 19 GLU GLU P . n
+A 1 20 LYS 20 20 20 LYS LYS P . n
+A 1 21 ILE 21 21 21 ILE ILE P . n
+A 1 22 LYS 22 22 22 LYS LYS P . n
+A 1 23 LYS 23 23 23 LYS LYS P . n
+A 1 24 ASP 24 24 24 ASP ASP P . n
+A 1 25 GLU 25 25 25 GLU GLU P . n
+A 1 26 LEU 26 26 26 LEU LEU P . n
+A 1 27 LYS 27 27 27 LYS LYS P . n
+A 1 28 LYS 28 28 28 LYS LYS P . n
+A 1 29 SER 29 29 29 SER SER P . n
+A 1 30 LEU 30 30 30 LEU LEU P . n
+A 1 31 HIS 31 31 31 HIS HIS P . n
+A 1 32 ALA 32 32 32 ALA ALA P . n
+A 1 33 ILE 33 33 33 ILE ILE P . n
+A 1 34 PHE 34 34 34 PHE PHE P . n
+A 1 35 SER 35 35 35 SER SER P . n
+A 1 36 ARG 36 36 36 ARG ARG P . n
+A 1 37 PHE 37 37 37 PHE PHE P . n
+A 1 38 GLY 38 38 38 GLY GLY P . n
+A 1 39 GLN 39 39 39 GLN GLN P . n
+A 1 40 ILE 40 40 40 ILE ILE P . n
+A 1 41 LEU 41 41 41 LEU LEU P . n
+A 1 42 ASP 42 42 42 ASP ASP P . n
+A 1 43 ILE 43 43 43 ILE ILE P . n
+A 1 44 LEU 44 44 44 LEU LEU P . n
+A 1 45 VAL 45 45 45 VAL VAL P . n
+A 1 46 SER 46 46 46 SER SER P . n
+A 1 47 ARG 47 47 47 ARG ARG P . n
+A 1 48 SER 48 48 48 SER SER P . n
+A 1 49 LEU 49 49 49 LEU LEU P . n
+A 1 50 LYS 50 50 50 LYS LYS P . n
+A 1 51 MET 51 51 51 MET MET P . n
+A 1 52 ARG 52 52 52 ARG ARG P . n
+A 1 53 GLY 53 53 53 GLY GLY P . n
+A 1 54 GLN 54 54 54 GLN GLN P . n
+A 1 55 ALA 55 55 55 ALA ALA P . n
+A 1 56 PHE 56 56 56 PHE PHE P . n
+A 1 57 VAL 57 57 57 VAL VAL P . n
+A 1 58 ILE 58 58 58 ILE ILE P . n
+A 1 59 PHE 59 59 59 PHE PHE P . n
+A 1 60 LYS 60 60 60 LYS LYS P . n
+A 1 61 GLU 61 61 61 GLU GLU P . n
+A 1 62 VAL 62 62 62 VAL VAL P . n
+A 1 63 SER 63 63 63 SER SER P . n
+A 1 64 SER 64 64 64 SER SER P . n
+A 1 65 ALA 65 65 65 ALA ALA P . n
+A 1 66 THR 66 66 66 THR THR P . n
+A 1 67 ASN 67 67 67 ASN ASN P . n
+A 1 68 ALA 68 68 68 ALA ALA P . n
+A 1 69 LEU 69 69 69 LEU LEU P . n
+A 1 70 ARG 70 70 70 ARG ARG P . n
+A 1 71 SER 71 71 71 SER SER P . n
+A 1 72 MET 72 72 72 MET MET P . n
+A 1 73 GLN 73 73 73 GLN GLN P . n
+A 1 74 GLY 74 74 74 GLY GLY P . n
+A 1 75 PHE 75 75 75 PHE PHE P . n
+A 1 76 PRO 76 76 76 PRO PRO P . n
+A 1 77 PHE 77 77 77 PHE PHE P . n
+A 1 78 TYR 78 78 78 TYR TYR P . n
+A 1 79 ASP 79 79 79 ASP ASP P . n
+A 1 80 LYS 80 80 80 LYS LYS P . n
+A 1 81 PRO 81 81 81 PRO PRO P . n
+A 1 82 MET 82 82 82 MET MET P . n
+A 1 83 ARG 83 83 83 ARG ARG P . n
+A 1 84 ILE 84 84 84 ILE ILE P . n
+A 1 85 GLN 85 85 85 GLN GLN P . n
+A 1 86 TYR 86 86 86 TYR TYR P . n
+A 1 87 ALA 87 87 87 ALA ALA P . n
+A 1 88 LYS 88 88 88 LYS LYS P . n
+A 1 89 THR 89 89 89 THR THR P . n
+A 1 90 ASP 90 90 90 ASP ASP P . n
+A 1 91 SER 91 91 91 SER SER P . n
+A 1 92 ASP 92 92 92 ASP ASP P . n
+A 1 93 ILE 93 93 93 ILE ILE P . n
+A 1 94 ILE 94 94 ? ? ? P . n
+A 1 95 ALA 95 95 ? ? ? P . n
+A 1 96 LYS 96 96 ? ? ? P . n
+A 1 97 MET 97 97 ? ? ? P . n
+A 1 98 LYS 98 98 ? ? ? P . n
+B 2 1 GTP 1 8 8 GTP GTP R . n
+B 2 2 G 2 9 9 G G R . n
+B 2 3 U 3 10 10 U U R . n
+B 2 4 C 4 11 11 C C R . n
+B 2 5 A 5 12 12 A A R . n
+B 2 6 C 6 13 13 C C R . n
+B 2 7 G 7 14 14 G G R . n
+B 2 8 C 8 15 15 C C R . n
+B 2 9 A 9 16 16 A A R . n
+B 2 10 C 10 17 17 C C R . n
+B 2 11 A 11 18 18 A A R . n
+B 2 12 G 12 19 19 G G R . n
+B 2 13 G 13 20 20 G G R . n
+B 2 14 G 14 21 21 G G R . n
+B 2 15 C 15 22 22 C C R . n
+B 2 16 A 16 23 23 A A R . n
+B 2 17 A 17 24 24 A A R . n
+B 2 18 A 18 25 25 A A R . n
+B 2 19 C 19 26 26 C C R . n
+B 2 20 C 20 27 27 C C R . n
+B 2 21 A 21 28 28 A A R . n
+B 2 22 U 22 29 29 U U R . n
+B 2 23 U 23 30 30 U U R . n
+B 2 24 C 24 31 31 C C R . n
+B 2 25 G 25 32 32 G G R . n
+B 2 26 A 26 33 33 A A R . n
+B 2 27 A 27 34 34 A A R . n
+B 2 28 A 28 35 35 A A R . n
+B 2 29 G 29 36 36 G G R . n
+B 2 30 A 30 37 37 A A R . n
+B 2 31 G 31 38 38 G G R . n
+B 2 32 U 32 39 39 U U R . n
+B 2 33 G 33 40 40 G G R . n
+B 2 34 G 34 41 41 G G R . n
+B 2 35 G 35 42 42 G G R . n
+B 2 36 A 36 43 43 A A R . n
+B 2 37 C 37 44 44 C C R . n
+B 2 38 G 38 45 45 G G R . n
+B 2 39 C 39 46 46 C C R . n
+B 2 40 A 40 47 47 A A R . n
+B 2 41 A 41 48 48 A A R . n
+B 2 42 A 42 49 49 A A R . n
+B 2 43 G 43 50 50 G G R . n
+B 2 44 C 44 51 51 C C R . n
+B 2 45 C 45 52 52 C C R . n
+B 2 46 U 46 53 53 U U R . n
+B 2 47 C 47 54 54 C C R . n
+B 2 48 C 48 55 55 C C R . n
+B 2 49 G 49 56 56 G G R . n
+B 2 50 G 50 57 57 G G R . n
+B 2 51 C 51 58 58 C C R . n
+B 2 52 C 52 59 59 C C R . n
+B 2 53 U 53 60 60 U U R . n
+B 2 54 A 54 61 61 A A R . n
+B 2 55 A 55 62 62 A A R . n
+B 2 56 A 56 63 63 A A R . n
+B 2 57 C 57 64 64 C C R . n
+B 2 58 C 58 65 65 C C R . n
+B 2 59 A 59 660 660 A A R . n
+B 2 60 U 60 661 661 U U R . n
+B 2 61 U 61 662 662 U U R . n
+B 2 62 G 62 663 663 G G R . n
+B 2 63 C 63 664 664 C C R . n
+B 2 64 A 64 665 665 A A R . n
+B 2 65 C 65 666 666 C C R . n
+B 2 66 U 66 667 667 U U R . n
+B 2 67 C 67 668 668 C C R . n
+B 2 68 C 68 669 669 C C R . n
+B 2 69 G 69 75 75 G G R . n
+B 2 70 G 70 76 76 G G R . n
+B 2 71 U 71 77 77 U U R . n
+B 2 72 A 72 78 78 A A R . n
+B 2 73 G 73 79 79 G G R . n
+B 2 74 G 74 80 80 G G R . n
+B 2 75 U 75 81 81 U U R . n
+B 2 76 A 76 82 82 A A R . n
+B 2 77 G 77 83 83 G G R . n
+B 2 78 C 78 84 84 C C R . n
+B 2 79 G 79 85 85 G G R . n
+B 2 80 G 80 86 86 G G R . n
+B 2 81 G 81 87 87 G G R . n
+B 2 82 G 82 88 88 G G R . n
+B 2 83 U 83 89 89 U U R . n
+B 2 84 U 84 90 90 U U R . n
+B 2 85 A 85 91 91 A A R . n
+B 2 86 C 86 92 92 C C R . n
+B 2 87 C 87 93 93 C C R . n
+B 2 88 G 88 94 94 G G R . n
+B 2 89 A 89 95 95 A A R . n
+B 2 90 U 90 96 96 U U R . n
+B 2 91 G 91 97 97 G G R . n
+B 2 92 G 92 98 98 G G R . n
+C 3 1 G 1 1 1 G G A . n
+C 3 2 G 2 2 2 G G A . n
+#
+_pdbx_struct_assembly.id                       1
+_pdbx_struct_assembly.details                  author_and_software_defined_assembly
+_pdbx_struct_assembly.method_details           PISA
+_pdbx_struct_assembly.oligomeric_details       trimeric
+_pdbx_struct_assembly.oligomeric_count         3
+#
+_pdbx_struct_assembly_gen.assembly_id           1
+_pdbx_struct_assembly_gen.oper_expression       1
+_pdbx_struct_assembly_gen.asym_id_list          A,E,B,D,F,C,G
+#
+loop_
+_pdbx_struct_assembly_prop.biol_id       
+_pdbx_struct_assembly_prop.type          
+_pdbx_struct_assembly_prop.value         
+_pdbx_struct_assembly_prop.details       
+1 "ABSA (A^2)" 3630 ?
+1 "SSA (A^2)" 18700 ?
+1 MORE -22 ?
+#
+_pdbx_struct_oper_list.id                       1
+_pdbx_struct_oper_list.type                     "identity operation"
+_pdbx_struct_oper_list.name                     1_555
+_pdbx_struct_oper_list.symmetry_operation       x,y,z
+_pdbx_struct_oper_list.matrix[1][1]             1.0000000000
+_pdbx_struct_oper_list.matrix[1][2]             0.0000000000
+_pdbx_struct_oper_list.matrix[1][3]             0.0000000000
+_pdbx_struct_oper_list.vector[1]                0.0000000000
+_pdbx_struct_oper_list.matrix[2][1]             0.0000000000
+_pdbx_struct_oper_list.matrix[2][2]             1.0000000000
+_pdbx_struct_oper_list.matrix[2][3]             0.0000000000
+_pdbx_struct_oper_list.vector[2]                0.0000000000
+_pdbx_struct_oper_list.matrix[3][1]             0.0000000000
+_pdbx_struct_oper_list.matrix[3][2]             0.0000000000
+_pdbx_struct_oper_list.matrix[3][3]             1.0000000000
+_pdbx_struct_oper_list.vector[3]                0.0000000000
+#
+loop_
+_ndb_struct_conf_na.entry_id       
+_ndb_struct_conf_na.feature        
+3UCU "double helix"
+3UCU "a-form double helix"
+3UCU tetraloop
+3UCU "bulge loop"
+3UCU "mismatched base pair"
+3UCU "triple helix"
+3UCU "quadruple helix"
+#
+loop_
+_ndb_struct_na_base_pair.model_number          
+_ndb_struct_na_base_pair.i_label_asym_id       
+_ndb_struct_na_base_pair.i_label_comp_id       
+_ndb_struct_na_base_pair.i_label_seq_id        
+_ndb_struct_na_base_pair.i_symmetry            
+_ndb_struct_na_base_pair.j_label_asym_id       
+_ndb_struct_na_base_pair.j_label_comp_id       
+_ndb_struct_na_base_pair.j_label_seq_id        
+_ndb_struct_na_base_pair.j_symmetry            
+_ndb_struct_na_base_pair.shear                 
+_ndb_struct_na_base_pair.stretch               
+_ndb_struct_na_base_pair.stagger               
+_ndb_struct_na_base_pair.buckle                
+_ndb_struct_na_base_pair.opening               
+_ndb_struct_na_base_pair.pair_number           
+_ndb_struct_na_base_pair.pair_name             
+_ndb_struct_na_base_pair.i_auth_asym_id        
+_ndb_struct_na_base_pair.i_auth_seq_id         
+_ndb_struct_na_base_pair.i_PDB_ins_code        
+_ndb_struct_na_base_pair.j_auth_asym_id        
+_ndb_struct_na_base_pair.j_auth_seq_id         
+_ndb_struct_na_base_pair.j_PDB_ins_code        
+_ndb_struct_na_base_pair.hbond_type_28         
+_ndb_struct_na_base_pair.hbond_type_12         
+1 B C 4 1_555 B G 92 1_555 0.187 0.071 0.337 9.615 -4.537 1 R_C11:G98_R R 11 ? R 98 ? 19 1
+1 B A 5 1_555 B G 91 1_555 0.554 1.617 -0.349 -16.822 -13.950 2 R_A12:G97_R R 12 ? R 97 ? 8 1
+1 B C 6 1_555 B G 88 1_555 -0.469 0.137 0.622 -20.707 -0.472 3 R_C13:G94_R R 13 ? R 94 ? 19 1
+1 B G 7 1_555 B C 87 1_555 0.184 0.135 0.584 4.716 -2.629 4 R_G14:C93_R R 14 ? R 93 ? 19 1
+1 C G 2 1_555 B C 86 1_555 0.338 0.113 -0.078 -4.607 5.538 5 A_G2:C92_R A 2 ? R 92 ? 19 1
+1 B G 12 1_555 B A 40 1_555 0.069 2.921 -0.085 -9.047 -51.751 6 R_G19:A47_R R 19 ? R 47 ? ? ?
+1 B G 13 1_555 C G 1 1_555 5.879 -0.700 -0.221 4.712 -110.433 7 R_G20:G1_A R 20 ? A 1 ? 7 4
+1 B G 14 1_555 B C 39 1_555 -0.212 0.039 -0.260 0.652 3.393 8 R_G21:C46_R R 21 ? R 46 ? 19 1
+1 B C 15 1_555 B G 38 1_555 0.173 -0.070 -0.159 9.064 3.213 9 R_C22:G45_R R 22 ? R 45 ? 19 1
+1 B G 77 1_555 B C 37 1_555 -0.330 -0.198 0.543 2.720 -5.761 10 R_G83:C44_R R 83 ? R 44 ? 19 1
+1 B A 18 1_555 B G 35 1_555 -6.754 -3.553 0.197 0.918 -0.465 11 R_A25:G42_R R 25 ? R 42 ? 11 9
+1 B C 19 1_555 B G 34 1_555 0.349 0.134 -0.325 10.614 1.783 12 R_C26:G41_R R 26 ? R 41 ? 19 1
+1 B C 20 1_555 B G 33 1_555 -0.075 -0.115 -0.112 8.320 1.321 13 R_C27:G40_R R 27 ? R 40 ? 19 1
+1 B A 21 1_555 B U 32 1_555 0.038 -0.172 0.059 1.620 5.470 14 R_A28:U39_R R 28 ? R 39 ? 20 1
+1 B U 22 1_555 B G 31 1_555 2.342 -0.524 -0.039 4.583 6.387 15 R_U29:G38_R R 29 ? R 38 ? 28 1
+1 B U 23 1_555 B A 30 1_555 0.476 -0.302 -0.019 -2.641 0.821 16 R_U30:A37_R R 30 ? R 37 ? 20 1
+1 B C 24 1_555 B G 29 1_555 0.436 -0.355 -0.148 3.903 -0.692 17 R_C31:G36_R R 31 ? R 36 ? 19 1
+1 B A 41 1_555 B U 84 1_555 -4.304 -2.416 -0.153 10.581 -89.980 18 R_A48:U90_R R 48 ? R 90 ? 24 4
+1 B G 43 1_555 B U 83 1_555 -2.395 -0.696 -0.297 -3.035 -4.662 19 R_G50:U89_R R 50 ? R 89 ? 28 1
+1 B C 44 1_555 B G 82 1_555 0.469 -0.285 -0.089 5.423 1.247 20 R_C51:G88_R R 51 ? R 88 ? 19 1
+1 B C 45 1_555 B G 81 1_555 0.087 -0.116 0.215 -1.792 1.383 21 R_C52:G87_R R 52 ? R 87 ? 19 1
+1 B C 47 1_555 B G 80 1_555 0.004 -0.104 -0.573 18.342 2.114 22 R_C54:G86_R R 54 ? R 86 ? 19 1
+1 B C 48 1_555 B G 79 1_555 0.240 -0.185 -0.103 3.870 -2.273 23 R_C55:G85_R R 55 ? R 85 ? 19 1
+1 B G 49 1_555 B C 78 1_555 -0.983 -0.389 0.218 8.779 0.707 24 R_G56:C84_R R 56 ? R 84 ? 19 1
+1 B G 50 1_555 B U 75 1_555 -1.511 -0.373 0.226 4.965 -5.608 25 R_G57:U81_R R 57 ? R 81 ? 28 1
+1 B C 51 1_555 B G 74 1_555 0.524 -0.235 0.049 12.425 3.189 26 R_C58:G80_R R 58 ? R 80 ? 19 1
+1 B C 52 1_555 B G 73 1_555 -0.007 -0.140 -0.228 3.193 -0.027 27 R_C59:G79_R R 59 ? R 79 ? 19 1
+1 B U 53 1_555 B A 72 1_555 0.250 -0.214 0.217 -5.026 -3.180 28 R_U60:A78_R R 60 ? R 78 ? 20 1
+1 B A 54 1_555 B U 71 1_555 1.394 -0.134 0.318 12.201 -3.591 29 R_A61:U77_R R 61 ? R 77 ? 20 1
+1 B C 57 1_555 B G 70 1_555 -0.041 -0.090 -0.669 18.961 6.074 30 R_C64:G76_R R 64 ? R 76 ? 19 1
+1 B C 58 1_555 B G 69 1_555 1.086 -0.174 0.344 -10.081 9.716 31 R_C65:G75_R R 65 ? R 75 ? 19 1
+#
+loop_
+_ndb_struct_na_base_pair_step.model_number            
+_ndb_struct_na_base_pair_step.i_label_asym_id_1       
+_ndb_struct_na_base_pair_step.i_label_comp_id_1       
+_ndb_struct_na_base_pair_step.i_label_seq_id_1        
+_ndb_struct_na_base_pair_step.i_symmetry_1            
+_ndb_struct_na_base_pair_step.j_label_asym_id_1       
+_ndb_struct_na_base_pair_step.j_label_comp_id_1       
+_ndb_struct_na_base_pair_step.j_label_seq_id_1        
+_ndb_struct_na_base_pair_step.j_symmetry_1            
+_ndb_struct_na_base_pair_step.i_label_asym_id_2       
+_ndb_struct_na_base_pair_step.i_label_comp_id_2       
+_ndb_struct_na_base_pair_step.i_label_seq_id_2        
+_ndb_struct_na_base_pair_step.i_symmetry_2            
+_ndb_struct_na_base_pair_step.j_label_asym_id_2       
+_ndb_struct_na_base_pair_step.j_label_comp_id_2       
+_ndb_struct_na_base_pair_step.j_label_seq_id_2        
+_ndb_struct_na_base_pair_step.j_symmetry_2            
+_ndb_struct_na_base_pair_step.shift                   
+_ndb_struct_na_base_pair_step.slide                   
+_ndb_struct_na_base_pair_step.rise                    
+_ndb_struct_na_base_pair_step.tilt                    
+_ndb_struct_na_base_pair_step.roll                    
+_ndb_struct_na_base_pair_step.twist                   
+_ndb_struct_na_base_pair_step.x_displacement          
+_ndb_struct_na_base_pair_step.y_displacement          
+_ndb_struct_na_base_pair_step.helical_rise            
+_ndb_struct_na_base_pair_step.inclination             
+_ndb_struct_na_base_pair_step.tip                     
+_ndb_struct_na_base_pair_step.helical_twist           
+_ndb_struct_na_base_pair_step.step_number             
+_ndb_struct_na_base_pair_step.step_name               
+_ndb_struct_na_base_pair_step.i_auth_asym_id_1        
+_ndb_struct_na_base_pair_step.i_auth_seq_id_1         
+_ndb_struct_na_base_pair_step.i_PDB_ins_code_1        
+_ndb_struct_na_base_pair_step.j_auth_asym_id_1        
+_ndb_struct_na_base_pair_step.j_auth_seq_id_1         
+_ndb_struct_na_base_pair_step.j_PDB_ins_code_1        
+_ndb_struct_na_base_pair_step.i_auth_asym_id_2        
+_ndb_struct_na_base_pair_step.i_auth_seq_id_2         
+_ndb_struct_na_base_pair_step.i_PDB_ins_code_2        
+_ndb_struct_na_base_pair_step.j_auth_asym_id_2        
+_ndb_struct_na_base_pair_step.j_auth_seq_id_2         
+_ndb_struct_na_base_pair_step.j_PDB_ins_code_2        
+1 B C 4 1_555 B G 92 1_555 B A 5 1_555 B G 91 1_555 0.329 -2.498 3.630 9.758 10.984 33.904 -5.459 0.820 2.710 17.833 -15.843 36.865 1 RR_C11A12:G97G98_RR R 11 ? R 98 ? R 12 ? R 97 ?
+1 B A 5 1_555 B G 91 1_555 B C 6 1_555 B G 88 1_555 2.181 -0.463 3.134 -0.142 6.202 41.158 -1.274 -3.085 3.029 8.762 0.201 41.602 2 RR_A12C13:G94G97_RR R 12 ? R 97 ? R 13 ? R 94 ?
+1 B C 6 1_555 B G 88 1_555 B G 7 1_555 B C 87 1_555 -1.045 -0.668 2.711 -5.009 16.791 28.698 -3.381 1.148 2.155 30.546 9.113 33.529 3 RR_C13G14:C93G94_RR R 13 ? R 94 ? R 14 ? R 93 ?
+1 B G 7 1_555 B C 87 1_555 C G 2 1_555 B C 86 1_555 -0.505 -1.440 3.425 1.406 5.304 40.341 -2.667 0.884 3.199 7.647 -2.027 40.697 4 RA_G14G2:C92C93_RR R 14 ? R 93 ? A 2 ? R 92 ?
+1 C G 2 1_555 B C 86 1_555 B G 12 1_555 B A 40 1_555 -2.554 3.400 3.088 -3.965 -4.060 117.011 2.032 1.459 3.067 -2.380 2.324 117.097 5 AR_G2G19:A47C92_RR A 2 ? R 92 ? R 19 ? R 47 ?
+1 B G 12 1_555 B A 40 1_555 B G 13 1_555 C G 1 1_555 -0.492 -2.731 3.149 -3.804 -0.002 46.167 -3.472 0.313 3.178 -0.003 4.842 46.315 6 RR_G19G20:G1A47_AR R 19 ? R 47 ? R 20 ? A 1 ?
+1 B G 13 1_555 C G 1 1_555 B G 14 1_555 B C 39 1_555 1.693 -1.439 3.386 0.537 0.911 -25.650 2.973 3.968 3.399 -2.052 1.208 -25.671 7 RR_G20G21:C46G1_RA R 20 ? A 1 ? R 21 ? R 46 ?
+1 B G 14 1_555 B C 39 1_555 B C 15 1_555 B G 38 1_555 0.330 -1.786 3.197 -1.954 0.154 31.912 -3.269 -0.944 3.163 0.281 3.550 31.971 8 RR_G21C22:G45C46_RR R 21 ? R 46 ? R 22 ? R 45 ?
+1 B C 15 1_555 B G 38 1_555 B G 77 1_555 B C 37 1_555 -5.423 -0.104 3.649 -12.294 -7.086 57.603 0.358 4.688 4.601 -7.234 12.551 59.179 9 RR_C22G83:C44G45_RR R 22 ? R 45 ? R 83 ? R 44 ?
+1 B A 18 1_555 B G 35 1_555 B C 19 1_555 B G 34 1_555 -0.219 -0.737 3.219 -2.754 6.282 61.924 -0.993 0.089 3.145 6.085 2.667 62.265 10 RR_A25C26:G41G42_RR R 25 ? R 42 ? R 26 ? R 41 ?
+1 B C 19 1_555 B G 34 1_555 B C 20 1_555 B G 33 1_555 -0.032 -1.880 3.288 -2.423 7.796 27.616 -5.406 -0.441 2.662 15.896 4.940 28.775 11 RR_C26C27:G40G41_RR R 26 ? R 41 ? R 27 ? R 40 ?
+1 B C 20 1_555 B G 33 1_555 B A 21 1_555 B U 32 1_555 0.231 -1.453 3.239 2.570 15.815 34.600 -4.050 -0.059 2.386 24.998 -4.062 38.027 12 RR_C27A28:U39G40_RR R 27 ? R 40 ? R 28 ? R 39 ?
+1 B A 21 1_555 B U 32 1_555 B U 22 1_555 B G 31 1_555 0.346 -0.978 3.140 2.582 10.221 39.782 -2.423 -0.232 2.831 14.709 -3.716 41.101 13 RR_A28U29:G38U39_RR R 28 ? R 39 ? R 29 ? R 38 ?
+1 B U 22 1_555 B G 31 1_555 B U 23 1_555 B A 30 1_555 -0.154 -1.916 3.126 3.332 10.226 26.693 -5.809 0.945 2.220 21.092 -6.873 28.742 14 RR_U29U30:A37G38_RR R 29 ? R 38 ? R 30 ? R 37 ?
+1 B U 23 1_555 B A 30 1_555 B C 24 1_555 B G 29 1_555 0.069 -1.598 3.105 1.614 6.134 29.658 -4.171 0.160 2.727 11.813 -3.108 30.313 15 RR_U30C31:G36A37_RR R 30 ? R 37 ? R 31 ? R 36 ?
+1 B A 41 1_555 B U 84 1_555 B G 43 1_555 B U 83 1_555 3.254 -2.249 3.664 -7.112 11.087 64.527 -2.535 -3.295 2.952 10.272 6.590 65.715 16 RR_A48G50:U89U90_RR R 48 ? R 90 ? R 50 ? R 89 ?
+1 B G 43 1_555 B U 83 1_555 B C 44 1_555 B G 82 1_555 0.267 -1.337 3.055 -3.574 4.044 42.574 -2.194 -0.690 2.892 5.543 4.899 42.899 17 RR_G50C51:G88U89_RR R 50 ? R 89 ? R 51 ? R 88 ?
+1 B C 44 1_555 B G 82 1_555 B C 45 1_555 B G 81 1_555 -0.010 -1.850 3.412 1.493 7.127 32.866 -4.342 0.257 2.954 12.406 -2.599 33.641 18 RR_C51C52:G87G88_RR R 51 ? R 88 ? R 52 ? R 87 ?
+1 B C 45 1_555 B G 81 1_555 B C 47 1_555 B G 80 1_555 -2.806 -1.058 2.913 11.418 5.518 51.856 -1.457 3.703 2.179 6.204 -12.838 53.280 19 RR_C52C54:G86G87_RR R 52 ? R 87 ? R 54 ? R 86 ?
+1 B C 47 1_555 B G 80 1_555 B C 48 1_555 B G 79 1_555 -0.843 -2.031 3.701 -4.921 10.685 34.219 -4.875 0.622 3.040 17.529 8.073 36.128 20 RR_C54C55:G85G86_RR R 54 ? R 86 ? R 55 ? R 85 ?
+1 B C 48 1_555 B G 79 1_555 B G 49 1_555 B C 78 1_555 0.175 -2.414 2.994 -3.793 6.575 19.300 -8.968 -1.788 2.000 18.701 10.789 20.726 21 RR_C55G56:C84G85_RR R 55 ? R 85 ? R 56 ? R 84 ?
+1 B G 49 1_555 B C 78 1_555 B G 50 1_555 B U 75 1_555 1.981 -1.778 3.113 0.112 6.738 49.194 -2.573 -2.352 2.866 8.050 -0.134 49.625 22 RR_G56G57:U81C84_RR R 56 ? R 84 ? R 57 ? R 81 ?
+1 B G 50 1_555 B U 75 1_555 B C 51 1_555 B G 74 1_555 0.406 -1.299 3.135 -2.152 3.525 40.540 -2.231 -0.806 2.992 5.071 3.095 40.741 23 RR_G57C58:G80U81_RR R 57 ? R 81 ? R 58 ? R 80 ?
+1 B C 51 1_555 B G 74 1_555 B C 52 1_555 B G 73 1_555 -0.649 -2.133 3.384 -0.838 7.242 27.415 -5.952 1.140 2.760 14.947 1.730 28.349 24 RR_C58C59:G79G80_RR R 58 ? R 80 ? R 59 ? R 79 ?
+1 B C 52 1_555 B G 73 1_555 B U 53 1_555 B A 72 1_555 -0.312 -2.050 3.572 -1.941 9.883 31.032 -5.378 0.217 2.817 17.891 3.513 32.587 25 RR_C59U60:A78G79_RR R 59 ? R 79 ? R 60 ? R 78 ?
+1 B U 53 1_555 B A 72 1_555 B A 54 1_555 B U 71 1_555 -0.076 -1.637 2.879 2.700 14.724 27.674 -5.130 0.526 1.786 28.311 -5.191 31.394 26 RR_U60A61:U77A78_RR R 60 ? R 78 ? R 61 ? R 77 ?
+1 B A 54 1_555 B U 71 1_555 B C 57 1_555 B G 70 1_555 -4.249 0.516 3.328 10.983 2.181 69.865 0.375 4.032 2.733 1.892 -9.528 70.643 27 RR_A61C64:G76U77_RR R 61 ? R 77 ? R 64 ? R 76 ?
+1 B C 57 1_555 B G 70 1_555 B C 58 1_555 B G 69 1_555 -0.004 -1.520 3.987 -6.292 13.783 37.819 -3.943 -0.796 3.225 20.297 9.267 40.638 28 RR_C64C65:G75G76_RR R 64 ? R 76 ? R 65 ? R 75 ?
+#
+loop_
+_software.name                 
+_software.classification       
+_software.version              
+_software.citation_id          
+_software.pdbx_ordinal         
+CBASS "data collection" . ? 1
+Phaser "model building" . ? 2
+REFMAC refinement 5.5.0109 ? 3
+#
+loop_
+_pdbx_unobs_or_zero_occ_residues.id                   
+_pdbx_unobs_or_zero_occ_residues.polymer_flag         
+_pdbx_unobs_or_zero_occ_residues.occupancy_flag       
+_pdbx_unobs_or_zero_occ_residues.PDB_model_num        
+_pdbx_unobs_or_zero_occ_residues.auth_asym_id         
+_pdbx_unobs_or_zero_occ_residues.auth_comp_id         
+_pdbx_unobs_or_zero_occ_residues.auth_seq_id          
+_pdbx_unobs_or_zero_occ_residues.PDB_ins_code         
+1 Y 1 1 P MET 1 ?
+2 Y 1 1 P ALA 2 ?
+3 Y 1 1 P VAL 3 ?
+4 Y 1 1 P PRO 4 ?
+5 Y 1 1 P GLU 5 ?
+6 Y 1 1 P THR 6 ?
+7 Y 1 1 P ILE 94 ?
+8 Y 1 1 P ALA 95 ?
+9 Y 1 1 P LYS 96 ?
+10 Y 1 1 P MET 97 ?
+11 Y 1 1 P LYS 98 ?
+#
+loop_
+_pdbx_nonpoly_scheme.asym_id             
+_pdbx_nonpoly_scheme.entity_id           
+_pdbx_nonpoly_scheme.mon_id              
+_pdbx_nonpoly_scheme.ndb_seq_num         
+_pdbx_nonpoly_scheme.pdb_seq_num         
+_pdbx_nonpoly_scheme.auth_seq_num        
+_pdbx_nonpoly_scheme.pdb_mon_id          
+_pdbx_nonpoly_scheme.auth_mon_id         
+_pdbx_nonpoly_scheme.pdb_strand_id       
+_pdbx_nonpoly_scheme.pdb_ins_code        
+D 4 MG 1 1 1 MG MO6 R .
+E 5 HOH 1 99 1 HOH HOH P .
+E 5 HOH 2 100 2 HOH HOH P .
+E 5 HOH 3 101 7 HOH HOH P .
+F 5 HOH 1 3 3 HOH HOH R .
+F 5 HOH 2 4 4 HOH HOH R .
+F 5 HOH 3 5 5 HOH HOH R .
+F 5 HOH 4 670 8 HOH HOH R .
+F 5 HOH 5 671 9 HOH HOH R .
+F 5 HOH 6 672 10 HOH HOH R .
+F 5 HOH 7 673 1 HOH MO6 R .
+F 5 HOH 8 674 1 HOH MO6 R .
+F 5 HOH 9 675 1 HOH MO6 R .
+F 5 HOH 10 676 1 HOH MO6 R .
+G 5 HOH 1 3 1 HOH MO6 A .
+#
+_pdbx_struct_mod_residue.id                   1
+_pdbx_struct_mod_residue.label_asym_id        B
+_pdbx_struct_mod_residue.label_seq_id         1
+_pdbx_struct_mod_residue.label_comp_id        GTP
+_pdbx_struct_mod_residue.auth_asym_id         R
+_pdbx_struct_mod_residue.auth_seq_id          8
+_pdbx_struct_mod_residue.auth_comp_id         GTP
+_pdbx_struct_mod_residue.PDB_ins_code         ?
+_pdbx_struct_mod_residue.parent_comp_id       G
+_pdbx_struct_mod_residue.details              "GUANOSINE-5'-TRIPHOSPHATE"
+#
+_pdbx_validate_rmsd_bond.id                   1
+_pdbx_validate_rmsd_bond.PDB_model_num        1
+_pdbx_validate_rmsd_bond.auth_atom_id_1       P
+_pdbx_validate_rmsd_bond.auth_asym_id_1       A
+_pdbx_validate_rmsd_bond.auth_comp_id_1       G
+_pdbx_validate_rmsd_bond.auth_seq_id_1        1
+_pdbx_validate_rmsd_bond.PDB_ins_code_1       ?
+_pdbx_validate_rmsd_bond.label_alt_id_1       ?
+_pdbx_validate_rmsd_bond.auth_atom_id_2       OP3
+_pdbx_validate_rmsd_bond.auth_asym_id_2       A
+_pdbx_validate_rmsd_bond.auth_comp_id_2       G
+_pdbx_validate_rmsd_bond.auth_seq_id_2        1
+_pdbx_validate_rmsd_bond.PDB_ins_code_2       ?
+_pdbx_validate_rmsd_bond.label_alt_id_2       ?
+_pdbx_validate_rmsd_bond.bond_deviation       -0.127
+#
+loop_
+_pdbx_validate_rmsd_angle.id                    
+_pdbx_validate_rmsd_angle.PDB_model_num         
+_pdbx_validate_rmsd_angle.auth_atom_id_1        
+_pdbx_validate_rmsd_angle.auth_asym_id_1        
+_pdbx_validate_rmsd_angle.auth_comp_id_1        
+_pdbx_validate_rmsd_angle.auth_seq_id_1         
+_pdbx_validate_rmsd_angle.PDB_ins_code_1        
+_pdbx_validate_rmsd_angle.label_alt_id_1        
+_pdbx_validate_rmsd_angle.auth_atom_id_2        
+_pdbx_validate_rmsd_angle.auth_asym_id_2        
+_pdbx_validate_rmsd_angle.auth_comp_id_2        
+_pdbx_validate_rmsd_angle.auth_seq_id_2         
+_pdbx_validate_rmsd_angle.PDB_ins_code_2        
+_pdbx_validate_rmsd_angle.label_alt_id_2        
+_pdbx_validate_rmsd_angle.auth_atom_id_3        
+_pdbx_validate_rmsd_angle.auth_asym_id_3        
+_pdbx_validate_rmsd_angle.auth_comp_id_3        
+_pdbx_validate_rmsd_angle.auth_seq_id_3         
+_pdbx_validate_rmsd_angle.PDB_ins_code_3        
+_pdbx_validate_rmsd_angle.label_alt_id_3        
+_pdbx_validate_rmsd_angle.angle_deviation       
+1 1 "O4'" R A 48 ? ? "C1'" R A 48 ? ? N9 R A 48 ? ? 5.2
+2 1 OP1 A G 1 ? ? P A G 1 ? ? OP2 A G 1 ? ? -12.1
+#
+_pdbx_validate_torsion.id                  1
+_pdbx_validate_torsion.PDB_model_num       1
+_pdbx_validate_torsion.auth_comp_id        ASP
+_pdbx_validate_torsion.auth_asym_id        P
+_pdbx_validate_torsion.auth_seq_id         92
+_pdbx_validate_torsion.PDB_ins_code        ?
+_pdbx_validate_torsion.phi                 74.40
+_pdbx_validate_torsion.psi                 -158.21
+#
+loop_
+_pdbx_entity_nonpoly.entity_id       
+_pdbx_entity_nonpoly.name            
+_pdbx_entity_nonpoly.comp_id         
+4 "MAGNESIUM ION" MG
+5 water HOH
+#
+loop_
+_chem_comp_bond.comp_id                  
+_chem_comp_bond.pdbx_stereo_config       
+_chem_comp_bond.pdbx_ordinal             
+_chem_comp_bond.pdbx_aromatic_flag       
+_chem_comp_bond.atom_id_1                
+_chem_comp_bond.atom_id_2                
+_chem_comp_bond.value_order              
+ARG N 1 N N CA SING
+ARG N 2 N N H SING
+ARG N 3 N N H2 SING
+ARG N 4 N CA C SING
+ARG N 5 N CA CB SING
+ARG N 6 N CA HA SING
+ARG N 7 N C O DOUB
+ARG N 8 N C OXT SING
+ARG N 9 N CB CG SING
+ARG N 10 N CB HB2 SING
+ARG N 11 N CB HB3 SING
+ARG N 12 N CG CD SING
+ARG N 13 N CG HG2 SING
+ARG N 14 N CG HG3 SING
+ARG N 15 N CD NE SING
+ARG N 16 N CD HD2 SING
+ARG N 17 N CD HD3 SING
+ARG N 18 N NE CZ SING
+ARG N 19 N NE HE SING
+ARG N 20 N CZ NH1 SING
+ARG N 21 N CZ NH2 DOUB
+ARG N 22 N NH1 HH11 SING
+ARG N 23 N NH1 HH12 SING
+ARG N 24 N NH2 HH21 SING
+ARG N 25 N NH2 HH22 SING
+ARG N 26 N OXT HXT SING
+PRO N 1 N N CA SING
+PRO N 2 N N CD SING
+PRO N 3 N N H SING
+PRO N 4 N CA C SING
+PRO N 5 N CA CB SING
+PRO N 6 N CA HA SING
+PRO N 7 N C O DOUB
+PRO N 8 N C OXT SING
+PRO N 9 N CB CG SING
+PRO N 10 N CB HB2 SING
+PRO N 11 N CB HB3 SING
+PRO N 12 N CG CD SING
+PRO N 13 N CG HG2 SING
+PRO N 14 N CG HG3 SING
+PRO N 15 N CD HD2 SING
+PRO N 16 N CD HD3 SING
+PRO N 17 N OXT HXT SING
+ASN N 1 N N CA SING
+ASN N 2 N N H SING
+ASN N 3 N N H2 SING
+ASN N 4 N CA C SING
+ASN N 5 N CA CB SING
+ASN N 6 N CA HA SING
+ASN N 7 N C O DOUB
+ASN N 8 N C OXT SING
+ASN N 9 N CB CG SING
+ASN N 10 N CB HB2 SING
+ASN N 11 N CB HB3 SING
+ASN N 12 N CG OD1 DOUB
+ASN N 13 N CG ND2 SING
+ASN N 14 N ND2 HD21 SING
+ASN N 15 N ND2 HD22 SING
+ASN N 16 N OXT HXT SING
+HIS N 1 N N CA SING
+HIS N 2 N N H SING
+HIS N 3 N N H2 SING
+HIS N 4 N CA C SING
+HIS N 5 N CA CB SING
+HIS N 6 N CA HA SING
+HIS N 7 N C O DOUB
+HIS N 8 N C OXT SING
+HIS N 9 N CB CG SING
+HIS N 10 N CB HB2 SING
+HIS N 11 N CB HB3 SING
+HIS N 12 Y CG ND1 SING
+HIS N 13 Y CG CD2 DOUB
+HIS N 14 Y ND1 CE1 DOUB
+HIS N 15 N ND1 HD1 SING
+HIS N 16 Y CD2 NE2 SING
+HIS N 17 N CD2 HD2 SING
+HIS N 18 Y CE1 NE2 SING
+HIS N 19 N CE1 HE1 SING
+HIS N 20 N NE2 HE2 SING
+HIS N 21 N OXT HXT SING
+THR N 1 N N CA SING
+THR N 2 N N H SING
+THR N 3 N N H2 SING
+THR N 4 N CA C SING
+THR N 5 N CA CB SING
+THR N 6 N CA HA SING
+THR N 7 N C O DOUB
+THR N 8 N C OXT SING
+THR N 9 N CB OG1 SING
+THR N 10 N CB CG2 SING
+THR N 11 N CB HB SING
+THR N 12 N OG1 HG1 SING
+THR N 13 N CG2 HG21 SING
+THR N 14 N CG2 HG22 SING
+THR N 15 N CG2 HG23 SING
+THR N 16 N OXT HXT SING
+ILE N 1 N N CA SING
+ILE N 2 N N H SING
+ILE N 3 N N H2 SING
+ILE N 4 N CA C SING
+ILE N 5 N CA CB SING
+ILE N 6 N CA HA SING
+ILE N 7 N C O DOUB
+ILE N 8 N C OXT SING
+ILE N 9 N CB CG1 SING
+ILE N 10 N CB CG2 SING
+ILE N 11 N CB HB SING
+ILE N 12 N CG1 CD1 SING
+ILE N 13 N CG1 HG12 SING
+ILE N 14 N CG1 HG13 SING
+ILE N 15 N CG2 HG21 SING
+ILE N 16 N CG2 HG22 SING
+ILE N 17 N CG2 HG23 SING
+ILE N 18 N CD1 HD11 SING
+ILE N 19 N CD1 HD12 SING
+ILE N 20 N CD1 HD13 SING
+ILE N 21 N OXT HXT SING
+TYR N 1 N N CA SING
+TYR N 2 N N H SING
+TYR N 3 N N H2 SING
+TYR N 4 N CA C SING
+TYR N 5 N CA CB SING
+TYR N 6 N CA HA SING
+TYR N 7 N C O DOUB
+TYR N 8 N C OXT SING
+TYR N 9 N CB CG SING
+TYR N 10 N CB HB2 SING
+TYR N 11 N CB HB3 SING
+TYR N 12 Y CG CD1 DOUB
+TYR N 13 Y CG CD2 SING
+TYR N 14 Y CD1 CE1 SING
+TYR N 15 N CD1 HD1 SING
+TYR N 16 Y CD2 CE2 DOUB
+TYR N 17 N CD2 HD2 SING
+TYR N 18 Y CE1 CZ DOUB
+TYR N 19 N CE1 HE1 SING
+TYR N 20 Y CE2 CZ SING
+TYR N 21 N CE2 HE2 SING
+TYR N 22 N CZ OH SING
+TYR N 23 N OH HH SING
+TYR N 24 N OXT HXT SING
+LEU N 1 N N CA SING
+LEU N 2 N N H SING
+LEU N 3 N N H2 SING
+LEU N 4 N CA C SING
+LEU N 5 N CA CB SING
+LEU N 6 N CA HA SING
+LEU N 7 N C O DOUB
+LEU N 8 N C OXT SING
+LEU N 9 N CB CG SING
+LEU N 10 N CB HB2 SING
+LEU N 11 N CB HB3 SING
+LEU N 12 N CG CD1 SING
+LEU N 13 N CG CD2 SING
+LEU N 14 N CG HG SING
+LEU N 15 N CD1 HD11 SING
+LEU N 16 N CD1 HD12 SING
+LEU N 17 N CD1 HD13 SING
+LEU N 18 N CD2 HD21 SING
+LEU N 19 N CD2 HD22 SING
+LEU N 20 N CD2 HD23 SING
+LEU N 21 N OXT HXT SING
+GLU N 1 N N CA SING
+GLU N 2 N N H SING
+GLU N 3 N N H2 SING
+GLU N 4 N CA C SING
+GLU N 5 N CA CB SING
+GLU N 6 N CA HA SING
+GLU N 7 N C O DOUB
+GLU N 8 N C OXT SING
+GLU N 9 N CB CG SING
+GLU N 10 N CB HB2 SING
+GLU N 11 N CB HB3 SING
+GLU N 12 N CG CD SING
+GLU N 13 N CG HG2 SING
+GLU N 14 N CG HG3 SING
+GLU N 15 N CD OE1 DOUB
+GLU N 16 N CD OE2 SING
+GLU N 17 N OE2 HE2 SING
+GLU N 18 N OXT HXT SING
+LYS N 1 N N CA SING
+LYS N 2 N N H SING
+LYS N 3 N N H2 SING
+LYS N 4 N CA C SING
+LYS N 5 N CA CB SING
+LYS N 6 N CA HA SING
+LYS N 7 N C O DOUB
+LYS N 8 N C OXT SING
+LYS N 9 N CB CG SING
+LYS N 10 N CB HB2 SING
+LYS N 11 N CB HB3 SING
+LYS N 12 N CG CD SING
+LYS N 13 N CG HG2 SING
+LYS N 14 N CG HG3 SING
+LYS N 15 N CD CE SING
+LYS N 16 N CD HD2 SING
+LYS N 17 N CD HD3 SING
+LYS N 18 N CE NZ SING
+LYS N 19 N CE HE2 SING
+LYS N 20 N CE HE3 SING
+LYS N 21 N NZ HZ1 SING
+LYS N 22 N NZ HZ2 SING
+LYS N 23 N NZ HZ3 SING
+LYS N 24 N OXT HXT SING
+ASP N 1 N N CA SING
+ASP N 2 N N H SING
+ASP N 3 N N H2 SING
+ASP N 4 N CA C SING
+ASP N 5 N CA CB SING
+ASP N 6 N CA HA SING
+ASP N 7 N C O DOUB
+ASP N 8 N C OXT SING
+ASP N 9 N CB CG SING
+ASP N 10 N CB HB2 SING
+ASP N 11 N CB HB3 SING
+ASP N 12 N CG OD1 DOUB
+ASP N 13 N CG OD2 SING
+ASP N 14 N OD2 HD2 SING
+ASP N 15 N OXT HXT SING
+SER N 1 N N CA SING
+SER N 2 N N H SING
+SER N 3 N N H2 SING
+SER N 4 N CA C SING
+SER N 5 N CA CB SING
+SER N 6 N CA HA SING
+SER N 7 N C O DOUB
+SER N 8 N C OXT SING
+SER N 9 N CB OG SING
+SER N 10 N CB HB2 SING
+SER N 11 N CB HB3 SING
+SER N 12 N OG HG SING
+SER N 13 N OXT HXT SING
+ALA N 1 N N CA SING
+ALA N 2 N N H SING
+ALA N 3 N N H2 SING
+ALA N 4 N CA C SING
+ALA N 5 N CA CB SING
+ALA N 6 N CA HA SING
+ALA N 7 N C O DOUB
+ALA N 8 N C OXT SING
+ALA N 9 N CB HB1 SING
+ALA N 10 N CB HB2 SING
+ALA N 11 N CB HB3 SING
+ALA N 12 N OXT HXT SING
+PHE N 1 N N CA SING
+PHE N 2 N N H SING
+PHE N 3 N N H2 SING
+PHE N 4 N CA C SING
+PHE N 5 N CA CB SING
+PHE N 6 N CA HA SING
+PHE N 7 N C O DOUB
+PHE N 8 N C OXT SING
+PHE N 9 N CB CG SING
+PHE N 10 N CB HB2 SING
+PHE N 11 N CB HB3 SING
+PHE N 12 Y CG CD1 DOUB
+PHE N 13 Y CG CD2 SING
+PHE N 14 Y CD1 CE1 SING
+PHE N 15 N CD1 HD1 SING
+PHE N 16 Y CD2 CE2 DOUB
+PHE N 17 N CD2 HD2 SING
+PHE N 18 Y CE1 CZ DOUB
+PHE N 19 N CE1 HE1 SING
+PHE N 20 Y CE2 CZ SING
+PHE N 21 N CE2 HE2 SING
+PHE N 22 N CZ HZ SING
+PHE N 23 N OXT HXT SING
+GLY N 1 N N CA SING
+GLY N 2 N N H SING
+GLY N 3 N N H2 SING
+GLY N 4 N CA C SING
+GLY N 5 N CA HA2 SING
+GLY N 6 N CA HA3 SING
+GLY N 7 N C O DOUB
+GLY N 8 N C OXT SING
+GLY N 9 N OXT HXT SING
+GLN N 1 N N CA SING
+GLN N 2 N N H SING
+GLN N 3 N N H2 SING
+GLN N 4 N CA C SING
+GLN N 5 N CA CB SING
+GLN N 6 N CA HA SING
+GLN N 7 N C O DOUB
+GLN N 8 N C OXT SING
+GLN N 9 N CB CG SING
+GLN N 10 N CB HB2 SING
+GLN N 11 N CB HB3 SING
+GLN N 12 N CG CD SING
+GLN N 13 N CG HG2 SING
+GLN N 14 N CG HG3 SING
+GLN N 15 N CD OE1 DOUB
+GLN N 16 N CD NE2 SING
+GLN N 17 N NE2 HE21 SING
+GLN N 18 N NE2 HE22 SING
+GLN N 19 N OXT HXT SING
+VAL N 1 N N CA SING
+VAL N 2 N N H SING
+VAL N 3 N N H2 SING
+VAL N 4 N CA C SING
+VAL N 5 N CA CB SING
+VAL N 6 N CA HA SING
+VAL N 7 N C O DOUB
+VAL N 8 N C OXT SING
+VAL N 9 N CB CG1 SING
+VAL N 10 N CB CG2 SING
+VAL N 11 N CB HB SING
+VAL N 12 N CG1 HG11 SING
+VAL N 13 N CG1 HG12 SING
+VAL N 14 N CG1 HG13 SING
+VAL N 15 N CG2 HG21 SING
+VAL N 16 N CG2 HG22 SING
+VAL N 17 N CG2 HG23 SING
+VAL N 18 N OXT HXT SING
+MET N 1 N N CA SING
+MET N 2 N N H SING
+MET N 3 N N H2 SING
+MET N 4 N CA C SING
+MET N 5 N CA CB SING
+MET N 6 N CA HA SING
+MET N 7 N C O DOUB
+MET N 8 N C OXT SING
+MET N 9 N CB CG SING
+MET N 10 N CB HB2 SING
+MET N 11 N CB HB3 SING
+MET N 12 N CG SD SING
+MET N 13 N CG HG2 SING
+MET N 14 N CG HG3 SING
+MET N 15 N SD CE SING
+MET N 16 N CE HE1 SING
+MET N 17 N CE HE2 SING
+MET N 18 N CE HE3 SING
+MET N 19 N OXT HXT SING
+GTP N 1 N PG O1G DOUB
+GTP N 2 N PG O2G SING
+GTP N 3 N PG O3G SING
+GTP N 4 N PG O3B SING
+GTP N 5 N O2G HOG2 SING
+GTP N 6 N O3G HOG3 SING
+GTP N 7 N O3B PB SING
+GTP N 8 N PB O1B DOUB
+GTP N 9 N PB O2B SING
+GTP N 10 N PB O3A SING
+GTP N 11 N O2B HOB2 SING
+GTP N 12 N O3A PA SING
+GTP N 13 N PA O1A DOUB
+GTP N 14 N PA O2A SING
+GTP N 15 N PA "O5'" SING
+GTP N 16 N O2A HOA2 SING
+GTP N 17 N "O5'" "C5'" SING
+GTP N 18 N "C5'" "C4'" SING
+GTP N 19 N "C5'" "H5'" SING
+GTP N 20 N "C5'" "H5''" SING
+GTP N 21 N "C4'" "O4'" SING
+GTP N 22 N "C4'" "C3'" SING
+GTP N 23 N "C4'" "H4'" SING
+GTP N 24 N "O4'" "C1'" SING
+GTP N 25 N "C3'" "O3'" SING
+GTP N 26 N "C3'" "C2'" SING
+GTP N 27 N "C3'" "H3'" SING
+GTP N 28 N "O3'" "HO3'" SING
+GTP N 29 N "C2'" "O2'" SING
+GTP N 30 N "C2'" "C1'" SING
+GTP N 31 N "C2'" "H2'" SING
+GTP N 32 N "O2'" "HO2'" SING
+GTP N 33 N "C1'" N9 SING
+GTP N 34 N "C1'" "H1'" SING
+GTP N 35 Y N9 C8 SING
+GTP N 36 Y N9 C4 SING
+GTP N 37 Y C8 N7 DOUB
+GTP N 38 N C8 H8 SING
+GTP N 39 Y N7 C5 SING
+GTP N 40 N C5 C6 SING
+GTP N 41 Y C5 C4 DOUB
+GTP N 42 N C6 O6 DOUB
+GTP N 43 N C6 N1 SING
+GTP N 44 N N1 C2 SING
+GTP N 45 N N1 HN1 SING
+GTP N 46 N C2 N2 SING
+GTP N 47 N C2 N3 DOUB
+GTP N 48 N N2 HN21 SING
+GTP N 49 N N2 HN22 SING
+GTP N 50 N N3 C4 SING
+G N 1 N OP3 P SING
+G N 2 N OP3 HOP3 SING
+G N 3 N P OP1 DOUB
+G N 4 N P OP2 SING
+G N 5 N P "O5'" SING
+G N 6 N OP2 HOP2 SING
+G N 7 N "O5'" "C5'" SING
+G N 8 N "C5'" "C4'" SING
+G N 9 N "C5'" "H5'" SING
+G N 10 N "C5'" "H5''" SING
+G N 11 N "C4'" "O4'" SING
+G N 12 N "C4'" "C3'" SING
+G N 13 N "C4'" "H4'" SING
+G N 14 N "O4'" "C1'" SING
+G N 15 N "C3'" "O3'" SING
+G N 16 N "C3'" "C2'" SING
+G N 17 N "C3'" "H3'" SING
+G N 18 N "O3'" "HO3'" SING
+G N 19 N "C2'" "O2'" SING
+G N 20 N "C2'" "C1'" SING
+G N 21 N "C2'" "H2'" SING
+G N 22 N "O2'" "HO2'" SING
+G N 23 N "C1'" N9 SING
+G N 24 N "C1'" "H1'" SING
+G N 25 Y N9 C8 SING
+G N 26 Y N9 C4 SING
+G N 27 Y C8 N7 DOUB
+G N 28 N C8 H8 SING
+G N 29 Y N7 C5 SING
+G N 30 N C5 C6 SING
+G N 31 Y C5 C4 DOUB
+G N 32 N C6 O6 DOUB
+G N 33 N C6 N1 SING
+G N 34 N N1 C2 SING
+G N 35 N N1 H1 SING
+G N 36 N C2 N2 SING
+G N 37 N C2 N3 DOUB
+G N 38 N N2 H21 SING
+G N 39 N N2 H22 SING
+G N 40 N N3 C4 SING
+U N 1 N OP3 P SING
+U N 2 N OP3 HOP3 SING
+U N 3 N P OP1 DOUB
+U N 4 N P OP2 SING
+U N 5 N P "O5'" SING
+U N 6 N OP2 HOP2 SING
+U N 7 N "O5'" "C5'" SING
+U N 8 N "C5'" "C4'" SING
+U N 9 N "C5'" "H5'" SING
+U N 10 N "C5'" "H5''" SING
+U N 11 N "C4'" "O4'" SING
+U N 12 N "C4'" "C3'" SING
+U N 13 N "C4'" "H4'" SING
+U N 14 N "O4'" "C1'" SING
+U N 15 N "C3'" "O3'" SING
+U N 16 N "C3'" "C2'" SING
+U N 17 N "C3'" "H3'" SING
+U N 18 N "O3'" "HO3'" SING
+U N 19 N "C2'" "O2'" SING
+U N 20 N "C2'" "C1'" SING
+U N 21 N "C2'" "H2'" SING
+U N 22 N "O2'" "HO2'" SING
+U N 23 N "C1'" N1 SING
+U N 24 N "C1'" "H1'" SING
+U N 25 N N1 C2 SING
+U N 26 N N1 C6 SING
+U N 27 N C2 O2 DOUB
+U N 28 N C2 N3 SING
+U N 29 N N3 C4 SING
+U N 30 N N3 H3 SING
+U N 31 N C4 O4 DOUB
+U N 32 N C4 C5 SING
+U N 33 N C5 C6 DOUB
+U N 34 N C5 H5 SING
+U N 35 N C6 H6 SING
+C N 1 N OP3 P SING
+C N 2 N OP3 HOP3 SING
+C N 3 N P OP1 DOUB
+C N 4 N P OP2 SING
+C N 5 N P "O5'" SING
+C N 6 N OP2 HOP2 SING
+C N 7 N "O5'" "C5'" SING
+C N 8 N "C5'" "C4'" SING
+C N 9 N "C5'" "H5'" SING
+C N 10 N "C5'" "H5''" SING
+C N 11 N "C4'" "O4'" SING
+C N 12 N "C4'" "C3'" SING
+C N 13 N "C4'" "H4'" SING
+C N 14 N "O4'" "C1'" SING
+C N 15 N "C3'" "O3'" SING
+C N 16 N "C3'" "C2'" SING
+C N 17 N "C3'" "H3'" SING
+C N 18 N "O3'" "HO3'" SING
+C N 19 N "C2'" "O2'" SING
+C N 20 N "C2'" "C1'" SING
+C N 21 N "C2'" "H2'" SING
+C N 22 N "O2'" "HO2'" SING
+C N 23 N "C1'" N1 SING
+C N 24 N "C1'" "H1'" SING
+C N 25 N N1 C2 SING
+C N 26 N N1 C6 SING
+C N 27 N C2 O2 DOUB
+C N 28 N C2 N3 SING
+C N 29 N N3 C4 DOUB
+C N 30 N C4 N4 SING
+C N 31 N C4 C5 SING
+C N 32 N N4 H41 SING
+C N 33 N N4 H42 SING
+C N 34 N C5 C6 DOUB
+C N 35 N C5 H5 SING
+C N 36 N C6 H6 SING
+A N 1 N OP3 P SING
+A N 2 N OP3 HOP3 SING
+A N 3 N P OP1 DOUB
+A N 4 N P OP2 SING
+A N 5 N P "O5'" SING
+A N 6 N OP2 HOP2 SING
+A N 7 N "O5'" "C5'" SING
+A N 8 N "C5'" "C4'" SING
+A N 9 N "C5'" "H5'" SING
+A N 10 N "C5'" "H5''" SING
+A N 11 N "C4'" "O4'" SING
+A N 12 N "C4'" "C3'" SING
+A N 13 N "C4'" "H4'" SING
+A N 14 N "O4'" "C1'" SING
+A N 15 N "C3'" "O3'" SING
+A N 16 N "C3'" "C2'" SING
+A N 17 N "C3'" "H3'" SING
+A N 18 N "O3'" "HO3'" SING
+A N 19 N "C2'" "O2'" SING
+A N 20 N "C2'" "C1'" SING
+A N 21 N "C2'" "H2'" SING
+A N 22 N "O2'" "HO2'" SING
+A N 23 N "C1'" N9 SING
+A N 24 N "C1'" "H1'" SING
+A N 25 Y N9 C8 SING
+A N 26 Y N9 C4 SING
+A N 27 Y C8 N7 DOUB
+A N 28 N C8 H8 SING
+A N 29 Y N7 C5 SING
+A N 30 Y C5 C6 SING
+A N 31 Y C5 C4 DOUB
+A N 32 N C6 N6 SING
+A N 33 Y C6 N1 DOUB
+A N 34 N N6 H61 SING
+A N 35 N N6 H62 SING
+A N 36 Y N1 C2 SING
+A N 37 Y C2 N3 DOUB
+A N 38 N C2 H2 SING
+A N 39 Y N3 C4 SING
+HOH N 1 N O H1 SING
+HOH N 2 N O H2 SING
+#
index 9a07ef7..d07f28c 100644 (file)
@@ -85,8 +85,8 @@ public class AnnotatedPDBFileInputTest
     {
       for (int q = p + 1; q < avec.length; q++)
       {
-        assertTrue("Found a duplicate annotation row "
-                + avec[p].label, avec[p] != avec[q]);
+        assertTrue("Found a duplicate annotation row " + avec[p].label,
+                avec[p] != avec[q]);
       }
     }
   }
@@ -104,7 +104,7 @@ public class AnnotatedPDBFileInputTest
         if (StructureImportSettings.getDefaultPDBFileParser().equals(
                 StructureParser.JALVIEW_PARSER))
         {
-        assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId));
+          assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId));
         }
       }
     }
@@ -122,9 +122,9 @@ public class AnnotatedPDBFileInputTest
     SequenceFeature[] sf = al.getSequenceAt(0).getSequenceFeatures();
     assertEquals(296, sf.length);
     assertEquals("RESNUM", sf[0].getType());
-    assertEquals("GLU:19 1gaqA", sf[0].getDescription());
+    assertEquals("GLU:  19  1gaqA", sf[0].getDescription());
     assertEquals("RESNUM", sf[295].getType());
-    assertEquals("TYR:314 1gaqA", sf[295].getDescription());
+    assertEquals("TYR: 314  1gaqA", sf[295].getDescription());
 
     /*
      * 1GAQ/B
@@ -132,9 +132,9 @@ public class AnnotatedPDBFileInputTest
     sf = al.getSequenceAt(1).getSequenceFeatures();
     assertEquals(98, sf.length);
     assertEquals("RESNUM", sf[0].getType());
-    assertEquals("ALA:1 1gaqB", sf[0].getDescription());
+    assertEquals("ALA:   1  1gaqB", sf[0].getDescription());
     assertEquals("RESNUM", sf[97].getType());
-    assertEquals("ALA:98 1gaqB", sf[97].getDescription());
+    assertEquals("ALA:  98  1gaqB", sf[97].getDescription());
 
     /*
      * 1GAQ/C
@@ -142,9 +142,9 @@ public class AnnotatedPDBFileInputTest
     sf = al.getSequenceAt(2).getSequenceFeatures();
     assertEquals(296, sf.length);
     assertEquals("RESNUM", sf[0].getType());
-    assertEquals("GLU:19 1gaqC", sf[0].getDescription());
+    assertEquals("GLU:  19  1gaqC", sf[0].getDescription());
     assertEquals("RESNUM", sf[295].getType());
-    assertEquals("TYR:314 1gaqC", sf[295].getDescription());
+    assertEquals("TYR: 314  1gaqC", sf[295].getDescription());
   }
 
   @Test(groups = { "Functional" })
@@ -221,8 +221,8 @@ public class AnnotatedPDBFileInputTest
         sq = sq.getDatasetSequence();
       }
       assertNotNull(sq.getAllPDBEntries());
-      assertEquals("Expected only one PDB ID",
-              sq.getAllPDBEntries().size(), 1);
+      assertEquals("Expected only one PDB ID", 1, sq.getAllPDBEntries()
+              .size());
       for (PDBEntry pdbentry : sq.getAllPDBEntries())
       {
         System.err.println("PDB Entry " + pdbentry.getId() + " "
index c39cc4a..f88fc47 100644 (file)
@@ -75,8 +75,7 @@ public class AnnotationFileIOTest
       // make sure dataset is initialised ? not sure about this
       for (int i = 0; i < al.getSequencesArray().length; ++i)
       {
-        al.getSequenceAt(i).setDatasetSequence(
-                al.getSequenceAt(i).createDatasetSequence());
+        al.getSequenceAt(i).createDatasetSequence();
       }
       assertNotNull("Couldn't read supplied alignment data.", al);
       return al;
index ddf9a15..77aa0f6 100644 (file)
@@ -54,7 +54,8 @@ public class BioJsHTMLOutputTest
       {
         e.printStackTrace();
       }
-      bjsTemplate = BioJsHTMLOutput.getBioJsTemplateAsString();
+      bjsTemplate = HTMLOutput.readFileAsString(BioJsHTMLOutput
+              .getCurrentBJSTemplateFile());
       // System.out.println(bjsTemplate);
     } catch (IOException e)
     {
@@ -70,7 +71,7 @@ public class BioJsHTMLOutputTest
   {
     try
     {
-      BioJsHTMLOutput.refreshBioJSVersionsInfo(null);
+      BioJsHTMLOutput.refreshVersionInfo(null);
     } catch (URISyntaxException e)
     {
       AssertJUnit.fail("Expception occured while testing!");
@@ -85,7 +86,7 @@ public class BioJsHTMLOutputTest
     try
     {
       BioJsHTMLOutput
-              .refreshBioJSVersionsInfo(BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+              .refreshVersionInfo(BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
       versions = BioJsHTMLOutput.getBioJsMSAVersions();
     } catch (URISyntaxException e)
     {
diff --git a/test/jalview/io/CrossRef2xmlTests.java b/test/jalview/io/CrossRef2xmlTests.java
new file mode 100644 (file)
index 0000000..070fa68
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * 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 jalview.analysis.CrossRef;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentTest;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.CrossRefAction;
+import jalview.gui.Desktop;
+import jalview.gui.Jalview2XML;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class CrossRef2xmlTests extends Jalview2xmlBase
+{
+
+  /**
+   * test store and recovery of all reachable cross refs from all reachable
+   * crossrefs for one or more fetched db refs. Currently, this test has a known
+   * failure case.
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Operational" }, enabled = true)
+  public void testRetrieveAndShowCrossref() throws Exception
+  {
+
+    List<String> failedDBRetr = new ArrayList<String>();
+    List<String> failedXrefMenuItems = new ArrayList<String>();
+    List<String> failedProjectRecoveries = new ArrayList<String>();
+
+    // for every set of db queries
+    // retrieve db query
+    // verify presence of expected xrefs
+    // show xrefs - verify expected type of frame is shown for each xref
+    // show xrefs again
+    // - verify original -> xref -> xref(original) recovers frame containing at
+    // least the first retrieved sequence
+    // store
+    // 1. whole project
+    // 2. individual frames
+    // 3. load each one back and verify
+    // . aligned sequences (.toString() )
+    // . xrefs (.toString() )
+    // . codonframes
+    //
+    //
+    HashMap<String, String> dbtoviewBit = new HashMap<String, String>();
+    List<String> keyseq = new ArrayList<String>();
+    HashMap<String, File> savedProjects = new HashMap<String, File>();
+
+    for (String[] did : new String[][] { { "ENSEMBL", "ENSG00000157764" },
+    { "UNIPROT", "P01731" } })
+    {
+      // pass counters - 0 - first pass, 1 means retrieve project rather than
+      // perform action
+      int pass1 = 0, pass2 = 0, pass3 = 0;
+      // each do loop performs two iterations in the first outer loop pass, but
+      // only performs one iteration on the second outer loop
+      // ie. pass 1 = 0 {pass 2= 0 { pass 3 = 0,1 }, pass 2=1 { pass 3 = 0 }}, 1
+      // { pass 2 = 0 { pass 3 = 0 } }
+      do
+      {
+        String first = did[0] + " " + did[1];
+        AlignFrame af = null;
+        boolean dna;
+        AlignmentI retral;
+        AlignmentI dataset;
+        SequenceI[] seqs;
+        List<String> ptypes = null;
+        if (pass1 == 0)
+        {
+          // retrieve dbref
+
+          List<AlignFrame> afs = jalview.gui.SequenceFetcher.fetchAndShow(
+                  did[0], did[1]);
+          if (afs.size() == 0)
+          {
+            failedDBRetr.add("Didn't retrieve " + first);
+            break;
+          }
+          keyseq.add(first);
+          af = afs.get(0);
+
+          // verify references for retrieved data
+          AlignmentTest.assertAlignmentDatasetRefs(af.getViewport()
+                  .getAlignment(), "Pass (" + pass1 + "," + pass2 + ","
+                  + pass3 + "): Fetch " + first + ":");
+          assertDatasetIsNormalisedKnownDefect(af.getViewport()
+                  .getAlignment(), "Pass (" + pass1 + "," + pass2 + ","
+                  + pass3 + "): Fetch " + first + ":");
+          dna = af.getViewport().getAlignment().isNucleotide();
+          retral = af.getViewport().getAlignment();
+          dataset = retral.getDataset();
+          seqs = retral.getSequencesArray();
+
+        }
+        else
+        {
+          Desktop.instance.closeAll_actionPerformed(null);
+          // recover stored project
+          af = new FileLoader(false).LoadFileWaitTillLoaded(savedProjects
+                  .get(first).toString(), DataSourceType.FILE);
+          System.out.println("Recovered view for '" + first + "' from '"
+                  + savedProjects.get(first).toString() + "'");
+          dna = af.getViewport().getAlignment().isNucleotide();
+          retral = af.getViewport().getAlignment();
+          dataset = retral.getDataset();
+          seqs = retral.getSequencesArray();
+
+          // verify references for recovered data
+          AlignmentTest.assertAlignmentDatasetRefs(af.getViewport()
+                  .getAlignment(), "Pass (" + pass1 + "," + pass2 + ","
+                  + pass3 + "): Recover " + first + ":");
+          assertDatasetIsNormalisedKnownDefect(af.getViewport()
+                  .getAlignment(), "Pass (" + pass1 + "," + pass2 + ","
+                  + pass3 + "): Recover " + first + ":");
+
+        }
+
+        // store project on first pass, compare next pass
+        stringify(dbtoviewBit, savedProjects, first, af.alignPanel);
+
+        ptypes = (seqs == null || seqs.length == 0) ? null : new CrossRef(
+                seqs, dataset).findXrefSourcesForSequences(dna);
+
+        // start of pass2: retrieve each cross-ref for fetched or restored
+        // project.
+        do // first cross ref and recover crossref loop
+        {
+
+          for (String db : ptypes)
+          {
+            // counter for splitframe views retrieved via crossref
+            int firstcr_ap = 0;
+            // build next key so we an retrieve all views
+            String nextxref = first + " -> " + db + "{" + firstcr_ap + "}";
+            // perform crossref action, or retrieve stored project
+            List<AlignmentViewPanel> cra_views = new ArrayList<AlignmentViewPanel>();
+            CrossRefAction cra = null;
+
+            if (pass2 == 0)
+            { // retrieve and show cross-refs in this thread
+              cra = new CrossRefAction(af, seqs, dna, db);
+              cra.run();
+              if (cra.getXrefViews().size() == 0)
+              {
+                failedXrefMenuItems.add("No crossrefs retrieved for "
+                        + first + " -> " + db);
+                continue;
+              }
+              cra_views = cra.getXrefViews();
+              assertNucleotide(cra_views.get(0),
+                      "Nucleotide panel included proteins for " + first
+                              + " -> " + db);
+              assertProtein(cra_views.get(1),
+                      "Protein panel included nucleotides for " + first
+                              + " -> " + db);
+            }
+            else
+            {
+              Desktop.instance.closeAll_actionPerformed(null);
+              pass3 = 0;
+              // recover stored project
+              File storedProject = savedProjects.get(nextxref);
+              if (storedProject == null)
+              {
+                failedProjectRecoveries.add("Failed to store a view for '"
+                        + nextxref + "'");
+                continue;
+              }
+
+              // recover stored project
+              AlignFrame af2 = new FileLoader(false)
+                      .LoadFileWaitTillLoaded(savedProjects.get(nextxref)
+                              .toString(), DataSourceType.FILE);
+              System.out.println("Recovered view for '" + nextxref
+                      + "' from '" + savedProjects.get(nextxref).toString()
+                      + "'");
+              // gymnastics to recover the alignPanel/Complementary alignPanel
+              if (af2.getViewport().isNucleotide())
+              {
+                // top view, then bottom
+                cra_views.add(af2.getViewport().getAlignPanel());
+                cra_views.add(((jalview.gui.AlignViewport) af2
+                        .getViewport().getCodingComplement())
+                        .getAlignPanel());
+
+              }
+              else
+              {
+                // bottom view, then top
+                cra_views.add(((jalview.gui.AlignViewport) af2
+                        .getViewport().getCodingComplement())
+                        .getAlignPanel());
+                cra_views.add(af2.getViewport().getAlignPanel());
+
+              }
+            }
+            HashMap<String, List<String>> xrptypes = new HashMap<String, List<String>>();
+            // first save/verify views.
+            for (AlignmentViewPanel avp : cra_views)
+            {
+              nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
+              // verify references for this panel
+              AlignmentTest.assertAlignmentDatasetRefs(avp.getAlignment(),
+                      "Pass (" + pass1 + "," + pass2 + "," + pass3
+                              + "): before start of pass3: " + nextxref
+                              + ":");
+              assertDatasetIsNormalisedKnownDefect(avp.getAlignment(),
+                      "Pass (" + pass1 + "," + pass2 + "," + pass3
+                              + "): before start of pass3: " + nextxref
+                              + ":");
+
+              SequenceI[] xrseqs = avp.getAlignment().getSequencesArray();
+
+              List<String> _xrptypes = (seqs == null || seqs.length == 0) ? null
+                      : new CrossRef(xrseqs, dataset)
+                              .findXrefSourcesForSequences(avp
+                                      .getAlignViewport().isNucleotide());
+
+              stringify(dbtoviewBit, savedProjects, nextxref, avp);
+              xrptypes.put(nextxref, _xrptypes);
+
+            }
+
+            // now do the second xref pass starting from either saved or just
+            // recovered split pane, in sequence
+            do // retrieve second set of cross refs or recover and verify
+            {
+              firstcr_ap = 0;
+              for (AlignmentViewPanel avp : cra_views)
+              {
+                nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
+                for (String xrefdb : xrptypes.get(nextxref))
+                {
+                  List<AlignmentViewPanel> cra_views2 = new ArrayList<AlignmentViewPanel>();
+                  int q = 0;
+                  String nextnextxref = nextxref + " -> " + xrefdb + "{"
+                          + q + "}";
+
+                  if (pass3 == 0)
+                  {
+
+                    SequenceI[] xrseqs = avp.getAlignment()
+                            .getSequencesArray();
+                    AlignFrame nextaf = Desktop.getAlignFrameFor(avp
+                            .getAlignViewport());
+
+                    cra = new CrossRefAction(nextaf, xrseqs, avp
+                            .getAlignViewport().isNucleotide(), xrefdb);
+                    cra.run();
+                    if (cra.getXrefViews().size() == 0)
+                    {
+                      failedXrefMenuItems
+                              .add("No crossrefs retrieved for '"
+                                      + nextxref + "' to " + xrefdb
+                                      + " via '" + nextaf.getTitle() + "'");
+                      continue;
+                    }
+                    cra_views2 = cra.getXrefViews();
+                    assertNucleotide(cra_views2.get(0),
+                            "Nucleotide panel included proteins for '"
+                                    + nextxref + "' to " + xrefdb
+                                    + " via '" + nextaf.getTitle() + "'");
+                    assertProtein(cra_views2.get(1),
+                            "Protein panel included nucleotides for '"
+                                    + nextxref + "' to " + xrefdb
+                                    + " via '" + nextaf.getTitle() + "'");
+
+                  }
+                  else
+                  {
+                    Desktop.instance.closeAll_actionPerformed(null);
+                    // recover stored project
+                    File storedProject = savedProjects.get(nextnextxref);
+                    if (storedProject == null)
+                    {
+                      failedProjectRecoveries
+                              .add("Failed to store a view for '"
+                                      + nextnextxref + "'");
+                      continue;
+                    }
+                    AlignFrame af2 = new FileLoader(false)
+                            .LoadFileWaitTillLoaded(
+                                    savedProjects.get(nextnextxref)
+                                            .toString(),
+                                    DataSourceType.FILE);
+                    System.out.println("Recovered view for '"
+                            + nextnextxref + "' from '"
+                            + savedProjects.get(nextnextxref).toString()
+                            + "'");
+                    // gymnastics to recover the alignPanel/Complementary
+                    // alignPanel
+                    if (af2.getViewport().isNucleotide())
+                    {
+                      // top view, then bottom
+                      cra_views2.add(af2.getViewport().getAlignPanel());
+                      cra_views2.add(((jalview.gui.AlignViewport) af2
+                              .getViewport().getCodingComplement())
+                              .getAlignPanel());
+
+                    }
+                    else
+                    {
+                      // bottom view, then top
+                      cra_views2.add(((jalview.gui.AlignViewport) af2
+                              .getViewport().getCodingComplement())
+                              .getAlignPanel());
+                      cra_views2.add(af2.getViewport().getAlignPanel());
+                    }
+                    Assert.assertEquals(cra_views2.size(), 2);
+                    Assert.assertNotNull(cra_views2.get(0));
+                    Assert.assertNotNull(cra_views2.get(1));
+                  }
+
+                  for (AlignmentViewPanel nextavp : cra_views2)
+                  {
+                    nextnextxref = nextxref + " -> " + xrefdb + "{" + q++
+                            + "}";
+
+                    // verify references for this panel
+                    AlignmentTest.assertAlignmentDatasetRefs(
+                            nextavp.getAlignment(), "" + "Pass (" + pass1
+                                    + "," + pass2 + "): For "
+                                    + nextnextxref + ":");
+                    assertDatasetIsNormalisedKnownDefect(
+                            nextavp.getAlignment(), "" + "Pass (" + pass1
+                                    + "," + pass2 + "): For "
+                                    + nextnextxref + ":");
+
+                    stringify(dbtoviewBit, savedProjects, nextnextxref,
+                            nextavp);
+                    keyseq.add(nextnextxref);
+                  }
+                } // end of loop around showing all xrefdb for crossrf2
+
+              } // end of loop around all viewpanels from crossrf1
+            } while (pass2 == 2 && pass3++ < 2);
+            // fetchdb->crossref1->crossref-2->verify for xrefs we
+            // either loop twice when pass2=0, or just once when pass2=1
+            // (recovered project from previous crossref)
+
+          } // end of loop over db-xrefs for crossref-2
+
+          // fetchdb-->crossref1
+          // for each xref we try to retrieve xref, store and verify when
+          // pass1=0, or just retrieve and verify when pass1=1
+        } while (pass1 == 1 && pass2++ < 2);
+        // fetchdb
+        // for each ref we
+        // loop twice: first, do the retrieve, second recover from saved project
+
+        // increment pass counters, so we repeat traversal starting from the
+        // oldest saved project first.
+        if (pass1 == 0)
+        {
+          // verify stored projects for first set of cross references
+          pass1 = 1;
+          // and verify cross-references retrieved from stored projects
+          pass2 = 0;
+          pass3 = 0;
+        }
+        else
+        {
+          pass1++;
+        }
+      } while (pass1 < 3);
+    }
+    if (failedXrefMenuItems.size() > 0)
+    {
+      for (String s : failedXrefMenuItems)
+      {
+        System.err.println(s);
+      }
+      Assert.fail("Faulty xref menu (" + failedXrefMenuItems.size()
+              + " counts)");
+    }
+    if (failedProjectRecoveries.size() > 0)
+    {
+
+      for (String s : failedProjectRecoveries)
+      {
+        System.err.println(s);
+      }
+      Assert.fail("Didn't recover projects for some retrievals (did they retrieve ?) ("
+              + failedProjectRecoveries.size() + " counts)");
+    }
+    if (failedDBRetr.size() > 0)
+    {
+      for (String s : failedProjectRecoveries)
+      {
+        System.err.println(s);
+      }
+      Assert.fail("Didn't retrieve some db refs for checking cross-refs ("
+              + failedDBRetr.size() + " counts)");
+    }
+  }
+
+  /**
+   * wrapper to trap known defect for AH002001 testcase
+   * 
+   * @param alignment
+   * @param string
+   */
+  private void assertDatasetIsNormalisedKnownDefect(AlignmentI al,
+          String message)
+  {
+    try
+    {
+      AlignmentTest.assertDatasetIsNormalised(al, message);
+    } catch (AssertionError ae)
+    {
+      if (!ae.getMessage().endsWith("EMBL|AH002001"))
+      {
+        throw ae;
+      }
+      else
+      {
+        System.out
+                .println("Ignored exception for known defect: JAL-2179 : "
+                        + message);
+      }
+
+    }
+  }
+
+  private void assertProtein(AlignmentViewPanel alignmentViewPanel,
+          String message)
+  {
+    assertType(true, alignmentViewPanel, message);
+  }
+
+  private void assertNucleotide(AlignmentViewPanel alignmentViewPanel,
+          String message)
+  {
+    assertType(false, alignmentViewPanel, message);
+  }
+
+  private void assertType(boolean expectProtein,
+          AlignmentViewPanel alignmentViewPanel, String message)
+  {
+    List<SequenceI> nonType = new ArrayList<SequenceI>();
+    for (SequenceI sq : alignmentViewPanel.getAlignViewport()
+            .getAlignment().getSequences())
+    {
+      if (sq.isProtein() != expectProtein)
+      {
+        nonType.add(sq);
+      }
+    }
+    if (nonType.size() > 0)
+    {
+      Assert.fail(message + " [ "
+              + (expectProtein ? "nucleotides were " : "proteins were ")
+              + nonType.toString() + " ]");
+    }
+  }
+
+  /**
+   * first time called, record strings derived from alignment and
+   * alignedcodonframes, and save view to a project file. Second time called,
+   * compare strings to existing ones. org.testng.Assert.assertTrue on
+   * stringmatch
+   * 
+   * @param dbtoviewBit
+   *          map between xrefpath and view string
+   * @param savedProjects
+   *          - map from xrefpath to saved project filename (createTempFile)
+   * @param xrefpath
+   *          - xrefpath - unique ID for this context (composed of sequence of
+   *          db-fetch/cross-ref actions preceeding state)
+   * @param avp
+   *          - viewpanel to store (for viewpanels in splitframe, the same
+   *          project should be written for both panels, only one needs
+   *          recovering for comparison on the next stringify call, but each
+   *          viewpanel needs to be called with a distinct xrefpath to ensure
+   *          each one's strings are compared)
+   */
+  private void stringify(HashMap<String, String> dbtoviewBit,
+          HashMap<String, File> savedProjects, String xrefpath,
+          AlignmentViewPanel avp)
+  {
+    if (savedProjects != null)
+    {
+      if (savedProjects.get(xrefpath) == null)
+      {
+        // write a project file for this view. On the second pass, this will be
+        // recovered and cross-references verified
+        try
+        {
+          File prfile = File.createTempFile("crossRefTest", ".jvp");
+          AlignFrame af = Desktop.getAlignFrameFor(avp.getAlignViewport());
+          new Jalview2XML(false).saveAlignment(af, prfile.toString(),
+                  af.getTitle());
+          System.out.println("Written view from '" + xrefpath + "' as '"
+                  + prfile.getAbsolutePath() + "'");
+          savedProjects.put(xrefpath, prfile);
+        } catch (IOException q)
+        {
+          Assert.fail("Unexpected IO Exception", q);
+        }
+      }
+      else
+      {
+        System.out.println("Stringify check on view from '" + xrefpath
+                + "' [ possibly retrieved from '"
+                + savedProjects.get(xrefpath).getAbsolutePath() + "' ]");
+
+      }
+    }
+
+    StringBuilder sbr = new StringBuilder();
+    sbr.append(avp.getAlignment().toString());
+    sbr.append("\n");
+    sbr.append("<End of alignment>");
+    sbr.append("\n");
+    sbr.append(avp.getAlignment().getDataset());
+    sbr.append("\n");
+    sbr.append("<End of dataset>");
+    sbr.append("\n");
+    int p = 0;
+    if (avp.getAlignment().getCodonFrames() != null)
+    {
+      for (AlignedCodonFrame ac : avp.getAlignment().getCodonFrames())
+      {
+        sbr.append("<AlignedCodonFrame " + p++ + ">");
+        sbr.append("\n");
+        sbr.append(ac.toString());
+        sbr.append("\n");
+      }
+    }
+    String dbt = dbtoviewBit.get(xrefpath);
+    if (dbt == null)
+    {
+      dbtoviewBit.put(xrefpath, sbr.toString());
+    }
+    else
+    {
+      Assert.assertEquals(sbr.toString(), dbt, "stringify mismatch for "
+              + xrefpath);
+    }
+  }
+}
index 0cfe46a..a00c3a2 100644 (file)
@@ -153,7 +153,8 @@ public class FeaturesFileTest
     Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
     // GFF2 uses space as name/value separator in column 9
-    String gffData = "METAL\tcc9900\n" + "GFF\n"
+    String gffData = "METAL\tcc9900\n"
+            + "GFF\n"
             + "FER_CAPAA\tuniprot\tMETAL\t44\t45\t4.0\t.\t.\tNote Iron-sulfur; Note 2Fe-2S\n"
             + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t2.0\t.\t.";
     FeaturesFile featuresFile = new FeaturesFile(gffData,
@@ -304,7 +305,7 @@ public class FeaturesFileTest
   {
     assertEquals("no sequences extracted from GFF3 file", 2,
             dataset.getHeight());
-  
+
     SequenceI seq1 = dataset.findName("seq1");
     SequenceI seq2 = dataset.findName("seq2");
     assertNotNull(seq1);
@@ -335,7 +336,7 @@ public class FeaturesFileTest
             "Expected at least one CDNA/Protein mapping for seq1",
             dataset.getCodonFrame(seq1) != null
                     && dataset.getCodonFrame(seq1).size() > 0);
-  
+
   }
 
   @Test(groups = { "Functional" })
@@ -408,8 +409,7 @@ public class FeaturesFileTest
      * first with no features displayed
      */
     FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
-    Map<String, FeatureColourI> visible = fr
-            .getDisplayedFeatureCols();
+    Map<String, FeatureColourI> visible = fr.getDisplayedFeatureCols();
     String exported = featuresFile.printJalviewFormat(
             al.getSequencesArray(), visible);
     String expected = "No Features Visible";
index a7c2bf9..1cabc15 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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 static org.testng.AssertJUnit.assertEquals;
@@ -57,9 +77,8 @@ public class FormatAdapterTest
          */
         sequenceString = adjustForGapTreatment(sequenceString, gap, format);
         assertEquals(
-                String.format("Sequence %d: %s", i,
-                        seqs[i].getName()), seqs[i].getSequenceAsString(),
-                sequenceString);
+                String.format("Sequence %d: %s", i, seqs[i].getName()),
+                seqs[i].getSequenceAsString(), sequenceString);
         i++;
       }
     } catch (IOException e)
index cd40bab..a18f395 100644 (file)
@@ -114,7 +114,7 @@ public class JSONFileTest
 
     for (Sequence seq : seqs)
     {
-      seq.setDatasetSequence(seq);
+      seq.createDatasetSequence();
       expectedSeqs.put(seq.getName(), seq);
     }
 
@@ -305,7 +305,8 @@ public class JSONFileTest
     Assert.assertNotNull(cs.getHiddenColumns());
     List<int[]> hiddenCols = cs.getHiddenColumns();
     Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
-    Assert.assertEquals(hiddenCols, expectedColSel.getHiddenColumns(),
+    Assert.assertEquals(hiddenCols.get(0), expectedColSel
+            .getHiddenColumns().get(0),
             "Mismatched hidden columns!");
   }
 
@@ -314,7 +315,8 @@ public class JSONFileTest
   {
     Assert.assertNotNull(testJsonFile.getHiddenSequences(),
             "Hidden sequence Expected but found Null");
-    Assert.assertEquals(jf.getHiddenSequences().length, 1, "Hidden sequece");
+    Assert.assertEquals(jf.getHiddenSequences().length, 1,
+            "Hidden sequence");
   }
 
   @Test(groups = { "Functional" })
diff --git a/test/jalview/io/Jalview2xmlBase.java b/test/jalview/io/Jalview2xmlBase.java
new file mode 100644 (file)
index 0000000..7f38dec
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.SequenceI;
+import jalview.gui.Desktop;
+
+import java.util.Date;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeTest;
+
+public class Jalview2xmlBase
+{
+
+  /**
+   * @throws java.lang.Exception
+   */
+  @BeforeClass(alwaysRun = true)
+  public static void setUpBeforeClass() throws Exception
+  {
+    /*
+     * use read-only test properties file
+     */
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+
+    /*
+     * set news feed last read to a future time to ensure no
+     * 'unread' news item is displayed
+     */
+    Date oneHourFromNow = new Date(System.currentTimeMillis() + 3600 * 1000);
+    Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", oneHourFromNow);
+
+    Jalview.main(new String[] {});
+  }
+
+  /**
+   * @throws java.lang.Exception
+   */
+  @AfterClass(alwaysRun = true)
+  public static void tearDownAfterClass() throws Exception
+  {
+    jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
+  }
+
+  @BeforeTest(alwaysRun = true)
+  public static void clearDesktop()
+  {
+    if (Desktop.instance != null && Desktop.getAlignFrames() != null)
+    {
+      Desktop.instance.closeAll_actionPerformed(null);
+    }
+  }
+
+  public int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
+  {
+    int numdsann = 0;
+    for (SequenceI sq : avp.getAlignment().getDataset().getSequences())
+    {
+      if (sq.getAnnotation() != null)
+      {
+        for (AlignmentAnnotation dssa : sq.getAnnotation())
+        {
+          if (dssa.isValidStruc())
+          {
+            numdsann++;
+          }
+        }
+      }
+    }
+    return numdsann;
+  }
+
+}
index 266b0f8..b6f29ae 100644 (file)
@@ -29,12 +29,11 @@ import static org.testng.AssertJUnit.assertTrue;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.ViewStyleI;
-import jalview.bin.Cache;
-import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.PDBEntry;
+import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -44,82 +43,32 @@ import jalview.gui.Desktop;
 import jalview.gui.Jalview2XML;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.TCoffeeColourScheme;
 import jalview.structure.StructureImportSettings;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.testng.Assert;
 import org.testng.AssertJUnit;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 @Test(singleThreaded = true)
-public class Jalview2xmlTests
+public class Jalview2xmlTests extends Jalview2xmlBase
 {
 
-  /**
-   * @throws java.lang.Exception
-   */
-  @BeforeClass(alwaysRun = true)
-  public static void setUpBeforeClass() throws Exception
-  {
-    /*
-     * use read-only test properties file
-     */
-    Cache.loadProperties("test/jalview/io/testProps.jvprops");
-
-    /*
-     * set news feed last read to a future time to ensure no
-     * 'unread' news item is displayed
-     */
-    Date oneHourFromNow = new Date(System.currentTimeMillis() + 3600 * 1000);
-    Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", oneHourFromNow);
-
-    Jalview.main(new String[] {});
-  }
-
-  /**
-   * @throws java.lang.Exception
-   */
-  @AfterClass(alwaysRun = true)
-  public static void tearDownAfterClass() throws Exception
-  {
-    Desktop.instance.closeAll_actionPerformed(null);
-  }
-
-  int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
-  {
-    int numdsann = 0;
-    for (SequenceI sq : avp.getAlignment().getDataset().getSequences())
-    {
-      if (sq.getAnnotation() != null)
-      {
-        for (AlignmentAnnotation dssa : sq.getAnnotation())
-        {
-          if (dssa.isValidStruc())
-          {
-            numdsann++;
-          }
-        }
-      }
-    }
-    return numdsann;
-  }
-
   @Test(groups = { "Functional" })
   public void testRNAStructureRecovery() throws Exception
   {
     String inFile = "examples/RF00031_folded.stk";
     String tfile = File.createTempFile("JalviewTest", ".jvp")
             .getAbsolutePath();
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             inFile, DataSourceType.FILE);
     assertTrue("Didn't read input file " + inFile, af != null);
     int olddsann = countDsAnn(af.getViewport());
@@ -132,8 +81,7 @@ public class Jalview2xmlTests
             af.saveAlignment(tfile, FileFormat.Jalview));
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
-            DataSourceType.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
     assertTrue("Failed to import new project", af != null);
     int newdsann = countDsAnn(af.getViewport());
     assertTrue(
@@ -154,32 +102,27 @@ public class Jalview2xmlTests
     String inFile = "examples/uniref50.fa", inAnnot = "examples/uniref50.score_ascii";
     String tfile = File.createTempFile("JalviewTest", ".jvp")
             .getAbsolutePath();
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             inFile, DataSourceType.FILE);
-    assertTrue("Didn't read input file " + inFile, af != null);
+    assertNotNull("Didn't read input file " + inFile, af);
     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
-    assertTrue(
-            "Didn't set T-coffee colourscheme",
-            af.getViewport().getGlobalColourScheme().getClass()
-                    .equals(jalview.schemes.TCoffeeColourScheme.class));
-    assertTrue(
-            "Recognise T-Coffee score from string",
-            jalview.schemes.ColourSchemeProperty.getColour(af.getViewport()
-                    .getAlignment(),
-                    jalview.schemes.ColourSchemeProperty.getColourName(af
-                            .getViewport().getGlobalColourScheme())) != null);
+    assertSame("Didn't set T-coffee colourscheme", af.getViewport()
+            .getGlobalColourScheme().getClass(), TCoffeeColourScheme.class);
+    assertNotNull("Recognise T-Coffee score from string",
+            ColourSchemeProperty.getColour(af.getViewport()
+                    .getAlignment(), ColourSchemeProperty.getColourName(af
+                    .getViewport().getGlobalColourScheme())));
 
     assertTrue("Failed to store as a project.",
             af.saveAlignment(tfile, FileFormat.Jalview));
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
             DataSourceType.FILE);
-    assertTrue("Failed to import new project", af != null);
-    assertTrue(
-            "Didn't set T-coffee colourscheme for imported project.",
-            af.getViewport().getGlobalColourScheme().getClass()
-                    .equals(jalview.schemes.TCoffeeColourScheme.class));
+    assertNotNull("Failed to import new project", af);
+    assertSame("Didn't set T-coffee colourscheme for imported project.", af
+            .getViewport().getGlobalColourScheme().getClass(),
+            TCoffeeColourScheme.class);
     System.out
             .println("T-Coffee score shading successfully recovered from project.");
   }
@@ -190,19 +133,18 @@ public class Jalview2xmlTests
     String inFile = "examples/uniref50.fa", inAnnot = "examples/testdata/uniref50_iupred.jva";
     String tfile = File.createTempFile("JalviewTest", ".jvp")
             .getAbsolutePath();
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
-            inFile, DataSourceType.FILE);
-    assertTrue("Didn't read input file " + inFile, af != null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile, DataSourceType.FILE);
+    assertNotNull("Didn't read input file " + inFile, af);
     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
     AlignmentAnnotation[] aa = af.getViewport().getAlignment()
             .getSequenceAt(0).getAnnotation("IUPredWS (Short)");
     assertTrue(
             "Didn't find any IUPred annotation to use to shade alignment.",
             aa != null && aa.length > 0);
-    AnnotationColourGradient cs = new jalview.schemes.AnnotationColourGradient(
-            aa[0], null, AnnotationColourGradient.ABOVE_THRESHOLD);
-    AnnotationColourGradient gcs = new jalview.schemes.AnnotationColourGradient(
-            aa[0], null, AnnotationColourGradient.BELOW_THRESHOLD);
+    AnnotationColourGradient cs = new AnnotationColourGradient(aa[0], null,
+            AnnotationColourGradient.ABOVE_THRESHOLD);
+    AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0],
+            null, AnnotationColourGradient.BELOW_THRESHOLD);
     cs.setSeqAssociated(true);
     gcs.setSeqAssociated(true);
     af.changeColour(cs);
@@ -218,8 +160,7 @@ public class Jalview2xmlTests
             af.saveAlignment(tfile, FileFormat.Jalview));
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
-            DataSourceType.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
     assertTrue("Failed to import new project", af != null);
 
     // check for group and alignment colourschemes
@@ -227,7 +168,7 @@ public class Jalview2xmlTests
     ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme();
     ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups()
             .get(0).cs;
-    assertTrue("Didn't recover global colourscheme", _rcs != null);
+    assertNotNull("Didn't recover global colourscheme", _rcs);
     assertTrue("Didn't recover annotation colour global scheme",
             _rcs instanceof AnnotationColourGradient);
     AnnotationColourGradient __rcs = (AnnotationColourGradient) _rcs;
@@ -249,7 +190,7 @@ public class Jalview2xmlTests
     System.out
             .println("Per sequence colourscheme (Background) successfully applied and recovered.");
 
-    assertTrue("Didn't recover group colourscheme", _rgcs != null);
+    assertNotNull("Didn't recover group colourscheme", _rgcs);
     assertTrue("Didn't recover annotation colour group colourscheme",
             _rgcs instanceof AnnotationColourGradient);
     __rcs = (AnnotationColourGradient) _rgcs;
@@ -275,9 +216,9 @@ public class Jalview2xmlTests
   {
     int origCount = Desktop.getAlignFrames() == null ? 0 : Desktop
             .getAlignFrames().length;
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    assertNotNull("Didn't read in the example file correctly.", af);
     assertTrue("Didn't gather the views in the example file.",
             Desktop.getAlignFrames().length == 1 + origCount);
 
@@ -286,14 +227,11 @@ public class Jalview2xmlTests
   @Test(groups = { "Functional" })
   public void viewRefPdbAnnotation() throws Exception
   {
-    // TODO: Make this pass without setting StructureParser.JALVIEW_PARSER
-    // StructureImportSettings
-    // .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
     StructureImportSettings.setProcessSecondaryStructure(true);
     StructureImportSettings.setVisibleChainAnnotation(true);
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    assertNotNull("Didn't read in the example file correctly.", af);
     AlignmentViewPanel sps = null;
     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
     {
@@ -303,8 +241,7 @@ public class Jalview2xmlTests
         break;
       }
     }
-    assertTrue("Couldn't find the structure view", sps != null);
-    SequenceI sq = sps.getAlignment().findName("1A70|");
+    assertNotNull("Couldn't find the structure view", sps);
     AlignmentAnnotation refan = null;
     for (AlignmentAnnotation ra : sps.getAlignment()
             .getAlignmentAnnotation())
@@ -315,10 +252,13 @@ public class Jalview2xmlTests
         break;
       }
     }
-    assertTrue("Annotation secondary structure not found.", refan != null);
-    assertTrue("Couldn't find 1a70 null chain", sq != null);
+    assertNotNull("Annotation secondary structure not found.", refan);
+    SequenceI sq = sps.getAlignment().findName("1A70|");
+    assertNotNull("Couldn't find 1a70 null chain", sq);
     // compare the manually added temperature factor annotation
     // to the track automatically transferred from the pdb structure on load
+    assertNotNull("1a70 has no annotation", sq.getDatasetSequence()
+            .getAnnotation());
     for (AlignmentAnnotation ala : sq.getDatasetSequence().getAnnotation())
     {
       AlignmentAnnotation alaa;
@@ -350,9 +290,9 @@ public class Jalview2xmlTests
   @Test(groups = { "Functional" })
   public void testCopyViewSettings() throws Exception
   {
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    assertNotNull("Didn't read in the example file correctly.", af);
     AlignmentViewPanel sps = null, groups = null;
     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
     {
@@ -365,8 +305,8 @@ public class Jalview2xmlTests
         groups = ap;
       }
     }
-    assertTrue("Couldn't find the structure view", sps != null);
-    assertTrue("Couldn't find the MAFFT view", groups != null);
+    assertNotNull("Couldn't find the structure view", sps);
+    assertNotNull("Couldn't find the MAFFT view", groups);
 
     ViewStyleI structureStyle = sps.getAlignViewport().getViewStyle();
     ViewStyleI groupStyle = groups.getAlignViewport().getViewStyle();
@@ -390,9 +330,8 @@ public class Jalview2xmlTests
   {
     Desktop.instance.closeAll_actionPerformed(null);
 
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
     Assert.assertEquals(Desktop.getAlignFrames().length, 1);
     String afid = af.getViewport().getSequenceSetId();
 
@@ -423,7 +362,7 @@ public class Jalview2xmlTests
     {
       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
     }
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    af = new FileLoader().LoadFileWaitTillLoaded(
             tfile.getAbsolutePath(), DataSourceType.FILE);
     Assert.assertNotNull(af);
     Assert.assertEquals(
@@ -446,7 +385,7 @@ public class Jalview2xmlTests
     Desktop.instance.closeAll_actionPerformed(null);
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    assertNotNull("Didn't read in the example file correctly.", af);
     String afid = af.getViewport().getSequenceSetId();
 
     // remember reference sequence for each panel
@@ -579,18 +518,18 @@ public class Jalview2xmlTests
     Desktop.instance.closeAll_actionPerformed(null);
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    assertNotNull("Didn't read in the example file correctly.", af);
     String afid = af.getViewport().getSequenceSetId();
     // make a second view of the alignment
     af.newView_actionPerformed(null);
-  
+
     /*
      * remember representative and hidden sequences marked 
      * on each panel
      */
     Map<String, SequenceI> repSeqs = new HashMap<String, SequenceI>();
     Map<String, List<String>> hiddenSeqNames = new HashMap<String, List<String>>();
-  
+
     /*
      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
      * as reference sequence for itself and the preceding sequence
@@ -607,7 +546,7 @@ public class Jalview2xmlTests
       repSeqs.put(ap.getViewName(), repSeq);
       List<String> hiddenNames = new ArrayList<String>();
       hiddenSeqNames.put(ap.getViewName(), hiddenNames);
-  
+
       /*
        * have rep sequence represent itself and the one before it
        * this hides the group (except for the rep seq)
@@ -631,7 +570,8 @@ public class Jalview2xmlTests
       assertTrue(sg.getSequences().contains(repSeq));
       assertTrue(sg.getSequences().contains(precedingSeq));
       assertTrue("alignment has groups", alignment.getGroups().isEmpty());
-      Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av.getHiddenRepSequences();
+      Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
+              .getHiddenRepSequences();
       assertNotNull(hiddenRepSeqsMap);
       assertEquals(1, hiddenRepSeqsMap.size());
       assertSame(sg, hiddenRepSeqsMap.get(repSeq));
@@ -642,8 +582,7 @@ public class Jalview2xmlTests
       n++;
     }
     File tfile = File
-            .createTempFile("testStoreAndRecoverGroupReps",
-            ".jvp");
+            .createTempFile("testStoreAndRecoverGroupReps", ".jvp");
     try
     {
       new Jalview2XML(false).saveState(tfile);
@@ -660,7 +599,7 @@ public class Jalview2xmlTests
     af = new FileLoader().LoadFileWaitTillLoaded(
             tfile.getAbsolutePath(), DataSourceType.FILE);
     afid = af.getViewport().getSequenceSetId();
-  
+
     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
     {
       String viewName = ap.getViewName();
@@ -684,8 +623,7 @@ public class Jalview2xmlTests
       HiddenSequences hs = alignment.getHiddenSequences();
       assertEquals(
               "wrong number of restored hidden sequences in "
-                      + ap.getViewName(),
-              hidden.size(), hs.getSize());
+                      + ap.getViewName(), hidden.size(), hs.getSize());
     }
   }
 
@@ -701,7 +639,7 @@ public class Jalview2xmlTests
     String exampleFile = "examples/3W5V.pdb";
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
             DataSourceType.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    assertNotNull("Didn't read in the example file correctly.", af);
     String afid = af.getViewport().getSequenceSetId();
 
     AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
@@ -721,18 +659,18 @@ public class Jalview2xmlTests
     Assert.assertNotNull(seqs[2].getDatasetSequence());
     Assert.assertNotNull(seqs[3].getDatasetSequence());
     PDBEntry[] pdbEntries = new PDBEntry[4];
-    pdbEntries[0] = new PDBEntry("3W5V", "A", null, testFile);
-    pdbEntries[1] = new PDBEntry("3W5V", "B", null, testFile);
-    pdbEntries[2] = new PDBEntry("3W5V", "C", null, testFile);
-    pdbEntries[3] = new PDBEntry("3W5V", "D", null, testFile);
-    Assert.assertTrue(seqs[0].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[0]));
-    Assert.assertTrue(seqs[1].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[1]));
-    Assert.assertTrue(seqs[2].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[2]));
-    Assert.assertTrue(seqs[3].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[3]));
+    pdbEntries[0] = new PDBEntry("3W5V", "A", Type.PDB, testFile);
+    pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile);
+    pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile);
+    pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile);
+    Assert.assertEquals(seqs[0].getDatasetSequence().getAllPDBEntries()
+            .get(0), pdbEntries[0]);
+    Assert.assertEquals(seqs[1].getDatasetSequence().getAllPDBEntries()
+            .get(0), pdbEntries[1]);
+    Assert.assertEquals(seqs[2].getDatasetSequence().getAllPDBEntries()
+            .get(0), pdbEntries[2]);
+    Assert.assertEquals(seqs[3].getDatasetSequence().getAllPDBEntries()
+            .get(0), pdbEntries[3]);
 
     File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
     try
@@ -767,13 +705,19 @@ public class Jalview2xmlTests
 
     // The Asserts below are expected to fail until the PDB chainCode is
     // recoverable from a Jalview projects
-    Assert.assertTrue(rseqs[0].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[0]));
-    Assert.assertTrue(rseqs[1].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[1]));
-    Assert.assertTrue(rseqs[2].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[2]));
-    Assert.assertTrue(rseqs[3].getDatasetSequence().getAllPDBEntries()
-            .get(0).equals(pdbEntries[3]));
+    for (int chain = 0; chain < 4; chain++)
+    {
+      PDBEntry recov = rseqs[chain].getDatasetSequence().getAllPDBEntries()
+              .get(0);
+      PDBEntry expected = pdbEntries[chain];
+      Assert.assertEquals(recov.getId(), expected.getId(),
+              "Mismatch PDB ID");
+      Assert.assertEquals(recov.getChainCode(), expected.getChainCode(),
+              "Mismatch PDB ID");
+      Assert.assertEquals(recov.getType(), expected.getType(),
+              "Mismatch PDBEntry 'Type'");
+      Assert.assertNotNull(recov.getFile(),
+              "Recovered PDBEntry should have a non-null file entry");
+    }
   }
 }
index 7acc37d..227af46 100644 (file)
@@ -116,24 +116,23 @@ public class NewickFileTests
       AssertJUnit.assertTrue(stage + "Null Tree", tree_regen != null);
       stage = "Compare original and generated tree" + treename;
 
-      Vector oseqs, nseqs;
-      oseqs = new NJTree(new SequenceI[0], nf).findLeaves(nf.getTree(),
-              new Vector());
+      Vector<SequenceNode> oseqs, nseqs;
+      oseqs = new NJTree(new SequenceI[0], nf).findLeaves(nf.getTree());
       AssertJUnit.assertTrue(stage + "No nodes in original tree.",
               oseqs.size() > 0);
       SequenceI[] olsqs = new SequenceI[oseqs.size()];
       for (int i = 0, iSize = oseqs.size(); i < iSize; i++)
       {
-        olsqs[i] = (SequenceI) ((SequenceNode) oseqs.get(i)).element();
+        olsqs[i] = (SequenceI) oseqs.get(i).element();
       }
-      nseqs = new NJTree(new SequenceI[0], nf_regen).findLeaves(
-              nf_regen.getTree(), new Vector());
+      nseqs = new NJTree(new SequenceI[0], nf_regen).findLeaves(nf_regen
+              .getTree());
       AssertJUnit.assertTrue(stage + "No nodes in regerated tree.",
               nseqs.size() > 0);
       SequenceI[] nsqs = new SequenceI[nseqs.size()];
       for (int i = 0, iSize = nseqs.size(); i < iSize; i++)
       {
-        nsqs[i] = (SequenceI) ((SequenceNode) nseqs.get(i)).element();
+        nsqs[i] = (SequenceI) nseqs.get(i).element();
       }
       AssertJUnit.assertTrue(stage
               + " Different number of leaves (original " + olsqs.length
index 8eb3c60..f0986af 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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 jalview.datamodel.AlignmentI;
@@ -9,10 +29,10 @@ import org.testng.annotations.Test;
 
 public class PfamFormatInputTest
 {
-  @Test
+  @Test(groups = "Functional")
   public void testPfamFormatNoLimits() throws IOException
   {
-    AlignmentI al = new jalview.io.AppletFormatAdapter().readFile("ASEQ"
+    AlignmentI al = new AppletFormatAdapter().readFile("ASEQ"
             + '\t' + "...--FFAFAFF--", DataSourceType.PASTE,
             FileFormat.Pfam);
     Assert.assertEquals(1, al.getHeight(), "Wrong number of sequences");
@@ -20,13 +40,11 @@ public class PfamFormatInputTest
             "Didn't extract limits from PFAM ID");
   }
 
-  @Test
+  @Test(groups = "Functional")
   public void testPfamFormatValidLimits() throws IOException
   {
-    AlignmentI al = new jalview.io.AppletFormatAdapter().readFile(
-            "ASEQ/15-25" + '\t' + "...--FFAFAFF--",
- DataSourceType.PASTE,
-            FileFormat.Pfam);
+    AlignmentI al = new AppletFormatAdapter().readFile("ASEQ/15-25" + '\t'
+            + "...--FFAFAFF--", DataSourceType.PASTE, FileFormat.Pfam);
     Assert.assertEquals(1, al.getHeight(), "Wrong number of sequences");
     Assert.assertTrue(al.hasValidSequence(),
             "Didn't extract limits from PFAM ID");
index f551571..1392157 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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 static org.testng.AssertJUnit.assertEquals;
@@ -15,7 +35,7 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_disulfideBond()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     sb.append("123456");
     SequenceFeature sf = new SequenceFeature("disulfide bond", "desc", 1,
             3, 1.2f, "group");
@@ -40,11 +60,11 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_status()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
             Float.NaN, "group");
     sf.setStatus("Confirmed");
-  
+
     sar.appendFeature(sb, 1, null, sf);
     assertEquals("METAL 1 3; Fe2-S; (Confirmed)", sb.toString());
   }
@@ -53,7 +73,7 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_withScore()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
             "group");
 
@@ -86,10 +106,10 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_noScore()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
             Float.NaN, "group");
-  
+
     sar.appendFeature(sb, 1, null, sf);
     assertEquals("METAL 1 3; Fe2-S", sb.toString());
   }
@@ -98,11 +118,11 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_clinicalSignificance()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
             Float.NaN, "group");
     sf.setValue("clinical_significance", "Benign");
-  
+
     sar.appendFeature(sb, 1, null, sf);
     assertEquals("METAL 1 3; Fe2-S; Benign", sb.toString());
   }
@@ -111,7 +131,7 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_withScoreStatusClinicalSignificance()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
             "group");
     sf.setStatus("Confirmed");
@@ -128,10 +148,10 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_DescEqualsType()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL", "METAL", 1, 3,
             Float.NaN, "group");
-  
+
     // description is not included if it duplicates type:
     sar.appendFeature(sb, 1, null, sf);
     assertEquals("METAL 1 3", sb.toString());
@@ -147,15 +167,14 @@ public class SequenceAnnotationReportTest
   public void testAppendFeature_stripHtml()
   {
     SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     SequenceFeature sf = new SequenceFeature("METAL",
             "<html><body>hello<em>world</em></body></html>", 1, 3,
             Float.NaN, "group");
-  
+
     sar.appendFeature(sb, 1, null, sf);
     // !! strips off </body> but not <body> ??
-    assertEquals("METAL 1 3; <body>hello<em>world</em>",
-            sb.toString());
+    assertEquals("METAL 1 3; <body>hello<em>world</em>", sb.toString());
 
     sb.setLength(0);
     sf.setDescription("<br>&kHD>6");
index bdd311b..d0561b0 100644 (file)
@@ -103,7 +103,7 @@ public class StockholmFileTest
       // make sure dataset is initialised ? not sure about this
       for (int i = 0; i < al.getSequencesArray().length; ++i)
       {
-        al.getSequenceAt(i).setDatasetSequence(al.getSequenceAt(i));
+        al.getSequenceAt(i).createDatasetSequence();
       }
       String outputfile = rf.formatSequences(ioformat, al, true);
       System.out.println("Output file in '" + ioformat + "':\n"
@@ -228,7 +228,7 @@ public class StockholmFileTest
     }
     assertEquals(
             "Generated and imported alignment have different annotation sets",
-            aa_new_size, aa_original_size);
+            aa_original_size, aa_new_size);
 
     // check sequences, annotation and features
     SequenceI[] seq_original = new SequenceI[al.getSequencesArray().length];
@@ -281,8 +281,7 @@ public class StockholmFileTest
 
             assertEquals("different number of features",
                     seq_original[i].getSequenceFeatures().length,
-                    seq_new[in]
-                    .getSequenceFeatures().length);
+                    seq_new[in].getSequenceFeatures().length);
 
             for (int feat = 0; feat < seq_original[i].getSequenceFeatures().length; feat++)
             {
index 28036b2..a0c3577 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import static org.testng.AssertJUnit.assertEquals;
index 420b032..4355e40 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -161,7 +181,7 @@ public class Gff3HelperTest
             "GAATTCGTTCATGTAGGTTGATTTTTATT");
     seq.createDatasetSequence();
     AlignmentI align = new Alignment(new SequenceI[] {});
-  
+
     // mapping from gi|68711 12923-13060 to gi|N37351 1-138
     String[] gff = "gi|68711\tblat-pasa\tcDNA_match\t12923\t13060\t98.55\t+\t.\tID=align_68;Target=gi|N37351 1 138 +"
             .split("\\t");
@@ -179,7 +199,7 @@ public class Gff3HelperTest
     // (this is important for 'align cdna to genome' to work correctly)
     assertEquals(1, align.getCodonFrames().size());
     AlignedCodonFrame mapping = align.getCodonFrames().get(0);
-  
+
     /*
      * 'dnaseqs' (map from) is here [gi|68711]
      * 'aaseqs' (map to) is here [gi|N37351]
@@ -192,8 +212,7 @@ public class Gff3HelperTest
     assertEquals(1, mapping.getdnaToProt().length);
     assertEquals(2, mapping.getdnaToProt()[0].getFromRanges().size());
     // the two spliced dna ranges are combined in one MapList
-    assertArrayEquals(new int[] { 12923, 13060 },
-            mapping.getdnaToProt()[0]
+    assertArrayEquals(new int[] { 12923, 13060 }, mapping.getdnaToProt()[0]
             .getFromRanges().get(0));
     assertArrayEquals(new int[] { 13411, 13550 }, mapping.getdnaToProt()[0]
             .getFromRanges().get(1));
index fe8f88e..a1032ef 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import static org.testng.AssertJUnit.assertEquals;
index 657b5bd..cfe1d12 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import static org.testng.AssertJUnit.assertNull;
index 72ea7e2..f0381e7 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import static org.testng.AssertJUnit.assertEquals;
index 2ef4c99..75546fb 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.gff;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -38,7 +58,7 @@ public class InterProScanHelperTest
     seq.createDatasetSequence();
     AlignmentI align = new Alignment(new SequenceI[] {});
     Map<String, List<String>> set = Gff3Helper.parseNameValuePairs(gff[8]);
-  
+
     /*
      * this should create a mapping from Prot1/5-30 to virtual sequence
      * match$17_5_30 (added to newseqs) positions 1-26
diff --git a/test/jalview/io/testProps_nodas.jvprops b/test/jalview/io/testProps_nodas.jvprops
new file mode 100644 (file)
index 0000000..da95549
--- /dev/null
@@ -0,0 +1,83 @@
+#---JalviewX Properties File---
+#Fri Apr 25 09:54:25 BST 2014
+SCREEN_Y=768
+SCREEN_X=936
+SHOW_WSDISCOVERY_ERRORS=true
+LATEST_VERSION=2.8.0b1
+SHOW_CONSERVATION=true
+JALVIEW_RSS_WINDOW_SCREEN_WIDTH=550
+JAVA_CONSOLE_SCREEN_WIDTH=450
+LAST_DIRECTORY=/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples
+ID_ITALICS=true
+SORT_ALIGNMENT=No sort
+SHOW_IDENTITY=true
+WSMENU_BYHOST=false
+SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$
+SHOW_FULLSCREEN=false
+RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar
+FONT_NAME=SansSerif
+BLC_JVSUFFIX=true
+VERSION_CHECK=false
+YEAR=2011
+SHOW_DBREFS_TOOLTIP=true
+MSF_JVSUFFIX=true
+SCREENGEOMETRY_HEIGHT=1600
+JAVA_CONSOLE_SCREEN_Y=475
+JAVA_CONSOLE_SCREEN_X=830
+PFAM_JVSUFFIX=true
+PIR_JVSUFFIX=true
+STARTUP_FILE=http\://www.jalview.org/examples/exampleFile_2_3.jar
+JAVA_CONSOLE_SCREEN_HEIGHT=162
+PIR_MODELLER=false
+GAP_SYMBOL=-
+SHOW_QUALITY=true
+SHOW_GROUP_CONSERVATION=false
+SHOW_JWS2_SERVICES=true
+SHOW_NPFEATS_TOOLTIP=true
+FONT_STYLE=plain
+ANTI_ALIAS=false
+SORT_BY_TREE=false
+RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$
+AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton
+JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328
+SHOW_GROUP_CONSENSUS=false
+SHOW_CONSENSUS_HISTOGRAM=true
+SHOW_OVERVIEW=false
+AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
+FIGURE_AUTOIDWIDTH=false
+SCREEN_WIDTH=900
+ANNOTATIONCOLOUR_MIN=ffc800
+SHOW_STARTUP_FILE=false
+RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out
+DEFAULT_FILE_FORMAT=FASTA
+SHOW_JAVA_CONSOLE=false
+VERSION=2.8b1
+FIGURE_USERIDWIDTH=
+WSMENU_BYTYPE=false
+DEFAULT_COLOUR=None
+NOQUESTIONNAIRES=true
+JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM
+BUILD_DATE=01 November 2013
+PILEUP_JVSUFFIX=true
+SHOW_CONSENSUS_LOGO=false
+SCREENGEOMETRY_WIDTH=2560
+SHOW_ANNOTATIONS=true
+JALVIEW_RSS_WINDOW_SCREEN_Y=0
+USAGESTATS=false
+JALVIEW_RSS_WINDOW_SCREEN_X=0
+SHOW_UNCONSERVED=false
+SHOW_JVSUFFIX=true
+SCREEN_HEIGHT=650
+ANNOTATIONCOLOUR_MAX=ff0000
+AUTO_CALC_CONSENSUS=true
+FASTA_JVSUFFIX=true
+DAS_ACTIVE_SOURCE=
+JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws
+PAD_GAPS=false
+CLUSTAL_JVSUFFIX=true
+SHOW_ENFIN_SERVICES=true
+FONT_SIZE=10
+RIGHT_ALIGN_IDS=false
+USE_PROXY=false
+WRAP_ALIGNMENT=false
+DAS_REGISTRY_URL=http\://www.nowhere/
index ff2f2aa..45b56c2 100644 (file)
@@ -55,43 +55,4 @@ public class DnaCodonTests
               + codon.getKey() + "\", \"" + codon.getValue() + "\");");
     }
   }
-
-  @Test(groups = { "Functional" })
-  public void checkOldCodonagainstNewCodonTable()
-  {
-    // note - this test will be removed once the old codon table (including
-    // Vectors) is removed
-    String additional = "", failtrans = "", differentTr = "";
-    for (String amacid : ResidueProperties.codonHash.keySet())
-    {
-      for (String codon : ResidueProperties.codonHash.get(amacid))
-      {
-        String trans = ResidueProperties.codonTranslate(codon);
-        String oldtrans = ResidueProperties._codonTranslate(codon);
-        if (trans == null)
-        {
-          additional += "\nOld translation table includes additional codons for "
-                  + amacid + " : " + codon;
-        }
-        if (oldtrans == null)
-        {
-          failtrans += ("\nold translation routine failed for old translation entry (aa was "
-                  + amacid + " codon was " + codon + ")");
-        }
-        if (!oldtrans.equals(trans))
-        {
-          differentTr += ("\nDifferent translation for old and new routines: "
-                  + amacid
-                  + " "
-                  + codon
-                  + " => expected "
-                  + oldtrans
-                  + " and got " + trans);
-        }
-      }
-    }
-    assertTrue("" + additional + "\n" + failtrans + "\n" + differentTr,
-            additional.length() == 0 && failtrans.length() == 0
-                    && differentTr.length() == 0);
-  }
 }
index e13f542..fd49971 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.schemes;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -123,7 +143,8 @@ public class FeatureColourTest
   @Test(groups = { "Functional" })
   public void testGetColor_Graduated()
   {
-    // graduated colour from score 0 to 100, gray(128, 128, 128) to red(255, 0, 0)
+    // graduated colour from score 0 to 100, gray(128, 128, 128) to red(255, 0,
+    // 0)
     FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
     // feature score is 75 which is 3/4 of the way from GRAY to RED
     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
@@ -166,7 +187,7 @@ public class FeatureColourTest
     String redHex = Format.getHexString(Color.RED);
     String hexColour = redHex;
     assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
-    
+
     /*
      * colour by label (no threshold)
      */
diff --git a/test/jalview/schemes/ResidueColourSchemeTest.java b/test/jalview/schemes/ResidueColourSchemeTest.java
new file mode 100644 (file)
index 0000000..a02ca06
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * 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.schemes;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.datamodel.Profile;
+import jalview.datamodel.ProfileI;
+import jalview.datamodel.Profiles;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class ResidueColourSchemeTest
+{
+  @Test(groups = "Functional")
+  public void testAboveThreshold()
+  {
+    /*
+     * make up profiles for this alignment:
+     * AR-Q
+     * AR--
+     * SR-T
+     * SR-T
+     */
+    ProfileI[] profiles = new ProfileI[4];
+    profiles[0] = new Profile(4, 0, 2, "AS");
+    profiles[1] = new Profile(4, 0, 4, "R");
+    profiles[2] = new Profile(4, 4, 0, "");
+    profiles[3] = new Profile(4, 1, 2, "T");
+    ResidueColourScheme rcs = new ResidueColourScheme();
+    rcs.setConsensus(new Profiles(profiles));
+    
+    /*
+     * no threshold
+     */
+    rcs.setThreshold(0, true);
+    assertTrue(rcs.aboveThreshold('a', 0));
+    assertTrue(rcs.aboveThreshold('S', 0));
+    assertFalse(rcs.aboveThreshold('W', 0));
+    assertTrue(rcs.aboveThreshold('R', 1));
+    assertFalse(rcs.aboveThreshold('W', 2));
+    assertTrue(rcs.aboveThreshold('t', 3));
+    assertFalse(rcs.aboveThreshold('Q', 3));
+
+    /*
+     * with threshold, include gaps
+     */
+    rcs.setThreshold(60, false);
+    assertFalse(rcs.aboveThreshold('a', 0));
+    assertFalse(rcs.aboveThreshold('S', 0));
+    assertTrue(rcs.aboveThreshold('R', 1));
+    assertFalse(rcs.aboveThreshold('W', 2));
+    assertFalse(rcs.aboveThreshold('t', 3)); // 50% < 60%
+
+    /*
+     * with threshold, ignore gaps
+     */
+    rcs.setThreshold(60, true);
+    assertFalse(rcs.aboveThreshold('a', 0));
+    assertFalse(rcs.aboveThreshold('S', 0));
+    assertTrue(rcs.aboveThreshold('R', 1));
+    assertFalse(rcs.aboveThreshold('W', 2));
+    assertTrue(rcs.aboveThreshold('t', 3)); // 67% > 60%
+  }
+
+  /**
+   * Test colour bleaching based on conservation score and conservation slider.
+   * Scores of 10 or 11 should leave colours unchanged. Gap is always white.
+   */
+  @Test(groups = "Functional")
+  public void testApplyConservation()
+  {
+    ResidueColourScheme rcs = new ResidueColourScheme();
+
+    // no conservation present - no fading
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 12));
+    
+    // cheat by setting conservation sequence directly
+    // rather than calculating it - good enough for this test
+    String consensus = "0123456789+*-";
+    rcs.conservation = consensus.toCharArray();
+
+    // column out of range:
+    assertEquals(Color.RED,
+            rcs.applyConservation(Color.RED, consensus.length()));
+
+    /*
+     * with 100% threshold, 'fade factor' is 
+     * (11-score)/10 * 100/20 = (11-score)/2
+     * which is >= 1 for all scores i.e. all fade to white except +, *
+     */
+    rcs.setConservationInc(100);
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 0));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 1));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 2));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 3));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 4));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 5));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 6));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 7));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 8));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 9));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 10));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 11));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 12));
+
+    /*
+     * with 0% threshold, there should be no fading
+     */
+    rcs.setConservationInc(0);
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 0));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 1));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 2));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 3));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 4));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 5));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 6));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 7));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 8));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 9));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 10));
+    assertEquals(Color.RED, rcs.applyConservation(Color.RED, 11));
+    assertEquals(Color.WHITE, rcs.applyConservation(Color.RED, 12)); // gap
+
+    /*
+     * with 40% threshold, 'fade factor' is 
+     * (11-score)/10 * 40/20 = (11-score)/5
+     * which is {>1, >1, >1, >1, >1, >1, 1, 0.8, 0.6, 0.4} for score 0-9
+     * e.g. score 7 colour fades 80% of the way to white (255, 255, 255)
+     */
+    rcs.setConservationInc(40);
+    Color colour = new Color(155, 105, 55);
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 0));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 1));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 2));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 3));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 4));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 5));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 6));
+    assertEquals(new Color(235, 225, 215), rcs.applyConservation(colour, 7));
+    assertEquals(new Color(215, 195, 175), rcs.applyConservation(colour, 8));
+    assertEquals(new Color(195, 165, 135), rcs.applyConservation(colour, 9));
+    assertEquals(colour, rcs.applyConservation(colour, 10));
+    assertEquals(colour, rcs.applyConservation(colour, 11));
+    assertEquals(Color.WHITE, rcs.applyConservation(colour, 12));
+  }
+}
index b68ca68..be6a10c 100644 (file)
@@ -25,6 +25,7 @@ import static org.testng.AssertJUnit.assertNull;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import org.testng.annotations.Test;
 
@@ -1556,4 +1557,62 @@ public class ResiduePropertiesTest
     assertEquals('Q', ResidueProperties.getSingleCharacterCode("Gln"));
     assertEquals('Q', ResidueProperties.getSingleCharacterCode("gln"));
   }
+
+  @Test(groups = { "Functional" })
+  public void testPhysicoChemicalProperties()
+  {
+    checkProperty("aromatic", "FYWH-*");
+    checkProperty("aliphatic", "IVL-*");
+    checkProperty("tiny", "GAS-*");
+    checkProperty("small", "VCTGACSDNP-*");
+    checkProperty("charged", "HKRDE-*");
+    checkProperty("negative", "DE-*");
+    checkProperty("polar", "YWHRKTSNDEQ-*X");
+    checkProperty("positive", "HKR-*");
+    checkProperty("proline", "P-*");
+    checkProperty("hydrophobic", "MILVFYWHKTGAC-*X");
+  }
+
+  /**
+   * Verify that the residues in the list have the named property, and other
+   * residues do not
+   * 
+   * @param property
+   * @param residues
+   */
+  void checkProperty(String property, String residues)
+  {
+    Map<String, Integer> props = ResidueProperties.propHash.get(property);
+
+    /*
+     * assert residues have the property (value 1 in lookup)
+     */
+    for (char res : residues.toCharArray())
+    {
+      assertEquals(res + " should be " + property, 1,
+              props.get(String.valueOf(res)).intValue());
+    }
+
+    /*
+     * assert other residues do not (value 0 in lookup)
+     */
+    for (String res : ResidueProperties.aa)
+    {
+      if (!residues.contains(res))
+      {
+        Integer propValue = props.get(String.valueOf(res));
+
+        if (propValue != null)
+        {
+          /*
+           * conservation calculation assigns unexpected symbols
+           * the same value as '-'; here we just check those which
+           * explicitly do not have the property
+           */
+          assertEquals(res + " should not be " + property, 0,
+                  propValue.intValue());
+        }
+      }
+    }
+  }
 }
index e524cb4..34af086 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.schemes;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -7,6 +27,7 @@ import static org.testng.AssertJUnit.assertSame;
 import java.awt.Color;
 
 import org.testng.annotations.Test;
+
 public class UserColourSchemeTest
 {
 
index 13387db..ceb098b 100644 (file)
@@ -69,7 +69,7 @@ public class Mapping
       StructureSelectionManager ssm = new jalview.structure.StructureSelectionManager();
       StructureFile pmap = ssm.setMapping(true, new SequenceI[] { uprot },
               new String[] { "A" }, "test/jalview/ext/jmol/1QCF.pdb",
-              jalview.io.DataSourceType.FILE);
+              DataSourceType.FILE);
       assertTrue(pmap != null);
       SequenceI protseq = pmap.getSeqsAsArray()[0];
       AlignmentAnnotation pstra = protseq
@@ -140,7 +140,7 @@ public class Mapping
     // source
     StructureFile pde = ssm.setMapping(true, new SequenceI[] { sq },
             new String[]
-    { "A" }, inFile = "examples/1gaq.txt", jalview.io.DataSourceType.FILE);
+    { "A" }, inFile = "examples/1gaq.txt", DataSourceType.FILE);
     assertTrue("PDB File couldn't be found", pde != null);
     StructureMapping[] mp = ssm.getMapping(inFile);
     assertTrue("No mappings made.", mp != null && mp.length > 0);
@@ -237,7 +237,7 @@ public class Mapping
     StructureSelectionManager ssm = new jalview.structure.StructureSelectionManager();
     StructureFile pmap = ssm.setMapping(true, new SequenceI[] { newseq },
             new String[] { null }, "examples/3W5V.pdb",
-            jalview.io.DataSourceType.FILE);
+            DataSourceType.FILE);
     if (pmap == null)
     {
       AssertJUnit.fail("Couldn't make a mapping for 3W5V to FER1_MAIZE");
@@ -254,7 +254,7 @@ public class Mapping
     StructureImportSettings.setShowSeqFeatures(true);
     AlignFrame ref = new FileLoader(false)
             .LoadFileWaitTillLoaded("test/jalview/ext/jmol/1QCF.pdb",
-                    jalview.io.DataSourceType.FILE);
+                    DataSourceType.FILE);
     SequenceI refseq = ref.getViewport().getAlignment().getSequenceAt(0);
     SequenceI newseq = new Sequence(refseq.getName() + "Copy",
             refseq.getSequenceAsString());
@@ -266,7 +266,7 @@ public class Mapping
     ssm.setAddTempFacAnnot(true);
     StructureFile pmap = ssm.setMapping(true, new SequenceI[] { newseq },
             new String[] { null }, "test/jalview/ext/jmol/1QCF.pdb",
-            jalview.io.DataSourceType.FILE);
+            DataSourceType.FILE);
     assertTrue(pmap != null);
     assertEquals("Original and copied sequence of different lengths.",
             refseq.getLength(), newseq.getLength());
index aecdbf9..d53aede 100644 (file)
@@ -138,7 +138,7 @@ public class StructureSelectionManagerTest
     SequenceFeature sf = pmap.getSeqs().get(0).getSequenceFeatures()[0];
     assertEquals("RESNUM", sf.getType());
     assertEquals("1gaq", sf.getFeatureGroup());
-    assertEquals("GLU:19 1gaqA", sf.getDescription());
+    assertEquals("GLU:  19  1gaqA", sf.getDescription());
 
     /*
      * Verify a RESNUM sequence feature in the StructureSelectionManager mapped
@@ -148,6 +148,6 @@ public class StructureSelectionManagerTest
     sf = map.sequence.getSequenceFeatures()[0];
     assertEquals("RESNUM", sf.getType());
     assertEquals("1gaq", sf.getFeatureGroup());
-    assertEquals("ALA:1 1gaqB", sf.getDescription());
+    assertEquals("ALA:   1  1gaqB", sf.getDescription());
   }
 }
index 2e0692e..1dcbd44 100644 (file)
@@ -49,26 +49,36 @@ import org.testng.annotations.Test;
  */
 public class AAStructureBindingModelTest
 {
+  /*
+   * Scenario: Jalview has 4 sequences, corresponding to 1YCS (chains A and B), 3A6S|B, 1OOT|A
+   */
   private static final String PDB_1 = "HEADER    COMPLEX (ANTI-ONCOGENE/ANKYRIN REPEATS) 30-SEP-96   1YCS              \n"
           + "ATOM      2  CA  VAL A  97      24.134   4.926  45.821  1.00 47.43           C  \n"
           + "ATOM      9  CA  PRO A  98      25.135   8.584  46.217  1.00 41.60           C  \n"
           + "ATOM     16  CA  SER A  99      28.243   9.596  44.271  1.00 39.63           C  \n"
           + "ATOM     22  CA  GLN A 100      31.488  10.133  46.156  1.00 35.60           C  \n"
-          + "ATOM     31  CA  LYS A 101      33.323  11.587  43.115  1.00 41.69           C  \n";
+          // artificial jump in residue numbering to prove it is correctly
+          // mapped:
+          + "ATOM     31  CA  LYS A 102      33.323  11.587  43.115  1.00 41.69           C  \n"
+          + "ATOM   1857  CA  GLU B 374       9.193 -16.005  95.870  1.00 54.22           C  \n"
+          + "ATOM   1866  CA  ILE B 375       7.101 -14.921  92.847  1.00 46.82           C  \n"
+          + "ATOM   1874  CA  VAL B 376      10.251 -13.625  91.155  1.00 47.80           C  \n"
+          + "ATOM   1881  CA  LYS B 377      11.767 -17.068  91.763  1.00 50.21           C  \n"
+          + "ATOM   1890  CA  PHE B 378       8.665 -18.948  90.632  1.00 44.85           C  \n";
 
   private static final String PDB_2 = "HEADER    HYDROLASE                               09-SEP-09   3A6S              \n"
-          + "ATOM      2  CA  MET A   1      15.366 -11.648  24.854  1.00 32.05           C  \n"
-          + "ATOM     10  CA  LYS A   2      16.846  -9.215  22.340  1.00 25.68           C  \n"
-          + "ATOM     19  CA  LYS A   3      15.412  -6.335  20.343  1.00 19.42           C  \n"
-          + "ATOM     28  CA  LEU A   4      15.629  -5.719  16.616  1.00 15.49           C  \n"
-          + "ATOM     36  CA  GLN A   5      14.412  -2.295  15.567  1.00 12.19           C  \n";
+          + "ATOM      2  CA  MET B   1      15.366 -11.648  24.854  1.00 32.05           C  \n"
+          + "ATOM     10  CA  LYS B   2      16.846  -9.215  22.340  1.00 25.68           C  \n"
+          + "ATOM     19  CA  LYS B   3      15.412  -6.335  20.343  1.00 19.42           C  \n"
+          + "ATOM     28  CA  LEU B   4      15.629  -5.719  16.616  1.00 15.49           C  \n"
+          + "ATOM     36  CA  GLN B   5      14.412  -2.295  15.567  1.00 12.19           C  \n";
 
   private static final String PDB_3 = "HEADER    STRUCTURAL GENOMICS                     04-MAR-03   1OOT              \n"
-          + "ATOM      2  CA  SER A   1      29.427   3.330  -6.578  1.00 32.50           C  \n"
-          + "ATOM      8  CA  PRO A   2      29.975   3.340  -2.797  1.00 17.62           C  \n"
-          + "ATOM     16  CA ALYS A   3      26.958   3.024  -0.410  0.50  8.78           C  \n"
-          + "ATOM     33  CA  ALA A   4      26.790   4.320   3.172  1.00 11.98           C  \n"
-          + "ATOM     39  CA AVAL A   5      24.424   3.853   6.106  0.50 13.83           C  \n";
+          + "ATOM      2  CA  SER A   7      29.427   3.330  -6.578  1.00 32.50           C  \n"
+          + "ATOM      8  CA  PRO A   8      29.975   3.340  -2.797  1.00 17.62           C  \n"
+          + "ATOM     16  CA ALYS A   9      26.958   3.024  -0.410  0.50  8.78           C  \n"
+          + "ATOM     33  CA  ALA A  10      26.790   4.320   3.172  1.00 11.98           C  \n"
+          + "ATOM     39  CA AVAL A  12      24.424   3.853   6.106  0.50 13.83           C  \n";
 
   AAStructureBindingModel testee;
 
@@ -80,39 +90,38 @@ public class AAStructureBindingModelTest
   @BeforeMethod(alwaysRun = true)
   public void setUp()
   {
-    SequenceI seq1 = new Sequence("1YCS", "-VPSQK");
+    SequenceI seq1a = new Sequence("1YCS|A", "-VPSQK");
+    SequenceI seq1b = new Sequence("1YCS|B", "EIVKF-");
     SequenceI seq2 = new Sequence("3A6S", "MK-KLQ");
     SequenceI seq3 = new Sequence("1OOT", "SPK-AV");
-    al = new Alignment(new SequenceI[] { seq1, seq2, seq3 });
+    al = new Alignment(new SequenceI[] { seq1a, seq1b, seq2, seq3 });
     al.setDataset(null);
 
+    /*
+     * give pdb files the name generated by Jalview for PASTE source
+     */
     PDBEntry[] pdbFiles = new PDBEntry[3];
-    pdbFiles[0] = new PDBEntry("1YCS", "A", Type.PDB, "1YCS.pdb");
-    pdbFiles[1] = new PDBEntry("3A6S", "B", Type.PDB, "3A6S.pdb");
-    pdbFiles[2] = new PDBEntry("1OOT", "A", Type.PDB, "1OOT.pdb");
-    String[][] chains = new String[3][];
+    pdbFiles[0] = new PDBEntry("1YCS", "A", Type.PDB, "INLINE1YCS");
+    pdbFiles[1] = new PDBEntry("3A6S", "B", Type.PDB, "INLINE3A6S");
+    pdbFiles[2] = new PDBEntry("1OOT", "A", Type.PDB, "INLINE1OOT");
     SequenceI[][] seqs = new SequenceI[3][];
-    seqs[0] = new SequenceI[] { seq1 };
+    seqs[0] = new SequenceI[] { seq1a, seq1b };
     seqs[1] = new SequenceI[] { seq2 };
     seqs[2] = new SequenceI[] { seq3 };
     StructureSelectionManager ssm = new StructureSelectionManager();
 
-    ssm.setMapping(new SequenceI[] { seq1 }, null, PDB_1,
+    ssm.setMapping(new SequenceI[] { seq1a, seq1b }, null, PDB_1,
             DataSourceType.PASTE);
     ssm.setMapping(new SequenceI[] { seq2 }, null, PDB_2,
             DataSourceType.PASTE);
     ssm.setMapping(new SequenceI[] { seq3 }, null, PDB_3,
             DataSourceType.PASTE);
 
-    testee = new AAStructureBindingModel(ssm, pdbFiles, seqs, chains, null)
+    testee = new AAStructureBindingModel(ssm, pdbFiles, seqs, null)
     {
       @Override
       public String[] getPdbFile()
       {
-        /*
-         * fudge 'filenames' to match those generated when PDBFile parses PASTE
-         * data
-         */
         return new String[] { "INLINE1YCS", "INLINE3A6S", "INLINE1OOT" };
       }
 
@@ -130,6 +139,12 @@ public class AAStructureBindingModelTest
       public void highlightAtoms(List<AtomSpec> atoms)
       {
       }
+
+      @Override
+      public List<String> getChainNames()
+      {
+        return null;
+      }
     };
   }
 
@@ -140,7 +155,10 @@ public class AAStructureBindingModelTest
   @Test(groups = { "Functional" })
   public void testFindSuperposableResidues()
   {
-    SuperposeData[] structs = new SuperposeData[al.getHeight()];
+    /*
+     * create a data bean to hold data per structure file
+     */
+    SuperposeData[] structs = new SuperposeData[testee.getPdbFile().length];
     for (int i = 0; i < structs.length; i++)
     {
       structs[i] = testee.new SuperposeData(al.getWidth());
@@ -162,10 +180,23 @@ public class AAStructureBindingModelTest
      */
     assertFalse(matched[0]); // gap in first sequence
     assertTrue(matched[1]);
-    assertFalse(matched[2]); // gap in second sequence
-    assertFalse(matched[3]); // gap in third sequence
+    assertFalse(matched[2]); // gap in third sequence
+    assertFalse(matched[3]); // gap in fourth sequence
     assertTrue(matched[4]);
-    assertTrue(matched[5]);
+    assertTrue(matched[5]); // gap in second sequence
+
+    assertEquals("1YCS", structs[0].pdbId);
+    assertEquals("3A6S", structs[1].pdbId);
+    assertEquals("1OOT", structs[2].pdbId);
+    assertEquals("A", structs[0].chain); // ? struct has chains A _and_ B
+    assertEquals("B", structs[1].chain);
+    assertEquals("A", structs[2].chain);
+    // the 0's for unsuperposable positions propagate down the columns:
+    assertEquals("[0, 97, 98, 99, 100, 102]",
+            Arrays.toString(structs[0].pdbResNo));
+    assertEquals("[0, 2, 0, 3, 4, 5]", Arrays.toString(structs[1].pdbResNo));
+    assertEquals("[0, 8, 0, 0, 10, 12]",
+            Arrays.toString(structs[2].pdbResNo));
   }
 
   @Test(groups = { "Functional" })
index 5a2674a..30cc07d 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.AssertJUnit.assertEquals;
@@ -8,8 +28,9 @@ import org.testng.annotations.Test;
 
 public class ArrayUtilsTest
 {
-  @Test(groups="Functional")
-  public void testReverseIntArray() {
+  @Test(groups = "Functional")
+  public void testReverseIntArray()
+  {
 
     // null value: should be no exception
     ArrayUtils.reverseIntArray((int[]) null);
diff --git a/test/jalview/util/CaseInsensitiveStringTest.java b/test/jalview/util/CaseInsensitiveStringTest.java
new file mode 100644 (file)
index 0000000..0429cce
--- /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.
+ */
+package jalview.util;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+public class CaseInsensitiveStringTest
+{
+  @Test(groups = "Functional")
+  public void testEquals()
+  {
+    CaseInsensitiveString s1 = new CaseInsensitiveString(null);
+    CaseInsensitiveString s2 = new CaseInsensitiveString("a");
+    CaseInsensitiveString s3 = new CaseInsensitiveString("A");
+    CaseInsensitiveString s4 = new CaseInsensitiveString("b");
+
+    assertFalse(s1.equals(null));
+    assertTrue(s1.equals(s1));
+    assertFalse(s1.equals(s2));
+    assertTrue(s2.equals(s2));
+    assertFalse(s2.equals(s1));
+    assertTrue(s2.equals(s3));
+    assertTrue(s3.equals(s2));
+    assertFalse(s3.equals(s4));
+    assertFalse(s4.equals(s3));
+  }
+
+  @Test(groups = "Functional")
+  public void testHashcode()
+  {
+    CaseInsensitiveString s1 = new CaseInsensitiveString(null);
+    CaseInsensitiveString s2 = new CaseInsensitiveString("a");
+    CaseInsensitiveString s3 = new CaseInsensitiveString("A");
+    CaseInsensitiveString s4 = new CaseInsensitiveString("b");
+
+    assertNotEquals(s1.hashCode(), s2.hashCode());
+    assertEquals(s2.hashCode(), s3.hashCode());
+    assertNotEquals(s3.hashCode(), s4.hashCode());
+  }
+}
index a82b9c0..77a023f 100644 (file)
@@ -22,6 +22,7 @@ package jalview.util;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
 
 import java.awt.Color;
 
@@ -122,8 +123,7 @@ public class ColorUtilsTest
      * value > max
      */
     col = ColorUtils
-            .getGraduatedColour(40f, 10f, minColour, 30f,
-            maxColour);
+            .getGraduatedColour(40f, 10f, minColour, 30f, maxColour);
     assertEquals(maxColour, col);
 
     /*
@@ -133,4 +133,27 @@ public class ColorUtilsTest
             .getGraduatedColour(40f, 10f, minColour, 10f, maxColour);
     assertEquals(minColour, col);
   }
+
+  @Test(groups = { "Functional" })
+  public void testBleachColour()
+  {
+    Color colour = new Color(155, 105, 55);
+    assertSame(colour, ColorUtils.bleachColour(colour, 0));
+    assertEquals(Color.WHITE, ColorUtils.bleachColour(colour, 1));
+    assertEquals(Color.WHITE, ColorUtils.bleachColour(colour, 2));
+    assertEquals(new Color(175, 135, 95),
+            ColorUtils.bleachColour(colour, 0.2f));
+    assertEquals(new Color(225, 210, 195),
+            ColorUtils.bleachColour(colour, 0.7f));
+
+    /*
+     * and some 'negative fade'
+     */
+    assertEquals(Color.BLACK, ColorUtils.bleachColour(colour, -1));
+    assertEquals(Color.BLACK, ColorUtils.bleachColour(colour, -2));
+    assertEquals(new Color(124, 84, 44),
+            ColorUtils.bleachColour(colour, -0.2f));
+    assertEquals(new Color(46, 31, 16), // with rounding down
+            ColorUtils.bleachColour(colour, -0.7f));
+  }
 }
index 9aab66c..b71c270 100644 (file)
@@ -188,4 +188,16 @@ public class ComparisonTest
     assertTrue(Comparison.isNucleotideSequence("a A-g.GcCtTuU", true));
     assertFalse(Comparison.isNucleotideSequence("a A-g.GcCtTuU", false));
   }
+
+  @Test(groups = { "Functional" })
+  public void testIsSameResidue()
+  {
+    assertTrue(Comparison.isSameResidue('a', 'a', false));
+    assertTrue(Comparison.isSameResidue('a', 'a', true));
+    assertTrue(Comparison.isSameResidue('A', 'a', false));
+    assertTrue(Comparison.isSameResidue('a', 'A', false));
+
+    assertFalse(Comparison.isSameResidue('a', 'A', true));
+    assertFalse(Comparison.isSameResidue('A', 'a', true));
+  }
 }
index 96935ce..1c68a71 100644 (file)
@@ -74,9 +74,16 @@ public class DBRefUtilsTest
     assertSame(ref2, selected[0]);
     assertSame(ref3, selected[1]);
 
-    sources = new String[] { "Uniprot", "EMBLCDS" };
+    sources = new String[] { "EMBLCDS" };
     selected = DBRefUtils.selectRefs(dbrefs, sources);
     assertNull(selected);
+
+    sources = new String[] { "embl", "uniprot" };
+    selected = DBRefUtils.selectRefs(dbrefs, sources);
+    assertEquals(3, selected.length);
+    assertSame(ref1, selected[0]);
+    assertSame(ref2, selected[1]);
+    assertSame(ref3, selected[2]);
   }
 
   /**
@@ -99,6 +106,11 @@ public class DBRefUtilsTest
     assertEquals("UNIPROTKB/SWISS-CHEESE",
             DBRefUtils.getCanonicalName("UNIPROTKB/SWISS-CHEESE"));
     assertEquals("ENSEMBL", DBRefUtils.getCanonicalName("Ensembl"));
+
+    // these are not 'known' to Jalview
+    assertEquals("PFAM", DBRefUtils.getCanonicalName("PFAM"));
+    assertEquals("pfam", DBRefUtils.getCanonicalName("pfam"));
+
   }
 
   @Test(groups = { "Functional" })
@@ -158,6 +170,9 @@ public class DBRefUtilsTest
     SequenceI seq = new Sequence("Seq1", "ABCD");
     DBRefEntry ref = DBRefUtils.parseToDbRef(seq, "pdb", "1.2",
             "1WRI A; 7-80;");
+    // TODO: correct PDBEntry and PDB DBRef accessions need to be generated for
+    // PDB ref in Stockholm
+
     DBRefEntry[] refs = seq.getDBRefs();
     assertEquals(1, refs.length);
     assertSame(ref, refs[0]);
@@ -194,8 +209,7 @@ public class DBRefUtilsTest
         1 }, 1, 1)));
 
     List<DBRefEntry> matches = DBRefUtils.searchRefs(new DBRefEntry[] {
-        ref1,
-        ref2, ref3, ref4, ref5 }, target);
+        ref1, ref2, ref3, ref4, ref5 }, target);
     assertEquals(3, matches.size());
     assertSame(ref1, matches.get(0));
     assertSame(ref2, matches.get(1));
@@ -228,8 +242,7 @@ public class DBRefUtilsTest
     ref3.setMap(map3);
 
     List<DBRefEntry> matches = DBRefUtils.searchRefs(new DBRefEntry[] {
-        ref1,
-        ref2, ref3 }, target);
+        ref1, ref2, ref3 }, target);
     assertEquals(2, matches.size());
     assertSame(ref1, matches.get(0));
     assertSame(ref2, matches.get(1));
@@ -242,7 +255,7 @@ public class DBRefUtilsTest
   @Test(groups = { "Functional" })
   public void testSearchRefs_accessionid()
   {
-  
+
     DBRefEntry ref1 = new DBRefEntry("Uniprot", "1", "A1234"); // matches
     DBRefEntry ref2 = new DBRefEntry("embl", "1", "A1234"); // matches
     // constructor does not upper-case accession id
@@ -252,9 +265,8 @@ public class DBRefUtilsTest
     DBRefEntry ref5 = new DBRefEntry("EMBL", "1", "A1234");
     ref5.setMap(new Mapping(new MapList(new int[] { 1, 1 }, new int[] { 1,
         1 }, 1, 1)));
-  
-    DBRefEntry[] dbrefs = new DBRefEntry[] { ref1,
-        ref2, ref3, ref4, ref5 };
+
+    DBRefEntry[] dbrefs = new DBRefEntry[] { ref1, ref2, ref3, ref4, ref5 };
     List<DBRefEntry> matches = DBRefUtils.searchRefs(dbrefs, "A1234");
     assertEquals(3, matches.size());
     assertSame(ref1, matches.get(0));
@@ -270,7 +282,7 @@ public class DBRefUtilsTest
   public void testSearchRefs_wildcardAccessionid()
   {
     DBRefEntry target = new DBRefEntry("EMBL", "2", null);
-  
+
     DBRefEntry ref1 = new DBRefEntry("EMBL", "1", "A1234"); // matches
     // constructor changes embl to EMBL
     DBRefEntry ref2 = new DBRefEntry("embl", "1", "A1235"); // matches
@@ -281,10 +293,9 @@ public class DBRefUtilsTest
     DBRefEntry ref5 = new DBRefEntry("EMBL", "1", "A1237");
     ref5.setMap(new Mapping(new MapList(new int[] { 1, 1 }, new int[] { 1,
         1 }, 1, 1)));
-  
+
     List<DBRefEntry> matches = DBRefUtils.searchRefs(new DBRefEntry[] {
-        ref1,
-        ref2, ref3, ref4, ref5 }, target);
+        ref1, ref2, ref3, ref4, ref5 }, target);
     assertEquals(4, matches.size());
     assertSame(ref1, matches.get(0));
     assertSame(ref2, matches.get(1));
index fbc95ad..b9083f5 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.AssertJUnit.assertEquals;
diff --git a/test/jalview/util/FormatTest.java b/test/jalview/util/FormatTest.java
new file mode 100644 (file)
index 0000000..d957b7c
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.assertEquals;
+
+import org.testng.annotations.Test;
+
+public class FormatTest
+{
+  @Test(groups = "Functional")
+  public void testAppendPercentage()
+  {
+    StringBuilder sb = new StringBuilder();
+    Format.appendPercentage(sb, 123.436f, 0);
+    assertEquals(sb.toString(), "123");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.536f, 0);
+    assertEquals(sb.toString(), "124");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 799.536f, 0);
+    assertEquals(sb.toString(), "800");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.436f, 1);
+    assertEquals(sb.toString(), "123.4");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.436f, 2);
+    assertEquals(sb.toString(), "123.44");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.436f, 3);
+    assertEquals(sb.toString(), "123.436");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.436f, 4);
+    assertEquals(sb.toString(), "123.4360");
+  }
+
+  @Test(groups = "Functional")
+  public void testForm_float()
+  {
+    Format f = new Format("%3.2f");
+    assertEquals(f.form(123f), "123.00");
+    assertEquals(f.form(123.1f), "123.10");
+    assertEquals(f.form(123.12f), "123.12");
+    assertEquals(f.form(123.124f), "123.12");
+    assertEquals(f.form(123.125f), "123.13");
+    assertEquals(f.form(123.126f), "123.13");
+
+    f = new Format("%3.0f");
+    assertEquals(f.form(123f), "123.");
+    assertEquals(f.form(12f), "12.");
+    assertEquals(f.form(123.4f), "123.");
+    assertEquals(f.form(123.5f), "124.");
+    assertEquals(f.form(123.6f), "124.");
+    assertEquals(f.form(129.6f), "130.");
+  }
+
+  @Test(groups = "Functional")
+  public void testRepeat()
+  {
+    assertEquals(Format.repeat('a', 3), "aaa");
+    assertEquals(Format.repeat('b', 0), "");
+    assertEquals(Format.repeat('c', -1), "");
+  }
+}
index ba298c5..9a0bdd7 100644 (file)
@@ -535,8 +535,7 @@ public class MapListTest
     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);
+    assertEquals("[ [1, 5] [10, 15] [25, 20] ] 1:3 to [ [51, 1] ]", s);
   }
 
   @Test(groups = { "Functional" })
@@ -671,8 +670,8 @@ 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)
index 6ba69b0..6780af7 100644 (file)
@@ -33,8 +33,8 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.SearchResults;
-import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
@@ -83,9 +83,9 @@ public class MappingUtilsTest
     /*
      * Check protein residue 12 maps to codon 5-7, 13 to codon 8-10
      */
-    SearchResults sr = MappingUtils.buildSearchResults(aseq1, 12, acfList);
+    SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 12, acfList);
     assertEquals(1, sr.getResults().size());
-    Match m = sr.getResults().get(0);
+    SearchResultMatchI m = sr.getResults().get(0);
     assertEquals(seq1.getDatasetSequence(), m.getSequence());
     assertEquals(5, m.getStart());
     assertEquals(7, m.getEnd());
@@ -136,9 +136,9 @@ public class MappingUtilsTest
     /*
      * Check protein residue 8 maps to [6, 8, 9]
      */
-    SearchResults sr = MappingUtils.buildSearchResults(aseq1, 8, acfList);
+    SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 8, acfList);
     assertEquals(2, sr.getResults().size());
-    Match m = sr.getResults().get(0);
+    SearchResultMatchI m = sr.getResults().get(0);
     assertEquals(seq1.getDatasetSequence(), m.getSequence());
     assertEquals(6, m.getStart());
     assertEquals(6, m.getEnd());
@@ -711,7 +711,7 @@ public class MappingUtilsTest
    * subselect the mapping search
    */
   @Test(groups = { "Functional" })
-  public void testFindMappingsBetweenSequenceAndOthers()
+  public void testFindMappingsForSequenceAndOthers()
   {
     SequenceI seq1 = new Sequence("Seq1", "ABC");
     SequenceI seq2 = new Sequence("Seq2", "ABC");
@@ -723,7 +723,7 @@ public class MappingUtilsTest
     seq4.createDatasetSequence();
 
     /*
-     * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1
+     * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1, seq3 to seq4
      */
     AlignedCodonFrame acf1 = new AlignedCodonFrame();
     MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
@@ -732,23 +732,54 @@ public class MappingUtilsTest
     acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
     AlignedCodonFrame acf3 = new AlignedCodonFrame();
     acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
+    AlignedCodonFrame acf4 = new AlignedCodonFrame();
+    acf4.addMap(seq3.getDatasetSequence(), seq4.getDatasetSequence(), map);
 
     List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
     mappings.add(acf1);
     mappings.add(acf2);
     mappings.add(acf3);
+    mappings.add(acf4);
 
     /*
-     * Seq1 has three mappings
+     * test for null args
      */
     List<AlignedCodonFrame> result = MappingUtils
-            .findMappingsForSequenceAndOthers(seq1, mappings,
-                    new Alignment(new SequenceI[] { seq1, seq2 }));
+            .findMappingsForSequenceAndOthers(null, mappings,
+                    Arrays.asList(new SequenceI[] { seq1, seq2 }));
+    assertTrue(result.isEmpty());
+
+    result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null,
+            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() }));
+    assertEquals(2, result.size());
     assertTrue(result.contains(acf1));
     assertTrue(result.contains(acf2));
     assertFalse("Did not expect to find mapping acf3 - subselect failed",
             result.contains(acf3));
-    assertEquals(2, result.size());
+    assertFalse(
+            "Did not expect to find mapping acf4 - doesn't involve sequence",
+            result.contains(acf4));
+
+    /*
+     * and verify the no filter case
+     */
+    result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
+            null);
+    assertEquals(3, result.size());
+    assertTrue(result.contains(acf1));
+    assertTrue(result.contains(acf2));
+    assertTrue(result.contains(acf3));
   }
 
   @Test(groups = { "Functional" })
@@ -839,7 +870,7 @@ public class MappingUtilsTest
   public void testMapColumnSelection_hiddenColumns() throws IOException
   {
     setupMappedAlignments();
-  
+
     ColumnSelection proteinSelection = new ColumnSelection();
 
     /*
@@ -847,8 +878,8 @@ public class MappingUtilsTest
      * in dna respectively, overall 0-4
      */
     proteinSelection.hideColumns(0);
-    ColumnSelection dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
-            proteinView, dnaView);
+    ColumnSelection dnaSelection = MappingUtils.mapColumnSelection(
+            proteinSelection, proteinView, dnaView);
     assertEquals("[]", dnaSelection.getSelected().toString());
     List<int[]> hidden = dnaSelection.getHiddenColumns();
     assertEquals(1, hidden.size());
@@ -863,7 +894,8 @@ public class MappingUtilsTest
     // deselect these or hideColumns will be expanded to include 0
     proteinSelection.clear();
     proteinSelection.hideColumns(1);
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, proteinView, dnaView);
+    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
+            proteinView, dnaView);
     hidden = dnaSelection.getHiddenColumns();
     assertEquals(1, hidden.size());
     assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
@@ -874,7 +906,8 @@ public class MappingUtilsTest
     proteinSelection.revealAllHiddenColumns();
     proteinSelection.clear();
     proteinSelection.hideColumns(2);
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, proteinView, dnaView);
+    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
+            proteinView, dnaView);
     assertTrue(dnaSelection.getHiddenColumns().isEmpty());
 
     /*
@@ -885,7 +918,8 @@ public class MappingUtilsTest
     proteinSelection.clear();
     proteinSelection.hideColumns(3); // 5-10 hidden in dna
     proteinSelection.addElement(1); // 0-3 selected in dna
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, proteinView, dnaView);
+    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
+            proteinView, dnaView);
     assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
     hidden = dnaSelection.getHiddenColumns();
     assertEquals(1, hidden.size());
@@ -898,7 +932,8 @@ public class MappingUtilsTest
     proteinSelection.clear();
     proteinSelection.hideColumns(1);
     proteinSelection.hideColumns(3);
-    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection, proteinView, dnaView);
+    dnaSelection = MappingUtils.mapColumnSelection(proteinSelection,
+            proteinView, dnaView);
     hidden = dnaSelection.getHiddenColumns();
     assertEquals(2, hidden.size());
     assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
@@ -1032,42 +1067,42 @@ public class MappingUtilsTest
     int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
     assertEquals("[10, 1]", Arrays.toString(adjusted));
     assertEquals("[10, 1]", Arrays.toString(ranges));
-  
+
     ranges = adjusted;
     adjusted = MappingUtils.removeStartPositions(1, ranges);
     assertEquals("[9, 1]", Arrays.toString(adjusted));
     assertEquals("[10, 1]", Arrays.toString(ranges));
-  
+
     ranges = adjusted;
     adjusted = MappingUtils.removeStartPositions(1, ranges);
     assertEquals("[8, 1]", Arrays.toString(adjusted));
     assertEquals("[9, 1]", Arrays.toString(ranges));
-  
+
     ranges = new int[] { 12, 11, 9, 6 };
     adjusted = MappingUtils.removeStartPositions(1, ranges);
     assertEquals("[11, 11, 9, 6]", Arrays.toString(adjusted));
     assertEquals("[12, 11, 9, 6]", Arrays.toString(ranges));
-  
+
     ranges = new int[] { 12, 12, 8, 4 };
     adjusted = MappingUtils.removeStartPositions(1, ranges);
     assertEquals("[8, 4]", Arrays.toString(adjusted));
     assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
-  
+
     ranges = new int[] { 12, 12, 8, 4 };
     adjusted = MappingUtils.removeStartPositions(2, ranges);
     assertEquals("[7, 4]", Arrays.toString(adjusted));
     assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
-  
+
     ranges = new int[] { 12, 12, 10, 10, 8, 4 };
     adjusted = MappingUtils.removeStartPositions(1, ranges);
     assertEquals("[10, 10, 8, 4]", Arrays.toString(adjusted));
     assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
-  
+
     ranges = new int[] { 12, 12, 10, 10, 8, 4 };
     adjusted = MappingUtils.removeStartPositions(2, ranges);
     assertEquals("[8, 4]", Arrays.toString(adjusted));
     assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
-  
+
     ranges = new int[] { 12, 11, 8, 4 };
     adjusted = MappingUtils.removeStartPositions(3, ranges);
     assertEquals("[7, 4]", Arrays.toString(adjusted));
diff --git a/test/jalview/util/PlatformTest.java b/test/jalview/util/PlatformTest.java
new file mode 100644 (file)
index 0000000..e9e4628
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.awt.Button;
+import java.awt.Event;
+import java.awt.event.MouseEvent;
+
+import org.testng.annotations.Test;
+
+public class PlatformTest
+{
+  Button b = new Button();
+
+  /**
+   * isControlDown for Mac should answer true for Meta-down, but not for right
+   * mouse (popup trigger)
+   */
+  @Test(groups = "Functional")
+  public void testIsControlDown_mac()
+  {
+    int clickCount = 1;
+    boolean isPopupTrigger = false;
+    int buttonNo = MouseEvent.BUTTON1;
+    boolean mac = true;
+
+    int mods = 0;
+    // not concerned with MouseEvent id, when, x, y, xAbs, yAbs values
+    assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+
+    mods = Event.CTRL_MASK;
+    assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+
+    mods = Event.META_MASK;
+    assertTrue(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+
+    isPopupTrigger = true;
+    assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+
+    isPopupTrigger = false;
+    buttonNo = MouseEvent.BUTTON2;
+    mods = 0;
+    assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+  }
+
+  /**
+   * If not a Mac, we only care whether CTRL_MASK modifier is set on the mouse
+   * event
+   */
+  @Test(groups = "Functional")
+  public void testIsControlDown_notMac()
+  {
+    int clickCount = 1;
+    boolean isPopupTrigger = false;
+    int buttonNo = MouseEvent.BUTTON1;
+    boolean mac = false;
+
+    int mods = 0;
+    // not concerned with MouseEvent id, when, x, y, xAbs, yAbs values
+    assertFalse(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+
+    mods = Event.CTRL_MASK;
+    assertTrue(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+
+    mods = Event.CTRL_MASK | Event.SHIFT_MASK | Event.ALT_MASK;
+    clickCount = 2;
+    buttonNo = 2;
+    isPopupTrigger = true;
+    assertTrue(Platform.isControlDown(new MouseEvent(b, 0, 0L, mods, 0, 0,
+            0, 0, clickCount, isPopupTrigger, buttonNo), mac));
+  }
+}
index 54e46a0..f976955 100644 (file)
@@ -110,8 +110,7 @@ public class QuickSortTest
         "ALISON" };
     QuickSort.sort(values, things);
     assertTrue(Arrays.equals(new String[] { "lucy", "henry", "henry",
-        "JOHN",
-        "ALISON" }, values));
+        "JOHN", "ALISON" }, values));
     assertTrue(Arrays.equals(new Object[] { c3, c2, c4, c1, c5 }, things));
   }
 
diff --git a/test/jalview/util/SparseCountTest.java b/test/jalview/util/SparseCountTest.java
new file mode 100644 (file)
index 0000000..f4a0c97
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+public class SparseCountTest
+{
+  @Test(groups = "Functional")
+  public void testAdd()
+  {
+    SparseCount p = new SparseCount(8);
+    p.add('a', 1);
+    p.add('b', 2);
+    p.add('a', 3);
+    p.add('b', -4);
+    assertEquals(p.size(), 2);
+    assertEquals(p.get('a'), 4);
+    assertEquals(p.get('b'), -2);
+  }
+
+  @Test(groups = "Functional")
+  public void testPut()
+  {
+    SparseCount p = new SparseCount(8);
+    p.put('a', 3);
+    p.add('b', 2);
+    p.put('b', 4);
+    assertEquals(p.size(), 2);
+    assertEquals(p.get('a'), 3);
+    assertEquals(p.get('b'), 4);
+  }
+
+  /**
+   * Test handling overflow of short by switching to counting ints
+   */
+  @Test(groups = "Functional")
+  public void testOverflow()
+  {
+    SparseCount p = new SparseCount(8);
+    p.put('a', Short.MAX_VALUE - 1);
+    p.add('a', 1);
+    assertFalse(p.isUsingInt());
+    p.add('a', 1);
+    assertTrue(p.isUsingInt());
+  }
+
+  /**
+   * Test handling underflow of short by switching to counting ints
+   */
+  @Test(groups = "Functional")
+  public void testUnderflow()
+  {
+    SparseCount p = new SparseCount(8);
+    p.put('a', Short.MIN_VALUE + 1);
+    p.add('a', -1);
+    assertFalse(p.isUsingInt());
+    p.add('a', -1);
+    assertTrue(p.isUsingInt());
+  }
+
+  @Test(groups = "Functional")
+  public void testKeyAt_ValueAt()
+  {
+    SparseCount p = new SparseCount(8);
+    p.put('W', 12);
+    p.put('K', 9);
+    p.put('R', 6);
+    assertEquals(p.size(), 3);
+    assertEquals(p.keyAt(0), 'K');
+    assertEquals(p.valueAt(0), 9);
+    assertEquals(p.keyAt(1), 'R');
+    assertEquals(p.valueAt(1), 6);
+    assertEquals(p.keyAt(2), 'W');
+    assertEquals(p.valueAt(2), 12);
+  }
+
+}
diff --git a/test/jalview/util/UrlLinkTest.java b/test/jalview/util/UrlLinkTest.java
new file mode 100644 (file)
index 0000000..f219fb8
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * 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 jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.Sequence;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+public class UrlLinkTest
+{
+
+  final static String DB = "Test";
+
+  final static String URL_PREFIX = "http://www.jalview.org/";
+
+  final static String URL_SUFFIX = "/blah";
+
+  final static String SEP = "|";
+
+  final static String DELIM = "$";
+
+  final static String REGEX_NESTED = "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=";
+  
+  final static String REGEX_RUBBISH = "=/[0-9]++/=";
+
+  /**
+   * Test URL link creation when the input string has no regex
+   */
+  @Test(groups = { "Functional" })
+  public void testUrlLinkCreationNoRegex()
+  {
+    // SEQUENCE_ID
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + DELIM + URL_SUFFIX);
+    assertEquals(DB, ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertFalse(ul.usesDBAccession());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // DB_ACCESSION
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION + DELIM
+            + URL_SUFFIX);
+    assertEquals(DB, ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesDBAccession());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // Not dynamic
+    ul = new UrlLink(DB + SEP + URL_PREFIX + URL_SUFFIX.substring(1));
+    assertEquals(DB, ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX + URL_SUFFIX.substring(1), ul.getUrl_prefix());
+    assertFalse(ul.isDynamic());
+    assertFalse(ul.usesDBAccession());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+  }
+
+  /**
+   * Test URL link creation when the input string has regex
+   */
+  @Test(groups = { "Functional" })
+  public void testUrlLinkCreationWithRegex()
+  {
+    // SEQUENCE_ID
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    assertEquals(DB, ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertFalse(ul.usesDBAccession());
+    assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+            ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // DB_ACCESSION
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    assertEquals(DB, ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesDBAccession());
+    assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+            ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // invalid regex
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION
+            + REGEX_RUBBISH + DELIM + URL_SUFFIX);
+    assertEquals(DB, ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesDBAccession());
+    assertEquals(REGEX_RUBBISH.substring(2, REGEX_RUBBISH.length() - 2),
+            ul.getRegexReplace());
+    assertFalse(ul.isValid());
+    assertEquals(
+            "Invalid Regular Expression : '"
+                    + REGEX_RUBBISH.substring(2, REGEX_RUBBISH.length() - 2)
+                    + "'\n",
+            ul.getInvalidMessage());
+  }
+
+  /**
+   * Test construction of link by substituting sequence id or name
+   */
+  @Test(groups = { "Functional" })
+  public void testMakeUrlNoRegex()
+  {
+    // Single non-regex
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + DELIM + URL_SUFFIX);
+    String idstring = "FER_CAPAA";
+    String[] urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+  }
+
+  /**
+   * Test construction of link by substituting sequence id or name using regular
+   * expression
+   */
+  @Test(groups = { "Functional" })
+  public void testMakeUrlWithRegex()
+  {
+    // Unused regex
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    String idstring = "FER_CAPAA";
+    String[] urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // nested regex
+    idstring = "Label:gi|9234|pdb|102L|A";
+    urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals("9234", urls[0]);
+    assertEquals(URL_PREFIX + "9234" + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals("9234", urls[0]);
+    assertEquals(URL_PREFIX + "9234" + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // unmatched regex
+    idstring = "this does not match";
+    urls = ul.makeUrls(idstring, true);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals(idstring, urls[0]);
+    assertEquals(URL_PREFIX + idstring + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // empty idstring
+    idstring = "";
+    urls = ul.makeUrls(idstring, true);
+
+    assertNull(urls);
+
+    urls = ul.makeUrls(idstring, false);
+
+    assertEquals(2, urls.length);
+    assertEquals("", urls[0]);
+    assertEquals(URL_PREFIX + URL_SUFFIX, urls[1]);
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+  }
+
+  /**
+   * Test creating links with null sequence
+   */
+  @Test(groups = { "Functional" })
+  public void testCreateLinksFromNullSequence()
+  {
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + DELIM + URL_SUFFIX);
+
+    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    ul.createLinksFromSeq(null, linkset);
+
+    String key = DB + SEP + URL_PREFIX;
+    assertEquals(1, linkset.size());
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), DB);
+    assertEquals(linkset.get(key).get(1), DB);
+    assertEquals(linkset.get(key).get(2), null);
+    assertEquals(linkset.get(key).get(3), URL_PREFIX);
+  }
+
+  /**
+   * Test creating links with non-dynamic urlLink
+   */
+  @Test(groups = { "Functional" })
+  public void testCreateLinksForNonDynamic()
+  {
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + URL_SUFFIX);
+
+    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    ul.createLinksFromSeq(null, linkset);
+
+    String key = DB + SEP + URL_PREFIX + URL_SUFFIX;
+    assertEquals(1, linkset.size());
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), DB);
+    assertEquals(linkset.get(key).get(1), DB);
+    assertEquals(linkset.get(key).get(2), null);
+    assertEquals(linkset.get(key).get(3), URL_PREFIX + URL_SUFFIX);
+  }
+
+  /**
+   * Test creating links
+   */
+  @Test(groups = { "Functional" })
+  public void testCreateLinksFromSequence()
+  {
+
+    // create list of links and list of DBRefs
+    List<String> links = new ArrayList<String>();
+    List<DBRefEntry> refs = new ArrayList<DBRefEntry>();
+
+    // links as might be added into Preferences | Connections dialog
+    links.add("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$"
+            + SEQUENCE_ID + "$");
+    links.add("UNIPROT | http://www.uniprot.org/uniprot/$" + DB_ACCESSION
+            + "$");
+    links.add("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$"
+            + DB_ACCESSION + "$");
+
+    // make seq0 dbrefs
+    refs.add(new DBRefEntry(DBRefSource.UNIPROT, "1", "P83527"));
+    refs.add(new DBRefEntry("INTERPRO", "1", "IPR001041"));
+    refs.add(new DBRefEntry("INTERPRO", "1", "IPR006058"));
+    refs.add(new DBRefEntry("INTERPRO", "1", "IPR012675"));
+
+    Sequence seq0 = new Sequence("FER1", "AKPNGVL");
+
+    // add all the dbrefs to the sequence
+    seq0.addDBRef(refs.get(0));
+    seq0.addDBRef(refs.get(1));
+    seq0.addDBRef(refs.get(2));
+    seq0.addDBRef(refs.get(3));
+    seq0.createDatasetSequence();
+
+    // Test where link takes a sequence id as replacement
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + DELIM + URL_SUFFIX);
+
+    Map<String, List<String>> linkset = new LinkedHashMap<String, List<String>>();
+    ul.createLinksFromSeq(seq0, linkset);
+
+    String key = seq0.getName() + SEP + URL_PREFIX + seq0.getName()
+            + URL_SUFFIX;
+    assertEquals(1, linkset.size());
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), DB);
+    assertEquals(linkset.get(key).get(1), DB);
+    assertEquals(linkset.get(key).get(2), seq0.getName());
+    assertEquals(linkset.get(key).get(3), URL_PREFIX + seq0.getName()
+            + URL_SUFFIX);
+
+    // Test where link takes a db annotation id and only has one dbref
+    ul = new UrlLink(links.get(1));
+    linkset = new LinkedHashMap<String, List<String>>();
+    ul.createLinksFromSeq(seq0, linkset);
+
+    key = "P83527|http://www.uniprot.org/uniprot/P83527";
+    assertEquals(1, linkset.size());
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), DBRefSource.UNIPROT);
+    assertEquals(linkset.get(key).get(1), DBRefSource.UNIPROT + SEP
+            + "P83527");
+    assertEquals(linkset.get(key).get(2), "P83527");
+    assertEquals(linkset.get(key).get(3),
+            "http://www.uniprot.org/uniprot/P83527");
+
+    // Test where link takes a db annotation id and has multiple dbrefs
+    ul = new UrlLink(links.get(2));
+    linkset = new LinkedHashMap<String, List<String>>();
+    ul.createLinksFromSeq(seq0, linkset);
+    assertEquals(3, linkset.size());
+
+    // check each link made it in correctly
+    key = "IPR001041|http://www.ebi.ac.uk/interpro/entry/IPR001041";
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), "INTERPRO");
+    assertEquals(linkset.get(key).get(1), "INTERPRO" + SEP + "IPR001041");
+    assertEquals(linkset.get(key).get(2), "IPR001041");
+    assertEquals(linkset.get(key).get(3),
+            "http://www.ebi.ac.uk/interpro/entry/IPR001041");
+
+    key = "IPR006058|http://www.ebi.ac.uk/interpro/entry/IPR006058";
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), "INTERPRO");
+    assertEquals(linkset.get(key).get(1), "INTERPRO" + SEP + "IPR006058");
+    assertEquals(linkset.get(key).get(2), "IPR006058");
+    assertEquals(linkset.get(key).get(3),
+            "http://www.ebi.ac.uk/interpro/entry/IPR006058");
+
+    key = "IPR012675|http://www.ebi.ac.uk/interpro/entry/IPR012675";
+    assertTrue(linkset.containsKey(key));
+    assertEquals(linkset.get(key).get(0), "INTERPRO");
+    assertEquals(linkset.get(key).get(1), "INTERPRO" + SEP + "IPR012675");
+    assertEquals(linkset.get(key).get(2), "IPR012675");
+    assertEquals(linkset.get(key).get(3),
+            "http://www.ebi.ac.uk/interpro/entry/IPR012675");
+
+    // Test where there are no matching dbrefs for the link
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + DB_ACCESSION + DELIM
+            + URL_SUFFIX);
+    linkset = new LinkedHashMap<String, List<String>>();
+    ul.createLinksFromSeq(seq0, linkset);
+    assertTrue(linkset.isEmpty());
+  }
+
+}
index 735c75d..acb9f33 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.workers;
 
 import static org.testng.AssertJUnit.assertEquals;
@@ -35,11 +55,9 @@ public class AlignCalcManagerTest
   {
     AlignCalcManagerI acm = alignFrame.getViewport().getCalcManager();
     final AlignmentAnnotation ann1 = new AlignmentAnnotation("Ann1",
-            "desc",
-            new Annotation[] {});
+            "desc", new Annotation[] {});
     final AlignmentAnnotation ann2 = new AlignmentAnnotation("Ann2",
-            "desc",
-            new Annotation[] {});
+            "desc", new Annotation[] {});
 
     /*
      * make two workers for ann1, one deletable, one not
@@ -68,7 +86,8 @@ public class AlignCalcManagerTest
       }
     }
 
-    List<AlignCalcWorkerI> workers = acm.getRegisteredWorkersOfClass(worker1.getClass());
+    List<AlignCalcWorkerI> workers = acm
+            .getRegisteredWorkersOfClass(worker1.getClass());
     assertEquals(2, workers.size());
     assertTrue(workers.contains(worker1));
     assertTrue(workers.contains(worker2));
@@ -119,8 +138,7 @@ public class AlignCalcManagerTest
       }
     };
     return new AnnotationWorker(alignFrame.getViewport(),
-            alignFrame.alignPanel,
-            annotationProvider)
+            alignFrame.alignPanel, annotationProvider)
     {
       @Override
       public boolean isDeletable()
index fda0198..4b9437a 100644 (file)
@@ -42,6 +42,7 @@ public class PDBSequenceFetcherTest
   @BeforeMethod(alwaysRun = true)
   public void setUp() throws Exception
   {
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // ensure 'add annotation from structure' is selected
     Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
@@ -62,10 +63,7 @@ public class PDBSequenceFetcherTest
   @Test(groups = { "Network" }, enabled = true)
   public void testRnaSeqRetrieve() throws Exception
   {
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
-            Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("DEFAULT_STRUCTURE_FORMAT",
-            "PDB");
+    Cache.applicationProperties.setProperty("PDB_DOWNLOAD_FORMAT", "PDB");
     List<DbSourceProxy> sps = sf.getSourceProxy("PDB");
     AlignmentI response = sps.get(0).getSequenceRecords("2GIS");
     assertTrue(response != null);
@@ -85,8 +83,6 @@ public class PDBSequenceFetcherTest
   @Test(groups = { "Network" }, enabled = true)
   public void testPdbSeqRetrieve() throws Exception
   {
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
-            Boolean.TRUE.toString());
     StructureImportSettings.setDefaultStructureFileFormat("PDB");
     StructureImportSettings
             .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
@@ -97,8 +93,6 @@ public class PDBSequenceFetcherTest
   @Test(groups = { "Network" }, enabled = true)
   public void testmmCifSeqRetrieve() throws Exception
   {
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
-            Boolean.TRUE.toString());
     StructureImportSettings.setDefaultStructureFileFormat("mmCIF");
     testRetrieveProteinSeqFromPDB();
   }
index 94bf979..bc9f9a2 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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;
 
 import jalview.analysis.CrossRef;
@@ -52,8 +72,7 @@ public class SequenceFetcherTest
           try
           {
             testRetrieval(argv[0], sp,
-                    argv.length > 1 ? argv[1] : sp
-                    .getTestQuery());
+                    argv.length > 1 ? argv[1] : sp.getTestQuery());
           } catch (Exception e)
           {
             e.printStackTrace();
index 72e599d..2df8be6 100644 (file)
 package jalview.ws.dbsources;
 
 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 jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
 import jalview.datamodel.UniprotEntry;
 
 import java.io.Reader;
@@ -46,6 +49,7 @@ public class UniprotTest
           + "<protein><recommendedName><fullName>Mitogen-activated protein kinase 13</fullName><fullName>Henry</fullName></recommendedName></protein>"
           + "<dbReference type=\"PDB\" id=\"2FSQ\"><property type=\"method\" value=\"X-ray\"/><property type=\"resolution\" value=\"1.40\"/></dbReference>"
           + "<dbReference type=\"PDBsum\" id=\"2FSR\"/>"
+          + "<dbReference type=\"EMBL\" id=\"AE007869\"><property type=\"protein sequence ID\" value=\"AAK85932.1\"/><property type=\"molecule type\" value=\"Genomic_DNA\"/></dbReference>"
           + "<feature type=\"signal peptide\" evidence=\"7\"><location><begin position=\"1\"/><end position=\"18\"/></location></feature>"
           + "<feature type=\"propeptide\" description=\"Activation peptide\" id=\"PRO_0000027399\" evidence=\"9 16 17 18\"><location><begin position=\"19\"/><end position=\"20\"/></location></feature>"
           + "<feature type=\"chain\" description=\"Granzyme B\" id=\"PRO_0000027400\"><location><begin position=\"21\"/><end position=\"247\"/></location></feature>"
@@ -109,19 +113,37 @@ public class UniprotTest
      * Check cross-references
      */
     Vector<PDBEntry> xrefs = entry.getDbReference();
-    assertEquals(2, xrefs.size());
+    assertEquals(3, xrefs.size());
 
     PDBEntry xref = xrefs.get(0);
     assertEquals("2FSQ", xref.getId());
     assertEquals("PDB", xref.getType());
-    assertEquals(2, xref.getProperty().size());
-    assertEquals("X-ray", xref.getProperty().get("method"));
-    assertEquals("1.40", xref.getProperty().get("resolution"));
+    assertEquals("X-ray", xref.getProperty("method"));
+    assertEquals("1.40", xref.getProperty("resolution"));
 
     xref = xrefs.get(1);
     assertEquals("2FSR", xref.getId());
     assertEquals("PDBsum", xref.getType());
-    assertNull(xref.getProperty());
+    assertFalse(xref.getProperties().hasMoreElements());
+
+    xref = xrefs.get(2);
+    assertEquals("AE007869", xref.getId());
+    assertEquals("EMBL", xref.getType());
+    assertEquals("AAK85932.1",
+ xref.getProperty("protein sequence ID"));
+    assertEquals("Genomic_DNA",
+ xref.getProperty("molecule type"));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetUniprotSequence()
+  {
+    UniprotEntry entry = new Uniprot().getUniprotEntries(
+            new StringReader(UNIPROT_XML)).get(0);
+    SequenceI seq = new Uniprot().uniprotEntryToSequenceI(entry);
+    assertNotNull(seq);
+    assertEquals(6, seq.getDBRefs().length); // 2*Uniprot, PDB, PDBsum, 2*EMBL
+
   }
 
   /**
@@ -149,7 +171,7 @@ public class UniprotTest
   {
     UniprotEntry entry = new Uniprot().getUniprotEntries(
             new StringReader(UNIPROT_XML)).get(0);
-  
+
     /*
      * recommended names concatenated with space separator
      */
index 4eaa5b1..e323a0d 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.ebi;
 
 import static org.testng.AssertJUnit.assertEquals;
index 85c075b..8ab5763 100644 (file)
@@ -121,11 +121,11 @@ public class DisorderAnnotExportImport
     {
       orig_alig.deleteAnnotation(aa);
     }
-    testAnnotationFileIO("Testing IUPred Annotation IO", orig_alig);
+    checkAnnotationFileIO("Testing IUPred Annotation IO", orig_alig);
 
   }
 
-  public static void testAnnotationFileIO(String testname, AlignmentI al)
+  static void checkAnnotationFileIO(String testname, AlignmentI al)
   {
     try
     {
index fbee3a7..dc8d0e4 100644 (file)
@@ -237,8 +237,8 @@ public class RNAStructExportImport
   public void testRnaalifoldSettingsRecovery()
   {
     List<Argument> opts = new ArrayList<Argument>();
-    for (Argument rg : (List<Argument>) rnaalifoldws
-            .getRunnerConfig().getArguments())
+    for (Argument rg : (List<Argument>) rnaalifoldws.getRunnerConfig()
+            .getArguments())
     {
       if (rg.getDescription().contains("emperature"))
       {
index b3c7e10..0a565bd 100644 (file)
@@ -37,6 +37,7 @@ import jalview.ws.dbsources.Pdb;
 import jalview.ws.dbsources.Uniprot;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.testng.annotations.AfterClass;
@@ -75,7 +76,9 @@ public class DbRefFetcherTest
   @Test(groups = { "Functional" })
   public void testStandardProtDbs()
   {
-    String[] defdb = DBRefSource.PROTEINDBS;
+    List<String> defdb = new ArrayList<String>();
+    defdb.addAll(Arrays.asList(DBRefSource.PROTEINDBS));
+    defdb.add(DBRefSource.PDB);
     List<DbSourceProxy> srces = new ArrayList<DbSourceProxy>();
     SequenceFetcher sfetcher = new SequenceFetcher();
     boolean pdbFound = false;
@@ -170,8 +173,7 @@ public class DbRefFetcherTest
                     sfs[0].getType()));
     assertEquals(embl.getDbSource(), sfs[0].getFeatureGroup());
     DBRefEntry[] dr = DBRefUtils.selectRefs(seq.getDBRefs(),
-            new String[] { DBRefSource.UNIPROT, DBRefSource.UNIPROTKB,
-                DBRefSource.EMBLCDSProduct, DBRefSource.ENSEMBL });
+            new String[] { DBRefSource.UNIPROT });
     assertNotNull(dr);
     assertEquals("Expected a single Uniprot cross reference", 1, dr.length);
     assertEquals("Expected cross reference map to be one amino acid", dr[0]
index 9d59b78..9f6e306 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.ws.sifts;
 
 import jalview.api.DBRefEntryI;
+import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Sequence;
@@ -67,7 +68,7 @@ public class SiftsClientTest
 
   @BeforeTest(alwaysRun = true)
   public void populateExpectedMapping() throws SiftsException
-   {
+  {
     expectedMapping.put(51, new int[] { 1, 2 });
     expectedMapping.put(52, new int[] { 2, 7 });
     expectedMapping.put(53, new int[] { 3, 12 });
@@ -165,11 +166,13 @@ public class SiftsClientTest
     expectedMapping.put(145, new int[] { 95, 714 });
     expectedMapping.put(146, new int[] { 96, 722 });
     expectedMapping.put(147, new int[] { 97, 729 });
-   }
-   
+  }
+
   @BeforeTest(alwaysRun = true)
   public void setUpSiftsClient() throws SiftsException
   {
+    // read test props before manipulating config
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // SIFTs entries are updated weekly - so use saved SIFTs file to enforce
     // test reproducibility
     new SiftsSettings();
@@ -233,7 +236,6 @@ public class SiftsClientTest
     }
   }
 
-
   @Test(groups = { "Functional" })
   public void getAllMappingAccessionTest()
   {
@@ -257,8 +259,7 @@ public class SiftsClientTest
     try
     {
       HashMap<Integer, int[]> actualMapping = siftsClient.getGreedyMapping(
-              "A", testSeq,
-              null);
+              "A", testSeq, null);
       Assert.assertEquals(testSeq.getStart(), 1);
       Assert.assertEquals(testSeq.getEnd(), 147);
       Assert.assertEquals(actualMapping, expectedMapping);
@@ -303,7 +304,7 @@ public class SiftsClientTest
   private void populateAtomPositionsNullTest1()
           throws IllegalArgumentException, SiftsException
   {
-      siftsClient.populateAtomPositions(null, null);
+    siftsClient.populateAtomPositions(null, null);
   }
 
   @Test(
@@ -337,7 +338,7 @@ public class SiftsClientTest
     expectedExceptions = SiftsException.class)
   public void getValidSourceDBRefExceptionTest() throws SiftsException
   {
-      SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
+    SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
     try
     {
       siftsClient.getValidSourceDBRef(invalidTestSeq);
@@ -386,8 +387,8 @@ public class SiftsClientTest
               testSeq, testPDBId, "A");
       String expectedMappingOutput = "\nSequence âŸ· Structure mapping details\n"
               + "Method: SIFTS\n\n"
-              + "P00221 :  1 - 97 Maps to \n"
-              + "1A70|A :  51 - 147\n\n"
+              + "P00221 :  51 - 147 Maps to \n"
+              + "1A70|A :  1 - 97\n\n"
               + "P00221 AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLD\n"
               + "       |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n"
               + "1A70|A AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLD\n\n"
@@ -448,7 +449,7 @@ public class SiftsClientTest
   }
 
   @Test(groups = { "Functional" })
-  public void getEntityByMostOptimalMatchedIdTest()
+  public void getEntityByMostOptimalMatchedIdTest1()
   {
     SiftsClient siftsClientX = null;
     PDBfile pdbFile;
@@ -471,4 +472,34 @@ public class SiftsClientTest
     Assert.assertEquals(entityD.getEntityId(), "D");
 
   }
+
+  @Test(groups = { "Functional" })
+  public void getEntityByMostOptimalMatchedIdTest2()
+  {
+    // This test is for a SIFTS file in which entity A should map to chain P for
+    // the given PDB Id. All the other chains shouldn't be mapped as there are
+    // no SIFTS entity records for them.
+    SiftsClient siftsClientX = null;
+    PDBfile pdbFile;
+    try
+    {
+      pdbFile = new PDBfile(false, false, false,
+              "test/jalview/io/3ucu.cif", DataSourceType.FILE);
+      siftsClientX = new SiftsClient(pdbFile);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    Entity entityA = siftsClientX.getEntityByMostOptimalMatchedId("P");
+    Entity entityP = siftsClientX.getEntityByMostOptimalMatchedId("A");
+    Entity entityR = siftsClientX.getEntityByMostOptimalMatchedId("R");
+    Assert.assertEquals(entityA.getEntityId(), "A");
+    Assert.assertNotEquals(entityR, "A");
+    Assert.assertNotEquals(entityP, "A");
+    Assert.assertNotEquals(entityR, "R");
+    Assert.assertNotEquals(entityP, "P");
+    Assert.assertNull(entityR);
+    Assert.assertNull(entityP);
+
+  }
 }
diff --git a/utils/BufferedLineReader.java b/utils/BufferedLineReader.java
new file mode 100644 (file)
index 0000000..b813fb2
--- /dev/null
@@ -0,0 +1,182 @@
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StringReader;
+
+/**
+ * A file reader that concatenates lines
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class BufferedLineReader
+{
+  interface LineCleaner
+  {
+    String cleanLine(String l);
+  }
+
+  /*
+   * a reader for the file being read
+   */
+  private BufferedReader br;
+  
+  /*
+   * optional handler to post-process each line as it is read
+   */
+  private LineCleaner cleaner;
+
+  /*
+   * current buffer of <bufferSize> post-processed input lines
+   */
+  private String[] buffer;
+
+  private boolean atEof;
+
+  /**
+   * Constructor
+   * 
+   * @param reader
+   * @param bufferSize
+   *          the number of lines to concatenate at a time while reading
+   * @param tidier
+   *          an optional callback handler to post-process each line after
+   *          reading
+   * @throws FileNotFoundException
+   */
+  public BufferedLineReader(BufferedReader reader, int bufferSize,
+          LineCleaner tidier)
+          throws IOException
+  {
+    br = reader;
+    buffer = new String[bufferSize];
+    cleaner = tidier;
+
+    /*
+     * load up the buffer with N-1 lines, ready for the first read
+     */
+    for (int i = 1; i < bufferSize; i++)
+    {
+      readLine();
+    }
+
+  }
+
+  /**
+   * Reads the next line from file, invokes the post-processor if one was
+   * provided, and returns the 'cleaned' line, or null at end of file.
+   * 
+   * @return
+   */
+  private String readLine() // throws IOException
+  {
+    if (atEof)
+    {
+      return null;
+    }
+
+    String line = null;
+    try
+    {
+      line = br.readLine();
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
+    if (line == null)
+    {
+      atEof = true;
+      return null;
+    }
+    if (cleaner != null)
+    {
+      line = cleaner.cleanLine(line);
+    }
+
+    /*
+     * shuffle down the lines buffer and add the new line
+     * in the last position
+     */
+    for (int i = 1; i < buffer.length; i++)
+    {
+      buffer[i - 1] = buffer[i];
+    }
+    buffer[buffer.length - 1] = line;
+    return line;
+  }
+
+  /**
+   * Returns a number of concatenated lines from the file, or null at end of
+   * file.
+   * 
+   * @return
+   */
+  public String read()
+  {
+    if (readLine() == null)
+    {
+      return null;
+    }
+    StringBuilder result = new StringBuilder(100 * buffer.length);
+    for (String line : buffer)
+    {
+      if (line != null)
+      {
+        result.append(line);
+      }
+    }
+    return result.toString();
+  }
+
+  /**
+   * A main 'test' method!
+   * 
+   * @throws IOException
+   */
+  public static void main(String[] args) throws IOException
+  {
+    String data = "Now is the winter\n" + "Of our discontent\n"
+            + "Made glorious summer\n" + "By this sun of York\n";
+    BufferedReader br = new BufferedReader(new StringReader(data));
+    BufferedLineReader reader = new BufferedLineReader(br, 3,
+            new LineCleaner()
+            {
+              @Override
+              public String cleanLine(String l)
+              {
+                return l.toUpperCase();
+              }
+            });
+    String line = reader.read();
+    String expect = "NOW IS THE WINTEROF OUR DISCONTENTMADE GLORIOUS SUMMER";
+    if (!line.equals(expect))
+    {
+      System.err.println("Fail: expected '" + expect + "', found '" + line
+              + ";");
+    }
+    else
+    {
+      System.out.println("Line one ok!");
+    }
+    line = reader.read();
+    expect = "OF OUR DISCONTENTMADE GLORIOUS SUMMERBY THIS SUN OF YORK";
+    if (!line.equals(expect))
+    {
+      System.err.println("Fail: expected '" + expect + "', found '" + line
+              + "'");
+    }
+    else
+    {
+      System.out.println("Line two ok!!");
+    }
+    line = reader.read();
+    if (line != null)
+    {
+      System.err.println("Fail: expected null at eof, got '" + line + "'");
+    }
+    else
+    {
+      System.out.println("EOF ok!!!");
+    }
+  }
+}
index 1ad5322..1279b31 100644 (file)
@@ -1,5 +1,23 @@
-
-
+/*
+ * 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.
+ */
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
@@ -16,7 +34,7 @@ import java.util.Map;
  * @author gmcarstairs
  *
  */
-public class HelpLinksChecker
+public class HelpLinksChecker implements BufferedLineReader.LineCleaner
 {
   private static final String HELP_HS = "help.hs";
 
@@ -34,6 +52,8 @@ public class HelpLinksChecker
 
   private int anchorRefCount = 0;
 
+  private int invalidAnchorRefCount = 0;
+
   private int externalHrefCount = 0;
 
   private int invalidMapUrlCount = 0;
@@ -62,7 +82,7 @@ public class HelpLinksChecker
     if (args.length == 0 || args.length > 2
             || (args.length == 2 && !args[1].equals("-nointernet")))
     {
-      System.out.println("Usage: <pathToHelpFolder> [-nointernet]");
+      log("Usage: <pathToHelpFolder> [-nointernet]");
       return;
     }
 
@@ -82,11 +102,11 @@ public class HelpLinksChecker
    */
   void checkLinks(String helpDirectoryPath) throws IOException
   {
-    System.out.println("Checking help file links");
-    File helpFolder = new File(helpDirectoryPath);
+    log("Checking help file links");
+    File helpFolder = new File(helpDirectoryPath).getCanonicalFile();
     if (!helpFolder.exists())
     {
-      System.out.println("Can't find " + helpDirectoryPath);
+      log("Can't find " + helpDirectoryPath);
       return;
     }
 
@@ -157,9 +177,8 @@ public class HelpLinksChecker
         unusedTargets.remove(image);
         if (!tocTargets.containsKey(image))
         {
-          System.out.println(String.format(
-                  "Invalid image '%s' at line %d of %s", image, lineNo,
-                  HELP_HS));
+          log(String.format("Invalid image '%s' at line %d of %s", image,
+                  lineNo, HELP_HS));
           invalidImageCount++;
         }
       }
@@ -175,35 +194,46 @@ public class HelpLinksChecker
    */
   private void reportResults(Map<String, String> unusedTargets)
   {
-    System.out.println("\nResults:");
-    System.out.println(targetCount + " distinct help targets");
-    System.out.println(mapCount + " help mappings");
-    System.out.println(invalidTargetCount + " invalid targets");
-    System.out.println(unusedTargets.size() + " unused targets");
+    log("\nResults:");
+    log(targetCount + " distinct help targets");
+    log(mapCount + " help mappings");
+    log(invalidTargetCount + " invalid targets");
+    log(unusedTargets.size() + " unused targets");
     for (String target : unusedTargets.keySet())
     {
-      System.out.println(String.format("    %s: %s", target,
-              unusedTargets.get(target)));
+      log(String.format("    %s: %s", target, unusedTargets.get(target)));
     }
-    System.out.println(invalidMapUrlCount + " invalid map urls");
-    System.out.println(invalidImageCount + " invalid image attributes");
-    System.out.println(String.format(
-            "%d internal href links (%d with anchors - not checked)",
+    log(invalidMapUrlCount + " invalid map urls");
+    log(invalidImageCount + " invalid image attributes");
+    log(String.format("%d internal href links (%d with anchors)",
             internalHrefCount, anchorRefCount));
-    System.out.println(invalidInternalHrefCount
-            + " invalid internal href links");
-    System.out.println(externalHrefCount + " external href links");
+    log(invalidInternalHrefCount + " invalid internal href links");
+    log(invalidAnchorRefCount + " invalid internal anchor links");
+    log(externalHrefCount + " external href links");
     if (internetAvailable)
     {
-      System.out.println(invalidExternalHrefCount
-              + " invalid external href links");
+      log(invalidExternalHrefCount + " invalid external href links");
     }
     else
     {
       System.out
               .println("External links not verified as internet not available");
     }
+    if (invalidInternalHrefCount > 0 || invalidExternalHrefCount > 0
+            || invalidImageCount > 0 || invalidAnchorRefCount > 0)
+    {
+      log("*** Failed ***");
+      System.exit(1);
+    }
+    log("*** Success ***");
+  }
 
+  /**
+   * @param s
+   */
+  static void log(String s)
+  {
+    System.out.println(s);
   }
 
   /**
@@ -254,7 +284,7 @@ public class HelpLinksChecker
           internalHrefCount++;
           File hrefFile = href.equals("") ? htmlFile : new File(htmlFolder,
                   href);
-          if (!hrefFile.exists())
+          if (hrefFile != htmlFile && !fileExists(hrefFile, href))
           {
             badLink = true;
             invalidInternalHrefCount++;
@@ -266,18 +296,17 @@ public class HelpLinksChecker
             {
               if (!checkAnchorExists(hrefFile, anchor))
               {
-                System.out.println(String.format(
-                        "Invalid anchor: %s at line %d of %s", anchor,
-                        lineNo, getPath(htmlFile)));
+                log(String.format("Invalid anchor: %s at line %d of %s",
+                        anchor, lineNo, getPath(htmlFile)));
+                invalidAnchorRefCount++;
               }
             }
           }
         }
         if (badLink)
         {
-          System.out.println(String.format(
-                  "Invalid href %s at line %d of %s", href, lineNo,
-                  getPath(htmlFile)));
+          log(String.format("Invalid href %s at line %d of %s", href,
+                  lineNo, getPath(htmlFile)));
         }
       }
       data = br.readLine();
@@ -286,6 +315,35 @@ public class HelpLinksChecker
   }
 
   /**
+   * Performs a case-sensitive check that the href'd file exists
+   * 
+   * @param hrefFile
+   * @return
+   * @throws IOException
+   */
+  boolean fileExists(File hrefFile, String href) throws IOException
+  {
+    if (!hrefFile.exists())
+    {
+      return false;
+    }
+
+    /*
+     * On Mac or Windows, file.exists() is not case sensitive, so do an
+     * additional check with case sensitivity 
+     */
+    int slashPos = href.lastIndexOf(File.separator);
+    String expectedFileName = slashPos == -1 ? href : href
+            .substring(slashPos + 1);
+    String cp = hrefFile.getCanonicalPath();
+    slashPos = cp.lastIndexOf(File.separator);
+    String actualFileName = slashPos == -1 ? cp : cp
+            .substring(slashPos + 1);
+
+    return expectedFileName.equals(actualFileName);
+  }
+
+  /**
    * Reads the file and checks for the presence of the given html anchor
    * 
    * @param hrefFile
@@ -300,7 +358,8 @@ public class HelpLinksChecker
     try
     {
       BufferedReader br = new BufferedReader(new FileReader(hrefFile));
-      String data = br.readLine();
+      BufferedLineReader blr = new BufferedLineReader(br, 3, this);
+      String data = blr.read();
       while (data != null)
       {
         if (data.contains(nameAnchor) || data.contains(idAnchor))
@@ -308,7 +367,7 @@ public class HelpLinksChecker
           found = true;
           break;
         }
-        data = br.readLine();
+        data = blr.read();
       }
       br.close();
     } catch (IOException e)
@@ -383,7 +442,7 @@ public class HelpLinksChecker
         mapCount++;
         if (targets.containsKey(target))
         {
-          System.out.println(String.format(
+          log(String.format(
                   "Duplicate target mapping to %s at line %d of %s",
                   target, lineNo, HELP_JHM));
         }
@@ -407,9 +466,8 @@ public class HelpLinksChecker
         }
         if (!new File(helpFolder, url).exists())
         {
-          System.out.println(String.format(
-                  "Invalid url path '%s' at line %d of %s", url, lineNo,
-                  HELP_JHM));
+          log(String.format("Invalid url path '%s' at line %d of %s", url,
+                  lineNo, HELP_JHM));
           invalidMapUrlCount++;
         }
       }
@@ -450,9 +508,8 @@ public class HelpLinksChecker
         unusedTargets.remove(target);
         if (!tocTargets.containsKey(target))
         {
-          System.out.println(String.format(
-                  "Invalid target '%s' at line %d of %s", target, lineNo,
-                  HELP_TOC_XML));
+          log(String.format("Invalid target '%s' at line %d of %s", target,
+                  lineNo, HELP_TOC_XML));
           invalidTargetCount++;
         }
       }
@@ -488,4 +545,14 @@ public class HelpLinksChecker
     }
     return value;
   }
+
+  /**
+   * Trim whitespace from concatenated lines but preserve one space for valid
+   * parsing
+   */
+  @Override
+  public String cleanLine(String l)
+  {
+    return l.trim() + " ";
+  }
 }
index fc799bb..45b3425 100755 (executable)
@@ -1245,7 +1245,7 @@ and any path to a file to save to the file]]></string>
                                                                <string><![CDATA[664]]></string>
                                                        </property>
                                                        <property name="sourceName">
-                                                               <string><![CDATA[Jmol-14.2.14_2015.06.11.jar]]></string>
+                                                               <string><![CDATA[Jmol-14.6.4_2016.10.26.jar]]></string>
                                                        </property>
                                                        <property name="overrideUnixPermissions">
                                                                <boolean>false</boolean>
@@ -1263,7 +1263,7 @@ and any path to a file to save to the file]]></string>
                                                                <boolean>true</boolean>
                                                        </property>
                                                        <property name="destinationName">
-                                                               <string><![CDATA[Jmol-14.2.14_2015.06.11.jar]]></string>
+                                                               <string><![CDATA[Jmol-14.6.4_2016.10.26.jar]]></string>
                                                        </property>
                                                        <property name="fileSize">
                                                                <long>5417196</long>
index 76375d6..5518e13 100644 (file)
@@ -36,7 +36,6 @@
 //========================================================================
 //
 
-
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.DefaultHandler;
@@ -70,16 +69,15 @@ public class JettyExamplesDir
     // In this example it is the current directory but it can be configured to
     // anything that the jvm has access to.
     resource_handler.setDirectoriesListed(true);
-    resource_handler.setWelcomeFiles(new String[]
-    { "applets.html" });
+    resource_handler.setWelcomeFiles(new String[] { "applets.html" });
     resource_handler.setResourceBase(".");
 
     // Add the ResourceHandler to the server.
     // GzipHandler gzip = new GzipHandler();
     // server.setHandler(gzip);
     HandlerList handlers = new HandlerList();
-    handlers.setHandlers(new Handler[]
-    { resource_handler, new DefaultHandler() });
+    handlers.setHandlers(new Handler[] { resource_handler,
+        new DefaultHandler() });
     server.setHandler(handlers);
 
     // Start things up! By using the server.join() the server thread will join
@@ -89,5 +87,5 @@ public class JettyExamplesDir
     // for more details.
     server.start();
     server.join();
-}
+  }
 }
index 9d322df..4489a93 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * 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.
+ */
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
@@ -20,7 +40,7 @@ import java.util.regex.Pattern;
  * @author gmcarstairs
  *
  */
-public class MessageBundleChecker
+public class MessageBundleChecker implements BufferedLineReader.LineCleaner
 {
   /*
    * regex ^"[^"]*"$
@@ -192,64 +212,37 @@ public class MessageBundleChecker
       return;
     }
 
-    String[] lines = new String[bufferSize];
     BufferedReader br = new BufferedReader(new FileReader(f));
-    for (int i = 0; i < bufferSize; i++)
-    {
-      String readLine = br.readLine();
-      lines[i] = stripCommentsAndTrim(readLine);
-    }
+    BufferedLineReader blr = new BufferedLineReader(br, bufferSize, this);
 
     int lineNo = 0;
-
-    while (lines[bufferSize - 1] != null)
+    String line = blr.read();
+    while (line != null)
     {
       lineNo++;
-      inspectSourceLines(path, lineNo, lines);
-
-      for (int i = 0; i < bufferSize - 1; i++)
-      {
-        lines[i] = lines[i + 1];
-      }
-      lines[bufferSize - 1] = stripCommentsAndTrim(br.readLine());
+      inspectSourceLines(path, lineNo, line);
+      line = blr.read();
     }
     br.close();
 
   }
 
-  /*
-   * removes anything after (and including) '//'
-   */
-  private String stripCommentsAndTrim(String line)
-  {
-    if (line != null)
-    {
-      int pos = line.indexOf("//");
-      if (pos != -1)
-      {
-        line = line.substring(0, pos);
-      }
-      line = line.replace("\t", " ").trim();
-    }
-    return line;
-  }
-
   /**
    * Look for calls to MessageManager methods, possibly split over two or more
-   * lines
+   * lines that have been concatenated while parsing the file
    * 
    * @param path
    * @param lineNo
-   * @param lines
+   * @param line
    */
-  private void inspectSourceLines(String path, int lineNo, String[] lines)
+  private void inspectSourceLines(String path, int lineNo, String line)
   {
-    String lineNos = String.format("%d-%d", lineNo, lineNo + lines.length
+    String lineNos = String
+            .format("%d-%d", lineNo, lineNo + bufferSize
             - 1);
-    String combined = combineLines(lines);
     for (String method : METHODS)
     {
-      int pos = combined.indexOf(method);
+      int pos = line.indexOf(method);
       if (pos == -1)
       {
         continue;
@@ -258,7 +251,7 @@ public class MessageBundleChecker
       /*
        * extract what follows the opening bracket of the method call
        */
-      String methodArgs = combined.substring(pos + method.length()).trim();
+      String methodArgs = line.substring(pos + method.length()).trim();
       if ("".equals(methodArgs))
       {
         /*
@@ -285,7 +278,7 @@ public class MessageBundleChecker
       if (METHOD3 == method)
       {
         System.out.println(String.format("Dynamic key at %s line %s %s",
-                path.substring(sourcePath.length()), lineNos, combined));
+                path.substring(sourcePath.length()), lineNos, line));
         continue;
       }
 
@@ -293,14 +286,14 @@ public class MessageBundleChecker
       if (messageKey == null)
       {
         System.out.println(String.format("Trouble parsing %s line %s %s",
-                path.substring(sourcePath.length()), lineNos, combined));
+                path.substring(sourcePath.length()), lineNos, line));
         continue;
       }
 
       if (!(STRING_PATTERN.matcher(messageKey).matches()))
       {
         System.out.println(String.format("Dynamic key at %s line %s %s",
-                path.substring(sourcePath.length()), lineNos, combined));
+                path.substring(sourcePath.length()), lineNos, line));
         continue;
       }
 
@@ -364,22 +357,6 @@ public class MessageBundleChecker
     return endPos == -1 ? null : key.substring(0, endPos);
   }
 
-  private String combineLines(String[] lines)
-  {
-    String combined = "";
-    if (lines != null)
-    {
-      for (String line : lines)
-      {
-        if (line != null)
-        {
-          combined += line;
-        }
-      }
-    }
-    return combined;
-  }
-
   /**
    * Loads properties from Message.properties
    * 
@@ -401,4 +378,22 @@ public class MessageBundleChecker
 
   }
 
+  /**
+   * Remove any trailing comments, change tabs to space, and trim
+   */
+  @Override
+  public String cleanLine(String l)
+  {
+    if (l != null)
+    {
+      int pos = l.indexOf("//");
+      if (pos != -1)
+      {
+        l = l.substring(0, pos);
+      }
+      l = l.replace("\t", " ").trim();
+    }
+    return l;
+  }
+
 }
index 8a5f14f..85ac8e6 100644 (file)
                        Check for TODO and similar comments 
                -->
                <module name="TodoComment">
-                       <property name="format" value="(TODO)|(FIXME)|(DOCUMENT ME)"/>
+                       <property name="format" value="(TODO)|(FIXME)"/>
+                       <message key="todo.match" value="TODO or FIXME comment"/>
+               </module>
+
+               <module name="TodoComment">
+                       <property name="format" value="DOCUMENT ME"/>
+                       <message key="todo.match" value="Documentation incomplete"/>
                </module>
 
        </module>
index b11b567..b41aab3 100644 (file)
@@ -20,6 +20,7 @@
                <allow pkg="com.stevesoft.pat"/>
                
                <subpackage name="appletgui">
+               <disallow pkg="javax.swing"/>
                <disallow pkg="jalview.gui"/>
                <disallow pkg="jalview.ws"/>
                <allow pkg="org.jmol"/>
index 98747f7..8496f8b 100644 (file)
@@ -28,28 +28,32 @@ import java.util.jar.JarInputStream;
 
 public class getJavaVersion
 {
-/**
- * Takes a set of Jars and/or class files as arguments. Reports the java version for the classes
- */
+  /**
+   * Takes a set of Jars and/or class files as arguments. Reports the java
+   * version for the classes
+   */
 
   public static void main(String[] args) throws IOException
   {
-    Hashtable observed=new Hashtable();
+    Hashtable observed = new Hashtable();
     for (int i = 0; i < args.length; i++)
-      {
-        checkClassVersion(args[i], observed);
-      }
+    {
+      checkClassVersion(args[i], observed);
+    }
     printVersions(observed, System.out);
   }
-  public static void printVersions(Hashtable observed, java.io.PrintStream outs)
+
+  public static void printVersions(Hashtable observed,
+          java.io.PrintStream outs)
   {
-    if (observed.size()>0)
+    if (observed.size() > 0)
     {
-      int space=0;
-      String key=null;
-      for (Enumeration keys = observed.keys(); keys.hasMoreElements(); ) {
+      int space = 0;
+      String key = null;
+      for (Enumeration keys = observed.keys(); keys.hasMoreElements();)
+      {
         key = (String) keys.nextElement();
-        if (space++>0)
+        if (space++ > 0)
         {
           outs.print(" ");
         }
@@ -65,13 +69,13 @@ public class getJavaVersion
     String version = checkClassVersion(filename);
     if (version == null)
     {
-//      System.err.println("Reading "+filename+" as  jar:");
+      // System.err.println("Reading "+filename+" as  jar:");
       try
       {
         JarInputStream jis = new JarInputStream(new FileInputStream(
                 filename));
         JarEntry entry;
-        Hashtable perjar=new Hashtable();
+        Hashtable perjar = new Hashtable();
         while ((entry = jis.getNextJarEntry()) != null)
         {
           if (entry != null)
@@ -93,8 +97,8 @@ public class getJavaVersion
             }
           }
         }
-        System.err.println("Jar : "+filename);
-        printVersions(perjar,System.err);
+        System.err.println("Jar : " + filename);
+        printVersions(perjar, System.err);
       } catch (Exception e)
       {
 
@@ -110,12 +114,11 @@ public class getJavaVersion
   {
     if (version != null)
     {
-//      System.err.println("Version is '"+version+"'");
+      // System.err.println("Version is '"+version+"'");
       int[] vrs = (int[]) observed.get(version);
       if (vrs == null)
       {
-        vrs = new int[]
-        { 0 };
+        vrs = new int[] { 0 };
       }
       vrs[0]++;
       observed.put(version, vrs);
@@ -147,14 +150,13 @@ public class getJavaVersion
       versions.put("52.0", "1.8");
 
     }
-    String version = (String) versions.get(major + "."
-            + minor);
+    String version = (String) versions.get(major + "." + minor);
     if (version == null)
     {
       // get nearest known version
       version = (String) versions.get(major + ".0");
     }
-//    System.err.println("Version "+version);
+    // System.err.println("Version "+version);
     if (version == null)
     {
       versions.put(major + "." + minor, "Class v" + major + ".0");
@@ -171,7 +173,7 @@ public class getJavaVersion
     }
     int minor = in.readUnsignedShort();
     int major = in.readUnsignedShort();
-//    System.err.println("Version "+major+"."+minor);
+    // System.err.println("Version "+major+"."+minor);
     return parseVersions(minor, major);
   }
 
index e9e9ce7..83e4b5f 100755 (executable)
@@ -24,93 +24,87 @@ import java.util.*;
 public class help2Website
 {
 
-       public static void main(String [] args)
-       {
-               String line = "";
-               try{
-                       Hashtable targets = new Hashtable();
+  public static void main(String[] args)
+  {
+    String line = "";
+    try
+    {
+      Hashtable targets = new Hashtable();
 
-                       File toc = new File("helpTOC.xml");
-                       File jhm = new File("help.jhm");
+      File toc = new File("helpTOC.xml");
+      File jhm = new File("help.jhm");
 
-                       BufferedReader in = new BufferedReader(new FileReader(jhm));
+      BufferedReader in = new BufferedReader(new FileReader(jhm));
 
-                       PrintWriter out = new PrintWriter(new FileWriter("helpTOC.html"));
-                       out.println("<html><head><title>Jalview - Help </title></head>\n"
-                       +"<body bgcolor=#F1F1F1>\n"
-                       +"<p><center><strong>Contents</strong></center></p>\n");
+      PrintWriter out = new PrintWriter(new FileWriter("helpTOC.html"));
+      out.println("<html><head><title>Jalview - Help </title></head>\n"
+              + "<body bgcolor=#F1F1F1>\n"
+              + "<p><center><strong>Contents</strong></center></p>\n");
 
+      StringTokenizer st;
+      StringBuffer indent = new StringBuffer();
+      String target, url, text;
+      while ((line = in.readLine()) != null)
+      {
+        if (line.indexOf("target") == -1)
+          continue;
 
-                       StringTokenizer st;
-                       StringBuffer indent = new StringBuffer();
-                       String target, url, text;
-                       while( (line = in.readLine()) != null)
-                       {
-                               if(line.indexOf("target")==-1)
-                                       continue;
+        st = new StringTokenizer(line, "\"");
+        st.nextToken(); // <mapID target="
 
+        target = st.nextToken();
+        st.nextToken(); // " url="
 
-                               st = new StringTokenizer(line, "\"");
-                               st.nextToken(); //<mapID target="
+        url = st.nextToken();
+        targets.put(target, url);
+      }
 
-                               target = st.nextToken();
-                               st.nextToken(); //" url="
+      in = new BufferedReader(new FileReader(toc));
+      while ((line = in.readLine()) != null)
+      {
+        if (line.indexOf("</tocitem>") != -1)
+          indent.setLength(indent.length() - 18);
 
-                               url = st.nextToken();
-                               targets.put(target, url);
-                       }
+        if (line.indexOf("<tocitem") == -1)
+          continue;
 
-                       in = new BufferedReader(new FileReader(toc));
-                       while( (line = in.readLine()) != null)
-                       {
-                               if(line.indexOf("</tocitem>")!=-1)
-                                       indent.setLength(indent.length()-18);
+        st = new StringTokenizer(line, "\"");
+        st.nextToken();
 
-                               if(line.indexOf("<tocitem")==-1)
-                                       continue;
+        text = st.nextToken();
+        st.nextToken();
 
-                               st = new StringTokenizer(line, "\"");
-                               st.nextToken();
+        target = st.nextToken();
 
-                               text = st.nextToken();
-                               st.nextToken();
+        if (targets.get(target) != null)
+        {
+          out.println("<br>" + indent + "<a href=\"" + targets.get(target)
+                  + "\" target=bodyframe>" + text + "</a>");
+        }
+        else
+          out.println("<br>" + indent + text);
 
-                               target = st.nextToken();
+        if (line.indexOf("/>") == -1)
+          indent.append("&nbsp;&nbsp;&nbsp;");
 
-                               if(targets.get(target)!=null)
-                               {
-                                       out.println("<br>"+indent+"<a href=\""
-                                                       + targets.get(target)
-                                                       +"\" target=bodyframe>"
-                                                       +text
-                                                       +"</a>");
-                               }
-                               else
-                                       out.println("<br>"+indent+text);
+      }
+      // Add Googletracker.
 
+      out.close();
 
-                               if(line.indexOf("/>")==-1)
-                                       indent.append("&nbsp;&nbsp;&nbsp;");
+    }
 
-                       }
-                       // Add Googletracker.
+    catch (Exception ex)
+    {
 
+      ex.printStackTrace();
 
-                       out.close();
-
-               }
-
-               catch(Exception ex)
-               {
-
-                       ex.printStackTrace();
-
-                       System.out.println("\n"+line+"\n");
-
-                       System.out.println("Usage: move to Help directory. help2Website will read"
-                       +"\nhelpTOC.xml and help.jhm producing output helpTOC.html");
-               }
-       }
+      System.out.println("\n" + line + "\n");
 
+      System.out
+              .println("Usage: move to Help directory. help2Website will read"
+                      + "\nhelpTOC.xml and help.jhm producing output helpTOC.html");
+    }
+  }
 
 }